4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
64 isTouch = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
212 sb = function(){sp.apply(this, arguments);};
214 var F = function(){}, sbp, spp = sp.prototype;
216 sbp = sb.prototype = new F();
220 if(spp.constructor == Object.prototype.constructor){
225 sb.override = function(o){
229 Roo.override(sb, overrides);
235 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
237 Roo.override(MyClass, {
238 newMethod1: function(){
241 newMethod2: function(foo){
246 * @param {Object} origclass The class to override
247 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
248 * containing one or more methods.
251 override : function(origclass, overrides){
253 var p = origclass.prototype;
254 for(var method in overrides){
255 p[method] = overrides[method];
260 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
266 * @param {String} namespace1
267 * @param {String} namespace2
268 * @param {String} etc
271 namespace : function(){
272 var a=arguments, o=null, i, j, d, rt;
273 for (i=0; i<a.length; ++i) {
277 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278 for (j=1; j<d.length; ++j) {
279 o[d[j]]=o[d[j]] || {};
285 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
290 * @param {String} classname
291 * @param {String} namespace (optional)
295 factory : function(c, ns)
297 // no xtype, no ns or c.xns - or forced off by c.xns
298 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
301 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302 if (c.constructor == ns[c.xtype]) {// already created...
306 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307 var ret = new ns[c.xtype](c);
311 c.xns = false; // prevent recursion..
315 * Logs to console if it can.
317 * @param {String|Object} string
322 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
329 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
333 urlEncode : function(o){
339 var ov = o[key], k = Roo.encodeURIComponent(key);
340 var type = typeof ov;
341 if(type == 'undefined'){
343 }else if(type != "function" && type != "object"){
344 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345 }else if(ov instanceof Array){
347 for(var i = 0, len = ov.length; i < len; i++) {
348 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
359 * Safe version of encodeURIComponent
360 * @param {String} data
364 encodeURIComponent : function (data)
367 return encodeURIComponent(data);
368 } catch(e) {} // should be an uri encode error.
370 if (data == '' || data == null){
373 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374 function nibble_to_hex(nibble){
375 var chars = '0123456789ABCDEF';
376 return chars.charAt(nibble);
378 data = data.toString();
380 for(var i=0; i<data.length; i++){
381 var c = data.charCodeAt(i);
382 var bs = new Array();
385 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388 bs[3] = 0x80 | (c & 0x3F);
389 }else if (c > 0x800){
391 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393 bs[2] = 0x80 | (c & 0x3F);
396 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397 bs[1] = 0x80 | (c & 0x3F);
402 for(var j=0; j<bs.length; j++){
404 var hex = nibble_to_hex((b & 0xF0) >>> 4)
405 + nibble_to_hex(b &0x0F);
414 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415 * @param {String} string
416 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417 * @return {Object} A literal with members
419 urlDecode : function(string, overwrite){
420 if(!string || !string.length){
424 var pairs = string.split('&');
425 var pair, name, value;
426 for(var i = 0, len = pairs.length; i < len; i++){
427 pair = pairs[i].split('=');
428 name = decodeURIComponent(pair[0]);
429 value = decodeURIComponent(pair[1]);
430 if(overwrite !== true){
431 if(typeof obj[name] == "undefined"){
433 }else if(typeof obj[name] == "string"){
434 obj[name] = [obj[name]];
435 obj[name].push(value);
437 obj[name].push(value);
447 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448 * passed array is not really an array, your function is called once with it.
449 * The supplied function is called with (Object item, Number index, Array allItems).
450 * @param {Array/NodeList/Mixed} array
451 * @param {Function} fn
452 * @param {Object} scope
454 each : function(array, fn, scope){
455 if(typeof array.length == "undefined" || typeof array == "string"){
458 for(var i = 0, len = array.length; i < len; i++){
459 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
464 combine : function(){
465 var as = arguments, l = as.length, r = [];
466 for(var i = 0; i < l; i++){
468 if(a instanceof Array){
470 }else if(a.length !== undefined && !a.substr){
471 r = r.concat(Array.prototype.slice.call(a, 0));
480 * Escapes the passed string for use in a regular expression
481 * @param {String} str
484 escapeRe : function(s) {
485 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
489 callback : function(cb, scope, args, delay){
490 if(typeof cb == "function"){
492 cb.defer(delay, scope, args || []);
494 cb.apply(scope, args || []);
500 * Return the dom node for the passed string (id), dom node, or Roo.Element
501 * @param {String/HTMLElement/Roo.Element} el
502 * @return HTMLElement
504 getDom : function(el){
508 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
512 * Shorthand for {@link Roo.ComponentMgr#get}
514 * @return Roo.Component
516 getCmp : function(id){
517 return Roo.ComponentMgr.get(id);
520 num : function(v, defaultValue){
521 if(typeof v != 'number'){
527 destroy : function(){
528 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
532 as.removeAllListeners();
536 if(typeof as.purgeListeners == 'function'){
539 if(typeof as.destroy == 'function'){
546 // inpired by a similar function in mootools library
548 * Returns the type of object that is passed in. If the object passed in is null or undefined it
549 * return false otherwise it returns one of the following values:<ul>
550 * <li><b>string</b>: If the object passed is a string</li>
551 * <li><b>number</b>: If the object passed is a number</li>
552 * <li><b>boolean</b>: If the object passed is a boolean value</li>
553 * <li><b>function</b>: If the object passed is a function reference</li>
554 * <li><b>object</b>: If the object passed is an object</li>
555 * <li><b>array</b>: If the object passed is an array</li>
556 * <li><b>regexp</b>: If the object passed is a regular expression</li>
557 * <li><b>element</b>: If the object passed is a DOM Element</li>
558 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561 * @param {Mixed} object
565 if(o === undefined || o === null){
572 if(t == 'object' && o.nodeName) {
574 case 1: return 'element';
575 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
578 if(t == 'object' || t == 'function') {
579 switch(o.constructor) {
580 case Array: return 'array';
581 case RegExp: return 'regexp';
583 if(typeof o.length == 'number' && typeof o.item == 'function') {
591 * Returns true if the passed value is null, undefined or an empty string (optional).
592 * @param {Mixed} value The value to test
593 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
596 isEmpty : function(v, allowBlank){
597 return v === null || v === undefined || (!allowBlank ? v === '' : false);
611 isBorderBox : isBorderBox,
613 isWindows : isWindows,
622 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
623 * you may want to set this to true.
626 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
631 * Selects a single element as a Roo Element
632 * This is about as close as you can get to jQuery's $('do crazy stuff')
633 * @param {String} selector The selector/xpath query
634 * @param {Node} root (optional) The start of the query (defaults to document).
635 * @return {Roo.Element}
637 selectNode : function(selector, root)
639 var node = Roo.DomQuery.selectNode(selector,root);
640 return node ? Roo.get(node) : new Roo.Element(false);
648 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
649 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
652 * Ext JS Library 1.1.1
653 * Copyright(c) 2006-2007, Ext JS, LLC.
655 * Originally Released Under LGPL - original licence link has changed is not relivant.
658 * <script type="text/javascript">
662 // wrappedn so fnCleanup is not in global scope...
664 function fnCleanUp() {
665 var p = Function.prototype;
666 delete p.createSequence;
668 delete p.createDelegate;
669 delete p.createCallback;
670 delete p.createInterceptor;
672 window.detachEvent("onunload", fnCleanUp);
674 window.attachEvent("onunload", fnCleanUp);
681 * These functions are available on every Function object (any JavaScript function).
683 Roo.apply(Function.prototype, {
685 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
686 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
687 * Will create a function that is bound to those 2 args.
688 * @return {Function} The new function
690 createCallback : function(/*args...*/){
691 // make args available, in function below
692 var args = arguments;
695 return method.apply(window, args);
700 * Creates a delegate (callback) that sets the scope to obj.
701 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
702 * Will create a function that is automatically scoped to this.
703 * @param {Object} obj (optional) The object for which the scope is set
704 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
705 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
706 * if a number the args are inserted at the specified position
707 * @return {Function} The new function
709 createDelegate : function(obj, args, appendArgs){
712 var callArgs = args || arguments;
713 if(appendArgs === true){
714 callArgs = Array.prototype.slice.call(arguments, 0);
715 callArgs = callArgs.concat(args);
716 }else if(typeof appendArgs == "number"){
717 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
718 var applyArgs = [appendArgs, 0].concat(args); // create method call params
719 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
721 return method.apply(obj || window, callArgs);
726 * Calls this function after the number of millseconds specified.
727 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
728 * @param {Object} obj (optional) The object for which the scope is set
729 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
730 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
731 * if a number the args are inserted at the specified position
732 * @return {Number} The timeout id that can be used with clearTimeout
734 defer : function(millis, obj, args, appendArgs){
735 var fn = this.createDelegate(obj, args, appendArgs);
737 return setTimeout(fn, millis);
743 * Create a combined function call sequence of the original function + the passed function.
744 * The resulting function returns the results of the original function.
745 * The passed fcn is called with the parameters of the original function
746 * @param {Function} fcn The function to sequence
747 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
748 * @return {Function} The new function
750 createSequence : function(fcn, scope){
751 if(typeof fcn != "function"){
756 var retval = method.apply(this || window, arguments);
757 fcn.apply(scope || this || window, arguments);
763 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
764 * The resulting function returns the results of the original function.
765 * The passed fcn is called with the parameters of the original function.
767 * @param {Function} fcn The function to call before the original
768 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
769 * @return {Function} The new function
771 createInterceptor : function(fcn, scope){
772 if(typeof fcn != "function"){
779 if(fcn.apply(scope || this || window, arguments) === false){
782 return method.apply(this || window, arguments);
788 * Ext JS Library 1.1.1
789 * Copyright(c) 2006-2007, Ext JS, LLC.
791 * Originally Released Under LGPL - original licence link has changed is not relivant.
794 * <script type="text/javascript">
797 Roo.applyIf(String, {
802 * Escapes the passed string for ' and \
803 * @param {String} string The string to escape
804 * @return {String} The escaped string
807 escape : function(string) {
808 return string.replace(/('|\\)/g, "\\$1");
812 * Pads the left side of a string with a specified character. This is especially useful
813 * for normalizing number and date strings. Example usage:
815 var s = String.leftPad('123', 5, '0');
816 // s now contains the string: '00123'
818 * @param {String} string The original string
819 * @param {Number} size The total length of the output string
820 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
821 * @return {String} The padded string
824 leftPad : function (val, size, ch) {
825 var result = new String(val);
826 if(ch === null || ch === undefined || ch === '') {
829 while (result.length < size) {
830 result = ch + result;
836 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
837 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
839 var cls = 'my-class', text = 'Some text';
840 var s = String.format('<div class="{0}">{1}</div>', cls, text);
841 // s now contains the string: '<div class="my-class">Some text</div>'
843 * @param {String} string The tokenized string to be formatted
844 * @param {String} value1 The value to replace token {0}
845 * @param {String} value2 Etc...
846 * @return {String} The formatted string
849 format : function(format){
850 var args = Array.prototype.slice.call(arguments, 1);
851 return format.replace(/\{(\d+)\}/g, function(m, i){
852 return Roo.util.Format.htmlEncode(args[i]);
858 * Utility function that allows you to easily switch a string between two alternating values. The passed value
859 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
860 * they are already different, the first value passed in is returned. Note that this method returns the new value
861 * but does not change the current string.
863 // alternate sort directions
864 sort = sort.toggle('ASC', 'DESC');
866 // instead of conditional logic:
867 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
869 * @param {String} value The value to compare to the current string
870 * @param {String} other The new value to use if the string already equals the first value passed in
871 * @return {String} The new value
874 String.prototype.toggle = function(value, other){
875 return this == value ? other : value;
878 * Ext JS Library 1.1.1
879 * Copyright(c) 2006-2007, Ext JS, LLC.
881 * Originally Released Under LGPL - original licence link has changed is not relivant.
884 * <script type="text/javascript">
890 Roo.applyIf(Number.prototype, {
892 * Checks whether or not the current number is within a desired range. If the number is already within the
893 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
894 * exceeded. Note that this method returns the constrained value but does not change the current number.
895 * @param {Number} min The minimum number in the range
896 * @param {Number} max The maximum number in the range
897 * @return {Number} The constrained value if outside the range, otherwise the current value
899 constrain : function(min, max){
900 return Math.min(Math.max(this, min), max);
904 * Ext JS Library 1.1.1
905 * Copyright(c) 2006-2007, Ext JS, LLC.
907 * Originally Released Under LGPL - original licence link has changed is not relivant.
910 * <script type="text/javascript">
915 Roo.applyIf(Array.prototype, {
917 * Checks whether or not the specified object exists in the array.
918 * @param {Object} o The object to check for
919 * @return {Number} The index of o in the array (or -1 if it is not found)
921 indexOf : function(o){
922 for (var i = 0, len = this.length; i < len; i++){
923 if(this[i] == o) return i;
929 * Removes the specified object from the array. If the object is not found nothing happens.
930 * @param {Object} o The object to remove
932 remove : function(o){
933 var index = this.indexOf(o);
935 this.splice(index, 1);
939 * Map (JS 1.6 compatibility)
940 * @param {Function} function to call
944 var len = this.length >>> 0;
945 if (typeof fun != "function")
946 throw new TypeError();
948 var res = new Array(len);
949 var thisp = arguments[1];
950 for (var i = 0; i < len; i++)
953 res[i] = fun.call(thisp, this[i], i, this);
964 * Ext JS Library 1.1.1
965 * Copyright(c) 2006-2007, Ext JS, LLC.
967 * Originally Released Under LGPL - original licence link has changed is not relivant.
970 * <script type="text/javascript">
976 * The date parsing and format syntax is a subset of
977 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
978 * supported will provide results equivalent to their PHP versions.
980 * Following is the list of all currently supported formats:
983 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
985 Format Output Description
986 ------ ---------- --------------------------------------------------------------
987 d 10 Day of the month, 2 digits with leading zeros
988 D Wed A textual representation of a day, three letters
989 j 10 Day of the month without leading zeros
990 l Wednesday A full textual representation of the day of the week
991 S th English ordinal day of month suffix, 2 chars (use with j)
992 w 3 Numeric representation of the day of the week
993 z 9 The julian date, or day of the year (0-365)
994 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
995 F January A full textual representation of the month
996 m 01 Numeric representation of a month, with leading zeros
997 M Jan Month name abbreviation, three letters
998 n 1 Numeric representation of a month, without leading zeros
999 t 31 Number of days in the given month
1000 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1001 Y 2007 A full numeric representation of a year, 4 digits
1002 y 07 A two digit representation of a year
1003 a pm Lowercase Ante meridiem and Post meridiem
1004 A PM Uppercase Ante meridiem and Post meridiem
1005 g 3 12-hour format of an hour without leading zeros
1006 G 15 24-hour format of an hour without leading zeros
1007 h 03 12-hour format of an hour with leading zeros
1008 H 15 24-hour format of an hour with leading zeros
1009 i 05 Minutes with leading zeros
1010 s 01 Seconds, with leading zeros
1011 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1012 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1013 T CST Timezone setting of the machine running the code
1014 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1017 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1019 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1020 document.write(dt.format('Y-m-d')); //2007-01-10
1021 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1022 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1025 * Here are some standard date/time patterns that you might find helpful. They
1026 * are not part of the source of Date.js, but to use them you can simply copy this
1027 * block of code into any script that is included after Date.js and they will also become
1028 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1031 ISO8601Long:"Y-m-d H:i:s",
1032 ISO8601Short:"Y-m-d",
1034 LongDate: "l, F d, Y",
1035 FullDateTime: "l, F d, Y g:i:s A",
1038 LongTime: "g:i:s A",
1039 SortableDateTime: "Y-m-d\\TH:i:s",
1040 UniversalSortableDateTime: "Y-m-d H:i:sO",
1047 var dt = new Date();
1048 document.write(dt.format(Date.patterns.ShortDate));
1053 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1054 * They generate precompiled functions from date formats instead of parsing and
1055 * processing the pattern every time you format a date. These functions are available
1056 * on every Date object (any javascript function).
1058 * The original article and download are here:
1059 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1066 Returns the number of milliseconds between this date and date
1067 @param {Date} date (optional) Defaults to now
1068 @return {Number} The diff in milliseconds
1069 @member Date getElapsed
1071 Date.prototype.getElapsed = function(date) {
1072 return Math.abs((date || new Date()).getTime()-this.getTime());
1074 // was in date file..
1078 Date.parseFunctions = {count:0};
1080 Date.parseRegexes = [];
1082 Date.formatFunctions = {count:0};
1085 Date.prototype.dateFormat = function(format) {
1086 if (Date.formatFunctions[format] == null) {
1087 Date.createNewFormat(format);
1089 var func = Date.formatFunctions[format];
1090 return this[func]();
1095 * Formats a date given the supplied format string
1096 * @param {String} format The format string
1097 * @return {String} The formatted date
1100 Date.prototype.format = Date.prototype.dateFormat;
1103 Date.createNewFormat = function(format) {
1104 var funcName = "format" + Date.formatFunctions.count++;
1105 Date.formatFunctions[format] = funcName;
1106 var code = "Date.prototype." + funcName + " = function(){return ";
1107 var special = false;
1109 for (var i = 0; i < format.length; ++i) {
1110 ch = format.charAt(i);
1111 if (!special && ch == "\\") {
1116 code += "'" + String.escape(ch) + "' + ";
1119 code += Date.getFormatCode(ch);
1122 /** eval:var:zzzzzzzzzzzzz */
1123 eval(code.substring(0, code.length - 3) + ";}");
1127 Date.getFormatCode = function(character) {
1128 switch (character) {
1130 return "String.leftPad(this.getDate(), 2, '0') + ";
1132 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1134 return "this.getDate() + ";
1136 return "Date.dayNames[this.getDay()] + ";
1138 return "this.getSuffix() + ";
1140 return "this.getDay() + ";
1142 return "this.getDayOfYear() + ";
1144 return "this.getWeekOfYear() + ";
1146 return "Date.monthNames[this.getMonth()] + ";
1148 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1150 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1152 return "(this.getMonth() + 1) + ";
1154 return "this.getDaysInMonth() + ";
1156 return "(this.isLeapYear() ? 1 : 0) + ";
1158 return "this.getFullYear() + ";
1160 return "('' + this.getFullYear()).substring(2, 4) + ";
1162 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1164 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1166 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1168 return "this.getHours() + ";
1170 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1172 return "String.leftPad(this.getHours(), 2, '0') + ";
1174 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1176 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1178 return "this.getGMTOffset() + ";
1180 return "this.getGMTColonOffset() + ";
1182 return "this.getTimezone() + ";
1184 return "(this.getTimezoneOffset() * -60) + ";
1186 return "'" + String.escape(character) + "' + ";
1191 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1192 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1193 * the date format that is not specified will default to the current date value for that part. Time parts can also
1194 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1195 * string or the parse operation will fail.
1198 //dt = Fri May 25 2007 (current date)
1199 var dt = new Date();
1201 //dt = Thu May 25 2006 (today's month/day in 2006)
1202 dt = Date.parseDate("2006", "Y");
1204 //dt = Sun Jan 15 2006 (all date parts specified)
1205 dt = Date.parseDate("2006-1-15", "Y-m-d");
1207 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1208 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1210 * @param {String} input The unparsed date as a string
1211 * @param {String} format The format the date is in
1212 * @return {Date} The parsed date
1215 Date.parseDate = function(input, format) {
1216 if (Date.parseFunctions[format] == null) {
1217 Date.createParser(format);
1219 var func = Date.parseFunctions[format];
1220 return Date[func](input);
1225 Date.createParser = function(format) {
1226 var funcName = "parse" + Date.parseFunctions.count++;
1227 var regexNum = Date.parseRegexes.length;
1228 var currentGroup = 1;
1229 Date.parseFunctions[format] = funcName;
1231 var code = "Date." + funcName + " = function(input){\n"
1232 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1233 + "var d = new Date();\n"
1234 + "y = d.getFullYear();\n"
1235 + "m = d.getMonth();\n"
1236 + "d = d.getDate();\n"
1237 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1238 + "if (results && results.length > 0) {";
1241 var special = false;
1243 for (var i = 0; i < format.length; ++i) {
1244 ch = format.charAt(i);
1245 if (!special && ch == "\\") {
1250 regex += String.escape(ch);
1253 var obj = Date.formatCodeToRegex(ch, currentGroup);
1254 currentGroup += obj.g;
1256 if (obj.g && obj.c) {
1262 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1263 + "{v = new Date(y, m, d, h, i, s);}\n"
1264 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1265 + "{v = new Date(y, m, d, h, i);}\n"
1266 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1267 + "{v = new Date(y, m, d, h);}\n"
1268 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1269 + "{v = new Date(y, m, d);}\n"
1270 + "else if (y >= 0 && m >= 0)\n"
1271 + "{v = new Date(y, m);}\n"
1272 + "else if (y >= 0)\n"
1273 + "{v = new Date(y);}\n"
1274 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1275 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1276 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1279 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1280 /** eval:var:zzzzzzzzzzzzz */
1285 Date.formatCodeToRegex = function(character, currentGroup) {
1286 switch (character) {
1290 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1293 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1294 s:"(\\d{1,2})"}; // day of month without leading zeroes
1297 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298 s:"(\\d{2})"}; // day of month with leading zeroes
1302 s:"(?:" + Date.dayNames.join("|") + ")"};
1306 s:"(?:st|nd|rd|th)"};
1321 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1322 s:"(" + Date.monthNames.join("|") + ")"};
1325 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1326 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1329 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1330 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1333 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1345 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1349 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1350 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1354 c:"if (results[" + currentGroup + "] == 'am') {\n"
1355 + "if (h == 12) { h = 0; }\n"
1356 + "} else { if (h < 12) { h += 12; }}",
1360 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1361 + "if (h == 12) { h = 0; }\n"
1362 + "} else { if (h < 12) { h += 12; }}",
1367 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1372 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1373 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1376 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1380 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1385 "o = results[", currentGroup, "];\n",
1386 "var sn = o.substring(0,1);\n", // get + / - sign
1387 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1388 "var mn = o.substring(3,5) % 60;\n", // get minutes
1389 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1390 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1392 s:"([+\-]\\d{2,4})"};
1398 "o = results[", currentGroup, "];\n",
1399 "var sn = o.substring(0,1);\n",
1400 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1401 "var mn = o.substring(4,6) % 60;\n",
1402 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1403 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1409 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1412 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1413 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1414 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1418 s:String.escape(character)};
1423 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1424 * @return {String} The abbreviated timezone name (e.g. 'CST')
1426 Date.prototype.getTimezone = function() {
1427 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1431 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1432 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1434 Date.prototype.getGMTOffset = function() {
1435 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1436 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1437 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1441 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1442 * @return {String} 2-characters representing hours and 2-characters representing minutes
1443 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1445 Date.prototype.getGMTColonOffset = function() {
1446 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1447 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1449 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1453 * Get the numeric day number of the year, adjusted for leap year.
1454 * @return {Number} 0 through 364 (365 in leap years)
1456 Date.prototype.getDayOfYear = function() {
1458 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1459 for (var i = 0; i < this.getMonth(); ++i) {
1460 num += Date.daysInMonth[i];
1462 return num + this.getDate() - 1;
1466 * Get the string representation of the numeric week number of the year
1467 * (equivalent to the format specifier 'W').
1468 * @return {String} '00' through '52'
1470 Date.prototype.getWeekOfYear = function() {
1471 // Skip to Thursday of this week
1472 var now = this.getDayOfYear() + (4 - this.getDay());
1473 // Find the first Thursday of the year
1474 var jan1 = new Date(this.getFullYear(), 0, 1);
1475 var then = (7 - jan1.getDay() + 4);
1476 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1480 * Whether or not the current date is in a leap year.
1481 * @return {Boolean} True if the current date is in a leap year, else false
1483 Date.prototype.isLeapYear = function() {
1484 var year = this.getFullYear();
1485 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1489 * Get the first day of the current month, adjusted for leap year. The returned value
1490 * is the numeric day index within the week (0-6) which can be used in conjunction with
1491 * the {@link #monthNames} array to retrieve the textual day name.
1494 var dt = new Date('1/10/2007');
1495 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1497 * @return {Number} The day number (0-6)
1499 Date.prototype.getFirstDayOfMonth = function() {
1500 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1501 return (day < 0) ? (day + 7) : day;
1505 * Get the last day of the current month, adjusted for leap year. The returned value
1506 * is the numeric day index within the week (0-6) which can be used in conjunction with
1507 * the {@link #monthNames} array to retrieve the textual day name.
1510 var dt = new Date('1/10/2007');
1511 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1513 * @return {Number} The day number (0-6)
1515 Date.prototype.getLastDayOfMonth = function() {
1516 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1517 return (day < 0) ? (day + 7) : day;
1522 * Get the first date of this date's month
1525 Date.prototype.getFirstDateOfMonth = function() {
1526 return new Date(this.getFullYear(), this.getMonth(), 1);
1530 * Get the last date of this date's month
1533 Date.prototype.getLastDateOfMonth = function() {
1534 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1537 * Get the number of days in the current month, adjusted for leap year.
1538 * @return {Number} The number of days in the month
1540 Date.prototype.getDaysInMonth = function() {
1541 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1542 return Date.daysInMonth[this.getMonth()];
1546 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1547 * @return {String} 'st, 'nd', 'rd' or 'th'
1549 Date.prototype.getSuffix = function() {
1550 switch (this.getDate()) {
1567 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1570 * An array of textual month names.
1571 * Override these values for international dates, for example...
1572 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1591 * An array of textual day names.
1592 * Override these values for international dates, for example...
1593 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1609 Date.monthNumbers = {
1624 * Creates and returns a new Date instance with the exact same date value as the called instance.
1625 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1626 * variable will also be changed. When the intention is to create a new variable that will not
1627 * modify the original instance, you should create a clone.
1629 * Example of correctly cloning a date:
1632 var orig = new Date('10/1/2006');
1635 document.write(orig); //returns 'Thu Oct 05 2006'!
1638 var orig = new Date('10/1/2006');
1639 var copy = orig.clone();
1641 document.write(orig); //returns 'Thu Oct 01 2006'
1643 * @return {Date} The new Date instance
1645 Date.prototype.clone = function() {
1646 return new Date(this.getTime());
1650 * Clears any time information from this date
1651 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1652 @return {Date} this or the clone
1654 Date.prototype.clearTime = function(clone){
1656 return this.clone().clearTime();
1661 this.setMilliseconds(0);
1666 // safari setMonth is broken
1668 Date.brokenSetMonth = Date.prototype.setMonth;
1669 Date.prototype.setMonth = function(num){
1671 var n = Math.ceil(-num);
1672 var back_year = Math.ceil(n/12);
1673 var month = (n % 12) ? 12 - n % 12 : 0 ;
1674 this.setFullYear(this.getFullYear() - back_year);
1675 return Date.brokenSetMonth.call(this, month);
1677 return Date.brokenSetMonth.apply(this, arguments);
1682 /** Date interval constant
1686 /** Date interval constant
1690 /** Date interval constant
1694 /** Date interval constant
1698 /** Date interval constant
1702 /** Date interval constant
1706 /** Date interval constant
1712 * Provides a convenient method of performing basic date arithmetic. This method
1713 * does not modify the Date instance being called - it creates and returns
1714 * a new Date instance containing the resulting date value.
1719 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1720 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1722 //Negative values will subtract correctly:
1723 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1724 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1726 //You can even chain several calls together in one line!
1727 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1728 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1731 * @param {String} interval A valid date interval enum value
1732 * @param {Number} value The amount to add to the current date
1733 * @return {Date} The new Date instance
1735 Date.prototype.add = function(interval, value){
1736 var d = this.clone();
1737 if (!interval || value === 0) return d;
1738 switch(interval.toLowerCase()){
1740 d.setMilliseconds(this.getMilliseconds() + value);
1743 d.setSeconds(this.getSeconds() + value);
1746 d.setMinutes(this.getMinutes() + value);
1749 d.setHours(this.getHours() + value);
1752 d.setDate(this.getDate() + value);
1755 var day = this.getDate();
1757 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1760 d.setMonth(this.getMonth() + value);
1763 d.setFullYear(this.getFullYear() + value);
1770 * Ext JS Library 1.1.1
1771 * Copyright(c) 2006-2007, Ext JS, LLC.
1773 * Originally Released Under LGPL - original licence link has changed is not relivant.
1776 * <script type="text/javascript">
1780 * @class Roo.lib.Dom
1783 * Dom utils (from YIU afaik)
1788 * Get the view width
1789 * @param {Boolean} full True will get the full document, otherwise it's the view width
1790 * @return {Number} The width
1793 getViewWidth : function(full) {
1794 return full ? this.getDocumentWidth() : this.getViewportWidth();
1797 * Get the view height
1798 * @param {Boolean} full True will get the full document, otherwise it's the view height
1799 * @return {Number} The height
1801 getViewHeight : function(full) {
1802 return full ? this.getDocumentHeight() : this.getViewportHeight();
1805 getDocumentHeight: function() {
1806 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1807 return Math.max(scrollHeight, this.getViewportHeight());
1810 getDocumentWidth: function() {
1811 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1812 return Math.max(scrollWidth, this.getViewportWidth());
1815 getViewportHeight: function() {
1816 var height = self.innerHeight;
1817 var mode = document.compatMode;
1819 if ((mode || Roo.isIE) && !Roo.isOpera) {
1820 height = (mode == "CSS1Compat") ?
1821 document.documentElement.clientHeight :
1822 document.body.clientHeight;
1828 getViewportWidth: function() {
1829 var width = self.innerWidth;
1830 var mode = document.compatMode;
1832 if (mode || Roo.isIE) {
1833 width = (mode == "CSS1Compat") ?
1834 document.documentElement.clientWidth :
1835 document.body.clientWidth;
1840 isAncestor : function(p, c) {
1847 if (p.contains && !Roo.isSafari) {
1848 return p.contains(c);
1849 } else if (p.compareDocumentPosition) {
1850 return !!(p.compareDocumentPosition(c) & 16);
1852 var parent = c.parentNode;
1857 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1860 parent = parent.parentNode;
1866 getRegion : function(el) {
1867 return Roo.lib.Region.getRegion(el);
1870 getY : function(el) {
1871 return this.getXY(el)[1];
1874 getX : function(el) {
1875 return this.getXY(el)[0];
1878 getXY : function(el) {
1879 var p, pe, b, scroll, bd = document.body;
1880 el = Roo.getDom(el);
1881 var fly = Roo.lib.AnimBase.fly;
1882 if (el.getBoundingClientRect) {
1883 b = el.getBoundingClientRect();
1884 scroll = fly(document).getScroll();
1885 return [b.left + scroll.left, b.top + scroll.top];
1891 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1898 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1905 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1906 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1913 if (p != el && pe.getStyle('overflow') != 'visible') {
1921 if (Roo.isSafari && hasAbsolute) {
1926 if (Roo.isGecko && !hasAbsolute) {
1928 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1929 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1933 while (p && p != bd) {
1934 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1946 setXY : function(el, xy) {
1947 el = Roo.fly(el, '_setXY');
1949 var pts = el.translatePoints(xy);
1950 if (xy[0] !== false) {
1951 el.dom.style.left = pts.left + "px";
1953 if (xy[1] !== false) {
1954 el.dom.style.top = pts.top + "px";
1958 setX : function(el, x) {
1959 this.setXY(el, [x, false]);
1962 setY : function(el, y) {
1963 this.setXY(el, [false, y]);
1967 * Portions of this file are based on pieces of Yahoo User Interface Library
1968 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1969 * YUI licensed under the BSD License:
1970 * http://developer.yahoo.net/yui/license.txt
1971 * <script type="text/javascript">
1975 Roo.lib.Event = function() {
1976 var loadComplete = false;
1978 var unloadListeners = [];
1980 var onAvailStack = [];
1982 var lastError = null;
1995 startInterval: function() {
1996 if (!this._interval) {
1998 var callback = function() {
1999 self._tryPreloadAttach();
2001 this._interval = setInterval(callback, this.POLL_INTERVAL);
2006 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2007 onAvailStack.push({ id: p_id,
2010 override: p_override,
2011 checkReady: false });
2013 retryCount = this.POLL_RETRYS;
2014 this.startInterval();
2018 addListener: function(el, eventName, fn) {
2019 el = Roo.getDom(el);
2024 if ("unload" == eventName) {
2025 unloadListeners[unloadListeners.length] =
2026 [el, eventName, fn];
2030 var wrappedFn = function(e) {
2031 return fn(Roo.lib.Event.getEvent(e));
2034 var li = [el, eventName, fn, wrappedFn];
2036 var index = listeners.length;
2037 listeners[index] = li;
2039 this.doAdd(el, eventName, wrappedFn, false);
2045 removeListener: function(el, eventName, fn) {
2048 el = Roo.getDom(el);
2051 return this.purgeElement(el, false, eventName);
2055 if ("unload" == eventName) {
2057 for (i = 0,len = unloadListeners.length; i < len; i++) {
2058 var li = unloadListeners[i];
2061 li[1] == eventName &&
2063 unloadListeners.splice(i, 1);
2071 var cacheItem = null;
2074 var index = arguments[3];
2076 if ("undefined" == typeof index) {
2077 index = this._getCacheIndex(el, eventName, fn);
2081 cacheItem = listeners[index];
2084 if (!el || !cacheItem) {
2088 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2090 delete listeners[index][this.WFN];
2091 delete listeners[index][this.FN];
2092 listeners.splice(index, 1);
2099 getTarget: function(ev, resolveTextNode) {
2100 ev = ev.browserEvent || ev;
2101 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2102 var t = ev.target || ev.srcElement;
2103 return this.resolveTextNode(t);
2107 resolveTextNode: function(node) {
2108 if (Roo.isSafari && node && 3 == node.nodeType) {
2109 return node.parentNode;
2116 getPageX: function(ev) {
2117 ev = ev.browserEvent || ev;
2118 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2120 if (!x && 0 !== x) {
2121 x = ev.clientX || 0;
2124 x += this.getScroll()[1];
2132 getPageY: function(ev) {
2133 ev = ev.browserEvent || ev;
2134 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2136 if (!y && 0 !== y) {
2137 y = ev.clientY || 0;
2140 y += this.getScroll()[0];
2149 getXY: function(ev) {
2150 ev = ev.browserEvent || ev;
2151 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2152 return [this.getPageX(ev), this.getPageY(ev)];
2156 getRelatedTarget: function(ev) {
2157 ev = ev.browserEvent || ev;
2158 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2159 var t = ev.relatedTarget;
2161 if (ev.type == "mouseout") {
2163 } else if (ev.type == "mouseover") {
2168 return this.resolveTextNode(t);
2172 getTime: function(ev) {
2173 ev = ev.browserEvent || ev;
2174 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2176 var t = new Date().getTime();
2180 this.lastError = ex;
2189 stopEvent: function(ev) {
2190 this.stopPropagation(ev);
2191 this.preventDefault(ev);
2195 stopPropagation: function(ev) {
2196 ev = ev.browserEvent || ev;
2197 if (ev.stopPropagation) {
2198 ev.stopPropagation();
2200 ev.cancelBubble = true;
2205 preventDefault: function(ev) {
2206 ev = ev.browserEvent || ev;
2207 if(ev.preventDefault) {
2208 ev.preventDefault();
2210 ev.returnValue = false;
2215 getEvent: function(e) {
2216 var ev = e || window.event;
2218 var c = this.getEvent.caller;
2220 ev = c.arguments[0];
2221 if (ev && Event == ev.constructor) {
2231 getCharCode: function(ev) {
2232 ev = ev.browserEvent || ev;
2233 return ev.charCode || ev.keyCode || 0;
2237 _getCacheIndex: function(el, eventName, fn) {
2238 for (var i = 0,len = listeners.length; i < len; ++i) {
2239 var li = listeners[i];
2241 li[this.FN] == fn &&
2242 li[this.EL] == el &&
2243 li[this.TYPE] == eventName) {
2255 getEl: function(id) {
2256 return document.getElementById(id);
2260 clearCache: function() {
2264 _load: function(e) {
2265 loadComplete = true;
2266 var EU = Roo.lib.Event;
2270 EU.doRemove(window, "load", EU._load);
2275 _tryPreloadAttach: function() {
2284 var tryAgain = !loadComplete;
2286 tryAgain = (retryCount > 0);
2291 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2292 var item = onAvailStack[i];
2294 var el = this.getEl(item.id);
2297 if (!item.checkReady ||
2300 (document && document.body)) {
2303 if (item.override) {
2304 if (item.override === true) {
2307 scope = item.override;
2310 item.fn.call(scope, item.obj);
2311 onAvailStack[i] = null;
2314 notAvail.push(item);
2319 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2323 this.startInterval();
2325 clearInterval(this._interval);
2326 this._interval = null;
2329 this.locked = false;
2336 purgeElement: function(el, recurse, eventName) {
2337 var elListeners = this.getListeners(el, eventName);
2339 for (var i = 0,len = elListeners.length; i < len; ++i) {
2340 var l = elListeners[i];
2341 this.removeListener(el, l.type, l.fn);
2345 if (recurse && el && el.childNodes) {
2346 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2347 this.purgeElement(el.childNodes[i], recurse, eventName);
2353 getListeners: function(el, eventName) {
2354 var results = [], searchLists;
2356 searchLists = [listeners, unloadListeners];
2357 } else if (eventName == "unload") {
2358 searchLists = [unloadListeners];
2360 searchLists = [listeners];
2363 for (var j = 0; j < searchLists.length; ++j) {
2364 var searchList = searchLists[j];
2365 if (searchList && searchList.length > 0) {
2366 for (var i = 0,len = searchList.length; i < len; ++i) {
2367 var l = searchList[i];
2368 if (l && l[this.EL] === el &&
2369 (!eventName || eventName === l[this.TYPE])) {
2374 adjust: l[this.ADJ_SCOPE],
2382 return (results.length) ? results : null;
2386 _unload: function(e) {
2388 var EU = Roo.lib.Event, i, j, l, len, index;
2390 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2391 l = unloadListeners[i];
2394 if (l[EU.ADJ_SCOPE]) {
2395 if (l[EU.ADJ_SCOPE] === true) {
2398 scope = l[EU.ADJ_SCOPE];
2401 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2402 unloadListeners[i] = null;
2408 unloadListeners = null;
2410 if (listeners && listeners.length > 0) {
2411 j = listeners.length;
2414 l = listeners[index];
2416 EU.removeListener(l[EU.EL], l[EU.TYPE],
2426 EU.doRemove(window, "unload", EU._unload);
2431 getScroll: function() {
2432 var dd = document.documentElement, db = document.body;
2433 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2434 return [dd.scrollTop, dd.scrollLeft];
2436 return [db.scrollTop, db.scrollLeft];
2443 doAdd: function () {
2444 if (window.addEventListener) {
2445 return function(el, eventName, fn, capture) {
2446 el.addEventListener(eventName, fn, (capture));
2448 } else if (window.attachEvent) {
2449 return function(el, eventName, fn, capture) {
2450 el.attachEvent("on" + eventName, fn);
2459 doRemove: function() {
2460 if (window.removeEventListener) {
2461 return function (el, eventName, fn, capture) {
2462 el.removeEventListener(eventName, fn, (capture));
2464 } else if (window.detachEvent) {
2465 return function (el, eventName, fn) {
2466 el.detachEvent("on" + eventName, fn);
2478 var E = Roo.lib.Event;
2479 E.on = E.addListener;
2480 E.un = E.removeListener;
2482 if (document && document.body) {
2485 E.doAdd(window, "load", E._load);
2487 E.doAdd(window, "unload", E._unload);
2488 E._tryPreloadAttach();
2492 * Portions of this file are based on pieces of Yahoo User Interface Library
2493 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2494 * YUI licensed under the BSD License:
2495 * http://developer.yahoo.net/yui/license.txt
2496 * <script type="text/javascript">
2502 * @class Roo.lib.Ajax
2509 request : function(method, uri, cb, data, options) {
2511 var hs = options.headers;
2514 if(hs.hasOwnProperty(h)){
2515 this.initHeader(h, hs[h], false);
2519 if(options.xmlData){
2520 this.initHeader('Content-Type', 'text/xml', false);
2522 data = options.xmlData;
2526 return this.asyncRequest(method, uri, cb, data);
2529 serializeForm : function(form) {
2530 if(typeof form == 'string') {
2531 form = (document.getElementById(form) || document.forms[form]);
2534 var el, name, val, disabled, data = '', hasSubmit = false;
2535 for (var i = 0; i < form.elements.length; i++) {
2536 el = form.elements[i];
2537 disabled = form.elements[i].disabled;
2538 name = form.elements[i].name;
2539 val = form.elements[i].value;
2541 if (!disabled && name){
2545 case 'select-multiple':
2546 for (var j = 0; j < el.options.length; j++) {
2547 if (el.options[j].selected) {
2549 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2552 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2560 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2573 if(hasSubmit == false) {
2574 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2579 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2584 data = data.substr(0, data.length - 1);
2592 useDefaultHeader:true,
2594 defaultPostHeader:'application/x-www-form-urlencoded',
2596 useDefaultXhrHeader:true,
2598 defaultXhrHeader:'XMLHttpRequest',
2600 hasDefaultHeaders:true,
2612 setProgId:function(id)
2614 this.activeX.unshift(id);
2617 setDefaultPostHeader:function(b)
2619 this.useDefaultHeader = b;
2622 setDefaultXhrHeader:function(b)
2624 this.useDefaultXhrHeader = b;
2627 setPollingInterval:function(i)
2629 if (typeof i == 'number' && isFinite(i)) {
2630 this.pollInterval = i;
2634 createXhrObject:function(transactionId)
2640 http = new XMLHttpRequest();
2642 obj = { conn:http, tId:transactionId };
2646 for (var i = 0; i < this.activeX.length; ++i) {
2650 http = new ActiveXObject(this.activeX[i]);
2652 obj = { conn:http, tId:transactionId };
2665 getConnectionObject:function()
2668 var tId = this.transactionId;
2672 o = this.createXhrObject(tId);
2674 this.transactionId++;
2685 asyncRequest:function(method, uri, callback, postData)
2687 var o = this.getConnectionObject();
2693 o.conn.open(method, uri, true);
2695 if (this.useDefaultXhrHeader) {
2696 if (!this.defaultHeaders['X-Requested-With']) {
2697 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2701 if(postData && this.useDefaultHeader){
2702 this.initHeader('Content-Type', this.defaultPostHeader);
2705 if (this.hasDefaultHeaders || this.hasHeaders) {
2709 this.handleReadyState(o, callback);
2710 o.conn.send(postData || null);
2716 handleReadyState:function(o, callback)
2720 if (callback && callback.timeout) {
2722 this.timeout[o.tId] = window.setTimeout(function() {
2723 oConn.abort(o, callback, true);
2724 }, callback.timeout);
2727 this.poll[o.tId] = window.setInterval(
2729 if (o.conn && o.conn.readyState == 4) {
2730 window.clearInterval(oConn.poll[o.tId]);
2731 delete oConn.poll[o.tId];
2733 if(callback && callback.timeout) {
2734 window.clearTimeout(oConn.timeout[o.tId]);
2735 delete oConn.timeout[o.tId];
2738 oConn.handleTransactionResponse(o, callback);
2741 , this.pollInterval);
2744 handleTransactionResponse:function(o, callback, isAbort)
2748 this.releaseObject(o);
2752 var httpStatus, responseObject;
2756 if (o.conn.status !== undefined && o.conn.status != 0) {
2757 httpStatus = o.conn.status;
2769 if (httpStatus >= 200 && httpStatus < 300) {
2770 responseObject = this.createResponseObject(o, callback.argument);
2771 if (callback.success) {
2772 if (!callback.scope) {
2773 callback.success(responseObject);
2778 callback.success.apply(callback.scope, [responseObject]);
2783 switch (httpStatus) {
2791 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2792 if (callback.failure) {
2793 if (!callback.scope) {
2794 callback.failure(responseObject);
2797 callback.failure.apply(callback.scope, [responseObject]);
2802 responseObject = this.createResponseObject(o, callback.argument);
2803 if (callback.failure) {
2804 if (!callback.scope) {
2805 callback.failure(responseObject);
2808 callback.failure.apply(callback.scope, [responseObject]);
2814 this.releaseObject(o);
2815 responseObject = null;
2818 createResponseObject:function(o, callbackArg)
2825 var headerStr = o.conn.getAllResponseHeaders();
2826 var header = headerStr.split('\n');
2827 for (var i = 0; i < header.length; i++) {
2828 var delimitPos = header[i].indexOf(':');
2829 if (delimitPos != -1) {
2830 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2838 obj.status = o.conn.status;
2839 obj.statusText = o.conn.statusText;
2840 obj.getResponseHeader = headerObj;
2841 obj.getAllResponseHeaders = headerStr;
2842 obj.responseText = o.conn.responseText;
2843 obj.responseXML = o.conn.responseXML;
2845 if (typeof callbackArg !== undefined) {
2846 obj.argument = callbackArg;
2852 createExceptionObject:function(tId, callbackArg, isAbort)
2855 var COMM_ERROR = 'communication failure';
2856 var ABORT_CODE = -1;
2857 var ABORT_ERROR = 'transaction aborted';
2863 obj.status = ABORT_CODE;
2864 obj.statusText = ABORT_ERROR;
2867 obj.status = COMM_CODE;
2868 obj.statusText = COMM_ERROR;
2872 obj.argument = callbackArg;
2878 initHeader:function(label, value, isDefault)
2880 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2882 if (headerObj[label] === undefined) {
2883 headerObj[label] = value;
2888 headerObj[label] = value + "," + headerObj[label];
2892 this.hasDefaultHeaders = true;
2895 this.hasHeaders = true;
2900 setHeader:function(o)
2902 if (this.hasDefaultHeaders) {
2903 for (var prop in this.defaultHeaders) {
2904 if (this.defaultHeaders.hasOwnProperty(prop)) {
2905 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2910 if (this.hasHeaders) {
2911 for (var prop in this.headers) {
2912 if (this.headers.hasOwnProperty(prop)) {
2913 o.conn.setRequestHeader(prop, this.headers[prop]);
2917 this.hasHeaders = false;
2921 resetDefaultHeaders:function() {
2922 delete this.defaultHeaders;
2923 this.defaultHeaders = {};
2924 this.hasDefaultHeaders = false;
2927 abort:function(o, callback, isTimeout)
2929 if(this.isCallInProgress(o)) {
2931 window.clearInterval(this.poll[o.tId]);
2932 delete this.poll[o.tId];
2934 delete this.timeout[o.tId];
2937 this.handleTransactionResponse(o, callback, true);
2947 isCallInProgress:function(o)
2950 return o.conn.readyState != 4 && o.conn.readyState != 0;
2959 releaseObject:function(o)
2968 'MSXML2.XMLHTTP.3.0',
2976 * Portions of this file are based on pieces of Yahoo User Interface Library
2977 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2978 * YUI licensed under the BSD License:
2979 * http://developer.yahoo.net/yui/license.txt
2980 * <script type="text/javascript">
2984 Roo.lib.Region = function(t, r, b, l) {
2994 Roo.lib.Region.prototype = {
2995 contains : function(region) {
2996 return ( region.left >= this.left &&
2997 region.right <= this.right &&
2998 region.top >= this.top &&
2999 region.bottom <= this.bottom );
3003 getArea : function() {
3004 return ( (this.bottom - this.top) * (this.right - this.left) );
3007 intersect : function(region) {
3008 var t = Math.max(this.top, region.top);
3009 var r = Math.min(this.right, region.right);
3010 var b = Math.min(this.bottom, region.bottom);
3011 var l = Math.max(this.left, region.left);
3013 if (b >= t && r >= l) {
3014 return new Roo.lib.Region(t, r, b, l);
3019 union : function(region) {
3020 var t = Math.min(this.top, region.top);
3021 var r = Math.max(this.right, region.right);
3022 var b = Math.max(this.bottom, region.bottom);
3023 var l = Math.min(this.left, region.left);
3025 return new Roo.lib.Region(t, r, b, l);
3028 adjust : function(t, l, b, r) {
3037 Roo.lib.Region.getRegion = function(el) {
3038 var p = Roo.lib.Dom.getXY(el);
3041 var r = p[0] + el.offsetWidth;
3042 var b = p[1] + el.offsetHeight;
3045 return new Roo.lib.Region(t, r, b, l);
3048 * Portions of this file are based on pieces of Yahoo User Interface Library
3049 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3050 * YUI licensed under the BSD License:
3051 * http://developer.yahoo.net/yui/license.txt
3052 * <script type="text/javascript">
3055 //@@dep Roo.lib.Region
3058 Roo.lib.Point = function(x, y) {
3059 if (x instanceof Array) {
3063 this.x = this.right = this.left = this[0] = x;
3064 this.y = this.top = this.bottom = this[1] = y;
3067 Roo.lib.Point.prototype = new Roo.lib.Region();
3069 * Portions of this file are based on pieces of Yahoo User Interface Library
3070 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3071 * YUI licensed under the BSD License:
3072 * http://developer.yahoo.net/yui/license.txt
3073 * <script type="text/javascript">
3080 scroll : function(el, args, duration, easing, cb, scope) {
3081 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3084 motion : function(el, args, duration, easing, cb, scope) {
3085 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3088 color : function(el, args, duration, easing, cb, scope) {
3089 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3092 run : function(el, args, duration, easing, cb, scope, type) {
3093 type = type || Roo.lib.AnimBase;
3094 if (typeof easing == "string") {
3095 easing = Roo.lib.Easing[easing];
3097 var anim = new type(el, args, duration, easing);
3098 anim.animateX(function() {
3099 Roo.callback(cb, scope);
3105 * Portions of this file are based on pieces of Yahoo User Interface Library
3106 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3107 * YUI licensed under the BSD License:
3108 * http://developer.yahoo.net/yui/license.txt
3109 * <script type="text/javascript">
3117 if (!libFlyweight) {
3118 libFlyweight = new Roo.Element.Flyweight();
3120 libFlyweight.dom = el;
3121 return libFlyweight;
3124 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3128 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3130 this.init(el, attributes, duration, method);
3134 Roo.lib.AnimBase.fly = fly;
3138 Roo.lib.AnimBase.prototype = {
3140 toString: function() {
3141 var el = this.getEl();
3142 var id = el.id || el.tagName;
3143 return ("Anim " + id);
3147 noNegatives: /width|height|opacity|padding/i,
3148 offsetAttribute: /^((width|height)|(top|left))$/,
3149 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3150 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3154 doMethod: function(attr, start, end) {
3155 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3159 setAttribute: function(attr, val, unit) {
3160 if (this.patterns.noNegatives.test(attr)) {
3161 val = (val > 0) ? val : 0;
3164 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3168 getAttribute: function(attr) {
3169 var el = this.getEl();
3170 var val = fly(el).getStyle(attr);
3172 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3173 return parseFloat(val);
3176 var a = this.patterns.offsetAttribute.exec(attr) || [];
3177 var pos = !!( a[3] );
3178 var box = !!( a[2] );
3181 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3182 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3191 getDefaultUnit: function(attr) {
3192 if (this.patterns.defaultUnit.test(attr)) {
3199 animateX : function(callback, scope) {
3200 var f = function() {
3201 this.onComplete.removeListener(f);
3202 if (typeof callback == "function") {
3203 callback.call(scope || this, this);
3206 this.onComplete.addListener(f, this);
3211 setRuntimeAttribute: function(attr) {
3214 var attributes = this.attributes;
3216 this.runtimeAttributes[attr] = {};
3218 var isset = function(prop) {
3219 return (typeof prop !== 'undefined');
3222 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3226 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3229 if (isset(attributes[attr]['to'])) {
3230 end = attributes[attr]['to'];
3231 } else if (isset(attributes[attr]['by'])) {
3232 if (start.constructor == Array) {
3234 for (var i = 0, len = start.length; i < len; ++i) {
3235 end[i] = start[i] + attributes[attr]['by'][i];
3238 end = start + attributes[attr]['by'];
3242 this.runtimeAttributes[attr].start = start;
3243 this.runtimeAttributes[attr].end = end;
3246 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3250 init: function(el, attributes, duration, method) {
3252 var isAnimated = false;
3255 var startTime = null;
3258 var actualFrames = 0;
3261 el = Roo.getDom(el);
3264 this.attributes = attributes || {};
3267 this.duration = duration || 1;
3270 this.method = method || Roo.lib.Easing.easeNone;
3273 this.useSeconds = true;
3276 this.currentFrame = 0;
3279 this.totalFrames = Roo.lib.AnimMgr.fps;
3282 this.getEl = function() {
3287 this.isAnimated = function() {
3292 this.getStartTime = function() {
3296 this.runtimeAttributes = {};
3299 this.animate = function() {
3300 if (this.isAnimated()) {
3304 this.currentFrame = 0;
3306 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3308 Roo.lib.AnimMgr.registerElement(this);
3312 this.stop = function(finish) {
3314 this.currentFrame = this.totalFrames;
3315 this._onTween.fire();
3317 Roo.lib.AnimMgr.stop(this);
3320 var onStart = function() {
3321 this.onStart.fire();
3323 this.runtimeAttributes = {};
3324 for (var attr in this.attributes) {
3325 this.setRuntimeAttribute(attr);
3330 startTime = new Date();
3334 var onTween = function() {
3336 duration: new Date() - this.getStartTime(),
3337 currentFrame: this.currentFrame
3340 data.toString = function() {
3342 'duration: ' + data.duration +
3343 ', currentFrame: ' + data.currentFrame
3347 this.onTween.fire(data);
3349 var runtimeAttributes = this.runtimeAttributes;
3351 for (var attr in runtimeAttributes) {
3352 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3358 var onComplete = function() {
3359 var actual_duration = (new Date() - startTime) / 1000 ;
3362 duration: actual_duration,
3363 frames: actualFrames,
3364 fps: actualFrames / actual_duration
3367 data.toString = function() {
3369 'duration: ' + data.duration +
3370 ', frames: ' + data.frames +
3371 ', fps: ' + data.fps
3377 this.onComplete.fire(data);
3381 this._onStart = new Roo.util.Event(this);
3382 this.onStart = new Roo.util.Event(this);
3383 this.onTween = new Roo.util.Event(this);
3384 this._onTween = new Roo.util.Event(this);
3385 this.onComplete = new Roo.util.Event(this);
3386 this._onComplete = new Roo.util.Event(this);
3387 this._onStart.addListener(onStart);
3388 this._onTween.addListener(onTween);
3389 this._onComplete.addListener(onComplete);
3394 * Portions of this file are based on pieces of Yahoo User Interface Library
3395 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3396 * YUI licensed under the BSD License:
3397 * http://developer.yahoo.net/yui/license.txt
3398 * <script type="text/javascript">
3402 Roo.lib.AnimMgr = new function() {
3419 this.registerElement = function(tween) {
3420 queue[queue.length] = tween;
3422 tween._onStart.fire();
3427 this.unRegister = function(tween, index) {
3428 tween._onComplete.fire();
3429 index = index || getIndex(tween);
3431 queue.splice(index, 1);
3435 if (tweenCount <= 0) {
3441 this.start = function() {
3442 if (thread === null) {
3443 thread = setInterval(this.run, this.delay);
3448 this.stop = function(tween) {
3450 clearInterval(thread);
3452 for (var i = 0, len = queue.length; i < len; ++i) {
3453 if (queue[0].isAnimated()) {
3454 this.unRegister(queue[0], 0);
3463 this.unRegister(tween);
3468 this.run = function() {
3469 for (var i = 0, len = queue.length; i < len; ++i) {
3470 var tween = queue[i];
3471 if (!tween || !tween.isAnimated()) {
3475 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3477 tween.currentFrame += 1;
3479 if (tween.useSeconds) {
3480 correctFrame(tween);
3482 tween._onTween.fire();
3485 Roo.lib.AnimMgr.stop(tween, i);
3490 var getIndex = function(anim) {
3491 for (var i = 0, len = queue.length; i < len; ++i) {
3492 if (queue[i] == anim) {
3500 var correctFrame = function(tween) {
3501 var frames = tween.totalFrames;
3502 var frame = tween.currentFrame;
3503 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3504 var elapsed = (new Date() - tween.getStartTime());
3507 if (elapsed < tween.duration * 1000) {
3508 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3510 tweak = frames - (frame + 1);
3512 if (tweak > 0 && isFinite(tweak)) {
3513 if (tween.currentFrame + tweak >= frames) {
3514 tweak = frames - (frame + 1);
3517 tween.currentFrame += tweak;
3523 * Portions of this file are based on pieces of Yahoo User Interface Library
3524 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3525 * YUI licensed under the BSD License:
3526 * http://developer.yahoo.net/yui/license.txt
3527 * <script type="text/javascript">
3530 Roo.lib.Bezier = new function() {
3532 this.getPosition = function(points, t) {
3533 var n = points.length;
3536 for (var i = 0; i < n; ++i) {
3537 tmp[i] = [points[i][0], points[i][1]];
3540 for (var j = 1; j < n; ++j) {
3541 for (i = 0; i < n - j; ++i) {
3542 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3543 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3547 return [ tmp[0][0], tmp[0][1] ];
3551 * Portions of this file are based on pieces of Yahoo User Interface Library
3552 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3553 * YUI licensed under the BSD License:
3554 * http://developer.yahoo.net/yui/license.txt
3555 * <script type="text/javascript">
3560 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3561 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3564 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3566 var fly = Roo.lib.AnimBase.fly;
3568 var superclass = Y.ColorAnim.superclass;
3569 var proto = Y.ColorAnim.prototype;
3571 proto.toString = function() {
3572 var el = this.getEl();
3573 var id = el.id || el.tagName;
3574 return ("ColorAnim " + id);
3577 proto.patterns.color = /color$/i;
3578 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3579 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3580 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3581 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3584 proto.parseColor = function(s) {
3585 if (s.length == 3) {
3589 var c = this.patterns.hex.exec(s);
3590 if (c && c.length == 4) {
3591 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3594 c = this.patterns.rgb.exec(s);
3595 if (c && c.length == 4) {
3596 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3599 c = this.patterns.hex3.exec(s);
3600 if (c && c.length == 4) {
3601 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3606 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3607 proto.getAttribute = function(attr) {
3608 var el = this.getEl();
3609 if (this.patterns.color.test(attr)) {
3610 var val = fly(el).getStyle(attr);
3612 if (this.patterns.transparent.test(val)) {
3613 var parent = el.parentNode;
3614 val = fly(parent).getStyle(attr);
3616 while (parent && this.patterns.transparent.test(val)) {
3617 parent = parent.parentNode;
3618 val = fly(parent).getStyle(attr);
3619 if (parent.tagName.toUpperCase() == 'HTML') {
3625 val = superclass.getAttribute.call(this, attr);
3630 proto.getAttribute = function(attr) {
3631 var el = this.getEl();
3632 if (this.patterns.color.test(attr)) {
3633 var val = fly(el).getStyle(attr);
3635 if (this.patterns.transparent.test(val)) {
3636 var parent = el.parentNode;
3637 val = fly(parent).getStyle(attr);
3639 while (parent && this.patterns.transparent.test(val)) {
3640 parent = parent.parentNode;
3641 val = fly(parent).getStyle(attr);
3642 if (parent.tagName.toUpperCase() == 'HTML') {
3648 val = superclass.getAttribute.call(this, attr);
3654 proto.doMethod = function(attr, start, end) {
3657 if (this.patterns.color.test(attr)) {
3659 for (var i = 0, len = start.length; i < len; ++i) {
3660 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3663 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3666 val = superclass.doMethod.call(this, attr, start, end);
3672 proto.setRuntimeAttribute = function(attr) {
3673 superclass.setRuntimeAttribute.call(this, attr);
3675 if (this.patterns.color.test(attr)) {
3676 var attributes = this.attributes;
3677 var start = this.parseColor(this.runtimeAttributes[attr].start);
3678 var end = this.parseColor(this.runtimeAttributes[attr].end);
3680 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3681 end = this.parseColor(attributes[attr].by);
3683 for (var i = 0, len = start.length; i < len; ++i) {
3684 end[i] = start[i] + end[i];
3688 this.runtimeAttributes[attr].start = start;
3689 this.runtimeAttributes[attr].end = end;
3695 * Portions of this file are based on pieces of Yahoo User Interface Library
3696 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3697 * YUI licensed under the BSD License:
3698 * http://developer.yahoo.net/yui/license.txt
3699 * <script type="text/javascript">
3705 easeNone: function (t, b, c, d) {
3706 return c * t / d + b;
3710 easeIn: function (t, b, c, d) {
3711 return c * (t /= d) * t + b;
3715 easeOut: function (t, b, c, d) {
3716 return -c * (t /= d) * (t - 2) + b;
3720 easeBoth: function (t, b, c, d) {
3721 if ((t /= d / 2) < 1) {
3722 return c / 2 * t * t + b;
3725 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3729 easeInStrong: function (t, b, c, d) {
3730 return c * (t /= d) * t * t * t + b;
3734 easeOutStrong: function (t, b, c, d) {
3735 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3739 easeBothStrong: function (t, b, c, d) {
3740 if ((t /= d / 2) < 1) {
3741 return c / 2 * t * t * t * t + b;
3744 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3749 elasticIn: function (t, b, c, d, a, p) {
3753 if ((t /= d) == 1) {
3760 if (!a || a < Math.abs(c)) {
3765 var s = p / (2 * Math.PI) * Math.asin(c / a);
3768 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3772 elasticOut: function (t, b, c, d, a, p) {
3776 if ((t /= d) == 1) {
3783 if (!a || a < Math.abs(c)) {
3788 var s = p / (2 * Math.PI) * Math.asin(c / a);
3791 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3795 elasticBoth: function (t, b, c, d, a, p) {
3800 if ((t /= d / 2) == 2) {
3808 if (!a || a < Math.abs(c)) {
3813 var s = p / (2 * Math.PI) * Math.asin(c / a);
3817 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3818 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3820 return a * Math.pow(2, -10 * (t -= 1)) *
3821 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3826 backIn: function (t, b, c, d, s) {
3827 if (typeof s == 'undefined') {
3830 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3834 backOut: function (t, b, c, d, s) {
3835 if (typeof s == 'undefined') {
3838 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3842 backBoth: function (t, b, c, d, s) {
3843 if (typeof s == 'undefined') {
3847 if ((t /= d / 2 ) < 1) {
3848 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3850 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3854 bounceIn: function (t, b, c, d) {
3855 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3859 bounceOut: function (t, b, c, d) {
3860 if ((t /= d) < (1 / 2.75)) {
3861 return c * (7.5625 * t * t) + b;
3862 } else if (t < (2 / 2.75)) {
3863 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3864 } else if (t < (2.5 / 2.75)) {
3865 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3867 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3871 bounceBoth: function (t, b, c, d) {
3873 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3875 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3878 * Portions of this file are based on pieces of Yahoo User Interface Library
3879 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3880 * YUI licensed under the BSD License:
3881 * http://developer.yahoo.net/yui/license.txt
3882 * <script type="text/javascript">
3886 Roo.lib.Motion = function(el, attributes, duration, method) {
3888 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3892 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3896 var superclass = Y.Motion.superclass;
3897 var proto = Y.Motion.prototype;
3899 proto.toString = function() {
3900 var el = this.getEl();
3901 var id = el.id || el.tagName;
3902 return ("Motion " + id);
3905 proto.patterns.points = /^points$/i;
3907 proto.setAttribute = function(attr, val, unit) {
3908 if (this.patterns.points.test(attr)) {
3909 unit = unit || 'px';
3910 superclass.setAttribute.call(this, 'left', val[0], unit);
3911 superclass.setAttribute.call(this, 'top', val[1], unit);
3913 superclass.setAttribute.call(this, attr, val, unit);
3917 proto.getAttribute = function(attr) {
3918 if (this.patterns.points.test(attr)) {
3920 superclass.getAttribute.call(this, 'left'),
3921 superclass.getAttribute.call(this, 'top')
3924 val = superclass.getAttribute.call(this, attr);
3930 proto.doMethod = function(attr, start, end) {
3933 if (this.patterns.points.test(attr)) {
3934 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3935 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3937 val = superclass.doMethod.call(this, attr, start, end);
3942 proto.setRuntimeAttribute = function(attr) {
3943 if (this.patterns.points.test(attr)) {
3944 var el = this.getEl();
3945 var attributes = this.attributes;
3947 var control = attributes['points']['control'] || [];
3951 if (control.length > 0 && !(control[0] instanceof Array)) {
3952 control = [control];
3955 for (i = 0,len = control.length; i < len; ++i) {
3956 tmp[i] = control[i];
3961 Roo.fly(el).position();
3963 if (isset(attributes['points']['from'])) {
3964 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3967 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3970 start = this.getAttribute('points');
3973 if (isset(attributes['points']['to'])) {
3974 end = translateValues.call(this, attributes['points']['to'], start);
3976 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3977 for (i = 0,len = control.length; i < len; ++i) {
3978 control[i] = translateValues.call(this, control[i], start);
3982 } else if (isset(attributes['points']['by'])) {
3983 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3985 for (i = 0,len = control.length; i < len; ++i) {
3986 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3990 this.runtimeAttributes[attr] = [start];
3992 if (control.length > 0) {
3993 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3996 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3999 superclass.setRuntimeAttribute.call(this, attr);
4003 var translateValues = function(val, start) {
4004 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4005 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4010 var isset = function(prop) {
4011 return (typeof prop !== 'undefined');
4015 * Portions of this file are based on pieces of Yahoo User Interface Library
4016 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4017 * YUI licensed under the BSD License:
4018 * http://developer.yahoo.net/yui/license.txt
4019 * <script type="text/javascript">
4023 Roo.lib.Scroll = function(el, attributes, duration, method) {
4025 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4029 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4033 var superclass = Y.Scroll.superclass;
4034 var proto = Y.Scroll.prototype;
4036 proto.toString = function() {
4037 var el = this.getEl();
4038 var id = el.id || el.tagName;
4039 return ("Scroll " + id);
4042 proto.doMethod = function(attr, start, end) {
4045 if (attr == 'scroll') {
4047 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4048 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4052 val = superclass.doMethod.call(this, attr, start, end);
4057 proto.getAttribute = function(attr) {
4059 var el = this.getEl();
4061 if (attr == 'scroll') {
4062 val = [ el.scrollLeft, el.scrollTop ];
4064 val = superclass.getAttribute.call(this, attr);
4070 proto.setAttribute = function(attr, val, unit) {
4071 var el = this.getEl();
4073 if (attr == 'scroll') {
4074 el.scrollLeft = val[0];
4075 el.scrollTop = val[1];
4077 superclass.setAttribute.call(this, attr, val, unit);
4083 * Ext JS Library 1.1.1
4084 * Copyright(c) 2006-2007, Ext JS, LLC.
4086 * Originally Released Under LGPL - original licence link has changed is not relivant.
4089 * <script type="text/javascript">
4093 // nasty IE9 hack - what a pile of crap that is..
4095 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4096 Range.prototype.createContextualFragment = function (html) {
4097 var doc = window.document;
4098 var container = doc.createElement("div");
4099 container.innerHTML = html;
4100 var frag = doc.createDocumentFragment(), n;
4101 while ((n = container.firstChild)) {
4102 frag.appendChild(n);
4109 * @class Roo.DomHelper
4110 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4111 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4114 Roo.DomHelper = function(){
4115 var tempTableEl = null;
4116 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4117 var tableRe = /^table|tbody|tr|td$/i;
4119 // build as innerHTML where available
4121 var createHtml = function(o){
4122 if(typeof o == 'string'){
4131 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4132 if(attr == "style"){
4134 if(typeof s == "function"){
4137 if(typeof s == "string"){
4138 b += ' style="' + s + '"';
4139 }else if(typeof s == "object"){
4142 if(typeof s[key] != "function"){
4143 b += key + ":" + s[key] + ";";
4150 b += ' class="' + o["cls"] + '"';
4151 }else if(attr == "htmlFor"){
4152 b += ' for="' + o["htmlFor"] + '"';
4154 b += " " + attr + '="' + o[attr] + '"';
4158 if(emptyTags.test(o.tag)){
4162 var cn = o.children || o.cn;
4164 //http://bugs.kde.org/show_bug.cgi?id=71506
4165 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4166 for(var i = 0, len = cn.length; i < len; i++) {
4167 b += createHtml(cn[i], b);
4170 b += createHtml(cn, b);
4176 b += "</" + o.tag + ">";
4183 var createDom = function(o, parentNode){
4185 // defininition craeted..
4187 if (o.ns && o.ns != 'html') {
4189 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4190 xmlns[o.ns] = o.xmlns;
4193 if (typeof(xmlns[o.ns]) == 'undefined') {
4194 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4200 if (typeof(o) == 'string') {
4201 return parentNode.appendChild(document.createTextNode(o));
4203 o.tag = o.tag || div;
4204 if (o.ns && Roo.isIE) {
4206 o.tag = o.ns + ':' + o.tag;
4209 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4210 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4213 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4214 attr == "style" || typeof o[attr] == "function") continue;
4216 if(attr=="cls" && Roo.isIE){
4217 el.className = o["cls"];
4219 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4220 else el[attr] = o[attr];
4223 Roo.DomHelper.applyStyles(el, o.style);
4224 var cn = o.children || o.cn;
4226 //http://bugs.kde.org/show_bug.cgi?id=71506
4227 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4228 for(var i = 0, len = cn.length; i < len; i++) {
4229 createDom(cn[i], el);
4236 el.innerHTML = o.html;
4239 parentNode.appendChild(el);
4244 var ieTable = function(depth, s, h, e){
4245 tempTableEl.innerHTML = [s, h, e].join('');
4246 var i = -1, el = tempTableEl;
4253 // kill repeat to save bytes
4257 tbe = '</tbody>'+te,
4263 * Nasty code for IE's broken table implementation
4265 var insertIntoTable = function(tag, where, el, html){
4267 tempTableEl = document.createElement('div');
4272 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4275 if(where == 'beforebegin'){
4279 before = el.nextSibling;
4282 node = ieTable(4, trs, html, tre);
4284 else if(tag == 'tr'){
4285 if(where == 'beforebegin'){
4288 node = ieTable(3, tbs, html, tbe);
4289 } else if(where == 'afterend'){
4290 before = el.nextSibling;
4292 node = ieTable(3, tbs, html, tbe);
4293 } else{ // INTO a TR
4294 if(where == 'afterbegin'){
4295 before = el.firstChild;
4297 node = ieTable(4, trs, html, tre);
4299 } else if(tag == 'tbody'){
4300 if(where == 'beforebegin'){
4303 node = ieTable(2, ts, html, te);
4304 } else if(where == 'afterend'){
4305 before = el.nextSibling;
4307 node = ieTable(2, ts, html, te);
4309 if(where == 'afterbegin'){
4310 before = el.firstChild;
4312 node = ieTable(3, tbs, html, tbe);
4315 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4318 if(where == 'afterbegin'){
4319 before = el.firstChild;
4321 node = ieTable(2, ts, html, te);
4323 el.insertBefore(node, before);
4328 /** True to force the use of DOM instead of html fragments @type Boolean */
4332 * Returns the markup for the passed Element(s) config
4333 * @param {Object} o The Dom object spec (and children)
4336 markup : function(o){
4337 return createHtml(o);
4341 * Applies a style specification to an element
4342 * @param {String/HTMLElement} el The element to apply styles to
4343 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4344 * a function which returns such a specification.
4346 applyStyles : function(el, styles){
4349 if(typeof styles == "string"){
4350 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4352 while ((matches = re.exec(styles)) != null){
4353 el.setStyle(matches[1], matches[2]);
4355 }else if (typeof styles == "object"){
4356 for (var style in styles){
4357 el.setStyle(style, styles[style]);
4359 }else if (typeof styles == "function"){
4360 Roo.DomHelper.applyStyles(el, styles.call());
4366 * Inserts an HTML fragment into the Dom
4367 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4368 * @param {HTMLElement} el The context element
4369 * @param {String} html The HTML fragmenet
4370 * @return {HTMLElement} The new node
4372 insertHtml : function(where, el, html){
4373 where = where.toLowerCase();
4374 if(el.insertAdjacentHTML){
4375 if(tableRe.test(el.tagName)){
4377 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4383 el.insertAdjacentHTML('BeforeBegin', html);
4384 return el.previousSibling;
4386 el.insertAdjacentHTML('AfterBegin', html);
4387 return el.firstChild;
4389 el.insertAdjacentHTML('BeforeEnd', html);
4390 return el.lastChild;
4392 el.insertAdjacentHTML('AfterEnd', html);
4393 return el.nextSibling;
4395 throw 'Illegal insertion point -> "' + where + '"';
4397 var range = el.ownerDocument.createRange();
4401 range.setStartBefore(el);
4402 frag = range.createContextualFragment(html);
4403 el.parentNode.insertBefore(frag, el);
4404 return el.previousSibling;
4407 range.setStartBefore(el.firstChild);
4408 frag = range.createContextualFragment(html);
4409 el.insertBefore(frag, el.firstChild);
4410 return el.firstChild;
4412 el.innerHTML = html;
4413 return el.firstChild;
4417 range.setStartAfter(el.lastChild);
4418 frag = range.createContextualFragment(html);
4419 el.appendChild(frag);
4420 return el.lastChild;
4422 el.innerHTML = html;
4423 return el.lastChild;
4426 range.setStartAfter(el);
4427 frag = range.createContextualFragment(html);
4428 el.parentNode.insertBefore(frag, el.nextSibling);
4429 return el.nextSibling;
4431 throw 'Illegal insertion point -> "' + where + '"';
4435 * Creates new Dom element(s) and inserts them before el
4436 * @param {String/HTMLElement/Element} el The context element
4437 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4438 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4439 * @return {HTMLElement/Roo.Element} The new node
4441 insertBefore : function(el, o, returnElement){
4442 return this.doInsert(el, o, returnElement, "beforeBegin");
4446 * Creates new Dom element(s) and inserts them after el
4447 * @param {String/HTMLElement/Element} el The context element
4448 * @param {Object} o The Dom object spec (and children)
4449 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4450 * @return {HTMLElement/Roo.Element} The new node
4452 insertAfter : function(el, o, returnElement){
4453 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4457 * Creates new Dom element(s) and inserts them as the first child of el
4458 * @param {String/HTMLElement/Element} el The context element
4459 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4460 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4461 * @return {HTMLElement/Roo.Element} The new node
4463 insertFirst : function(el, o, returnElement){
4464 return this.doInsert(el, o, returnElement, "afterBegin");
4468 doInsert : function(el, o, returnElement, pos, sibling){
4469 el = Roo.getDom(el);
4471 if(this.useDom || o.ns){
4472 newNode = createDom(o, null);
4473 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4475 var html = createHtml(o);
4476 newNode = this.insertHtml(pos, el, html);
4478 return returnElement ? Roo.get(newNode, true) : newNode;
4482 * Creates new Dom element(s) and appends them to el
4483 * @param {String/HTMLElement/Element} el The context element
4484 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486 * @return {HTMLElement/Roo.Element} The new node
4488 append : function(el, o, returnElement){
4489 el = Roo.getDom(el);
4491 if(this.useDom || o.ns){
4492 newNode = createDom(o, null);
4493 el.appendChild(newNode);
4495 var html = createHtml(o);
4496 newNode = this.insertHtml("beforeEnd", el, html);
4498 return returnElement ? Roo.get(newNode, true) : newNode;
4502 * Creates new Dom element(s) and overwrites the contents of el with them
4503 * @param {String/HTMLElement/Element} el The context element
4504 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4505 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4506 * @return {HTMLElement/Roo.Element} The new node
4508 overwrite : function(el, o, returnElement){
4509 el = Roo.getDom(el);
4512 while (el.childNodes.length) {
4513 el.removeChild(el.firstChild);
4517 el.innerHTML = createHtml(o);
4520 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4524 * Creates a new Roo.DomHelper.Template from the Dom object spec
4525 * @param {Object} o The Dom object spec (and children)
4526 * @return {Roo.DomHelper.Template} The new template
4528 createTemplate : function(o){
4529 var html = createHtml(o);
4530 return new Roo.Template(html);
4536 * Ext JS Library 1.1.1
4537 * Copyright(c) 2006-2007, Ext JS, LLC.
4539 * Originally Released Under LGPL - original licence link has changed is not relivant.
4542 * <script type="text/javascript">
4546 * @class Roo.Template
4547 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4548 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4551 var t = new Roo.Template({
4552 html : '<div name="{id}">' +
4553 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4555 myformat: function (value, allValues) {
4556 return 'XX' + value;
4559 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4561 * For more information see this blog post with examples:
4562 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4563 - Create Elements using DOM, HTML fragments and Templates</a>.
4565 * @param {Object} cfg - Configuration object.
4567 Roo.Template = function(cfg){
4569 if(cfg instanceof Array){
4571 }else if(arguments.length > 1){
4572 cfg = Array.prototype.join.call(arguments, "");
4576 if (typeof(cfg) == 'object') {
4587 Roo.Template.prototype = {
4590 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4591 * it should be fixed so that template is observable...
4595 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4599 * Returns an HTML fragment of this template with the specified values applied.
4600 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4601 * @return {String} The HTML fragment
4603 applyTemplate : function(values){
4607 return this.compiled(values);
4609 var useF = this.disableFormats !== true;
4610 var fm = Roo.util.Format, tpl = this;
4611 var fn = function(m, name, format, args){
4613 if(format.substr(0, 5) == "this."){
4614 return tpl.call(format.substr(5), values[name], values);
4617 // quoted values are required for strings in compiled templates,
4618 // but for non compiled we need to strip them
4619 // quoted reversed for jsmin
4620 var re = /^\s*['"](.*)["']\s*$/;
4621 args = args.split(',');
4622 for(var i = 0, len = args.length; i < len; i++){
4623 args[i] = args[i].replace(re, "$1");
4625 args = [values[name]].concat(args);
4627 args = [values[name]];
4629 return fm[format].apply(fm, args);
4632 return values[name] !== undefined ? values[name] : "";
4635 return this.html.replace(this.re, fn);
4653 this.loading = true;
4654 this.compiled = false;
4656 var cx = new Roo.data.Connection();
4660 success : function (response) {
4662 _t.html = response.responseText;
4666 failure : function(response) {
4667 Roo.log("Template failed to load from " + _t.url);
4674 * Sets the HTML used as the template and optionally compiles it.
4675 * @param {String} html
4676 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4677 * @return {Roo.Template} this
4679 set : function(html, compile){
4681 this.compiled = null;
4689 * True to disable format functions (defaults to false)
4692 disableFormats : false,
4695 * The regular expression used to match template variables
4699 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4702 * Compiles the template into an internal function, eliminating the RegEx overhead.
4703 * @return {Roo.Template} this
4705 compile : function(){
4706 var fm = Roo.util.Format;
4707 var useF = this.disableFormats !== true;
4708 var sep = Roo.isGecko ? "+" : ",";
4709 var fn = function(m, name, format, args){
4711 args = args ? ',' + args : "";
4712 if(format.substr(0, 5) != "this."){
4713 format = "fm." + format + '(';
4715 format = 'this.call("'+ format.substr(5) + '", ';
4719 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4721 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4724 // branched to use + in gecko and [].join() in others
4726 body = "this.compiled = function(values){ return '" +
4727 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4730 body = ["this.compiled = function(values){ return ['"];
4731 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4732 body.push("'].join('');};");
4733 body = body.join('');
4743 // private function used to call members
4744 call : function(fnName, value, allValues){
4745 return this[fnName](value, allValues);
4749 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4750 * @param {String/HTMLElement/Roo.Element} el The context element
4751 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4752 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4753 * @return {HTMLElement/Roo.Element} The new node or Element
4755 insertFirst: function(el, values, returnElement){
4756 return this.doInsert('afterBegin', el, values, returnElement);
4760 * Applies the supplied values to the template and inserts the new node(s) before el.
4761 * @param {String/HTMLElement/Roo.Element} el The context element
4762 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4763 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4764 * @return {HTMLElement/Roo.Element} The new node or Element
4766 insertBefore: function(el, values, returnElement){
4767 return this.doInsert('beforeBegin', el, values, returnElement);
4771 * Applies the supplied values to the template and inserts the new node(s) after el.
4772 * @param {String/HTMLElement/Roo.Element} el The context element
4773 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4774 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775 * @return {HTMLElement/Roo.Element} The new node or Element
4777 insertAfter : function(el, values, returnElement){
4778 return this.doInsert('afterEnd', el, values, returnElement);
4782 * Applies the supplied values to the template and appends the new node(s) to el.
4783 * @param {String/HTMLElement/Roo.Element} el The context element
4784 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4785 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4786 * @return {HTMLElement/Roo.Element} The new node or Element
4788 append : function(el, values, returnElement){
4789 return this.doInsert('beforeEnd', el, values, returnElement);
4792 doInsert : function(where, el, values, returnEl){
4793 el = Roo.getDom(el);
4794 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4795 return returnEl ? Roo.get(newNode, true) : newNode;
4799 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4800 * @param {String/HTMLElement/Roo.Element} el The context element
4801 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4802 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4803 * @return {HTMLElement/Roo.Element} The new node or Element
4805 overwrite : function(el, values, returnElement){
4806 el = Roo.getDom(el);
4807 el.innerHTML = this.applyTemplate(values);
4808 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4812 * Alias for {@link #applyTemplate}
4815 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4818 Roo.DomHelper.Template = Roo.Template;
4821 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4822 * @param {String/HTMLElement} el A DOM element or its id
4823 * @returns {Roo.Template} The created template
4826 Roo.Template.from = function(el){
4827 el = Roo.getDom(el);
4828 return new Roo.Template(el.value || el.innerHTML);
4831 * Ext JS Library 1.1.1
4832 * Copyright(c) 2006-2007, Ext JS, LLC.
4834 * Originally Released Under LGPL - original licence link has changed is not relivant.
4837 * <script type="text/javascript">
4842 * This is code is also distributed under MIT license for use
4843 * with jQuery and prototype JavaScript libraries.
4846 * @class Roo.DomQuery
4847 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4849 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4852 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4854 <h4>Element Selectors:</h4>
4856 <li> <b>*</b> any element</li>
4857 <li> <b>E</b> an element with the tag E</li>
4858 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4859 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4860 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4861 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4863 <h4>Attribute Selectors:</h4>
4864 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4866 <li> <b>E[foo]</b> has an attribute "foo"</li>
4867 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4868 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4869 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4870 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4871 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4872 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4874 <h4>Pseudo Classes:</h4>
4876 <li> <b>E:first-child</b> E is the first child of its parent</li>
4877 <li> <b>E:last-child</b> E is the last child of its parent</li>
4878 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4879 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4880 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4881 <li> <b>E:only-child</b> E is the only child of its parent</li>
4882 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4883 <li> <b>E:first</b> the first E in the resultset</li>
4884 <li> <b>E:last</b> the last E in the resultset</li>
4885 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4886 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4887 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4888 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4889 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4890 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4891 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4892 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4893 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4895 <h4>CSS Value Selectors:</h4>
4897 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4898 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4899 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4900 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4901 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4902 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4906 Roo.DomQuery = function(){
4907 var cache = {}, simpleCache = {}, valueCache = {};
4908 var nonSpace = /\S/;
4909 var trimRe = /^\s+|\s+$/g;
4910 var tplRe = /\{(\d+)\}/g;
4911 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4912 var tagTokenRe = /^(#)?([\w-\*]+)/;
4913 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4915 function child(p, index){
4917 var n = p.firstChild;
4919 if(n.nodeType == 1){
4930 while((n = n.nextSibling) && n.nodeType != 1);
4935 while((n = n.previousSibling) && n.nodeType != 1);
4939 function children(d){
4940 var n = d.firstChild, ni = -1;
4942 var nx = n.nextSibling;
4943 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4953 function byClassName(c, a, v){
4957 var r = [], ri = -1, cn;
4958 for(var i = 0, ci; ci = c[i]; i++){
4959 if((' '+ci.className+' ').indexOf(v) != -1){
4966 function attrValue(n, attr){
4967 if(!n.tagName && typeof n.length != "undefined"){
4976 if(attr == "class" || attr == "className"){
4979 return n.getAttribute(attr) || n[attr];
4983 function getNodes(ns, mode, tagName){
4984 var result = [], ri = -1, cs;
4988 tagName = tagName || "*";
4989 if(typeof ns.getElementsByTagName != "undefined"){
4993 for(var i = 0, ni; ni = ns[i]; i++){
4994 cs = ni.getElementsByTagName(tagName);
4995 for(var j = 0, ci; ci = cs[j]; j++){
4999 }else if(mode == "/" || mode == ">"){
5000 var utag = tagName.toUpperCase();
5001 for(var i = 0, ni, cn; ni = ns[i]; i++){
5002 cn = ni.children || ni.childNodes;
5003 for(var j = 0, cj; cj = cn[j]; j++){
5004 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5009 }else if(mode == "+"){
5010 var utag = tagName.toUpperCase();
5011 for(var i = 0, n; n = ns[i]; i++){
5012 while((n = n.nextSibling) && n.nodeType != 1);
5013 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5017 }else if(mode == "~"){
5018 for(var i = 0, n; n = ns[i]; i++){
5019 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5028 function concat(a, b){
5032 for(var i = 0, l = b.length; i < l; i++){
5038 function byTag(cs, tagName){
5039 if(cs.tagName || cs == document){
5045 var r = [], ri = -1;
5046 tagName = tagName.toLowerCase();
5047 for(var i = 0, ci; ci = cs[i]; i++){
5048 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5055 function byId(cs, attr, id){
5056 if(cs.tagName || cs == document){
5062 var r = [], ri = -1;
5063 for(var i = 0,ci; ci = cs[i]; i++){
5064 if(ci && ci.id == id){
5072 function byAttribute(cs, attr, value, op, custom){
5073 var r = [], ri = -1, st = custom=="{";
5074 var f = Roo.DomQuery.operators[op];
5075 for(var i = 0, ci; ci = cs[i]; i++){
5078 a = Roo.DomQuery.getStyle(ci, attr);
5080 else if(attr == "class" || attr == "className"){
5082 }else if(attr == "for"){
5084 }else if(attr == "href"){
5085 a = ci.getAttribute("href", 2);
5087 a = ci.getAttribute(attr);
5089 if((f && f(a, value)) || (!f && a)){
5096 function byPseudo(cs, name, value){
5097 return Roo.DomQuery.pseudos[name](cs, value);
5100 // This is for IE MSXML which does not support expandos.
5101 // IE runs the same speed using setAttribute, however FF slows way down
5102 // and Safari completely fails so they need to continue to use expandos.
5103 var isIE = window.ActiveXObject ? true : false;
5105 // this eval is stop the compressor from
5106 // renaming the variable to something shorter
5108 /** eval:var:batch */
5113 function nodupIEXml(cs){
5115 cs[0].setAttribute("_nodup", d);
5117 for(var i = 1, len = cs.length; i < len; i++){
5119 if(!c.getAttribute("_nodup") != d){
5120 c.setAttribute("_nodup", d);
5124 for(var i = 0, len = cs.length; i < len; i++){
5125 cs[i].removeAttribute("_nodup");
5134 var len = cs.length, c, i, r = cs, cj, ri = -1;
5135 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5138 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5139 return nodupIEXml(cs);
5143 for(i = 1; c = cs[i]; i++){
5148 for(var j = 0; j < i; j++){
5151 for(j = i+1; cj = cs[j]; j++){
5163 function quickDiffIEXml(c1, c2){
5165 for(var i = 0, len = c1.length; i < len; i++){
5166 c1[i].setAttribute("_qdiff", d);
5169 for(var i = 0, len = c2.length; i < len; i++){
5170 if(c2[i].getAttribute("_qdiff") != d){
5171 r[r.length] = c2[i];
5174 for(var i = 0, len = c1.length; i < len; i++){
5175 c1[i].removeAttribute("_qdiff");
5180 function quickDiff(c1, c2){
5181 var len1 = c1.length;
5185 if(isIE && c1[0].selectSingleNode){
5186 return quickDiffIEXml(c1, c2);
5189 for(var i = 0; i < len1; i++){
5193 for(var i = 0, len = c2.length; i < len; i++){
5194 if(c2[i]._qdiff != d){
5195 r[r.length] = c2[i];
5201 function quickId(ns, mode, root, id){
5203 var d = root.ownerDocument || root;
5204 return d.getElementById(id);
5206 ns = getNodes(ns, mode, "*");
5207 return byId(ns, null, id);
5211 getStyle : function(el, name){
5212 return Roo.fly(el).getStyle(name);
5215 * Compiles a selector/xpath query into a reusable function. The returned function
5216 * takes one parameter "root" (optional), which is the context node from where the query should start.
5217 * @param {String} selector The selector/xpath query
5218 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5219 * @return {Function}
5221 compile : function(path, type){
5222 type = type || "select";
5224 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5225 var q = path, mode, lq;
5226 var tk = Roo.DomQuery.matchers;
5227 var tklen = tk.length;
5230 // accept leading mode switch
5231 var lmode = q.match(modeRe);
5232 if(lmode && lmode[1]){
5233 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5234 q = q.replace(lmode[1], "");
5236 // strip leading slashes
5237 while(path.substr(0, 1)=="/"){
5238 path = path.substr(1);
5241 while(q && lq != q){
5243 var tm = q.match(tagTokenRe);
5244 if(type == "select"){
5247 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5249 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5251 q = q.replace(tm[0], "");
5252 }else if(q.substr(0, 1) != '@'){
5253 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5258 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5260 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5262 q = q.replace(tm[0], "");
5265 while(!(mm = q.match(modeRe))){
5266 var matched = false;
5267 for(var j = 0; j < tklen; j++){
5269 var m = q.match(t.re);
5271 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5274 q = q.replace(m[0], "");
5279 // prevent infinite loop on bad selector
5281 throw 'Error parsing selector, parsing failed at "' + q + '"';
5285 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5286 q = q.replace(mm[1], "");
5289 fn[fn.length] = "return nodup(n);\n}";
5292 * list of variables that need from compression as they are used by eval.
5302 * eval:var:byClassName
5304 * eval:var:byAttribute
5305 * eval:var:attrValue
5313 * Selects a group of elements.
5314 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5315 * @param {Node} root (optional) The start of the query (defaults to document).
5318 select : function(path, root, type){
5319 if(!root || root == document){
5322 if(typeof root == "string"){
5323 root = document.getElementById(root);
5325 var paths = path.split(",");
5327 for(var i = 0, len = paths.length; i < len; i++){
5328 var p = paths[i].replace(trimRe, "");
5330 cache[p] = Roo.DomQuery.compile(p);
5332 throw p + " is not a valid selector";
5335 var result = cache[p](root);
5336 if(result && result != document){
5337 results = results.concat(result);
5340 if(paths.length > 1){
5341 return nodup(results);
5347 * Selects a single element.
5348 * @param {String} selector The selector/xpath query
5349 * @param {Node} root (optional) The start of the query (defaults to document).
5352 selectNode : function(path, root){
5353 return Roo.DomQuery.select(path, root)[0];
5357 * Selects the value of a node, optionally replacing null with the defaultValue.
5358 * @param {String} selector The selector/xpath query
5359 * @param {Node} root (optional) The start of the query (defaults to document).
5360 * @param {String} defaultValue
5362 selectValue : function(path, root, defaultValue){
5363 path = path.replace(trimRe, "");
5364 if(!valueCache[path]){
5365 valueCache[path] = Roo.DomQuery.compile(path, "select");
5367 var n = valueCache[path](root);
5368 n = n[0] ? n[0] : n;
5369 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5370 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5374 * Selects the value of a node, parsing integers and floats.
5375 * @param {String} selector The selector/xpath query
5376 * @param {Node} root (optional) The start of the query (defaults to document).
5377 * @param {Number} defaultValue
5380 selectNumber : function(path, root, defaultValue){
5381 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5382 return parseFloat(v);
5386 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5387 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5388 * @param {String} selector The simple selector to test
5391 is : function(el, ss){
5392 if(typeof el == "string"){
5393 el = document.getElementById(el);
5395 var isArray = (el instanceof Array);
5396 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5397 return isArray ? (result.length == el.length) : (result.length > 0);
5401 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5402 * @param {Array} el An array of elements to filter
5403 * @param {String} selector The simple selector to test
5404 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5405 * the selector instead of the ones that match
5408 filter : function(els, ss, nonMatches){
5409 ss = ss.replace(trimRe, "");
5410 if(!simpleCache[ss]){
5411 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5413 var result = simpleCache[ss](els);
5414 return nonMatches ? quickDiff(result, els) : result;
5418 * Collection of matching regular expressions and code snippets.
5422 select: 'n = byClassName(n, null, " {1} ");'
5424 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5425 select: 'n = byPseudo(n, "{1}", "{2}");'
5427 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5428 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5431 select: 'n = byId(n, null, "{1}");'
5434 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5439 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5440 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5443 "=" : function(a, v){
5446 "!=" : function(a, v){
5449 "^=" : function(a, v){
5450 return a && a.substr(0, v.length) == v;
5452 "$=" : function(a, v){
5453 return a && a.substr(a.length-v.length) == v;
5455 "*=" : function(a, v){
5456 return a && a.indexOf(v) !== -1;
5458 "%=" : function(a, v){
5459 return (a % v) == 0;
5461 "|=" : function(a, v){
5462 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5464 "~=" : function(a, v){
5465 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5470 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5471 * and the argument (if any) supplied in the selector.
5474 "first-child" : function(c){
5475 var r = [], ri = -1, n;
5476 for(var i = 0, ci; ci = n = c[i]; i++){
5477 while((n = n.previousSibling) && n.nodeType != 1);
5485 "last-child" : function(c){
5486 var r = [], ri = -1, n;
5487 for(var i = 0, ci; ci = n = c[i]; i++){
5488 while((n = n.nextSibling) && n.nodeType != 1);
5496 "nth-child" : function(c, a) {
5497 var r = [], ri = -1;
5498 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5499 var f = (m[1] || 1) - 0, l = m[2] - 0;
5500 for(var i = 0, n; n = c[i]; i++){
5501 var pn = n.parentNode;
5502 if (batch != pn._batch) {
5504 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5505 if(cn.nodeType == 1){
5512 if (l == 0 || n.nodeIndex == l){
5515 } else if ((n.nodeIndex + l) % f == 0){
5523 "only-child" : function(c){
5524 var r = [], ri = -1;;
5525 for(var i = 0, ci; ci = c[i]; i++){
5526 if(!prev(ci) && !next(ci)){
5533 "empty" : function(c){
5534 var r = [], ri = -1;
5535 for(var i = 0, ci; ci = c[i]; i++){
5536 var cns = ci.childNodes, j = 0, cn, empty = true;
5539 if(cn.nodeType == 1 || cn.nodeType == 3){
5551 "contains" : function(c, v){
5552 var r = [], ri = -1;
5553 for(var i = 0, ci; ci = c[i]; i++){
5554 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5561 "nodeValue" : function(c, v){
5562 var r = [], ri = -1;
5563 for(var i = 0, ci; ci = c[i]; i++){
5564 if(ci.firstChild && ci.firstChild.nodeValue == v){
5571 "checked" : function(c){
5572 var r = [], ri = -1;
5573 for(var i = 0, ci; ci = c[i]; i++){
5574 if(ci.checked == true){
5581 "not" : function(c, ss){
5582 return Roo.DomQuery.filter(c, ss, true);
5585 "odd" : function(c){
5586 return this["nth-child"](c, "odd");
5589 "even" : function(c){
5590 return this["nth-child"](c, "even");
5593 "nth" : function(c, a){
5594 return c[a-1] || [];
5597 "first" : function(c){
5601 "last" : function(c){
5602 return c[c.length-1] || [];
5605 "has" : function(c, ss){
5606 var s = Roo.DomQuery.select;
5607 var r = [], ri = -1;
5608 for(var i = 0, ci; ci = c[i]; i++){
5609 if(s(ss, ci).length > 0){
5616 "next" : function(c, ss){
5617 var is = Roo.DomQuery.is;
5618 var r = [], ri = -1;
5619 for(var i = 0, ci; ci = c[i]; i++){
5628 "prev" : function(c, ss){
5629 var is = Roo.DomQuery.is;
5630 var r = [], ri = -1;
5631 for(var i = 0, ci; ci = c[i]; i++){
5644 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5645 * @param {String} path The selector/xpath query
5646 * @param {Node} root (optional) The start of the query (defaults to document).
5651 Roo.query = Roo.DomQuery.select;
5654 * Ext JS Library 1.1.1
5655 * Copyright(c) 2006-2007, Ext JS, LLC.
5657 * Originally Released Under LGPL - original licence link has changed is not relivant.
5660 * <script type="text/javascript">
5664 * @class Roo.util.Observable
5665 * Base class that provides a common interface for publishing events. Subclasses are expected to
5666 * to have a property "events" with all the events defined.<br>
5669 Employee = function(name){
5676 Roo.extend(Employee, Roo.util.Observable);
5678 * @param {Object} config properties to use (incuding events / listeners)
5681 Roo.util.Observable = function(cfg){
5684 this.addEvents(cfg.events || {});
5686 delete cfg.events; // make sure
5689 Roo.apply(this, cfg);
5692 this.on(this.listeners);
5693 delete this.listeners;
5696 Roo.util.Observable.prototype = {
5698 * @cfg {Object} listeners list of events and functions to call for this object,
5702 'click' : function(e) {
5712 * Fires the specified event with the passed parameters (minus the event name).
5713 * @param {String} eventName
5714 * @param {Object...} args Variable number of parameters are passed to handlers
5715 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5717 fireEvent : function(){
5718 var ce = this.events[arguments[0].toLowerCase()];
5719 if(typeof ce == "object"){
5720 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5727 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5730 * Appends an event handler to this component
5731 * @param {String} eventName The type of event to listen for
5732 * @param {Function} handler The method the event invokes
5733 * @param {Object} scope (optional) The scope in which to execute the handler
5734 * function. The handler function's "this" context.
5735 * @param {Object} options (optional) An object containing handler configuration
5736 * properties. This may contain any of the following properties:<ul>
5737 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5738 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5739 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5740 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5741 * by the specified number of milliseconds. If the event fires again within that time, the original
5742 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5745 * <b>Combining Options</b><br>
5746 * Using the options argument, it is possible to combine different types of listeners:<br>
5748 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5750 el.on('click', this.onClick, this, {
5757 * <b>Attaching multiple handlers in 1 call</b><br>
5758 * The method also allows for a single argument to be passed which is a config object containing properties
5759 * which specify multiple handlers.
5768 fn: this.onMouseOver,
5772 fn: this.onMouseOut,
5778 * Or a shorthand syntax which passes the same scope object to all handlers:
5781 'click': this.onClick,
5782 'mouseover': this.onMouseOver,
5783 'mouseout': this.onMouseOut,
5788 addListener : function(eventName, fn, scope, o){
5789 if(typeof eventName == "object"){
5792 if(this.filterOptRe.test(e)){
5795 if(typeof o[e] == "function"){
5797 this.addListener(e, o[e], o.scope, o);
5799 // individual options
5800 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5805 o = (!o || typeof o == "boolean") ? {} : o;
5806 eventName = eventName.toLowerCase();
5807 var ce = this.events[eventName] || true;
5808 if(typeof ce == "boolean"){
5809 ce = new Roo.util.Event(this, eventName);
5810 this.events[eventName] = ce;
5812 ce.addListener(fn, scope, o);
5816 * Removes a listener
5817 * @param {String} eventName The type of event to listen for
5818 * @param {Function} handler The handler to remove
5819 * @param {Object} scope (optional) The scope (this object) for the handler
5821 removeListener : function(eventName, fn, scope){
5822 var ce = this.events[eventName.toLowerCase()];
5823 if(typeof ce == "object"){
5824 ce.removeListener(fn, scope);
5829 * Removes all listeners for this object
5831 purgeListeners : function(){
5832 for(var evt in this.events){
5833 if(typeof this.events[evt] == "object"){
5834 this.events[evt].clearListeners();
5839 relayEvents : function(o, events){
5840 var createHandler = function(ename){
5842 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5845 for(var i = 0, len = events.length; i < len; i++){
5846 var ename = events[i];
5847 if(!this.events[ename]){ this.events[ename] = true; };
5848 o.on(ename, createHandler(ename), this);
5853 * Used to define events on this Observable
5854 * @param {Object} object The object with the events defined
5856 addEvents : function(o){
5860 Roo.applyIf(this.events, o);
5864 * Checks to see if this object has any listeners for a specified event
5865 * @param {String} eventName The name of the event to check for
5866 * @return {Boolean} True if the event is being listened for, else false
5868 hasListener : function(eventName){
5869 var e = this.events[eventName];
5870 return typeof e == "object" && e.listeners.length > 0;
5874 * Appends an event handler to this element (shorthand for addListener)
5875 * @param {String} eventName The type of event to listen for
5876 * @param {Function} handler The method the event invokes
5877 * @param {Object} scope (optional) The scope in which to execute the handler
5878 * function. The handler function's "this" context.
5879 * @param {Object} options (optional)
5882 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5884 * Removes a listener (shorthand for removeListener)
5885 * @param {String} eventName The type of event to listen for
5886 * @param {Function} handler The handler to remove
5887 * @param {Object} scope (optional) The scope (this object) for the handler
5890 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5893 * Starts capture on the specified Observable. All events will be passed
5894 * to the supplied function with the event name + standard signature of the event
5895 * <b>before</b> the event is fired. If the supplied function returns false,
5896 * the event will not fire.
5897 * @param {Observable} o The Observable to capture
5898 * @param {Function} fn The function to call
5899 * @param {Object} scope (optional) The scope (this object) for the fn
5902 Roo.util.Observable.capture = function(o, fn, scope){
5903 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5907 * Removes <b>all</b> added captures from the Observable.
5908 * @param {Observable} o The Observable to release
5911 Roo.util.Observable.releaseCapture = function(o){
5912 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5917 var createBuffered = function(h, o, scope){
5918 var task = new Roo.util.DelayedTask();
5920 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5924 var createSingle = function(h, e, fn, scope){
5926 e.removeListener(fn, scope);
5927 return h.apply(scope, arguments);
5931 var createDelayed = function(h, o, scope){
5933 var args = Array.prototype.slice.call(arguments, 0);
5934 setTimeout(function(){
5935 h.apply(scope, args);
5940 Roo.util.Event = function(obj, name){
5943 this.listeners = [];
5946 Roo.util.Event.prototype = {
5947 addListener : function(fn, scope, options){
5948 var o = options || {};
5949 scope = scope || this.obj;
5950 if(!this.isListening(fn, scope)){
5951 var l = {fn: fn, scope: scope, options: o};
5954 h = createDelayed(h, o, scope);
5957 h = createSingle(h, this, fn, scope);
5960 h = createBuffered(h, o, scope);
5963 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5964 this.listeners.push(l);
5966 this.listeners = this.listeners.slice(0);
5967 this.listeners.push(l);
5972 findListener : function(fn, scope){
5973 scope = scope || this.obj;
5974 var ls = this.listeners;
5975 for(var i = 0, len = ls.length; i < len; i++){
5977 if(l.fn == fn && l.scope == scope){
5984 isListening : function(fn, scope){
5985 return this.findListener(fn, scope) != -1;
5988 removeListener : function(fn, scope){
5990 if((index = this.findListener(fn, scope)) != -1){
5992 this.listeners.splice(index, 1);
5994 this.listeners = this.listeners.slice(0);
5995 this.listeners.splice(index, 1);
6002 clearListeners : function(){
6003 this.listeners = [];
6007 var ls = this.listeners, scope, len = ls.length;
6010 var args = Array.prototype.slice.call(arguments, 0);
6011 for(var i = 0; i < len; i++){
6013 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6014 this.firing = false;
6018 this.firing = false;
6025 * Ext JS Library 1.1.1
6026 * Copyright(c) 2006-2007, Ext JS, LLC.
6028 * Originally Released Under LGPL - original licence link has changed is not relivant.
6031 * <script type="text/javascript">
6035 * @class Roo.EventManager
6036 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6037 * several useful events directly.
6038 * See {@link Roo.EventObject} for more details on normalized event objects.
6041 Roo.EventManager = function(){
6042 var docReadyEvent, docReadyProcId, docReadyState = false;
6043 var resizeEvent, resizeTask, textEvent, textSize;
6044 var E = Roo.lib.Event;
6045 var D = Roo.lib.Dom;
6048 var fireDocReady = function(){
6050 docReadyState = true;
6053 clearInterval(docReadyProcId);
6055 if(Roo.isGecko || Roo.isOpera) {
6056 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6059 var defer = document.getElementById("ie-deferred-loader");
6061 defer.onreadystatechange = null;
6062 defer.parentNode.removeChild(defer);
6066 docReadyEvent.fire();
6067 docReadyEvent.clearListeners();
6072 var initDocReady = function(){
6073 docReadyEvent = new Roo.util.Event();
6074 if(Roo.isGecko || Roo.isOpera) {
6075 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6077 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6078 var defer = document.getElementById("ie-deferred-loader");
6079 defer.onreadystatechange = function(){
6080 if(this.readyState == "complete"){
6084 }else if(Roo.isSafari){
6085 docReadyProcId = setInterval(function(){
6086 var rs = document.readyState;
6087 if(rs == "complete") {
6092 // no matter what, make sure it fires on load
6093 E.on(window, "load", fireDocReady);
6096 var createBuffered = function(h, o){
6097 var task = new Roo.util.DelayedTask(h);
6099 // create new event object impl so new events don't wipe out properties
6100 e = new Roo.EventObjectImpl(e);
6101 task.delay(o.buffer, h, null, [e]);
6105 var createSingle = function(h, el, ename, fn){
6107 Roo.EventManager.removeListener(el, ename, fn);
6112 var createDelayed = function(h, o){
6114 // create new event object impl so new events don't wipe out properties
6115 e = new Roo.EventObjectImpl(e);
6116 setTimeout(function(){
6122 var listen = function(element, ename, opt, fn, scope){
6123 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6124 fn = fn || o.fn; scope = scope || o.scope;
6125 var el = Roo.getDom(element);
6127 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6129 var h = function(e){
6130 e = Roo.EventObject.setEvent(e);
6133 t = e.getTarget(o.delegate, el);
6140 if(o.stopEvent === true){
6143 if(o.preventDefault === true){
6146 if(o.stopPropagation === true){
6147 e.stopPropagation();
6150 if(o.normalized === false){
6154 fn.call(scope || el, e, t, o);
6157 h = createDelayed(h, o);
6160 h = createSingle(h, el, ename, fn);
6163 h = createBuffered(h, o);
6165 fn._handlers = fn._handlers || [];
6166 fn._handlers.push([Roo.id(el), ename, h]);
6169 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6170 el.addEventListener("DOMMouseScroll", h, false);
6171 E.on(window, 'unload', function(){
6172 el.removeEventListener("DOMMouseScroll", h, false);
6175 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6176 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6181 var stopListening = function(el, ename, fn){
6182 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6184 for(var i = 0, len = hds.length; i < len; i++){
6186 if(h[0] == id && h[1] == ename){
6193 E.un(el, ename, hd);
6194 el = Roo.getDom(el);
6195 if(ename == "mousewheel" && el.addEventListener){
6196 el.removeEventListener("DOMMouseScroll", hd, false);
6198 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6199 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6203 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6210 * @scope Roo.EventManager
6215 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6216 * object with a Roo.EventObject
6217 * @param {Function} fn The method the event invokes
6218 * @param {Object} scope An object that becomes the scope of the handler
6219 * @param {boolean} override If true, the obj passed in becomes
6220 * the execution scope of the listener
6221 * @return {Function} The wrapped function
6224 wrap : function(fn, scope, override){
6226 Roo.EventObject.setEvent(e);
6227 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6232 * Appends an event handler to an element (shorthand for addListener)
6233 * @param {String/HTMLElement} element The html element or id to assign the
6234 * @param {String} eventName The type of event to listen for
6235 * @param {Function} handler The method the event invokes
6236 * @param {Object} scope (optional) The scope in which to execute the handler
6237 * function. The handler function's "this" context.
6238 * @param {Object} options (optional) An object containing handler configuration
6239 * properties. This may contain any of the following properties:<ul>
6240 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6241 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6242 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6243 * <li>preventDefault {Boolean} True to prevent the default action</li>
6244 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6245 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6246 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6247 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6248 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6249 * by the specified number of milliseconds. If the event fires again within that time, the original
6250 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6253 * <b>Combining Options</b><br>
6254 * Using the options argument, it is possible to combine different types of listeners:<br>
6256 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6258 el.on('click', this.onClick, this, {
6265 * <b>Attaching multiple handlers in 1 call</b><br>
6266 * The method also allows for a single argument to be passed which is a config object containing properties
6267 * which specify multiple handlers.
6277 fn: this.onMouseOver
6286 * Or a shorthand syntax:<br>
6289 'click' : this.onClick,
6290 'mouseover' : this.onMouseOver,
6291 'mouseout' : this.onMouseOut
6295 addListener : function(element, eventName, fn, scope, options){
6296 if(typeof eventName == "object"){
6302 if(typeof o[e] == "function"){
6304 listen(element, e, o, o[e], o.scope);
6306 // individual options
6307 listen(element, e, o[e]);
6312 return listen(element, eventName, options, fn, scope);
6316 * Removes an event handler
6318 * @param {String/HTMLElement} element The id or html element to remove the
6320 * @param {String} eventName The type of event
6321 * @param {Function} fn
6322 * @return {Boolean} True if a listener was actually removed
6324 removeListener : function(element, eventName, fn){
6325 return stopListening(element, eventName, fn);
6329 * Fires when the document is ready (before onload and before images are loaded). Can be
6330 * accessed shorthanded Roo.onReady().
6331 * @param {Function} fn The method the event invokes
6332 * @param {Object} scope An object that becomes the scope of the handler
6333 * @param {boolean} options
6335 onDocumentReady : function(fn, scope, options){
6336 if(docReadyState){ // if it already fired
6337 docReadyEvent.addListener(fn, scope, options);
6338 docReadyEvent.fire();
6339 docReadyEvent.clearListeners();
6345 docReadyEvent.addListener(fn, scope, options);
6349 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6350 * @param {Function} fn The method the event invokes
6351 * @param {Object} scope An object that becomes the scope of the handler
6352 * @param {boolean} options
6354 onWindowResize : function(fn, scope, options){
6356 resizeEvent = new Roo.util.Event();
6357 resizeTask = new Roo.util.DelayedTask(function(){
6358 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6360 E.on(window, "resize", function(){
6362 resizeTask.delay(50);
6364 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6368 resizeEvent.addListener(fn, scope, options);
6372 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6373 * @param {Function} fn The method the event invokes
6374 * @param {Object} scope An object that becomes the scope of the handler
6375 * @param {boolean} options
6377 onTextResize : function(fn, scope, options){
6379 textEvent = new Roo.util.Event();
6380 var textEl = new Roo.Element(document.createElement('div'));
6381 textEl.dom.className = 'x-text-resize';
6382 textEl.dom.innerHTML = 'X';
6383 textEl.appendTo(document.body);
6384 textSize = textEl.dom.offsetHeight;
6385 setInterval(function(){
6386 if(textEl.dom.offsetHeight != textSize){
6387 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6389 }, this.textResizeInterval);
6391 textEvent.addListener(fn, scope, options);
6395 * Removes the passed window resize listener.
6396 * @param {Function} fn The method the event invokes
6397 * @param {Object} scope The scope of handler
6399 removeResizeListener : function(fn, scope){
6401 resizeEvent.removeListener(fn, scope);
6406 fireResize : function(){
6408 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6412 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6416 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6418 textResizeInterval : 50
6423 * @scopeAlias pub=Roo.EventManager
6427 * Appends an event handler to an element (shorthand for addListener)
6428 * @param {String/HTMLElement} element The html element or id to assign the
6429 * @param {String} eventName The type of event to listen for
6430 * @param {Function} handler The method the event invokes
6431 * @param {Object} scope (optional) The scope in which to execute the handler
6432 * function. The handler function's "this" context.
6433 * @param {Object} options (optional) An object containing handler configuration
6434 * properties. This may contain any of the following properties:<ul>
6435 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6436 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6437 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6438 * <li>preventDefault {Boolean} True to prevent the default action</li>
6439 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6440 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6441 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6442 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6443 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6444 * by the specified number of milliseconds. If the event fires again within that time, the original
6445 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6448 * <b>Combining Options</b><br>
6449 * Using the options argument, it is possible to combine different types of listeners:<br>
6451 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6453 el.on('click', this.onClick, this, {
6460 * <b>Attaching multiple handlers in 1 call</b><br>
6461 * The method also allows for a single argument to be passed which is a config object containing properties
6462 * which specify multiple handlers.
6472 fn: this.onMouseOver
6481 * Or a shorthand syntax:<br>
6484 'click' : this.onClick,
6485 'mouseover' : this.onMouseOver,
6486 'mouseout' : this.onMouseOut
6490 pub.on = pub.addListener;
6491 pub.un = pub.removeListener;
6493 pub.stoppedMouseDownEvent = new Roo.util.Event();
6497 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6498 * @param {Function} fn The method the event invokes
6499 * @param {Object} scope An object that becomes the scope of the handler
6500 * @param {boolean} override If true, the obj passed in becomes
6501 * the execution scope of the listener
6505 Roo.onReady = Roo.EventManager.onDocumentReady;
6507 Roo.onReady(function(){
6508 var bd = Roo.get(document.body);
6513 : Roo.isGecko ? "roo-gecko"
6514 : Roo.isOpera ? "roo-opera"
6515 : Roo.isSafari ? "roo-safari" : ""];
6518 cls.push("roo-mac");
6521 cls.push("roo-linux");
6523 if(Roo.isBorderBox){
6524 cls.push('roo-border-box');
6526 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6527 var p = bd.dom.parentNode;
6529 p.className += ' roo-strict';
6532 bd.addClass(cls.join(' '));
6536 * @class Roo.EventObject
6537 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6538 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6541 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6543 var target = e.getTarget();
6546 var myDiv = Roo.get("myDiv");
6547 myDiv.on("click", handleClick);
6549 Roo.EventManager.on("myDiv", 'click', handleClick);
6550 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6554 Roo.EventObject = function(){
6556 var E = Roo.lib.Event;
6558 // safari keypress events for special keys return bad keycodes
6561 63235 : 39, // right
6564 63276 : 33, // page up
6565 63277 : 34, // page down
6566 63272 : 46, // delete
6571 // normalize button clicks
6572 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6573 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6575 Roo.EventObjectImpl = function(e){
6577 this.setEvent(e.browserEvent || e);
6580 Roo.EventObjectImpl.prototype = {
6582 * Used to fix doc tools.
6583 * @scope Roo.EventObject.prototype
6589 /** The normal browser event */
6590 browserEvent : null,
6591 /** The button pressed in a mouse event */
6593 /** True if the shift key was down during the event */
6595 /** True if the control key was down during the event */
6597 /** True if the alt key was down during the event */
6656 setEvent : function(e){
6657 if(e == this || (e && e.browserEvent)){ // already wrapped
6660 this.browserEvent = e;
6662 // normalize buttons
6663 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6664 if(e.type == 'click' && this.button == -1){
6668 this.shiftKey = e.shiftKey;
6669 // mac metaKey behaves like ctrlKey
6670 this.ctrlKey = e.ctrlKey || e.metaKey;
6671 this.altKey = e.altKey;
6672 // in getKey these will be normalized for the mac
6673 this.keyCode = e.keyCode;
6674 // keyup warnings on firefox.
6675 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6676 // cache the target for the delayed and or buffered events
6677 this.target = E.getTarget(e);
6679 this.xy = E.getXY(e);
6682 this.shiftKey = false;
6683 this.ctrlKey = false;
6684 this.altKey = false;
6694 * Stop the event (preventDefault and stopPropagation)
6696 stopEvent : function(){
6697 if(this.browserEvent){
6698 if(this.browserEvent.type == 'mousedown'){
6699 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6701 E.stopEvent(this.browserEvent);
6706 * Prevents the browsers default handling of the event.
6708 preventDefault : function(){
6709 if(this.browserEvent){
6710 E.preventDefault(this.browserEvent);
6715 isNavKeyPress : function(){
6716 var k = this.keyCode;
6717 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6718 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6721 isSpecialKey : function(){
6722 var k = this.keyCode;
6723 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6724 (k == 16) || (k == 17) ||
6725 (k >= 18 && k <= 20) ||
6726 (k >= 33 && k <= 35) ||
6727 (k >= 36 && k <= 39) ||
6728 (k >= 44 && k <= 45);
6731 * Cancels bubbling of the event.
6733 stopPropagation : function(){
6734 if(this.browserEvent){
6735 if(this.type == 'mousedown'){
6736 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6738 E.stopPropagation(this.browserEvent);
6743 * Gets the key code for the event.
6746 getCharCode : function(){
6747 return this.charCode || this.keyCode;
6751 * Returns a normalized keyCode for the event.
6752 * @return {Number} The key code
6754 getKey : function(){
6755 var k = this.keyCode || this.charCode;
6756 return Roo.isSafari ? (safariKeys[k] || k) : k;
6760 * Gets the x coordinate of the event.
6763 getPageX : function(){
6768 * Gets the y coordinate of the event.
6771 getPageY : function(){
6776 * Gets the time of the event.
6779 getTime : function(){
6780 if(this.browserEvent){
6781 return E.getTime(this.browserEvent);
6787 * Gets the page coordinates of the event.
6788 * @return {Array} The xy values like [x, y]
6795 * Gets the target for the event.
6796 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6797 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6798 search as a number or element (defaults to 10 || document.body)
6799 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6800 * @return {HTMLelement}
6802 getTarget : function(selector, maxDepth, returnEl){
6803 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6806 * Gets the related target.
6807 * @return {HTMLElement}
6809 getRelatedTarget : function(){
6810 if(this.browserEvent){
6811 return E.getRelatedTarget(this.browserEvent);
6817 * Normalizes mouse wheel delta across browsers
6818 * @return {Number} The delta
6820 getWheelDelta : function(){
6821 var e = this.browserEvent;
6823 if(e.wheelDelta){ /* IE/Opera. */
6824 delta = e.wheelDelta/120;
6825 }else if(e.detail){ /* Mozilla case. */
6826 delta = -e.detail/3;
6832 * Returns true if the control, meta, shift or alt key was pressed during this event.
6835 hasModifier : function(){
6836 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6840 * Returns true if the target of this event equals el or is a child of el
6841 * @param {String/HTMLElement/Element} el
6842 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6845 within : function(el, related){
6846 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6847 return t && Roo.fly(el).contains(t);
6850 getPoint : function(){
6851 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6855 return new Roo.EventObjectImpl();
6860 * Ext JS Library 1.1.1
6861 * Copyright(c) 2006-2007, Ext JS, LLC.
6863 * Originally Released Under LGPL - original licence link has changed is not relivant.
6866 * <script type="text/javascript">
6870 // was in Composite Element!??!?!
6873 var D = Roo.lib.Dom;
6874 var E = Roo.lib.Event;
6875 var A = Roo.lib.Anim;
6877 // local style camelizing for speed
6879 var camelRe = /(-[a-z])/gi;
6880 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6881 var view = document.defaultView;
6884 * @class Roo.Element
6885 * Represents an Element in the DOM.<br><br>
6888 var el = Roo.get("my-div");
6891 var el = getEl("my-div");
6893 // or with a DOM element
6894 var el = Roo.get(myDivElement);
6896 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6897 * each call instead of constructing a new one.<br><br>
6898 * <b>Animations</b><br />
6899 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6900 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6902 Option Default Description
6903 --------- -------- ---------------------------------------------
6904 duration .35 The duration of the animation in seconds
6905 easing easeOut The YUI easing method
6906 callback none A function to execute when the anim completes
6907 scope this The scope (this) of the callback function
6909 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6910 * manipulate the animation. Here's an example:
6912 var el = Roo.get("my-div");
6917 // default animation
6918 el.setWidth(100, true);
6920 // animation with some options set
6927 // using the "anim" property to get the Anim object
6933 el.setWidth(100, opt);
6935 if(opt.anim.isAnimated()){
6939 * <b> Composite (Collections of) Elements</b><br />
6940 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6941 * @constructor Create a new Element directly.
6942 * @param {String/HTMLElement} element
6943 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6945 Roo.Element = function(element, forceNew){
6946 var dom = typeof element == "string" ?
6947 document.getElementById(element) : element;
6948 if(!dom){ // invalid id/element
6952 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6953 return Roo.Element.cache[id];
6963 * The DOM element ID
6966 this.id = id || Roo.id(dom);
6969 var El = Roo.Element;
6973 * The element's default display mode (defaults to "")
6976 originalDisplay : "",
6980 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6985 * Sets the element's visibility mode. When setVisible() is called it
6986 * will use this to determine whether to set the visibility or the display property.
6987 * @param visMode Element.VISIBILITY or Element.DISPLAY
6988 * @return {Roo.Element} this
6990 setVisibilityMode : function(visMode){
6991 this.visibilityMode = visMode;
6995 * Convenience method for setVisibilityMode(Element.DISPLAY)
6996 * @param {String} display (optional) What to set display to when visible
6997 * @return {Roo.Element} this
6999 enableDisplayMode : function(display){
7000 this.setVisibilityMode(El.DISPLAY);
7001 if(typeof display != "undefined") this.originalDisplay = display;
7006 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7007 * @param {String} selector The simple selector to test
7008 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7009 search as a number or element (defaults to 10 || document.body)
7010 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7011 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7013 findParent : function(simpleSelector, maxDepth, returnEl){
7014 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7015 maxDepth = maxDepth || 50;
7016 if(typeof maxDepth != "number"){
7017 stopEl = Roo.getDom(maxDepth);
7020 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7021 if(dq.is(p, simpleSelector)){
7022 return returnEl ? Roo.get(p) : p;
7032 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7033 * @param {String} selector The simple selector to test
7034 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7035 search as a number or element (defaults to 10 || document.body)
7036 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7037 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7039 findParentNode : function(simpleSelector, maxDepth, returnEl){
7040 var p = Roo.fly(this.dom.parentNode, '_internal');
7041 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7045 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7046 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7047 * @param {String} selector The simple selector to test
7048 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7049 search as a number or element (defaults to 10 || document.body)
7050 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7052 up : function(simpleSelector, maxDepth){
7053 return this.findParentNode(simpleSelector, maxDepth, true);
7059 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7060 * @param {String} selector The simple selector to test
7061 * @return {Boolean} True if this element matches the selector, else false
7063 is : function(simpleSelector){
7064 return Roo.DomQuery.is(this.dom, simpleSelector);
7068 * Perform animation on this element.
7069 * @param {Object} args The YUI animation control args
7070 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7071 * @param {Function} onComplete (optional) Function to call when animation completes
7072 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7073 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7074 * @return {Roo.Element} this
7076 animate : function(args, duration, onComplete, easing, animType){
7077 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7082 * @private Internal animation call
7084 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7085 animType = animType || 'run';
7087 var anim = Roo.lib.Anim[animType](
7089 (opt.duration || defaultDur) || .35,
7090 (opt.easing || defaultEase) || 'easeOut',
7092 Roo.callback(cb, this);
7093 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7101 // private legacy anim prep
7102 preanim : function(a, i){
7103 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7107 * Removes worthless text nodes
7108 * @param {Boolean} forceReclean (optional) By default the element
7109 * keeps track if it has been cleaned already so
7110 * you can call this over and over. However, if you update the element and
7111 * need to force a reclean, you can pass true.
7113 clean : function(forceReclean){
7114 if(this.isCleaned && forceReclean !== true){
7118 var d = this.dom, n = d.firstChild, ni = -1;
7120 var nx = n.nextSibling;
7121 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7128 this.isCleaned = true;
7133 calcOffsetsTo : function(el){
7136 var restorePos = false;
7137 if(el.getStyle('position') == 'static'){
7138 el.position('relative');
7143 while(op && op != d && op.tagName != 'HTML'){
7146 op = op.offsetParent;
7149 el.position('static');
7155 * Scrolls this element into view within the passed container.
7156 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7157 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7158 * @return {Roo.Element} this
7160 scrollIntoView : function(container, hscroll){
7161 var c = Roo.getDom(container) || document.body;
7164 var o = this.calcOffsetsTo(c),
7167 b = t+el.offsetHeight,
7168 r = l+el.offsetWidth;
7170 var ch = c.clientHeight;
7171 var ct = parseInt(c.scrollTop, 10);
7172 var cl = parseInt(c.scrollLeft, 10);
7174 var cr = cl + c.clientWidth;
7182 if(hscroll !== false){
7186 c.scrollLeft = r-c.clientWidth;
7193 scrollChildIntoView : function(child, hscroll){
7194 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7198 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7199 * the new height may not be available immediately.
7200 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7201 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7202 * @param {Function} onComplete (optional) Function to call when animation completes
7203 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7204 * @return {Roo.Element} this
7206 autoHeight : function(animate, duration, onComplete, easing){
7207 var oldHeight = this.getHeight();
7209 this.setHeight(1); // force clipping
7210 setTimeout(function(){
7211 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7213 this.setHeight(height);
7215 if(typeof onComplete == "function"){
7219 this.setHeight(oldHeight); // restore original height
7220 this.setHeight(height, animate, duration, function(){
7222 if(typeof onComplete == "function") onComplete();
7223 }.createDelegate(this), easing);
7225 }.createDelegate(this), 0);
7230 * Returns true if this element is an ancestor of the passed element
7231 * @param {HTMLElement/String} el The element to check
7232 * @return {Boolean} True if this element is an ancestor of el, else false
7234 contains : function(el){
7235 if(!el){return false;}
7236 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7240 * Checks whether the element is currently visible using both visibility and display properties.
7241 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7242 * @return {Boolean} True if the element is currently visible, else false
7244 isVisible : function(deep) {
7245 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7246 if(deep !== true || !vis){
7249 var p = this.dom.parentNode;
7250 while(p && p.tagName.toLowerCase() != "body"){
7251 if(!Roo.fly(p, '_isVisible').isVisible()){
7260 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7261 * @param {String} selector The CSS selector
7262 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7263 * @return {CompositeElement/CompositeElementLite} The composite element
7265 select : function(selector, unique){
7266 return El.select(selector, unique, this.dom);
7270 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7271 * @param {String} selector The CSS selector
7272 * @return {Array} An array of the matched nodes
7274 query : function(selector, unique){
7275 return Roo.DomQuery.select(selector, this.dom);
7279 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7280 * @param {String} selector The CSS selector
7281 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7282 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7284 child : function(selector, returnDom){
7285 var n = Roo.DomQuery.selectNode(selector, this.dom);
7286 return returnDom ? n : Roo.get(n);
7290 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7291 * @param {String} selector The CSS selector
7292 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7293 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7295 down : function(selector, returnDom){
7296 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7297 return returnDom ? n : Roo.get(n);
7301 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7302 * @param {String} group The group the DD object is member of
7303 * @param {Object} config The DD config object
7304 * @param {Object} overrides An object containing methods to override/implement on the DD object
7305 * @return {Roo.dd.DD} The DD object
7307 initDD : function(group, config, overrides){
7308 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7309 return Roo.apply(dd, overrides);
7313 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7314 * @param {String} group The group the DDProxy object is member of
7315 * @param {Object} config The DDProxy config object
7316 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7317 * @return {Roo.dd.DDProxy} The DDProxy object
7319 initDDProxy : function(group, config, overrides){
7320 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7321 return Roo.apply(dd, overrides);
7325 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7326 * @param {String} group The group the DDTarget object is member of
7327 * @param {Object} config The DDTarget config object
7328 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7329 * @return {Roo.dd.DDTarget} The DDTarget object
7331 initDDTarget : function(group, config, overrides){
7332 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7333 return Roo.apply(dd, overrides);
7337 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7338 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7339 * @param {Boolean} visible Whether the element is visible
7340 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7341 * @return {Roo.Element} this
7343 setVisible : function(visible, animate){
7345 if(this.visibilityMode == El.DISPLAY){
7346 this.setDisplayed(visible);
7349 this.dom.style.visibility = visible ? "visible" : "hidden";
7352 // closure for composites
7354 var visMode = this.visibilityMode;
7356 this.setOpacity(.01);
7357 this.setVisible(true);
7359 this.anim({opacity: { to: (visible?1:0) }},
7360 this.preanim(arguments, 1),
7361 null, .35, 'easeIn', function(){
7363 if(visMode == El.DISPLAY){
7364 dom.style.display = "none";
7366 dom.style.visibility = "hidden";
7368 Roo.get(dom).setOpacity(1);
7376 * Returns true if display is not "none"
7379 isDisplayed : function() {
7380 return this.getStyle("display") != "none";
7384 * Toggles the element's visibility or display, depending on visibility mode.
7385 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7386 * @return {Roo.Element} this
7388 toggle : function(animate){
7389 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7394 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7395 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7396 * @return {Roo.Element} this
7398 setDisplayed : function(value) {
7399 if(typeof value == "boolean"){
7400 value = value ? this.originalDisplay : "none";
7402 this.setStyle("display", value);
7407 * Tries to focus the element. Any exceptions are caught and ignored.
7408 * @return {Roo.Element} this
7410 focus : function() {
7418 * Tries to blur the element. Any exceptions are caught and ignored.
7419 * @return {Roo.Element} this
7429 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7430 * @param {String/Array} className The CSS class to add, or an array of classes
7431 * @return {Roo.Element} this
7433 addClass : function(className){
7434 if(className instanceof Array){
7435 for(var i = 0, len = className.length; i < len; i++) {
7436 this.addClass(className[i]);
7439 if(className && !this.hasClass(className)){
7440 this.dom.className = this.dom.className + " " + className;
7447 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7448 * @param {String/Array} className The CSS class to add, or an array of classes
7449 * @return {Roo.Element} this
7451 radioClass : function(className){
7452 var siblings = this.dom.parentNode.childNodes;
7453 for(var i = 0; i < siblings.length; i++) {
7454 var s = siblings[i];
7455 if(s.nodeType == 1){
7456 Roo.get(s).removeClass(className);
7459 this.addClass(className);
7464 * Removes one or more CSS classes from the element.
7465 * @param {String/Array} className The CSS class to remove, or an array of classes
7466 * @return {Roo.Element} this
7468 removeClass : function(className){
7469 if(!className || !this.dom.className){
7472 if(className instanceof Array){
7473 for(var i = 0, len = className.length; i < len; i++) {
7474 this.removeClass(className[i]);
7477 if(this.hasClass(className)){
7478 var re = this.classReCache[className];
7480 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7481 this.classReCache[className] = re;
7483 this.dom.className =
7484 this.dom.className.replace(re, " ");
7494 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7495 * @param {String} className The CSS class to toggle
7496 * @return {Roo.Element} this
7498 toggleClass : function(className){
7499 if(this.hasClass(className)){
7500 this.removeClass(className);
7502 this.addClass(className);
7508 * Checks if the specified CSS class exists on this element's DOM node.
7509 * @param {String} className The CSS class to check for
7510 * @return {Boolean} True if the class exists, else false
7512 hasClass : function(className){
7513 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7517 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7518 * @param {String} oldClassName The CSS class to replace
7519 * @param {String} newClassName The replacement CSS class
7520 * @return {Roo.Element} this
7522 replaceClass : function(oldClassName, newClassName){
7523 this.removeClass(oldClassName);
7524 this.addClass(newClassName);
7529 * Returns an object with properties matching the styles requested.
7530 * For example, el.getStyles('color', 'font-size', 'width') might return
7531 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7532 * @param {String} style1 A style name
7533 * @param {String} style2 A style name
7534 * @param {String} etc.
7535 * @return {Object} The style object
7537 getStyles : function(){
7538 var a = arguments, len = a.length, r = {};
7539 for(var i = 0; i < len; i++){
7540 r[a[i]] = this.getStyle(a[i]);
7546 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7547 * @param {String} property The style property whose value is returned.
7548 * @return {String} The current value of the style property for this element.
7550 getStyle : function(){
7551 return view && view.getComputedStyle ?
7553 var el = this.dom, v, cs, camel;
7554 if(prop == 'float'){
7557 if(el.style && (v = el.style[prop])){
7560 if(cs = view.getComputedStyle(el, "")){
7561 if(!(camel = propCache[prop])){
7562 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7569 var el = this.dom, v, cs, camel;
7570 if(prop == 'opacity'){
7571 if(typeof el.style.filter == 'string'){
7572 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7574 var fv = parseFloat(m[1]);
7576 return fv ? fv / 100 : 0;
7581 }else if(prop == 'float'){
7582 prop = "styleFloat";
7584 if(!(camel = propCache[prop])){
7585 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7587 if(v = el.style[camel]){
7590 if(cs = el.currentStyle){
7598 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7599 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7600 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7601 * @return {Roo.Element} this
7603 setStyle : function(prop, value){
7604 if(typeof prop == "string"){
7606 if (prop == 'float') {
7607 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7612 if(!(camel = propCache[prop])){
7613 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7616 if(camel == 'opacity') {
7617 this.setOpacity(value);
7619 this.dom.style[camel] = value;
7622 for(var style in prop){
7623 if(typeof prop[style] != "function"){
7624 this.setStyle(style, prop[style]);
7632 * More flexible version of {@link #setStyle} for setting style properties.
7633 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7634 * a function which returns such a specification.
7635 * @return {Roo.Element} this
7637 applyStyles : function(style){
7638 Roo.DomHelper.applyStyles(this.dom, style);
7643 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7644 * @return {Number} The X position of the element
7647 return D.getX(this.dom);
7651 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7652 * @return {Number} The Y position of the element
7655 return D.getY(this.dom);
7659 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7660 * @return {Array} The XY position of the element
7663 return D.getXY(this.dom);
7667 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7668 * @param {Number} The X position of the element
7669 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7670 * @return {Roo.Element} this
7672 setX : function(x, animate){
7674 D.setX(this.dom, x);
7676 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7682 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7683 * @param {Number} The Y position of the element
7684 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7685 * @return {Roo.Element} this
7687 setY : function(y, animate){
7689 D.setY(this.dom, y);
7691 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7697 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7698 * @param {String} left The left CSS property value
7699 * @return {Roo.Element} this
7701 setLeft : function(left){
7702 this.setStyle("left", this.addUnits(left));
7707 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7708 * @param {String} top The top CSS property value
7709 * @return {Roo.Element} this
7711 setTop : function(top){
7712 this.setStyle("top", this.addUnits(top));
7717 * Sets the element's CSS right style.
7718 * @param {String} right The right CSS property value
7719 * @return {Roo.Element} this
7721 setRight : function(right){
7722 this.setStyle("right", this.addUnits(right));
7727 * Sets the element's CSS bottom style.
7728 * @param {String} bottom The bottom CSS property value
7729 * @return {Roo.Element} this
7731 setBottom : function(bottom){
7732 this.setStyle("bottom", this.addUnits(bottom));
7737 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7738 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7739 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7740 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7741 * @return {Roo.Element} this
7743 setXY : function(pos, animate){
7745 D.setXY(this.dom, pos);
7747 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7753 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7754 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7755 * @param {Number} x X value for new position (coordinates are page-based)
7756 * @param {Number} y Y value for new position (coordinates are page-based)
7757 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7758 * @return {Roo.Element} this
7760 setLocation : function(x, y, animate){
7761 this.setXY([x, y], this.preanim(arguments, 2));
7766 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7767 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7768 * @param {Number} x X value for new position (coordinates are page-based)
7769 * @param {Number} y Y value for new position (coordinates are page-based)
7770 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7771 * @return {Roo.Element} this
7773 moveTo : function(x, y, animate){
7774 this.setXY([x, y], this.preanim(arguments, 2));
7779 * Returns the region of the given element.
7780 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7781 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7783 getRegion : function(){
7784 return D.getRegion(this.dom);
7788 * Returns the offset height of the element
7789 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7790 * @return {Number} The element's height
7792 getHeight : function(contentHeight){
7793 var h = this.dom.offsetHeight || 0;
7794 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7798 * Returns the offset width of the element
7799 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7800 * @return {Number} The element's width
7802 getWidth : function(contentWidth){
7803 var w = this.dom.offsetWidth || 0;
7804 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7808 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7809 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7810 * if a height has not been set using CSS.
7813 getComputedHeight : function(){
7814 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7816 h = parseInt(this.getStyle('height'), 10) || 0;
7817 if(!this.isBorderBox()){
7818 h += this.getFrameWidth('tb');
7825 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7826 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7827 * if a width has not been set using CSS.
7830 getComputedWidth : function(){
7831 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7833 w = parseInt(this.getStyle('width'), 10) || 0;
7834 if(!this.isBorderBox()){
7835 w += this.getFrameWidth('lr');
7842 * Returns the size of the element.
7843 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7844 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7846 getSize : function(contentSize){
7847 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7851 * Returns the width and height of the viewport.
7852 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7854 getViewSize : function(){
7855 var d = this.dom, doc = document, aw = 0, ah = 0;
7856 if(d == doc || d == doc.body){
7857 return {width : D.getViewWidth(), height: D.getViewHeight()};
7860 width : d.clientWidth,
7861 height: d.clientHeight
7867 * Returns the value of the "value" attribute
7868 * @param {Boolean} asNumber true to parse the value as a number
7869 * @return {String/Number}
7871 getValue : function(asNumber){
7872 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7876 adjustWidth : function(width){
7877 if(typeof width == "number"){
7878 if(this.autoBoxAdjust && !this.isBorderBox()){
7879 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7889 adjustHeight : function(height){
7890 if(typeof height == "number"){
7891 if(this.autoBoxAdjust && !this.isBorderBox()){
7892 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7902 * Set the width of the element
7903 * @param {Number} width The new width
7904 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7905 * @return {Roo.Element} this
7907 setWidth : function(width, animate){
7908 width = this.adjustWidth(width);
7910 this.dom.style.width = this.addUnits(width);
7912 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7918 * Set the height of the element
7919 * @param {Number} height The new height
7920 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7921 * @return {Roo.Element} this
7923 setHeight : function(height, animate){
7924 height = this.adjustHeight(height);
7926 this.dom.style.height = this.addUnits(height);
7928 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7934 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7935 * @param {Number} width The new width
7936 * @param {Number} height The new height
7937 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7938 * @return {Roo.Element} this
7940 setSize : function(width, height, animate){
7941 if(typeof width == "object"){ // in case of object from getSize()
7942 height = width.height; width = width.width;
7944 width = this.adjustWidth(width); height = this.adjustHeight(height);
7946 this.dom.style.width = this.addUnits(width);
7947 this.dom.style.height = this.addUnits(height);
7949 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7955 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7956 * @param {Number} x X value for new position (coordinates are page-based)
7957 * @param {Number} y Y value for new position (coordinates are page-based)
7958 * @param {Number} width The new width
7959 * @param {Number} height The new height
7960 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961 * @return {Roo.Element} this
7963 setBounds : function(x, y, width, height, animate){
7965 this.setSize(width, height);
7966 this.setLocation(x, y);
7968 width = this.adjustWidth(width); height = this.adjustHeight(height);
7969 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7970 this.preanim(arguments, 4), 'motion');
7976 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7977 * @param {Roo.lib.Region} region The region to fill
7978 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7979 * @return {Roo.Element} this
7981 setRegion : function(region, animate){
7982 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7987 * Appends an event handler
7989 * @param {String} eventName The type of event to append
7990 * @param {Function} fn The method the event invokes
7991 * @param {Object} scope (optional) The scope (this object) of the fn
7992 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7994 addListener : function(eventName, fn, scope, options){
7996 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8001 * Removes an event handler from this element
8002 * @param {String} eventName the type of event to remove
8003 * @param {Function} fn the method the event invokes
8004 * @return {Roo.Element} this
8006 removeListener : function(eventName, fn){
8007 Roo.EventManager.removeListener(this.dom, eventName, fn);
8012 * Removes all previous added listeners from this element
8013 * @return {Roo.Element} this
8015 removeAllListeners : function(){
8016 E.purgeElement(this.dom);
8020 relayEvent : function(eventName, observable){
8021 this.on(eventName, function(e){
8022 observable.fireEvent(eventName, e);
8027 * Set the opacity of the element
8028 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8029 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8030 * @return {Roo.Element} this
8032 setOpacity : function(opacity, animate){
8034 var s = this.dom.style;
8037 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8038 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8040 s.opacity = opacity;
8043 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8049 * Gets the left X coordinate
8050 * @param {Boolean} local True to get the local css position instead of page coordinate
8053 getLeft : function(local){
8057 return parseInt(this.getStyle("left"), 10) || 0;
8062 * Gets the right X coordinate of the element (element X position + element width)
8063 * @param {Boolean} local True to get the local css position instead of page coordinate
8066 getRight : function(local){
8068 return this.getX() + this.getWidth();
8070 return (this.getLeft(true) + this.getWidth()) || 0;
8075 * Gets the top Y coordinate
8076 * @param {Boolean} local True to get the local css position instead of page coordinate
8079 getTop : function(local) {
8083 return parseInt(this.getStyle("top"), 10) || 0;
8088 * Gets the bottom Y coordinate of the element (element Y position + element height)
8089 * @param {Boolean} local True to get the local css position instead of page coordinate
8092 getBottom : function(local){
8094 return this.getY() + this.getHeight();
8096 return (this.getTop(true) + this.getHeight()) || 0;
8101 * Initializes positioning on this element. If a desired position is not passed, it will make the
8102 * the element positioned relative IF it is not already positioned.
8103 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8104 * @param {Number} zIndex (optional) The zIndex to apply
8105 * @param {Number} x (optional) Set the page X position
8106 * @param {Number} y (optional) Set the page Y position
8108 position : function(pos, zIndex, x, y){
8110 if(this.getStyle('position') == 'static'){
8111 this.setStyle('position', 'relative');
8114 this.setStyle("position", pos);
8117 this.setStyle("z-index", zIndex);
8119 if(x !== undefined && y !== undefined){
8121 }else if(x !== undefined){
8123 }else if(y !== undefined){
8129 * Clear positioning back to the default when the document was loaded
8130 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8131 * @return {Roo.Element} this
8133 clearPositioning : function(value){
8141 "position" : "static"
8147 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8148 * snapshot before performing an update and then restoring the element.
8151 getPositioning : function(){
8152 var l = this.getStyle("left");
8153 var t = this.getStyle("top");
8155 "position" : this.getStyle("position"),
8157 "right" : l ? "" : this.getStyle("right"),
8159 "bottom" : t ? "" : this.getStyle("bottom"),
8160 "z-index" : this.getStyle("z-index")
8165 * Gets the width of the border(s) for the specified side(s)
8166 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8167 * passing lr would get the border (l)eft width + the border (r)ight width.
8168 * @return {Number} The width of the sides passed added together
8170 getBorderWidth : function(side){
8171 return this.addStyles(side, El.borders);
8175 * Gets the width of the padding(s) for the specified side(s)
8176 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8177 * passing lr would get the padding (l)eft + the padding (r)ight.
8178 * @return {Number} The padding of the sides passed added together
8180 getPadding : function(side){
8181 return this.addStyles(side, El.paddings);
8185 * Set positioning with an object returned by getPositioning().
8186 * @param {Object} posCfg
8187 * @return {Roo.Element} this
8189 setPositioning : function(pc){
8190 this.applyStyles(pc);
8191 if(pc.right == "auto"){
8192 this.dom.style.right = "";
8194 if(pc.bottom == "auto"){
8195 this.dom.style.bottom = "";
8201 fixDisplay : function(){
8202 if(this.getStyle("display") == "none"){
8203 this.setStyle("visibility", "hidden");
8204 this.setStyle("display", this.originalDisplay); // first try reverting to default
8205 if(this.getStyle("display") == "none"){ // if that fails, default to block
8206 this.setStyle("display", "block");
8212 * Quick set left and top adding default units
8213 * @param {String} left The left CSS property value
8214 * @param {String} top The top CSS property value
8215 * @return {Roo.Element} this
8217 setLeftTop : function(left, top){
8218 this.dom.style.left = this.addUnits(left);
8219 this.dom.style.top = this.addUnits(top);
8224 * Move this element relative to its current position.
8225 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8226 * @param {Number} distance How far to move the element in pixels
8227 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8228 * @return {Roo.Element} this
8230 move : function(direction, distance, animate){
8231 var xy = this.getXY();
8232 direction = direction.toLowerCase();
8236 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8240 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8245 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8250 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8257 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8258 * @return {Roo.Element} this
8261 if(!this.isClipped){
8262 this.isClipped = true;
8263 this.originalClip = {
8264 "o": this.getStyle("overflow"),
8265 "x": this.getStyle("overflow-x"),
8266 "y": this.getStyle("overflow-y")
8268 this.setStyle("overflow", "hidden");
8269 this.setStyle("overflow-x", "hidden");
8270 this.setStyle("overflow-y", "hidden");
8276 * Return clipping (overflow) to original clipping before clip() was called
8277 * @return {Roo.Element} this
8279 unclip : function(){
8281 this.isClipped = false;
8282 var o = this.originalClip;
8283 if(o.o){this.setStyle("overflow", o.o);}
8284 if(o.x){this.setStyle("overflow-x", o.x);}
8285 if(o.y){this.setStyle("overflow-y", o.y);}
8292 * Gets the x,y coordinates specified by the anchor position on the element.
8293 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8294 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8295 * {width: (target width), height: (target height)} (defaults to the element's current size)
8296 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8297 * @return {Array} [x, y] An array containing the element's x and y coordinates
8299 getAnchorXY : function(anchor, local, s){
8300 //Passing a different size is useful for pre-calculating anchors,
8301 //especially for anchored animations that change the el size.
8303 var w, h, vp = false;
8306 if(d == document.body || d == document){
8308 w = D.getViewWidth(); h = D.getViewHeight();
8310 w = this.getWidth(); h = this.getHeight();
8313 w = s.width; h = s.height;
8315 var x = 0, y = 0, r = Math.round;
8316 switch((anchor || "tl").toLowerCase()){
8358 var sc = this.getScroll();
8359 return [x + sc.left, y + sc.top];
8361 //Add the element's offset xy
8362 var o = this.getXY();
8363 return [x+o[0], y+o[1]];
8367 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8368 * supported position values.
8369 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8370 * @param {String} position The position to align to.
8371 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8372 * @return {Array} [x, y]
8374 getAlignToXY : function(el, p, o){
8378 throw "Element.alignTo with an element that doesn't exist";
8380 var c = false; //constrain to viewport
8381 var p1 = "", p2 = "";
8388 }else if(p.indexOf("-") == -1){
8391 p = p.toLowerCase();
8392 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8394 throw "Element.alignTo with an invalid alignment " + p;
8396 p1 = m[1]; p2 = m[2]; c = !!m[3];
8398 //Subtract the aligned el's internal xy from the target's offset xy
8399 //plus custom offset to get the aligned el's new offset xy
8400 var a1 = this.getAnchorXY(p1, true);
8401 var a2 = el.getAnchorXY(p2, false);
8402 var x = a2[0] - a1[0] + o[0];
8403 var y = a2[1] - a1[1] + o[1];
8405 //constrain the aligned el to viewport if necessary
8406 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8407 // 5px of margin for ie
8408 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8410 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8411 //perpendicular to the vp border, allow the aligned el to slide on that border,
8412 //otherwise swap the aligned el to the opposite border of the target.
8413 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8414 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8415 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8416 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8419 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8420 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8422 if((x+w) > dw + scrollX){
8423 x = swapX ? r.left-w : dw+scrollX-w;
8426 x = swapX ? r.right : scrollX;
8428 if((y+h) > dh + scrollY){
8429 y = swapY ? r.top-h : dh+scrollY-h;
8432 y = swapY ? r.bottom : scrollY;
8439 getConstrainToXY : function(){
8440 var os = {top:0, left:0, bottom:0, right: 0};
8442 return function(el, local, offsets, proposedXY){
8444 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8446 var vw, vh, vx = 0, vy = 0;
8447 if(el.dom == document.body || el.dom == document){
8448 vw = Roo.lib.Dom.getViewWidth();
8449 vh = Roo.lib.Dom.getViewHeight();
8451 vw = el.dom.clientWidth;
8452 vh = el.dom.clientHeight;
8454 var vxy = el.getXY();
8460 var s = el.getScroll();
8462 vx += offsets.left + s.left;
8463 vy += offsets.top + s.top;
8465 vw -= offsets.right;
8466 vh -= offsets.bottom;
8471 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8472 var x = xy[0], y = xy[1];
8473 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8475 // only move it if it needs it
8478 // first validate right/bottom
8487 // then make sure top/left isn't negative
8496 return moved ? [x, y] : false;
8501 adjustForConstraints : function(xy, parent, offsets){
8502 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8506 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8507 * document it aligns it to the viewport.
8508 * The position parameter is optional, and can be specified in any one of the following formats:
8510 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8511 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8512 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8513 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8514 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8515 * element's anchor point, and the second value is used as the target's anchor point.</li>
8517 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8518 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8519 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8520 * that specified in order to enforce the viewport constraints.
8521 * Following are all of the supported anchor positions:
8524 ----- -----------------------------
8525 tl The top left corner (default)
8526 t The center of the top edge
8527 tr The top right corner
8528 l The center of the left edge
8529 c In the center of the element
8530 r The center of the right edge
8531 bl The bottom left corner
8532 b The center of the bottom edge
8533 br The bottom right corner
8537 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8538 el.alignTo("other-el");
8540 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8541 el.alignTo("other-el", "tr?");
8543 // align the bottom right corner of el with the center left edge of other-el
8544 el.alignTo("other-el", "br-l?");
8546 // align the center of el with the bottom left corner of other-el and
8547 // adjust the x position by -6 pixels (and the y position by 0)
8548 el.alignTo("other-el", "c-bl", [-6, 0]);
8550 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8551 * @param {String} position The position to align to.
8552 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8553 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8554 * @return {Roo.Element} this
8556 alignTo : function(element, position, offsets, animate){
8557 var xy = this.getAlignToXY(element, position, offsets);
8558 this.setXY(xy, this.preanim(arguments, 3));
8563 * Anchors an element to another element and realigns it when the window is resized.
8564 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8565 * @param {String} position The position to align to.
8566 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8567 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8568 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8569 * is a number, it is used as the buffer delay (defaults to 50ms).
8570 * @param {Function} callback The function to call after the animation finishes
8571 * @return {Roo.Element} this
8573 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8574 var action = function(){
8575 this.alignTo(el, alignment, offsets, animate);
8576 Roo.callback(callback, this);
8578 Roo.EventManager.onWindowResize(action, this);
8579 var tm = typeof monitorScroll;
8580 if(tm != 'undefined'){
8581 Roo.EventManager.on(window, 'scroll', action, this,
8582 {buffer: tm == 'number' ? monitorScroll : 50});
8584 action.call(this); // align immediately
8588 * Clears any opacity settings from this element. Required in some cases for IE.
8589 * @return {Roo.Element} this
8591 clearOpacity : function(){
8592 if (window.ActiveXObject) {
8593 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8594 this.dom.style.filter = "";
8597 this.dom.style.opacity = "";
8598 this.dom.style["-moz-opacity"] = "";
8599 this.dom.style["-khtml-opacity"] = "";
8605 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8606 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8607 * @return {Roo.Element} this
8609 hide : function(animate){
8610 this.setVisible(false, this.preanim(arguments, 0));
8615 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8616 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8617 * @return {Roo.Element} this
8619 show : function(animate){
8620 this.setVisible(true, this.preanim(arguments, 0));
8625 * @private Test if size has a unit, otherwise appends the default
8627 addUnits : function(size){
8628 return Roo.Element.addUnits(size, this.defaultUnit);
8632 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8633 * @return {Roo.Element} this
8635 beginMeasure : function(){
8637 if(el.offsetWidth || el.offsetHeight){
8638 return this; // offsets work already
8641 var p = this.dom, b = document.body; // start with this element
8642 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8643 var pe = Roo.get(p);
8644 if(pe.getStyle('display') == 'none'){
8645 changed.push({el: p, visibility: pe.getStyle("visibility")});
8646 p.style.visibility = "hidden";
8647 p.style.display = "block";
8651 this._measureChanged = changed;
8657 * Restores displays to before beginMeasure was called
8658 * @return {Roo.Element} this
8660 endMeasure : function(){
8661 var changed = this._measureChanged;
8663 for(var i = 0, len = changed.length; i < len; i++) {
8665 r.el.style.visibility = r.visibility;
8666 r.el.style.display = "none";
8668 this._measureChanged = null;
8674 * Update the innerHTML of this element, optionally searching for and processing scripts
8675 * @param {String} html The new HTML
8676 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8677 * @param {Function} callback For async script loading you can be noticed when the update completes
8678 * @return {Roo.Element} this
8680 update : function(html, loadScripts, callback){
8681 if(typeof html == "undefined"){
8684 if(loadScripts !== true){
8685 this.dom.innerHTML = html;
8686 if(typeof callback == "function"){
8694 html += '<span id="' + id + '"></span>';
8696 E.onAvailable(id, function(){
8697 var hd = document.getElementsByTagName("head")[0];
8698 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8699 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8700 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8703 while(match = re.exec(html)){
8704 var attrs = match[1];
8705 var srcMatch = attrs ? attrs.match(srcRe) : false;
8706 if(srcMatch && srcMatch[2]){
8707 var s = document.createElement("script");
8708 s.src = srcMatch[2];
8709 var typeMatch = attrs.match(typeRe);
8710 if(typeMatch && typeMatch[2]){
8711 s.type = typeMatch[2];
8714 }else if(match[2] && match[2].length > 0){
8715 if(window.execScript) {
8716 window.execScript(match[2]);
8724 window.eval(match[2]);
8728 var el = document.getElementById(id);
8729 if(el){el.parentNode.removeChild(el);}
8730 if(typeof callback == "function"){
8734 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8739 * Direct access to the UpdateManager update() method (takes the same parameters).
8740 * @param {String/Function} url The url for this request or a function to call to get the url
8741 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8742 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8743 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8744 * @return {Roo.Element} this
8747 var um = this.getUpdateManager();
8748 um.update.apply(um, arguments);
8753 * Gets this element's UpdateManager
8754 * @return {Roo.UpdateManager} The UpdateManager
8756 getUpdateManager : function(){
8757 if(!this.updateManager){
8758 this.updateManager = new Roo.UpdateManager(this);
8760 return this.updateManager;
8764 * Disables text selection for this element (normalized across browsers)
8765 * @return {Roo.Element} this
8767 unselectable : function(){
8768 this.dom.unselectable = "on";
8769 this.swallowEvent("selectstart", true);
8770 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8771 this.addClass("x-unselectable");
8776 * Calculates the x, y to center this element on the screen
8777 * @return {Array} The x, y values [x, y]
8779 getCenterXY : function(){
8780 return this.getAlignToXY(document, 'c-c');
8784 * Centers the Element in either the viewport, or another Element.
8785 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8787 center : function(centerIn){
8788 this.alignTo(centerIn || document, 'c-c');
8793 * Tests various css rules/browsers to determine if this element uses a border box
8796 isBorderBox : function(){
8797 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8801 * Return a box {x, y, width, height} that can be used to set another elements
8802 * size/location to match this element.
8803 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8804 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8805 * @return {Object} box An object in the format {x, y, width, height}
8807 getBox : function(contentBox, local){
8812 var left = parseInt(this.getStyle("left"), 10) || 0;
8813 var top = parseInt(this.getStyle("top"), 10) || 0;
8816 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8818 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8820 var l = this.getBorderWidth("l")+this.getPadding("l");
8821 var r = this.getBorderWidth("r")+this.getPadding("r");
8822 var t = this.getBorderWidth("t")+this.getPadding("t");
8823 var b = this.getBorderWidth("b")+this.getPadding("b");
8824 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8826 bx.right = bx.x + bx.width;
8827 bx.bottom = bx.y + bx.height;
8832 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8833 for more information about the sides.
8834 * @param {String} sides
8837 getFrameWidth : function(sides, onlyContentBox){
8838 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8842 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8843 * @param {Object} box The box to fill {x, y, width, height}
8844 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8845 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8846 * @return {Roo.Element} this
8848 setBox : function(box, adjust, animate){
8849 var w = box.width, h = box.height;
8850 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8851 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8852 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8854 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8859 * Forces the browser to repaint this element
8860 * @return {Roo.Element} this
8862 repaint : function(){
8864 this.addClass("x-repaint");
8865 setTimeout(function(){
8866 Roo.get(dom).removeClass("x-repaint");
8872 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8873 * then it returns the calculated width of the sides (see getPadding)
8874 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8875 * @return {Object/Number}
8877 getMargins : function(side){
8880 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8881 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8882 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8883 right: parseInt(this.getStyle("margin-right"), 10) || 0
8886 return this.addStyles(side, El.margins);
8891 addStyles : function(sides, styles){
8893 for(var i = 0, len = sides.length; i < len; i++){
8894 v = this.getStyle(styles[sides.charAt(i)]);
8896 w = parseInt(v, 10);
8904 * Creates a proxy element of this element
8905 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8906 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8907 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8908 * @return {Roo.Element} The new proxy element
8910 createProxy : function(config, renderTo, matchBox){
8912 renderTo = Roo.getDom(renderTo);
8914 renderTo = document.body;
8916 config = typeof config == "object" ?
8917 config : {tag : "div", cls: config};
8918 var proxy = Roo.DomHelper.append(renderTo, config, true);
8920 proxy.setBox(this.getBox());
8926 * Puts a mask over this element to disable user interaction. Requires core.css.
8927 * This method can only be applied to elements which accept child nodes.
8928 * @param {String} msg (optional) A message to display in the mask
8929 * @param {String} msgCls (optional) A css class to apply to the msg element
8930 * @return {Element} The mask element
8932 mask : function(msg, msgCls)
8934 if(this.getStyle("position") == "static"){
8935 this.setStyle("position", "relative");
8938 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8940 this.addClass("x-masked");
8941 this._mask.setDisplayed(true);
8946 while (dom && dom.style) {
8947 if (!isNaN(parseInt(dom.style.zIndex))) {
8948 z = Math.max(z, parseInt(dom.style.zIndex));
8950 dom = dom.parentNode;
8952 // if we are masking the body - then it hides everything..
8953 if (this.dom == document.body) {
8955 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8956 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8959 if(typeof msg == 'string'){
8961 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8963 var mm = this._maskMsg;
8964 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8965 mm.dom.firstChild.innerHTML = msg;
8966 mm.setDisplayed(true);
8968 mm.setStyle('z-index', z + 102);
8970 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8971 this._mask.setHeight(this.getHeight());
8973 this._mask.setStyle('z-index', z + 100);
8979 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8980 * it is cached for reuse.
8982 unmask : function(removeEl){
8984 if(removeEl === true){
8985 this._mask.remove();
8988 this._maskMsg.remove();
8989 delete this._maskMsg;
8992 this._mask.setDisplayed(false);
8994 this._maskMsg.setDisplayed(false);
8998 this.removeClass("x-masked");
9002 * Returns true if this element is masked
9005 isMasked : function(){
9006 return this._mask && this._mask.isVisible();
9010 * Creates an iframe shim for this element to keep selects and other windowed objects from
9012 * @return {Roo.Element} The new shim element
9014 createShim : function(){
9015 var el = document.createElement('iframe');
9016 el.frameBorder = 'no';
9017 el.className = 'roo-shim';
9018 if(Roo.isIE && Roo.isSecure){
9019 el.src = Roo.SSL_SECURE_URL;
9021 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9022 shim.autoBoxAdjust = false;
9027 * Removes this element from the DOM and deletes it from the cache
9029 remove : function(){
9030 if(this.dom.parentNode){
9031 this.dom.parentNode.removeChild(this.dom);
9033 delete El.cache[this.dom.id];
9037 * Sets up event handlers to add and remove a css class when the mouse is over this element
9038 * @param {String} className
9039 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9040 * mouseout events for children elements
9041 * @return {Roo.Element} this
9043 addClassOnOver : function(className, preventFlicker){
9044 this.on("mouseover", function(){
9045 Roo.fly(this, '_internal').addClass(className);
9047 var removeFn = function(e){
9048 if(preventFlicker !== true || !e.within(this, true)){
9049 Roo.fly(this, '_internal').removeClass(className);
9052 this.on("mouseout", removeFn, this.dom);
9057 * Sets up event handlers to add and remove a css class when this element has the focus
9058 * @param {String} className
9059 * @return {Roo.Element} this
9061 addClassOnFocus : function(className){
9062 this.on("focus", function(){
9063 Roo.fly(this, '_internal').addClass(className);
9065 this.on("blur", function(){
9066 Roo.fly(this, '_internal').removeClass(className);
9071 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9072 * @param {String} className
9073 * @return {Roo.Element} this
9075 addClassOnClick : function(className){
9077 this.on("mousedown", function(){
9078 Roo.fly(dom, '_internal').addClass(className);
9079 var d = Roo.get(document);
9080 var fn = function(){
9081 Roo.fly(dom, '_internal').removeClass(className);
9082 d.removeListener("mouseup", fn);
9084 d.on("mouseup", fn);
9090 * Stops the specified event from bubbling and optionally prevents the default action
9091 * @param {String} eventName
9092 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9093 * @return {Roo.Element} this
9095 swallowEvent : function(eventName, preventDefault){
9096 var fn = function(e){
9097 e.stopPropagation();
9102 if(eventName instanceof Array){
9103 for(var i = 0, len = eventName.length; i < len; i++){
9104 this.on(eventName[i], fn);
9108 this.on(eventName, fn);
9115 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9118 * Sizes this element to its parent element's dimensions performing
9119 * neccessary box adjustments.
9120 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9121 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9122 * @return {Roo.Element} this
9124 fitToParent : function(monitorResize, targetParent) {
9125 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9126 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9127 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9130 var p = Roo.get(targetParent || this.dom.parentNode);
9131 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9132 if (monitorResize === true) {
9133 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9134 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9140 * Gets the next sibling, skipping text nodes
9141 * @return {HTMLElement} The next sibling or null
9143 getNextSibling : function(){
9144 var n = this.dom.nextSibling;
9145 while(n && n.nodeType != 1){
9152 * Gets the previous sibling, skipping text nodes
9153 * @return {HTMLElement} The previous sibling or null
9155 getPrevSibling : function(){
9156 var n = this.dom.previousSibling;
9157 while(n && n.nodeType != 1){
9158 n = n.previousSibling;
9165 * Appends the passed element(s) to this element
9166 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9167 * @return {Roo.Element} this
9169 appendChild: function(el){
9176 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9177 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9178 * automatically generated with the specified attributes.
9179 * @param {HTMLElement} insertBefore (optional) a child element of this element
9180 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9181 * @return {Roo.Element} The new child element
9183 createChild: function(config, insertBefore, returnDom){
9184 config = config || {tag:'div'};
9186 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9188 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9192 * Appends this element to the passed element
9193 * @param {String/HTMLElement/Element} el The new parent element
9194 * @return {Roo.Element} this
9196 appendTo: function(el){
9197 el = Roo.getDom(el);
9198 el.appendChild(this.dom);
9203 * Inserts this element before the passed element in the DOM
9204 * @param {String/HTMLElement/Element} el The element to insert before
9205 * @return {Roo.Element} this
9207 insertBefore: function(el){
9208 el = Roo.getDom(el);
9209 el.parentNode.insertBefore(this.dom, el);
9214 * Inserts this element after the passed element in the DOM
9215 * @param {String/HTMLElement/Element} el The element to insert after
9216 * @return {Roo.Element} this
9218 insertAfter: function(el){
9219 el = Roo.getDom(el);
9220 el.parentNode.insertBefore(this.dom, el.nextSibling);
9225 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9226 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9227 * @return {Roo.Element} The new child
9229 insertFirst: function(el, returnDom){
9231 if(typeof el == 'object' && !el.nodeType){ // dh config
9232 return this.createChild(el, this.dom.firstChild, returnDom);
9234 el = Roo.getDom(el);
9235 this.dom.insertBefore(el, this.dom.firstChild);
9236 return !returnDom ? Roo.get(el) : el;
9241 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9242 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9243 * @param {String} where (optional) 'before' or 'after' defaults to before
9244 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9245 * @return {Roo.Element} the inserted Element
9247 insertSibling: function(el, where, returnDom){
9248 where = where ? where.toLowerCase() : 'before';
9250 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9252 if(typeof el == 'object' && !el.nodeType){ // dh config
9253 if(where == 'after' && !this.dom.nextSibling){
9254 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9256 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9260 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9261 where == 'before' ? this.dom : this.dom.nextSibling);
9270 * Creates and wraps this element with another element
9271 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9272 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9273 * @return {HTMLElement/Element} The newly created wrapper element
9275 wrap: function(config, returnDom){
9277 config = {tag: "div"};
9279 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9280 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9285 * Replaces the passed element with this element
9286 * @param {String/HTMLElement/Element} el The element to replace
9287 * @return {Roo.Element} this
9289 replace: function(el){
9291 this.insertBefore(el);
9297 * Inserts an html fragment into this element
9298 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9299 * @param {String} html The HTML fragment
9300 * @param {Boolean} returnEl True to return an Roo.Element
9301 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9303 insertHtml : function(where, html, returnEl){
9304 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9305 return returnEl ? Roo.get(el) : el;
9309 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9310 * @param {Object} o The object with the attributes
9311 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9312 * @return {Roo.Element} this
9314 set : function(o, useSet){
9316 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9318 if(attr == "style" || typeof o[attr] == "function") continue;
9320 el.className = o["cls"];
9322 if(useSet) el.setAttribute(attr, o[attr]);
9323 else el[attr] = o[attr];
9327 Roo.DomHelper.applyStyles(el, o.style);
9333 * Convenience method for constructing a KeyMap
9334 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9335 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9336 * @param {Function} fn The function to call
9337 * @param {Object} scope (optional) The scope of the function
9338 * @return {Roo.KeyMap} The KeyMap created
9340 addKeyListener : function(key, fn, scope){
9342 if(typeof key != "object" || key instanceof Array){
9358 return new Roo.KeyMap(this, config);
9362 * Creates a KeyMap for this element
9363 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9364 * @return {Roo.KeyMap} The KeyMap created
9366 addKeyMap : function(config){
9367 return new Roo.KeyMap(this, config);
9371 * Returns true if this element is scrollable.
9374 isScrollable : function(){
9376 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9380 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9381 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9382 * @param {Number} value The new scroll value
9383 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9384 * @return {Element} this
9387 scrollTo : function(side, value, animate){
9388 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9390 this.dom[prop] = value;
9392 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9393 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9399 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9400 * within this element's scrollable range.
9401 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9402 * @param {Number} distance How far to scroll the element in pixels
9403 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9404 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9405 * was scrolled as far as it could go.
9407 scroll : function(direction, distance, animate){
9408 if(!this.isScrollable()){
9412 var l = el.scrollLeft, t = el.scrollTop;
9413 var w = el.scrollWidth, h = el.scrollHeight;
9414 var cw = el.clientWidth, ch = el.clientHeight;
9415 direction = direction.toLowerCase();
9416 var scrolled = false;
9417 var a = this.preanim(arguments, 2);
9422 var v = Math.min(l + distance, w-cw);
9423 this.scrollTo("left", v, a);
9430 var v = Math.max(l - distance, 0);
9431 this.scrollTo("left", v, a);
9439 var v = Math.max(t - distance, 0);
9440 this.scrollTo("top", v, a);
9448 var v = Math.min(t + distance, h-ch);
9449 this.scrollTo("top", v, a);
9458 * Translates the passed page coordinates into left/top css values for this element
9459 * @param {Number/Array} x The page x or an array containing [x, y]
9460 * @param {Number} y The page y
9461 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9463 translatePoints : function(x, y){
9464 if(typeof x == 'object' || x instanceof Array){
9467 var p = this.getStyle('position');
9468 var o = this.getXY();
9470 var l = parseInt(this.getStyle('left'), 10);
9471 var t = parseInt(this.getStyle('top'), 10);
9474 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9477 t = (p == "relative") ? 0 : this.dom.offsetTop;
9480 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9484 * Returns the current scroll position of the element.
9485 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9487 getScroll : function(){
9488 var d = this.dom, doc = document;
9489 if(d == doc || d == doc.body){
9490 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9491 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9492 return {left: l, top: t};
9494 return {left: d.scrollLeft, top: d.scrollTop};
9499 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9500 * are convert to standard 6 digit hex color.
9501 * @param {String} attr The css attribute
9502 * @param {String} defaultValue The default value to use when a valid color isn't found
9503 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9506 getColor : function(attr, defaultValue, prefix){
9507 var v = this.getStyle(attr);
9508 if(!v || v == "transparent" || v == "inherit") {
9509 return defaultValue;
9511 var color = typeof prefix == "undefined" ? "#" : prefix;
9512 if(v.substr(0, 4) == "rgb("){
9513 var rvs = v.slice(4, v.length -1).split(",");
9514 for(var i = 0; i < 3; i++){
9515 var h = parseInt(rvs[i]).toString(16);
9522 if(v.substr(0, 1) == "#"){
9524 for(var i = 1; i < 4; i++){
9525 var c = v.charAt(i);
9528 }else if(v.length == 7){
9529 color += v.substr(1);
9533 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9537 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9538 * gradient background, rounded corners and a 4-way shadow.
9539 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9540 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9541 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9542 * @return {Roo.Element} this
9544 boxWrap : function(cls){
9545 cls = cls || 'x-box';
9546 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9547 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9552 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9553 * @param {String} namespace The namespace in which to look for the attribute
9554 * @param {String} name The attribute name
9555 * @return {String} The attribute value
9557 getAttributeNS : Roo.isIE ? function(ns, name){
9559 var type = typeof d[ns+":"+name];
9560 if(type != 'undefined' && type != 'unknown'){
9561 return d[ns+":"+name];
9564 } : function(ns, name){
9566 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9571 * Sets or Returns the value the dom attribute value
9572 * @param {String} name The attribute name
9573 * @param {String} value (optional) The value to set the attribute to
9574 * @return {String} The attribute value
9576 attr : function(name){
9577 if (arguments.length > 1) {
9578 this.dom.setAttribute(name, arguments[1]);
9579 return arguments[1];
9581 if (!this.dom.hasAttribute(name)) {
9584 return this.dom.getAttribute(name);
9591 var ep = El.prototype;
9594 * Appends an event handler (Shorthand for addListener)
9595 * @param {String} eventName The type of event to append
9596 * @param {Function} fn The method the event invokes
9597 * @param {Object} scope (optional) The scope (this object) of the fn
9598 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9601 ep.on = ep.addListener;
9603 ep.mon = ep.addListener;
9606 * Removes an event handler from this element (shorthand for removeListener)
9607 * @param {String} eventName the type of event to remove
9608 * @param {Function} fn the method the event invokes
9609 * @return {Roo.Element} this
9612 ep.un = ep.removeListener;
9615 * true to automatically adjust width and height settings for box-model issues (default to true)
9617 ep.autoBoxAdjust = true;
9620 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9623 El.addUnits = function(v, defaultUnit){
9624 if(v === "" || v == "auto"){
9627 if(v === undefined){
9630 if(typeof v == "number" || !El.unitPattern.test(v)){
9631 return v + (defaultUnit || 'px');
9636 // special markup used throughout Roo when box wrapping elements
9637 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9639 * Visibility mode constant - Use visibility to hide element
9645 * Visibility mode constant - Use display to hide element
9651 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9652 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9653 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9665 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9666 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9667 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9668 * @return {Element} The Element object
9671 El.get = function(el){
9673 if(!el){ return null; }
9674 if(typeof el == "string"){ // element id
9675 if(!(elm = document.getElementById(el))){
9678 if(ex = El.cache[el]){
9681 ex = El.cache[el] = new El(elm);
9684 }else if(el.tagName){ // dom element
9688 if(ex = El.cache[id]){
9691 ex = El.cache[id] = new El(el);
9694 }else if(el instanceof El){
9696 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9697 // catch case where it hasn't been appended
9698 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9701 }else if(el.isComposite){
9703 }else if(el instanceof Array){
9704 return El.select(el);
9705 }else if(el == document){
9706 // create a bogus element object representing the document object
9708 var f = function(){};
9709 f.prototype = El.prototype;
9711 docEl.dom = document;
9719 El.uncache = function(el){
9720 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9722 delete El.cache[a[i].id || a[i]];
9728 // Garbage collection - uncache elements/purge listeners on orphaned elements
9729 // so we don't hold a reference and cause the browser to retain them
9730 El.garbageCollect = function(){
9731 if(!Roo.enableGarbageCollector){
9732 clearInterval(El.collectorThread);
9735 for(var eid in El.cache){
9736 var el = El.cache[eid], d = el.dom;
9737 // -------------------------------------------------------
9738 // Determining what is garbage:
9739 // -------------------------------------------------------
9741 // dom node is null, definitely garbage
9742 // -------------------------------------------------------
9744 // no parentNode == direct orphan, definitely garbage
9745 // -------------------------------------------------------
9746 // !d.offsetParent && !document.getElementById(eid)
9747 // display none elements have no offsetParent so we will
9748 // also try to look it up by it's id. However, check
9749 // offsetParent first so we don't do unneeded lookups.
9750 // This enables collection of elements that are not orphans
9751 // directly, but somewhere up the line they have an orphan
9753 // -------------------------------------------------------
9754 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9755 delete El.cache[eid];
9756 if(d && Roo.enableListenerCollection){
9762 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9766 El.Flyweight = function(dom){
9769 El.Flyweight.prototype = El.prototype;
9771 El._flyweights = {};
9773 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9774 * the dom node can be overwritten by other code.
9775 * @param {String/HTMLElement} el The dom node or id
9776 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9777 * prevent conflicts (e.g. internally Roo uses "_internal")
9779 * @return {Element} The shared Element object
9781 El.fly = function(el, named){
9782 named = named || '_global';
9783 el = Roo.getDom(el);
9787 if(!El._flyweights[named]){
9788 El._flyweights[named] = new El.Flyweight();
9790 El._flyweights[named].dom = el;
9791 return El._flyweights[named];
9795 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9796 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9797 * Shorthand of {@link Roo.Element#get}
9798 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9799 * @return {Element} The Element object
9805 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9806 * the dom node can be overwritten by other code.
9807 * Shorthand of {@link Roo.Element#fly}
9808 * @param {String/HTMLElement} el The dom node or id
9809 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9810 * prevent conflicts (e.g. internally Roo uses "_internal")
9812 * @return {Element} The shared Element object
9818 // speedy lookup for elements never to box adjust
9819 var noBoxAdjust = Roo.isStrict ? {
9822 input:1, select:1, textarea:1
9824 if(Roo.isIE || Roo.isGecko){
9825 noBoxAdjust['button'] = 1;
9829 Roo.EventManager.on(window, 'unload', function(){
9831 delete El._flyweights;
9839 Roo.Element.selectorFunction = Roo.DomQuery.select;
9842 Roo.Element.select = function(selector, unique, root){
9844 if(typeof selector == "string"){
9845 els = Roo.Element.selectorFunction(selector, root);
9846 }else if(selector.length !== undefined){
9849 throw "Invalid selector";
9851 if(unique === true){
9852 return new Roo.CompositeElement(els);
9854 return new Roo.CompositeElementLite(els);
9858 * Selects elements based on the passed CSS selector to enable working on them as 1.
9859 * @param {String/Array} selector The CSS selector or an array of elements
9860 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9861 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9862 * @return {CompositeElementLite/CompositeElement}
9866 Roo.select = Roo.Element.select;
9883 * Ext JS Library 1.1.1
9884 * Copyright(c) 2006-2007, Ext JS, LLC.
9886 * Originally Released Under LGPL - original licence link has changed is not relivant.
9889 * <script type="text/javascript">
9894 //Notifies Element that fx methods are available
9895 Roo.enableFx = true;
9899 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9900 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9901 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9902 * Element effects to work.</p><br/>
9904 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9905 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9906 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9907 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9908 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9909 * expected results and should be done with care.</p><br/>
9911 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9912 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9915 ----- -----------------------------
9916 tl The top left corner
9917 t The center of the top edge
9918 tr The top right corner
9919 l The center of the left edge
9920 r The center of the right edge
9921 bl The bottom left corner
9922 b The center of the bottom edge
9923 br The bottom right corner
9925 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9926 * below are common options that can be passed to any Fx method.</b>
9927 * @cfg {Function} callback A function called when the effect is finished
9928 * @cfg {Object} scope The scope of the effect function
9929 * @cfg {String} easing A valid Easing value for the effect
9930 * @cfg {String} afterCls A css class to apply after the effect
9931 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9932 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9933 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9934 * effects that end with the element being visually hidden, ignored otherwise)
9935 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9936 * a function which returns such a specification that will be applied to the Element after the effect finishes
9937 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9938 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
9939 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9943 * Slides the element into view. An anchor point can be optionally passed to set the point of
9944 * origin for the slide effect. This function automatically handles wrapping the element with
9945 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9948 // default: slide the element in from the top
9951 // custom: slide the element in from the right with a 2-second duration
9952 el.slideIn('r', { duration: 2 });
9954 // common config options shown with default values
9960 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9961 * @param {Object} options (optional) Object literal with any of the Fx config options
9962 * @return {Roo.Element} The Element
9964 slideIn : function(anchor, o){
9965 var el = this.getFxEl();
9968 el.queueFx(o, function(){
9970 anchor = anchor || "t";
9972 // fix display to visibility
9975 // restore values after effect
9976 var r = this.getFxRestore();
9977 var b = this.getBox();
9978 // fixed size for slide
9982 var wrap = this.fxWrap(r.pos, o, "hidden");
9984 var st = this.dom.style;
9985 st.visibility = "visible";
9986 st.position = "absolute";
9988 // clear out temp styles after slide and unwrap
9989 var after = function(){
9990 el.fxUnwrap(wrap, r.pos, o);
9992 st.height = r.height;
9995 // time to calc the positions
9996 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9998 switch(anchor.toLowerCase()){
10000 wrap.setSize(b.width, 0);
10001 st.left = st.bottom = "0";
10005 wrap.setSize(0, b.height);
10006 st.right = st.top = "0";
10010 wrap.setSize(0, b.height);
10011 wrap.setX(b.right);
10012 st.left = st.top = "0";
10013 a = {width: bw, points: pt};
10016 wrap.setSize(b.width, 0);
10017 wrap.setY(b.bottom);
10018 st.left = st.top = "0";
10019 a = {height: bh, points: pt};
10022 wrap.setSize(0, 0);
10023 st.right = st.bottom = "0";
10024 a = {width: bw, height: bh};
10027 wrap.setSize(0, 0);
10028 wrap.setY(b.y+b.height);
10029 st.right = st.top = "0";
10030 a = {width: bw, height: bh, points: pt};
10033 wrap.setSize(0, 0);
10034 wrap.setXY([b.right, b.bottom]);
10035 st.left = st.top = "0";
10036 a = {width: bw, height: bh, points: pt};
10039 wrap.setSize(0, 0);
10040 wrap.setX(b.x+b.width);
10041 st.left = st.bottom = "0";
10042 a = {width: bw, height: bh, points: pt};
10045 this.dom.style.visibility = "visible";
10048 arguments.callee.anim = wrap.fxanim(a,
10058 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10059 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10060 * 'hidden') but block elements will still take up space in the document. The element must be removed
10061 * from the DOM using the 'remove' config option if desired. This function automatically handles
10062 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10065 // default: slide the element out to the top
10068 // custom: slide the element out to the right with a 2-second duration
10069 el.slideOut('r', { duration: 2 });
10071 // common config options shown with default values
10079 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10080 * @param {Object} options (optional) Object literal with any of the Fx config options
10081 * @return {Roo.Element} The Element
10083 slideOut : function(anchor, o){
10084 var el = this.getFxEl();
10087 el.queueFx(o, function(){
10089 anchor = anchor || "t";
10091 // restore values after effect
10092 var r = this.getFxRestore();
10094 var b = this.getBox();
10095 // fixed size for slide
10099 var wrap = this.fxWrap(r.pos, o, "visible");
10101 var st = this.dom.style;
10102 st.visibility = "visible";
10103 st.position = "absolute";
10107 var after = function(){
10109 el.setDisplayed(false);
10114 el.fxUnwrap(wrap, r.pos, o);
10116 st.width = r.width;
10117 st.height = r.height;
10122 var a, zero = {to: 0};
10123 switch(anchor.toLowerCase()){
10125 st.left = st.bottom = "0";
10126 a = {height: zero};
10129 st.right = st.top = "0";
10133 st.left = st.top = "0";
10134 a = {width: zero, points: {to:[b.right, b.y]}};
10137 st.left = st.top = "0";
10138 a = {height: zero, points: {to:[b.x, b.bottom]}};
10141 st.right = st.bottom = "0";
10142 a = {width: zero, height: zero};
10145 st.right = st.top = "0";
10146 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10149 st.left = st.top = "0";
10150 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10153 st.left = st.bottom = "0";
10154 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10158 arguments.callee.anim = wrap.fxanim(a,
10168 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10169 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10170 * The element must be removed from the DOM using the 'remove' config option if desired.
10176 // common config options shown with default values
10184 * @param {Object} options (optional) Object literal with any of the Fx config options
10185 * @return {Roo.Element} The Element
10187 puff : function(o){
10188 var el = this.getFxEl();
10191 el.queueFx(o, function(){
10192 this.clearOpacity();
10195 // restore values after effect
10196 var r = this.getFxRestore();
10197 var st = this.dom.style;
10199 var after = function(){
10201 el.setDisplayed(false);
10208 el.setPositioning(r.pos);
10209 st.width = r.width;
10210 st.height = r.height;
10215 var width = this.getWidth();
10216 var height = this.getHeight();
10218 arguments.callee.anim = this.fxanim({
10219 width : {to: this.adjustWidth(width * 2)},
10220 height : {to: this.adjustHeight(height * 2)},
10221 points : {by: [-(width * .5), -(height * .5)]},
10223 fontSize: {to:200, unit: "%"}
10234 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10235 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10236 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10242 // all config options shown with default values
10250 * @param {Object} options (optional) Object literal with any of the Fx config options
10251 * @return {Roo.Element} The Element
10253 switchOff : function(o){
10254 var el = this.getFxEl();
10257 el.queueFx(o, function(){
10258 this.clearOpacity();
10261 // restore values after effect
10262 var r = this.getFxRestore();
10263 var st = this.dom.style;
10265 var after = function(){
10267 el.setDisplayed(false);
10273 el.setPositioning(r.pos);
10274 st.width = r.width;
10275 st.height = r.height;
10280 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10281 this.clearOpacity();
10285 points:{by:[0, this.getHeight() * .5]}
10286 }, o, 'motion', 0.3, 'easeIn', after);
10287 }).defer(100, this);
10294 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10295 * changed using the "attr" config option) and then fading back to the original color. If no original
10296 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10299 // default: highlight background to yellow
10302 // custom: highlight foreground text to blue for 2 seconds
10303 el.highlight("0000ff", { attr: 'color', duration: 2 });
10305 // common config options shown with default values
10306 el.highlight("ffff9c", {
10307 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10308 endColor: (current color) or "ffffff",
10313 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10314 * @param {Object} options (optional) Object literal with any of the Fx config options
10315 * @return {Roo.Element} The Element
10317 highlight : function(color, o){
10318 var el = this.getFxEl();
10321 el.queueFx(o, function(){
10322 color = color || "ffff9c";
10323 attr = o.attr || "backgroundColor";
10325 this.clearOpacity();
10328 var origColor = this.getColor(attr);
10329 var restoreColor = this.dom.style[attr];
10330 endColor = (o.endColor || origColor) || "ffffff";
10332 var after = function(){
10333 el.dom.style[attr] = restoreColor;
10338 a[attr] = {from: color, to: endColor};
10339 arguments.callee.anim = this.fxanim(a,
10349 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10352 // default: a single light blue ripple
10355 // custom: 3 red ripples lasting 3 seconds total
10356 el.frame("ff0000", 3, { duration: 3 });
10358 // common config options shown with default values
10359 el.frame("C3DAF9", 1, {
10360 duration: 1 //duration of entire animation (not each individual ripple)
10361 // Note: Easing is not configurable and will be ignored if included
10364 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10365 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10366 * @param {Object} options (optional) Object literal with any of the Fx config options
10367 * @return {Roo.Element} The Element
10369 frame : function(color, count, o){
10370 var el = this.getFxEl();
10373 el.queueFx(o, function(){
10374 color = color || "#C3DAF9";
10375 if(color.length == 6){
10376 color = "#" + color;
10378 count = count || 1;
10379 duration = o.duration || 1;
10382 var b = this.getBox();
10383 var animFn = function(){
10384 var proxy = this.createProxy({
10387 visbility:"hidden",
10388 position:"absolute",
10389 "z-index":"35000", // yee haw
10390 border:"0px solid " + color
10393 var scale = Roo.isBorderBox ? 2 : 1;
10395 top:{from:b.y, to:b.y - 20},
10396 left:{from:b.x, to:b.x - 20},
10397 borderWidth:{from:0, to:10},
10398 opacity:{from:1, to:0},
10399 height:{from:b.height, to:(b.height + (20*scale))},
10400 width:{from:b.width, to:(b.width + (20*scale))}
10401 }, duration, function(){
10405 animFn.defer((duration/2)*1000, this);
10416 * Creates a pause before any subsequent queued effects begin. If there are
10417 * no effects queued after the pause it will have no effect.
10422 * @param {Number} seconds The length of time to pause (in seconds)
10423 * @return {Roo.Element} The Element
10425 pause : function(seconds){
10426 var el = this.getFxEl();
10429 el.queueFx(o, function(){
10430 setTimeout(function(){
10432 }, seconds * 1000);
10438 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10439 * using the "endOpacity" config option.
10442 // default: fade in from opacity 0 to 100%
10445 // custom: fade in from opacity 0 to 75% over 2 seconds
10446 el.fadeIn({ endOpacity: .75, duration: 2});
10448 // common config options shown with default values
10450 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10455 * @param {Object} options (optional) Object literal with any of the Fx config options
10456 * @return {Roo.Element} The Element
10458 fadeIn : function(o){
10459 var el = this.getFxEl();
10461 el.queueFx(o, function(){
10462 this.setOpacity(0);
10464 this.dom.style.visibility = 'visible';
10465 var to = o.endOpacity || 1;
10466 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10467 o, null, .5, "easeOut", function(){
10469 this.clearOpacity();
10478 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10479 * using the "endOpacity" config option.
10482 // default: fade out from the element's current opacity to 0
10485 // custom: fade out from the element's current opacity to 25% over 2 seconds
10486 el.fadeOut({ endOpacity: .25, duration: 2});
10488 // common config options shown with default values
10490 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10497 * @param {Object} options (optional) Object literal with any of the Fx config options
10498 * @return {Roo.Element} The Element
10500 fadeOut : function(o){
10501 var el = this.getFxEl();
10503 el.queueFx(o, function(){
10504 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10505 o, null, .5, "easeOut", function(){
10506 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10507 this.dom.style.display = "none";
10509 this.dom.style.visibility = "hidden";
10511 this.clearOpacity();
10519 * Animates the transition of an element's dimensions from a starting height/width
10520 * to an ending height/width.
10523 // change height and width to 100x100 pixels
10524 el.scale(100, 100);
10526 // common config options shown with default values. The height and width will default to
10527 // the element's existing values if passed as null.
10530 [element's height], {
10535 * @param {Number} width The new width (pass undefined to keep the original width)
10536 * @param {Number} height The new height (pass undefined to keep the original height)
10537 * @param {Object} options (optional) Object literal with any of the Fx config options
10538 * @return {Roo.Element} The Element
10540 scale : function(w, h, o){
10541 this.shift(Roo.apply({}, o, {
10549 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10550 * Any of these properties not specified in the config object will not be changed. This effect
10551 * requires that at least one new dimension, position or opacity setting must be passed in on
10552 * the config object in order for the function to have any effect.
10555 // slide the element horizontally to x position 200 while changing the height and opacity
10556 el.shift({ x: 200, height: 50, opacity: .8 });
10558 // common config options shown with default values.
10560 width: [element's width],
10561 height: [element's height],
10562 x: [element's x position],
10563 y: [element's y position],
10564 opacity: [element's opacity],
10569 * @param {Object} options Object literal with any of the Fx config options
10570 * @return {Roo.Element} The Element
10572 shift : function(o){
10573 var el = this.getFxEl();
10575 el.queueFx(o, function(){
10576 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10577 if(w !== undefined){
10578 a.width = {to: this.adjustWidth(w)};
10580 if(h !== undefined){
10581 a.height = {to: this.adjustHeight(h)};
10583 if(x !== undefined || y !== undefined){
10585 x !== undefined ? x : this.getX(),
10586 y !== undefined ? y : this.getY()
10589 if(op !== undefined){
10590 a.opacity = {to: op};
10592 if(o.xy !== undefined){
10593 a.points = {to: o.xy};
10595 arguments.callee.anim = this.fxanim(a,
10596 o, 'motion', .35, "easeOut", function(){
10604 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10605 * ending point of the effect.
10608 // default: slide the element downward while fading out
10611 // custom: slide the element out to the right with a 2-second duration
10612 el.ghost('r', { duration: 2 });
10614 // common config options shown with default values
10622 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10623 * @param {Object} options (optional) Object literal with any of the Fx config options
10624 * @return {Roo.Element} The Element
10626 ghost : function(anchor, o){
10627 var el = this.getFxEl();
10630 el.queueFx(o, function(){
10631 anchor = anchor || "b";
10633 // restore values after effect
10634 var r = this.getFxRestore();
10635 var w = this.getWidth(),
10636 h = this.getHeight();
10638 var st = this.dom.style;
10640 var after = function(){
10642 el.setDisplayed(false);
10648 el.setPositioning(r.pos);
10649 st.width = r.width;
10650 st.height = r.height;
10655 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10656 switch(anchor.toLowerCase()){
10683 arguments.callee.anim = this.fxanim(a,
10693 * Ensures that all effects queued after syncFx is called on the element are
10694 * run concurrently. This is the opposite of {@link #sequenceFx}.
10695 * @return {Roo.Element} The Element
10697 syncFx : function(){
10698 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10707 * Ensures that all effects queued after sequenceFx is called on the element are
10708 * run in sequence. This is the opposite of {@link #syncFx}.
10709 * @return {Roo.Element} The Element
10711 sequenceFx : function(){
10712 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10714 concurrent : false,
10721 nextFx : function(){
10722 var ef = this.fxQueue[0];
10729 * Returns true if the element has any effects actively running or queued, else returns false.
10730 * @return {Boolean} True if element has active effects, else false
10732 hasActiveFx : function(){
10733 return this.fxQueue && this.fxQueue[0];
10737 * Stops any running effects and clears the element's internal effects queue if it contains
10738 * any additional effects that haven't started yet.
10739 * @return {Roo.Element} The Element
10741 stopFx : function(){
10742 if(this.hasActiveFx()){
10743 var cur = this.fxQueue[0];
10744 if(cur && cur.anim && cur.anim.isAnimated()){
10745 this.fxQueue = [cur]; // clear out others
10746 cur.anim.stop(true);
10753 beforeFx : function(o){
10754 if(this.hasActiveFx() && !o.concurrent){
10765 * Returns true if the element is currently blocking so that no other effect can be queued
10766 * until this effect is finished, else returns false if blocking is not set. This is commonly
10767 * used to ensure that an effect initiated by a user action runs to completion prior to the
10768 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10769 * @return {Boolean} True if blocking, else false
10771 hasFxBlock : function(){
10772 var q = this.fxQueue;
10773 return q && q[0] && q[0].block;
10777 queueFx : function(o, fn){
10781 if(!this.hasFxBlock()){
10782 Roo.applyIf(o, this.fxDefaults);
10784 var run = this.beforeFx(o);
10785 fn.block = o.block;
10786 this.fxQueue.push(fn);
10798 fxWrap : function(pos, o, vis){
10800 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10803 wrapXY = this.getXY();
10805 var div = document.createElement("div");
10806 div.style.visibility = vis;
10807 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10808 wrap.setPositioning(pos);
10809 if(wrap.getStyle("position") == "static"){
10810 wrap.position("relative");
10812 this.clearPositioning('auto');
10814 wrap.dom.appendChild(this.dom);
10816 wrap.setXY(wrapXY);
10823 fxUnwrap : function(wrap, pos, o){
10824 this.clearPositioning();
10825 this.setPositioning(pos);
10827 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10833 getFxRestore : function(){
10834 var st = this.dom.style;
10835 return {pos: this.getPositioning(), width: st.width, height : st.height};
10839 afterFx : function(o){
10841 this.applyStyles(o.afterStyle);
10844 this.addClass(o.afterCls);
10846 if(o.remove === true){
10849 Roo.callback(o.callback, o.scope, [this]);
10851 this.fxQueue.shift();
10857 getFxEl : function(){ // support for composite element fx
10858 return Roo.get(this.dom);
10862 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10863 animType = animType || 'run';
10865 var anim = Roo.lib.Anim[animType](
10867 (opt.duration || defaultDur) || .35,
10868 (opt.easing || defaultEase) || 'easeOut',
10870 Roo.callback(cb, this);
10879 // backwords compat
10880 Roo.Fx.resize = Roo.Fx.scale;
10882 //When included, Roo.Fx is automatically applied to Element so that all basic
10883 //effects are available directly via the Element API
10884 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10886 * Ext JS Library 1.1.1
10887 * Copyright(c) 2006-2007, Ext JS, LLC.
10889 * Originally Released Under LGPL - original licence link has changed is not relivant.
10892 * <script type="text/javascript">
10897 * @class Roo.CompositeElement
10898 * Standard composite class. Creates a Roo.Element for every element in the collection.
10900 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10901 * actions will be performed on all the elements in this collection.</b>
10903 * All methods return <i>this</i> and can be chained.
10905 var els = Roo.select("#some-el div.some-class", true);
10906 // or select directly from an existing element
10907 var el = Roo.get('some-el');
10908 el.select('div.some-class', true);
10910 els.setWidth(100); // all elements become 100 width
10911 els.hide(true); // all elements fade out and hide
10913 els.setWidth(100).hide(true);
10916 Roo.CompositeElement = function(els){
10917 this.elements = [];
10918 this.addElements(els);
10920 Roo.CompositeElement.prototype = {
10922 addElements : function(els){
10923 if(!els) return this;
10924 if(typeof els == "string"){
10925 els = Roo.Element.selectorFunction(els);
10927 var yels = this.elements;
10928 var index = yels.length-1;
10929 for(var i = 0, len = els.length; i < len; i++) {
10930 yels[++index] = Roo.get(els[i]);
10936 * Clears this composite and adds the elements returned by the passed selector.
10937 * @param {String/Array} els A string CSS selector, an array of elements or an element
10938 * @return {CompositeElement} this
10940 fill : function(els){
10941 this.elements = [];
10947 * Filters this composite to only elements that match the passed selector.
10948 * @param {String} selector A string CSS selector
10949 * @param {Boolean} inverse return inverse filter (not matches)
10950 * @return {CompositeElement} this
10952 filter : function(selector, inverse){
10954 inverse = inverse || false;
10955 this.each(function(el){
10956 var match = inverse ? !el.is(selector) : el.is(selector);
10958 els[els.length] = el.dom;
10965 invoke : function(fn, args){
10966 var els = this.elements;
10967 for(var i = 0, len = els.length; i < len; i++) {
10968 Roo.Element.prototype[fn].apply(els[i], args);
10973 * Adds elements to this composite.
10974 * @param {String/Array} els A string CSS selector, an array of elements or an element
10975 * @return {CompositeElement} this
10977 add : function(els){
10978 if(typeof els == "string"){
10979 this.addElements(Roo.Element.selectorFunction(els));
10980 }else if(els.length !== undefined){
10981 this.addElements(els);
10983 this.addElements([els]);
10988 * Calls the passed function passing (el, this, index) for each element in this composite.
10989 * @param {Function} fn The function to call
10990 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10991 * @return {CompositeElement} this
10993 each : function(fn, scope){
10994 var els = this.elements;
10995 for(var i = 0, len = els.length; i < len; i++){
10996 if(fn.call(scope || els[i], els[i], this, i) === false) {
11004 * Returns the Element object at the specified index
11005 * @param {Number} index
11006 * @return {Roo.Element}
11008 item : function(index){
11009 return this.elements[index] || null;
11013 * Returns the first Element
11014 * @return {Roo.Element}
11016 first : function(){
11017 return this.item(0);
11021 * Returns the last Element
11022 * @return {Roo.Element}
11025 return this.item(this.elements.length-1);
11029 * Returns the number of elements in this composite
11032 getCount : function(){
11033 return this.elements.length;
11037 * Returns true if this composite contains the passed element
11040 contains : function(el){
11041 return this.indexOf(el) !== -1;
11045 * Returns true if this composite contains the passed element
11048 indexOf : function(el){
11049 return this.elements.indexOf(Roo.get(el));
11054 * Removes the specified element(s).
11055 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11056 * or an array of any of those.
11057 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11058 * @return {CompositeElement} this
11060 removeElement : function(el, removeDom){
11061 if(el instanceof Array){
11062 for(var i = 0, len = el.length; i < len; i++){
11063 this.removeElement(el[i]);
11067 var index = typeof el == 'number' ? el : this.indexOf(el);
11070 var d = this.elements[index];
11074 d.parentNode.removeChild(d);
11077 this.elements.splice(index, 1);
11083 * Replaces the specified element with the passed element.
11084 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11086 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11087 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11088 * @return {CompositeElement} this
11090 replaceElement : function(el, replacement, domReplace){
11091 var index = typeof el == 'number' ? el : this.indexOf(el);
11094 this.elements[index].replaceWith(replacement);
11096 this.elements.splice(index, 1, Roo.get(replacement))
11103 * Removes all elements.
11105 clear : function(){
11106 this.elements = [];
11110 Roo.CompositeElement.createCall = function(proto, fnName){
11111 if(!proto[fnName]){
11112 proto[fnName] = function(){
11113 return this.invoke(fnName, arguments);
11117 for(var fnName in Roo.Element.prototype){
11118 if(typeof Roo.Element.prototype[fnName] == "function"){
11119 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11125 * Ext JS Library 1.1.1
11126 * Copyright(c) 2006-2007, Ext JS, LLC.
11128 * Originally Released Under LGPL - original licence link has changed is not relivant.
11131 * <script type="text/javascript">
11135 * @class Roo.CompositeElementLite
11136 * @extends Roo.CompositeElement
11137 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11139 var els = Roo.select("#some-el div.some-class");
11140 // or select directly from an existing element
11141 var el = Roo.get('some-el');
11142 el.select('div.some-class');
11144 els.setWidth(100); // all elements become 100 width
11145 els.hide(true); // all elements fade out and hide
11147 els.setWidth(100).hide(true);
11148 </code></pre><br><br>
11149 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11150 * actions will be performed on all the elements in this collection.</b>
11152 Roo.CompositeElementLite = function(els){
11153 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11154 this.el = new Roo.Element.Flyweight();
11156 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11157 addElements : function(els){
11159 if(els instanceof Array){
11160 this.elements = this.elements.concat(els);
11162 var yels = this.elements;
11163 var index = yels.length-1;
11164 for(var i = 0, len = els.length; i < len; i++) {
11165 yels[++index] = els[i];
11171 invoke : function(fn, args){
11172 var els = this.elements;
11174 for(var i = 0, len = els.length; i < len; i++) {
11176 Roo.Element.prototype[fn].apply(el, args);
11181 * Returns a flyweight Element of the dom element object at the specified index
11182 * @param {Number} index
11183 * @return {Roo.Element}
11185 item : function(index){
11186 if(!this.elements[index]){
11189 this.el.dom = this.elements[index];
11193 // fixes scope with flyweight
11194 addListener : function(eventName, handler, scope, opt){
11195 var els = this.elements;
11196 for(var i = 0, len = els.length; i < len; i++) {
11197 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11203 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11204 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11205 * a reference to the dom node, use el.dom.</b>
11206 * @param {Function} fn The function to call
11207 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11208 * @return {CompositeElement} this
11210 each : function(fn, scope){
11211 var els = this.elements;
11213 for(var i = 0, len = els.length; i < len; i++){
11215 if(fn.call(scope || el, el, this, i) === false){
11222 indexOf : function(el){
11223 return this.elements.indexOf(Roo.getDom(el));
11226 replaceElement : function(el, replacement, domReplace){
11227 var index = typeof el == 'number' ? el : this.indexOf(el);
11229 replacement = Roo.getDom(replacement);
11231 var d = this.elements[index];
11232 d.parentNode.insertBefore(replacement, d);
11233 d.parentNode.removeChild(d);
11235 this.elements.splice(index, 1, replacement);
11240 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11244 * Ext JS Library 1.1.1
11245 * Copyright(c) 2006-2007, Ext JS, LLC.
11247 * Originally Released Under LGPL - original licence link has changed is not relivant.
11250 * <script type="text/javascript">
11256 * @class Roo.data.Connection
11257 * @extends Roo.util.Observable
11258 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11259 * either to a configured URL, or to a URL specified at request time.<br><br>
11261 * Requests made by this class are asynchronous, and will return immediately. No data from
11262 * the server will be available to the statement immediately following the {@link #request} call.
11263 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11265 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11266 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11267 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11268 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11269 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11270 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11271 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11272 * standard DOM methods.
11274 * @param {Object} config a configuration object.
11276 Roo.data.Connection = function(config){
11277 Roo.apply(this, config);
11280 * @event beforerequest
11281 * Fires before a network request is made to retrieve a data object.
11282 * @param {Connection} conn This Connection object.
11283 * @param {Object} options The options config object passed to the {@link #request} method.
11285 "beforerequest" : true,
11287 * @event requestcomplete
11288 * Fires if the request was successfully completed.
11289 * @param {Connection} conn This Connection object.
11290 * @param {Object} response The XHR object containing the response data.
11291 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11292 * @param {Object} options The options config object passed to the {@link #request} method.
11294 "requestcomplete" : true,
11296 * @event requestexception
11297 * Fires if an error HTTP status was returned from the server.
11298 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11299 * @param {Connection} conn This Connection object.
11300 * @param {Object} response The XHR object containing the response data.
11301 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11302 * @param {Object} options The options config object passed to the {@link #request} method.
11304 "requestexception" : true
11306 Roo.data.Connection.superclass.constructor.call(this);
11309 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11311 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11314 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11315 * extra parameters to each request made by this object. (defaults to undefined)
11318 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11319 * to each request made by this object. (defaults to undefined)
11322 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11325 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11329 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11335 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11338 disableCaching: true,
11341 * Sends an HTTP request to a remote server.
11342 * @param {Object} options An object which may contain the following properties:<ul>
11343 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11344 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11345 * request, a url encoded string or a function to call to get either.</li>
11346 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11347 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11348 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11349 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11350 * <li>options {Object} The parameter to the request call.</li>
11351 * <li>success {Boolean} True if the request succeeded.</li>
11352 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11354 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11355 * The callback is passed the following parameters:<ul>
11356 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11357 * <li>options {Object} The parameter to the request call.</li>
11359 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11360 * The callback is passed the following parameters:<ul>
11361 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11362 * <li>options {Object} The parameter to the request call.</li>
11364 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11365 * for the callback function. Defaults to the browser window.</li>
11366 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11367 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11368 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11369 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11370 * params for the post data. Any params will be appended to the URL.</li>
11371 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11373 * @return {Number} transactionId
11375 request : function(o){
11376 if(this.fireEvent("beforerequest", this, o) !== false){
11379 if(typeof p == "function"){
11380 p = p.call(o.scope||window, o);
11382 if(typeof p == "object"){
11383 p = Roo.urlEncode(o.params);
11385 if(this.extraParams){
11386 var extras = Roo.urlEncode(this.extraParams);
11387 p = p ? (p + '&' + extras) : extras;
11390 var url = o.url || this.url;
11391 if(typeof url == 'function'){
11392 url = url.call(o.scope||window, o);
11396 var form = Roo.getDom(o.form);
11397 url = url || form.action;
11399 var enctype = form.getAttribute("enctype");
11400 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11401 return this.doFormUpload(o, p, url);
11403 var f = Roo.lib.Ajax.serializeForm(form);
11404 p = p ? (p + '&' + f) : f;
11407 var hs = o.headers;
11408 if(this.defaultHeaders){
11409 hs = Roo.apply(hs || {}, this.defaultHeaders);
11416 success: this.handleResponse,
11417 failure: this.handleFailure,
11419 argument: {options: o},
11420 timeout : o.timeout || this.timeout
11423 var method = o.method||this.method||(p ? "POST" : "GET");
11425 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11426 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11429 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11433 }else if(this.autoAbort !== false){
11437 if((method == 'GET' && p) || o.xmlData){
11438 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11441 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11442 return this.transId;
11444 Roo.callback(o.callback, o.scope, [o, null, null]);
11450 * Determine whether this object has a request outstanding.
11451 * @param {Number} transactionId (Optional) defaults to the last transaction
11452 * @return {Boolean} True if there is an outstanding request.
11454 isLoading : function(transId){
11456 return Roo.lib.Ajax.isCallInProgress(transId);
11458 return this.transId ? true : false;
11463 * Aborts any outstanding request.
11464 * @param {Number} transactionId (Optional) defaults to the last transaction
11466 abort : function(transId){
11467 if(transId || this.isLoading()){
11468 Roo.lib.Ajax.abort(transId || this.transId);
11473 handleResponse : function(response){
11474 this.transId = false;
11475 var options = response.argument.options;
11476 response.argument = options ? options.argument : null;
11477 this.fireEvent("requestcomplete", this, response, options);
11478 Roo.callback(options.success, options.scope, [response, options]);
11479 Roo.callback(options.callback, options.scope, [options, true, response]);
11483 handleFailure : function(response, e){
11484 this.transId = false;
11485 var options = response.argument.options;
11486 response.argument = options ? options.argument : null;
11487 this.fireEvent("requestexception", this, response, options, e);
11488 Roo.callback(options.failure, options.scope, [response, options]);
11489 Roo.callback(options.callback, options.scope, [options, false, response]);
11493 doFormUpload : function(o, ps, url){
11495 var frame = document.createElement('iframe');
11498 frame.className = 'x-hidden';
11500 frame.src = Roo.SSL_SECURE_URL;
11502 document.body.appendChild(frame);
11505 document.frames[id].name = id;
11508 var form = Roo.getDom(o.form);
11510 form.method = 'POST';
11511 form.enctype = form.encoding = 'multipart/form-data';
11517 if(ps){ // add dynamic params
11519 ps = Roo.urlDecode(ps, false);
11521 if(ps.hasOwnProperty(k)){
11522 hd = document.createElement('input');
11523 hd.type = 'hidden';
11526 form.appendChild(hd);
11533 var r = { // bogus response object
11538 r.argument = o ? o.argument : null;
11543 doc = frame.contentWindow.document;
11545 doc = (frame.contentDocument || window.frames[id].document);
11547 if(doc && doc.body){
11548 r.responseText = doc.body.innerHTML;
11550 if(doc && doc.XMLDocument){
11551 r.responseXML = doc.XMLDocument;
11553 r.responseXML = doc;
11560 Roo.EventManager.removeListener(frame, 'load', cb, this);
11562 this.fireEvent("requestcomplete", this, r, o);
11563 Roo.callback(o.success, o.scope, [r, o]);
11564 Roo.callback(o.callback, o.scope, [o, true, r]);
11566 setTimeout(function(){document.body.removeChild(frame);}, 100);
11569 Roo.EventManager.on(frame, 'load', cb, this);
11572 if(hiddens){ // remove dynamic params
11573 for(var i = 0, len = hiddens.length; i < len; i++){
11574 form.removeChild(hiddens[i]);
11581 * Ext JS Library 1.1.1
11582 * Copyright(c) 2006-2007, Ext JS, LLC.
11584 * Originally Released Under LGPL - original licence link has changed is not relivant.
11587 * <script type="text/javascript">
11591 * Global Ajax request class.
11594 * @extends Roo.data.Connection
11597 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11598 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11599 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11600 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11601 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11602 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11603 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11605 Roo.Ajax = new Roo.data.Connection({
11614 * Serialize the passed form into a url encoded string
11616 * @param {String/HTMLElement} form
11619 serializeForm : function(form){
11620 return Roo.lib.Ajax.serializeForm(form);
11624 * Ext JS Library 1.1.1
11625 * Copyright(c) 2006-2007, Ext JS, LLC.
11627 * Originally Released Under LGPL - original licence link has changed is not relivant.
11630 * <script type="text/javascript">
11635 * @class Roo.UpdateManager
11636 * @extends Roo.util.Observable
11637 * Provides AJAX-style update for Element object.<br><br>
11640 * // Get it from a Roo.Element object
11641 * var el = Roo.get("foo");
11642 * var mgr = el.getUpdateManager();
11643 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11645 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11647 * // or directly (returns the same UpdateManager instance)
11648 * var mgr = new Roo.UpdateManager("myElementId");
11649 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11650 * mgr.on("update", myFcnNeedsToKnow);
11652 // short handed call directly from the element object
11653 Roo.get("foo").load({
11657 text: "Loading Foo..."
11661 * Create new UpdateManager directly.
11662 * @param {String/HTMLElement/Roo.Element} el The element to update
11663 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11665 Roo.UpdateManager = function(el, forceNew){
11667 if(!forceNew && el.updateManager){
11668 return el.updateManager;
11671 * The Element object
11672 * @type Roo.Element
11676 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11679 this.defaultUrl = null;
11683 * @event beforeupdate
11684 * Fired before an update is made, return false from your handler and the update is cancelled.
11685 * @param {Roo.Element} el
11686 * @param {String/Object/Function} url
11687 * @param {String/Object} params
11689 "beforeupdate": true,
11692 * Fired after successful update is made.
11693 * @param {Roo.Element} el
11694 * @param {Object} oResponseObject The response Object
11699 * Fired on update failure.
11700 * @param {Roo.Element} el
11701 * @param {Object} oResponseObject The response Object
11705 var d = Roo.UpdateManager.defaults;
11707 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11710 this.sslBlankUrl = d.sslBlankUrl;
11712 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11715 this.disableCaching = d.disableCaching;
11717 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11720 this.indicatorText = d.indicatorText;
11722 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11725 this.showLoadIndicator = d.showLoadIndicator;
11727 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11730 this.timeout = d.timeout;
11733 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11736 this.loadScripts = d.loadScripts;
11739 * Transaction object of current executing transaction
11741 this.transaction = null;
11746 this.autoRefreshProcId = null;
11748 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11751 this.refreshDelegate = this.refresh.createDelegate(this);
11753 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11756 this.updateDelegate = this.update.createDelegate(this);
11758 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11761 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11765 this.successDelegate = this.processSuccess.createDelegate(this);
11769 this.failureDelegate = this.processFailure.createDelegate(this);
11771 if(!this.renderer){
11773 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11775 this.renderer = new Roo.UpdateManager.BasicRenderer();
11778 Roo.UpdateManager.superclass.constructor.call(this);
11781 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11783 * Get the Element this UpdateManager is bound to
11784 * @return {Roo.Element} The element
11786 getEl : function(){
11790 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11791 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11794 url: "your-url.php",<br/>
11795 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11796 callback: yourFunction,<br/>
11797 scope: yourObject, //(optional scope) <br/>
11798 discardUrl: false, <br/>
11799 nocache: false,<br/>
11800 text: "Loading...",<br/>
11802 scripts: false<br/>
11805 * The only required property is url. The optional properties nocache, text and scripts
11806 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11807 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11808 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11809 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11811 update : function(url, params, callback, discardUrl){
11812 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11813 var method = this.method,
11815 if(typeof url == "object"){ // must be config object
11818 params = params || cfg.params;
11819 callback = callback || cfg.callback;
11820 discardUrl = discardUrl || cfg.discardUrl;
11821 if(callback && cfg.scope){
11822 callback = callback.createDelegate(cfg.scope);
11824 if(typeof cfg.method != "undefined"){method = cfg.method;};
11825 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11826 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11827 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11828 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11830 this.showLoading();
11832 this.defaultUrl = url;
11834 if(typeof url == "function"){
11835 url = url.call(this);
11838 method = method || (params ? "POST" : "GET");
11839 if(method == "GET"){
11840 url = this.prepareUrl(url);
11843 var o = Roo.apply(cfg ||{}, {
11846 success: this.successDelegate,
11847 failure: this.failureDelegate,
11848 callback: undefined,
11849 timeout: (this.timeout*1000),
11850 argument: {"url": url, "form": null, "callback": callback, "params": params}
11852 Roo.log("updated manager called with timeout of " + o.timeout);
11853 this.transaction = Roo.Ajax.request(o);
11858 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11859 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11860 * @param {String/HTMLElement} form The form Id or form element
11861 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11862 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11863 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11865 formUpdate : function(form, url, reset, callback){
11866 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11867 if(typeof url == "function"){
11868 url = url.call(this);
11870 form = Roo.getDom(form);
11871 this.transaction = Roo.Ajax.request({
11874 success: this.successDelegate,
11875 failure: this.failureDelegate,
11876 timeout: (this.timeout*1000),
11877 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11879 this.showLoading.defer(1, this);
11884 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11885 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11887 refresh : function(callback){
11888 if(this.defaultUrl == null){
11891 this.update(this.defaultUrl, null, callback, true);
11895 * Set this element to auto refresh.
11896 * @param {Number} interval How often to update (in seconds).
11897 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11898 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11899 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11900 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11902 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11904 this.update(url || this.defaultUrl, params, callback, true);
11906 if(this.autoRefreshProcId){
11907 clearInterval(this.autoRefreshProcId);
11909 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11913 * Stop auto refresh on this element.
11915 stopAutoRefresh : function(){
11916 if(this.autoRefreshProcId){
11917 clearInterval(this.autoRefreshProcId);
11918 delete this.autoRefreshProcId;
11922 isAutoRefreshing : function(){
11923 return this.autoRefreshProcId ? true : false;
11926 * Called to update the element to "Loading" state. Override to perform custom action.
11928 showLoading : function(){
11929 if(this.showLoadIndicator){
11930 this.el.update(this.indicatorText);
11935 * Adds unique parameter to query string if disableCaching = true
11938 prepareUrl : function(url){
11939 if(this.disableCaching){
11940 var append = "_dc=" + (new Date().getTime());
11941 if(url.indexOf("?") !== -1){
11942 url += "&" + append;
11944 url += "?" + append;
11953 processSuccess : function(response){
11954 this.transaction = null;
11955 if(response.argument.form && response.argument.reset){
11956 try{ // put in try/catch since some older FF releases had problems with this
11957 response.argument.form.reset();
11960 if(this.loadScripts){
11961 this.renderer.render(this.el, response, this,
11962 this.updateComplete.createDelegate(this, [response]));
11964 this.renderer.render(this.el, response, this);
11965 this.updateComplete(response);
11969 updateComplete : function(response){
11970 this.fireEvent("update", this.el, response);
11971 if(typeof response.argument.callback == "function"){
11972 response.argument.callback(this.el, true, response);
11979 processFailure : function(response){
11980 this.transaction = null;
11981 this.fireEvent("failure", this.el, response);
11982 if(typeof response.argument.callback == "function"){
11983 response.argument.callback(this.el, false, response);
11988 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11989 * @param {Object} renderer The object implementing the render() method
11991 setRenderer : function(renderer){
11992 this.renderer = renderer;
11995 getRenderer : function(){
11996 return this.renderer;
12000 * Set the defaultUrl used for updates
12001 * @param {String/Function} defaultUrl The url or a function to call to get the url
12003 setDefaultUrl : function(defaultUrl){
12004 this.defaultUrl = defaultUrl;
12008 * Aborts the executing transaction
12010 abort : function(){
12011 if(this.transaction){
12012 Roo.Ajax.abort(this.transaction);
12017 * Returns true if an update is in progress
12018 * @return {Boolean}
12020 isUpdating : function(){
12021 if(this.transaction){
12022 return Roo.Ajax.isLoading(this.transaction);
12029 * @class Roo.UpdateManager.defaults
12030 * @static (not really - but it helps the doc tool)
12031 * The defaults collection enables customizing the default properties of UpdateManager
12033 Roo.UpdateManager.defaults = {
12035 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12041 * True to process scripts by default (Defaults to false).
12044 loadScripts : false,
12047 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12050 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12052 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12055 disableCaching : false,
12057 * Whether to show indicatorText when loading (Defaults to true).
12060 showLoadIndicator : true,
12062 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12065 indicatorText : '<div class="loading-indicator">Loading...</div>'
12069 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12071 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12072 * @param {String/HTMLElement/Roo.Element} el The element to update
12073 * @param {String} url The url
12074 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12075 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12078 * @member Roo.UpdateManager
12080 Roo.UpdateManager.updateElement = function(el, url, params, options){
12081 var um = Roo.get(el, true).getUpdateManager();
12082 Roo.apply(um, options);
12083 um.update(url, params, options ? options.callback : null);
12085 // alias for backwards compat
12086 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12088 * @class Roo.UpdateManager.BasicRenderer
12089 * Default Content renderer. Updates the elements innerHTML with the responseText.
12091 Roo.UpdateManager.BasicRenderer = function(){};
12093 Roo.UpdateManager.BasicRenderer.prototype = {
12095 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12096 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12097 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12098 * @param {Roo.Element} el The element being rendered
12099 * @param {Object} response The YUI Connect response object
12100 * @param {UpdateManager} updateManager The calling update manager
12101 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12103 render : function(el, response, updateManager, callback){
12104 el.update(response.responseText, updateManager.loadScripts, callback);
12110 * (c)) Alan Knowles
12116 * @class Roo.DomTemplate
12117 * @extends Roo.Template
12118 * An effort at a dom based template engine..
12120 * Similar to XTemplate, except it uses dom parsing to create the template..
12122 * Supported features:
12127 {a_variable} - output encoded.
12128 {a_variable.format:("Y-m-d")} - call a method on the variable
12129 {a_variable:raw} - unencoded output
12130 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12131 {a_variable:this.method_on_template(...)} - call a method on the template object.
12136 <div roo-for="a_variable or condition.."></div>
12137 <div roo-if="a_variable or condition"></div>
12138 <div roo-exec="some javascript"></div>
12139 <div roo-name="named_template"></div>
12144 Roo.DomTemplate = function()
12146 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12153 Roo.extend(Roo.DomTemplate, Roo.Template, {
12155 * id counter for sub templates.
12159 * flag to indicate if dom parser is inside a pre,
12160 * it will strip whitespace if not.
12165 * The various sub templates
12173 * basic tag replacing syntax
12176 * // you can fake an object call by doing this
12180 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12181 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12183 iterChild : function (node, method) {
12185 var oldPre = this.inPre;
12186 if (node.tagName == 'PRE') {
12189 for( var i = 0; i < node.childNodes.length; i++) {
12190 method.call(this, node.childNodes[i]);
12192 this.inPre = oldPre;
12198 * compile the template
12200 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12203 compile: function()
12207 // covert the html into DOM...
12211 doc = document.implementation.createHTMLDocument("");
12212 doc.documentElement.innerHTML = this.html ;
12213 div = doc.documentElement;
12215 // old IE... - nasty -- it causes all sorts of issues.. with
12216 // images getting pulled from server..
12217 div = document.createElement('div');
12218 div.innerHTML = this.html;
12220 //doc.documentElement.innerHTML = htmlBody
12226 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12228 var tpls = this.tpls;
12230 // create a top level template from the snippet..
12232 //Roo.log(div.innerHTML);
12239 body : div.innerHTML,
12252 Roo.each(tpls, function(tp){
12253 this.compileTpl(tp);
12254 this.tpls[tp.id] = tp;
12257 this.master = tpls[0];
12263 compileNode : function(node, istop) {
12268 // skip anything not a tag..
12269 if (node.nodeType != 1) {
12270 if (node.nodeType == 3 && !this.inPre) {
12271 // reduce white space..
12272 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12295 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12296 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12297 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12298 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12304 // just itterate children..
12305 this.iterChild(node,this.compileNode);
12308 tpl.uid = this.id++;
12309 tpl.value = node.getAttribute('roo-' + tpl.attr);
12310 node.removeAttribute('roo-'+ tpl.attr);
12311 if (tpl.attr != 'name') {
12312 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12313 node.parentNode.replaceChild(placeholder, node);
12316 var placeholder = document.createElement('span');
12317 placeholder.className = 'roo-tpl-' + tpl.value;
12318 node.parentNode.replaceChild(placeholder, node);
12321 // parent now sees '{domtplXXXX}
12322 this.iterChild(node,this.compileNode);
12324 // we should now have node body...
12325 var div = document.createElement('div');
12326 div.appendChild(node);
12328 // this has the unfortunate side effect of converting tagged attributes
12329 // eg. href="{...}" into %7C...%7D
12330 // this has been fixed by searching for those combo's although it's a bit hacky..
12333 tpl.body = div.innerHTML;
12340 switch (tpl.value) {
12341 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12342 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12343 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12348 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12352 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12356 tpl.id = tpl.value; // replace non characters???
12362 this.tpls.push(tpl);
12372 * Compile a segment of the template into a 'sub-template'
12378 compileTpl : function(tpl)
12380 var fm = Roo.util.Format;
12381 var useF = this.disableFormats !== true;
12383 var sep = Roo.isGecko ? "+\n" : ",\n";
12385 var undef = function(str) {
12386 Roo.debug && Roo.log("Property not found :" + str);
12390 //Roo.log(tpl.body);
12394 var fn = function(m, lbrace, name, format, args)
12397 //Roo.log(arguments);
12398 args = args ? args.replace(/\\'/g,"'") : args;
12399 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12400 if (typeof(format) == 'undefined') {
12401 format = 'htmlEncode';
12403 if (format == 'raw' ) {
12407 if(name.substr(0, 6) == 'domtpl'){
12408 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12411 // build an array of options to determine if value is undefined..
12413 // basically get 'xxxx.yyyy' then do
12414 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12415 // (function () { Roo.log("Property not found"); return ''; })() :
12420 Roo.each(name.split('.'), function(st) {
12421 lookfor += (lookfor.length ? '.': '') + st;
12422 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12425 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12428 if(format && useF){
12430 args = args ? ',' + args : "";
12432 if(format.substr(0, 5) != "this."){
12433 format = "fm." + format + '(';
12435 format = 'this.call("'+ format.substr(5) + '", ';
12439 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12442 if (args && args.length) {
12443 // called with xxyx.yuu:(test,test)
12445 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12447 // raw.. - :raw modifier..
12448 return "'"+ sep + udef_st + name + ")"+sep+"'";
12452 // branched to use + in gecko and [].join() in others
12454 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12455 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12458 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12459 body.push(tpl.body.replace(/(\r\n|\n)/g,
12460 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12461 body.push("'].join('');};};");
12462 body = body.join('');
12465 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12467 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12474 * same as applyTemplate, except it's done to one of the subTemplates
12475 * when using named templates, you can do:
12477 * var str = pl.applySubTemplate('your-name', values);
12480 * @param {Number} id of the template
12481 * @param {Object} values to apply to template
12482 * @param {Object} parent (normaly the instance of this object)
12484 applySubTemplate : function(id, values, parent)
12488 var t = this.tpls[id];
12492 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12493 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12497 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12504 if(t.execCall && t.execCall.call(this, values, parent)){
12508 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12514 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12515 parent = t.target ? values : parent;
12516 if(t.forCall && vs instanceof Array){
12518 for(var i = 0, len = vs.length; i < len; i++){
12520 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12522 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12524 //Roo.log(t.compiled);
12528 return buf.join('');
12531 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12536 return t.compiled.call(this, vs, parent);
12538 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12540 //Roo.log(t.compiled);
12548 applyTemplate : function(values){
12549 return this.master.compiled.call(this, values, {});
12550 //var s = this.subs;
12553 apply : function(){
12554 return this.applyTemplate.apply(this, arguments);
12559 Roo.DomTemplate.from = function(el){
12560 el = Roo.getDom(el);
12561 return new Roo.Domtemplate(el.value || el.innerHTML);
12564 * Ext JS Library 1.1.1
12565 * Copyright(c) 2006-2007, Ext JS, LLC.
12567 * Originally Released Under LGPL - original licence link has changed is not relivant.
12570 * <script type="text/javascript">
12574 * @class Roo.util.DelayedTask
12575 * Provides a convenient method of performing setTimeout where a new
12576 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12577 * You can use this class to buffer
12578 * the keypress events for a certain number of milliseconds, and perform only if they stop
12579 * for that amount of time.
12580 * @constructor The parameters to this constructor serve as defaults and are not required.
12581 * @param {Function} fn (optional) The default function to timeout
12582 * @param {Object} scope (optional) The default scope of that timeout
12583 * @param {Array} args (optional) The default Array of arguments
12585 Roo.util.DelayedTask = function(fn, scope, args){
12586 var id = null, d, t;
12588 var call = function(){
12589 var now = new Date().getTime();
12593 fn.apply(scope, args || []);
12597 * Cancels any pending timeout and queues a new one
12598 * @param {Number} delay The milliseconds to delay
12599 * @param {Function} newFn (optional) Overrides function passed to constructor
12600 * @param {Object} newScope (optional) Overrides scope passed to constructor
12601 * @param {Array} newArgs (optional) Overrides args passed to constructor
12603 this.delay = function(delay, newFn, newScope, newArgs){
12604 if(id && delay != d){
12608 t = new Date().getTime();
12610 scope = newScope || scope;
12611 args = newArgs || args;
12613 id = setInterval(call, d);
12618 * Cancel the last queued timeout
12620 this.cancel = function(){
12628 * Ext JS Library 1.1.1
12629 * Copyright(c) 2006-2007, Ext JS, LLC.
12631 * Originally Released Under LGPL - original licence link has changed is not relivant.
12634 * <script type="text/javascript">
12638 Roo.util.TaskRunner = function(interval){
12639 interval = interval || 10;
12640 var tasks = [], removeQueue = [];
12642 var running = false;
12644 var stopThread = function(){
12650 var startThread = function(){
12653 id = setInterval(runTasks, interval);
12657 var removeTask = function(task){
12658 removeQueue.push(task);
12664 var runTasks = function(){
12665 if(removeQueue.length > 0){
12666 for(var i = 0, len = removeQueue.length; i < len; i++){
12667 tasks.remove(removeQueue[i]);
12670 if(tasks.length < 1){
12675 var now = new Date().getTime();
12676 for(var i = 0, len = tasks.length; i < len; ++i){
12678 var itime = now - t.taskRunTime;
12679 if(t.interval <= itime){
12680 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12681 t.taskRunTime = now;
12682 if(rt === false || t.taskRunCount === t.repeat){
12687 if(t.duration && t.duration <= (now - t.taskStartTime)){
12694 * Queues a new task.
12695 * @param {Object} task
12697 this.start = function(task){
12699 task.taskStartTime = new Date().getTime();
12700 task.taskRunTime = 0;
12701 task.taskRunCount = 0;
12706 this.stop = function(task){
12711 this.stopAll = function(){
12713 for(var i = 0, len = tasks.length; i < len; i++){
12714 if(tasks[i].onStop){
12723 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12725 * Ext JS Library 1.1.1
12726 * Copyright(c) 2006-2007, Ext JS, LLC.
12728 * Originally Released Under LGPL - original licence link has changed is not relivant.
12731 * <script type="text/javascript">
12736 * @class Roo.util.MixedCollection
12737 * @extends Roo.util.Observable
12738 * A Collection class that maintains both numeric indexes and keys and exposes events.
12740 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12741 * collection (defaults to false)
12742 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12743 * and return the key value for that item. This is used when available to look up the key on items that
12744 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12745 * equivalent to providing an implementation for the {@link #getKey} method.
12747 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12755 * Fires when the collection is cleared.
12760 * Fires when an item is added to the collection.
12761 * @param {Number} index The index at which the item was added.
12762 * @param {Object} o The item added.
12763 * @param {String} key The key associated with the added item.
12768 * Fires when an item is replaced in the collection.
12769 * @param {String} key he key associated with the new added.
12770 * @param {Object} old The item being replaced.
12771 * @param {Object} new The new item.
12776 * Fires when an item is removed from the collection.
12777 * @param {Object} o The item being removed.
12778 * @param {String} key (optional) The key associated with the removed item.
12783 this.allowFunctions = allowFunctions === true;
12785 this.getKey = keyFn;
12787 Roo.util.MixedCollection.superclass.constructor.call(this);
12790 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12791 allowFunctions : false,
12794 * Adds an item to the collection.
12795 * @param {String} key The key to associate with the item
12796 * @param {Object} o The item to add.
12797 * @return {Object} The item added.
12799 add : function(key, o){
12800 if(arguments.length == 1){
12802 key = this.getKey(o);
12804 if(typeof key == "undefined" || key === null){
12806 this.items.push(o);
12807 this.keys.push(null);
12809 var old = this.map[key];
12811 return this.replace(key, o);
12814 this.items.push(o);
12816 this.keys.push(key);
12818 this.fireEvent("add", this.length-1, o, key);
12823 * MixedCollection has a generic way to fetch keys if you implement getKey.
12826 var mc = new Roo.util.MixedCollection();
12827 mc.add(someEl.dom.id, someEl);
12828 mc.add(otherEl.dom.id, otherEl);
12832 var mc = new Roo.util.MixedCollection();
12833 mc.getKey = function(el){
12839 // or via the constructor
12840 var mc = new Roo.util.MixedCollection(false, function(el){
12846 * @param o {Object} The item for which to find the key.
12847 * @return {Object} The key for the passed item.
12849 getKey : function(o){
12854 * Replaces an item in the collection.
12855 * @param {String} key The key associated with the item to replace, or the item to replace.
12856 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12857 * @return {Object} The new item.
12859 replace : function(key, o){
12860 if(arguments.length == 1){
12862 key = this.getKey(o);
12864 var old = this.item(key);
12865 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12866 return this.add(key, o);
12868 var index = this.indexOfKey(key);
12869 this.items[index] = o;
12871 this.fireEvent("replace", key, old, o);
12876 * Adds all elements of an Array or an Object to the collection.
12877 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12878 * an Array of values, each of which are added to the collection.
12880 addAll : function(objs){
12881 if(arguments.length > 1 || objs instanceof Array){
12882 var args = arguments.length > 1 ? arguments : objs;
12883 for(var i = 0, len = args.length; i < len; i++){
12887 for(var key in objs){
12888 if(this.allowFunctions || typeof objs[key] != "function"){
12889 this.add(key, objs[key]);
12896 * Executes the specified function once for every item in the collection, passing each
12897 * item as the first and only parameter. returning false from the function will stop the iteration.
12898 * @param {Function} fn The function to execute for each item.
12899 * @param {Object} scope (optional) The scope in which to execute the function.
12901 each : function(fn, scope){
12902 var items = [].concat(this.items); // each safe for removal
12903 for(var i = 0, len = items.length; i < len; i++){
12904 if(fn.call(scope || items[i], items[i], i, len) === false){
12911 * Executes the specified function once for every key in the collection, passing each
12912 * key, and its associated item as the first two parameters.
12913 * @param {Function} fn The function to execute for each item.
12914 * @param {Object} scope (optional) The scope in which to execute the function.
12916 eachKey : function(fn, scope){
12917 for(var i = 0, len = this.keys.length; i < len; i++){
12918 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12923 * Returns the first item in the collection which elicits a true return value from the
12924 * passed selection function.
12925 * @param {Function} fn The selection function to execute for each item.
12926 * @param {Object} scope (optional) The scope in which to execute the function.
12927 * @return {Object} The first item in the collection which returned true from the selection function.
12929 find : function(fn, scope){
12930 for(var i = 0, len = this.items.length; i < len; i++){
12931 if(fn.call(scope || window, this.items[i], this.keys[i])){
12932 return this.items[i];
12939 * Inserts an item at the specified index in the collection.
12940 * @param {Number} index The index to insert the item at.
12941 * @param {String} key The key to associate with the new item, or the item itself.
12942 * @param {Object} o (optional) If the second parameter was a key, the new item.
12943 * @return {Object} The item inserted.
12945 insert : function(index, key, o){
12946 if(arguments.length == 2){
12948 key = this.getKey(o);
12950 if(index >= this.length){
12951 return this.add(key, o);
12954 this.items.splice(index, 0, o);
12955 if(typeof key != "undefined" && key != null){
12958 this.keys.splice(index, 0, key);
12959 this.fireEvent("add", index, o, key);
12964 * Removed an item from the collection.
12965 * @param {Object} o The item to remove.
12966 * @return {Object} The item removed.
12968 remove : function(o){
12969 return this.removeAt(this.indexOf(o));
12973 * Remove an item from a specified index in the collection.
12974 * @param {Number} index The index within the collection of the item to remove.
12976 removeAt : function(index){
12977 if(index < this.length && index >= 0){
12979 var o = this.items[index];
12980 this.items.splice(index, 1);
12981 var key = this.keys[index];
12982 if(typeof key != "undefined"){
12983 delete this.map[key];
12985 this.keys.splice(index, 1);
12986 this.fireEvent("remove", o, key);
12991 * Removed an item associated with the passed key fom the collection.
12992 * @param {String} key The key of the item to remove.
12994 removeKey : function(key){
12995 return this.removeAt(this.indexOfKey(key));
12999 * Returns the number of items in the collection.
13000 * @return {Number} the number of items in the collection.
13002 getCount : function(){
13003 return this.length;
13007 * Returns index within the collection of the passed Object.
13008 * @param {Object} o The item to find the index of.
13009 * @return {Number} index of the item.
13011 indexOf : function(o){
13012 if(!this.items.indexOf){
13013 for(var i = 0, len = this.items.length; i < len; i++){
13014 if(this.items[i] == o) return i;
13018 return this.items.indexOf(o);
13023 * Returns index within the collection of the passed key.
13024 * @param {String} key The key to find the index of.
13025 * @return {Number} index of the key.
13027 indexOfKey : function(key){
13028 if(!this.keys.indexOf){
13029 for(var i = 0, len = this.keys.length; i < len; i++){
13030 if(this.keys[i] == key) return i;
13034 return this.keys.indexOf(key);
13039 * Returns the item associated with the passed key OR index. Key has priority over index.
13040 * @param {String/Number} key The key or index of the item.
13041 * @return {Object} The item associated with the passed key.
13043 item : function(key){
13044 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13045 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13049 * Returns the item at the specified index.
13050 * @param {Number} index The index of the item.
13053 itemAt : function(index){
13054 return this.items[index];
13058 * Returns the item associated with the passed key.
13059 * @param {String/Number} key The key of the item.
13060 * @return {Object} The item associated with the passed key.
13062 key : function(key){
13063 return this.map[key];
13067 * Returns true if the collection contains the passed Object as an item.
13068 * @param {Object} o The Object to look for in the collection.
13069 * @return {Boolean} True if the collection contains the Object as an item.
13071 contains : function(o){
13072 return this.indexOf(o) != -1;
13076 * Returns true if the collection contains the passed Object as a key.
13077 * @param {String} key The key to look for in the collection.
13078 * @return {Boolean} True if the collection contains the Object as a key.
13080 containsKey : function(key){
13081 return typeof this.map[key] != "undefined";
13085 * Removes all items from the collection.
13087 clear : function(){
13092 this.fireEvent("clear");
13096 * Returns the first item in the collection.
13097 * @return {Object} the first item in the collection..
13099 first : function(){
13100 return this.items[0];
13104 * Returns the last item in the collection.
13105 * @return {Object} the last item in the collection..
13108 return this.items[this.length-1];
13111 _sort : function(property, dir, fn){
13112 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13113 fn = fn || function(a, b){
13116 var c = [], k = this.keys, items = this.items;
13117 for(var i = 0, len = items.length; i < len; i++){
13118 c[c.length] = {key: k[i], value: items[i], index: i};
13120 c.sort(function(a, b){
13121 var v = fn(a[property], b[property]) * dsc;
13123 v = (a.index < b.index ? -1 : 1);
13127 for(var i = 0, len = c.length; i < len; i++){
13128 items[i] = c[i].value;
13131 this.fireEvent("sort", this);
13135 * Sorts this collection with the passed comparison function
13136 * @param {String} direction (optional) "ASC" or "DESC"
13137 * @param {Function} fn (optional) comparison function
13139 sort : function(dir, fn){
13140 this._sort("value", dir, fn);
13144 * Sorts this collection by keys
13145 * @param {String} direction (optional) "ASC" or "DESC"
13146 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13148 keySort : function(dir, fn){
13149 this._sort("key", dir, fn || function(a, b){
13150 return String(a).toUpperCase()-String(b).toUpperCase();
13155 * Returns a range of items in this collection
13156 * @param {Number} startIndex (optional) defaults to 0
13157 * @param {Number} endIndex (optional) default to the last item
13158 * @return {Array} An array of items
13160 getRange : function(start, end){
13161 var items = this.items;
13162 if(items.length < 1){
13165 start = start || 0;
13166 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13169 for(var i = start; i <= end; i++) {
13170 r[r.length] = items[i];
13173 for(var i = start; i >= end; i--) {
13174 r[r.length] = items[i];
13181 * Filter the <i>objects</i> in this collection by a specific property.
13182 * Returns a new collection that has been filtered.
13183 * @param {String} property A property on your objects
13184 * @param {String/RegExp} value Either string that the property values
13185 * should start with or a RegExp to test against the property
13186 * @return {MixedCollection} The new filtered collection
13188 filter : function(property, value){
13189 if(!value.exec){ // not a regex
13190 value = String(value);
13191 if(value.length == 0){
13192 return this.clone();
13194 value = new RegExp("^" + Roo.escapeRe(value), "i");
13196 return this.filterBy(function(o){
13197 return o && value.test(o[property]);
13202 * Filter by a function. * Returns a new collection that has been filtered.
13203 * The passed function will be called with each
13204 * object in the collection. If the function returns true, the value is included
13205 * otherwise it is filtered.
13206 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13207 * @param {Object} scope (optional) The scope of the function (defaults to this)
13208 * @return {MixedCollection} The new filtered collection
13210 filterBy : function(fn, scope){
13211 var r = new Roo.util.MixedCollection();
13212 r.getKey = this.getKey;
13213 var k = this.keys, it = this.items;
13214 for(var i = 0, len = it.length; i < len; i++){
13215 if(fn.call(scope||this, it[i], k[i])){
13216 r.add(k[i], it[i]);
13223 * Creates a duplicate of this collection
13224 * @return {MixedCollection}
13226 clone : function(){
13227 var r = new Roo.util.MixedCollection();
13228 var k = this.keys, it = this.items;
13229 for(var i = 0, len = it.length; i < len; i++){
13230 r.add(k[i], it[i]);
13232 r.getKey = this.getKey;
13237 * Returns the item associated with the passed key or index.
13239 * @param {String/Number} key The key or index of the item.
13240 * @return {Object} The item associated with the passed key.
13242 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13244 * Ext JS Library 1.1.1
13245 * Copyright(c) 2006-2007, Ext JS, LLC.
13247 * Originally Released Under LGPL - original licence link has changed is not relivant.
13250 * <script type="text/javascript">
13253 * @class Roo.util.JSON
13254 * Modified version of Douglas Crockford"s json.js that doesn"t
13255 * mess with the Object prototype
13256 * http://www.json.org/js.html
13259 Roo.util.JSON = new (function(){
13260 var useHasOwn = {}.hasOwnProperty ? true : false;
13262 // crashes Safari in some instances
13263 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13265 var pad = function(n) {
13266 return n < 10 ? "0" + n : n;
13279 var encodeString = function(s){
13280 if (/["\\\x00-\x1f]/.test(s)) {
13281 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13286 c = b.charCodeAt();
13288 Math.floor(c / 16).toString(16) +
13289 (c % 16).toString(16);
13292 return '"' + s + '"';
13295 var encodeArray = function(o){
13296 var a = ["["], b, i, l = o.length, v;
13297 for (i = 0; i < l; i += 1) {
13299 switch (typeof v) {
13308 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13316 var encodeDate = function(o){
13317 return '"' + o.getFullYear() + "-" +
13318 pad(o.getMonth() + 1) + "-" +
13319 pad(o.getDate()) + "T" +
13320 pad(o.getHours()) + ":" +
13321 pad(o.getMinutes()) + ":" +
13322 pad(o.getSeconds()) + '"';
13326 * Encodes an Object, Array or other value
13327 * @param {Mixed} o The variable to encode
13328 * @return {String} The JSON string
13330 this.encode = function(o)
13332 // should this be extended to fully wrap stringify..
13334 if(typeof o == "undefined" || o === null){
13336 }else if(o instanceof Array){
13337 return encodeArray(o);
13338 }else if(o instanceof Date){
13339 return encodeDate(o);
13340 }else if(typeof o == "string"){
13341 return encodeString(o);
13342 }else if(typeof o == "number"){
13343 return isFinite(o) ? String(o) : "null";
13344 }else if(typeof o == "boolean"){
13347 var a = ["{"], b, i, v;
13349 if(!useHasOwn || o.hasOwnProperty(i)) {
13351 switch (typeof v) {
13360 a.push(this.encode(i), ":",
13361 v === null ? "null" : this.encode(v));
13372 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13373 * @param {String} json The JSON string
13374 * @return {Object} The resulting object
13376 this.decode = function(json){
13378 return /** eval:var:json */ eval("(" + json + ')');
13382 * Shorthand for {@link Roo.util.JSON#encode}
13383 * @member Roo encode
13385 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13387 * Shorthand for {@link Roo.util.JSON#decode}
13388 * @member Roo decode
13390 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13393 * Ext JS Library 1.1.1
13394 * Copyright(c) 2006-2007, Ext JS, LLC.
13396 * Originally Released Under LGPL - original licence link has changed is not relivant.
13399 * <script type="text/javascript">
13403 * @class Roo.util.Format
13404 * Reusable data formatting functions
13407 Roo.util.Format = function(){
13408 var trimRe = /^\s+|\s+$/g;
13411 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13412 * @param {String} value The string to truncate
13413 * @param {Number} length The maximum length to allow before truncating
13414 * @return {String} The converted text
13416 ellipsis : function(value, len){
13417 if(value && value.length > len){
13418 return value.substr(0, len-3)+"...";
13424 * Checks a reference and converts it to empty string if it is undefined
13425 * @param {Mixed} value Reference to check
13426 * @return {Mixed} Empty string if converted, otherwise the original value
13428 undef : function(value){
13429 return typeof value != "undefined" ? value : "";
13433 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13434 * @param {String} value The string to encode
13435 * @return {String} The encoded text
13437 htmlEncode : function(value){
13438 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13442 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13443 * @param {String} value The string to decode
13444 * @return {String} The decoded text
13446 htmlDecode : function(value){
13447 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13451 * Trims any whitespace from either side of a string
13452 * @param {String} value The text to trim
13453 * @return {String} The trimmed text
13455 trim : function(value){
13456 return String(value).replace(trimRe, "");
13460 * Returns a substring from within an original string
13461 * @param {String} value The original text
13462 * @param {Number} start The start index of the substring
13463 * @param {Number} length The length of the substring
13464 * @return {String} The substring
13466 substr : function(value, start, length){
13467 return String(value).substr(start, length);
13471 * Converts a string to all lower case letters
13472 * @param {String} value The text to convert
13473 * @return {String} The converted text
13475 lowercase : function(value){
13476 return String(value).toLowerCase();
13480 * Converts a string to all upper case letters
13481 * @param {String} value The text to convert
13482 * @return {String} The converted text
13484 uppercase : function(value){
13485 return String(value).toUpperCase();
13489 * Converts the first character only of a string to upper case
13490 * @param {String} value The text to convert
13491 * @return {String} The converted text
13493 capitalize : function(value){
13494 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13498 call : function(value, fn){
13499 if(arguments.length > 2){
13500 var args = Array.prototype.slice.call(arguments, 2);
13501 args.unshift(value);
13503 return /** eval:var:value */ eval(fn).apply(window, args);
13505 /** eval:var:value */
13506 return /** eval:var:value */ eval(fn).call(window, value);
13512 * safer version of Math.toFixed..??/
13513 * @param {Number/String} value The numeric value to format
13514 * @param {Number/String} value Decimal places
13515 * @return {String} The formatted currency string
13517 toFixed : function(v, n)
13519 // why not use to fixed - precision is buggered???
13521 return Math.round(v-0);
13523 var fact = Math.pow(10,n+1);
13524 v = (Math.round((v-0)*fact))/fact;
13525 var z = (''+fact).substring(2);
13526 if (v == Math.floor(v)) {
13527 return Math.floor(v) + '.' + z;
13530 // now just padd decimals..
13531 var ps = String(v).split('.');
13532 var fd = (ps[1] + z);
13533 var r = fd.substring(0,n);
13534 var rm = fd.substring(n);
13536 return ps[0] + '.' + r;
13538 r*=1; // turn it into a number;
13540 if (String(r).length != n) {
13543 r = String(r).substring(1); // chop the end off.
13546 return ps[0] + '.' + r;
13551 * Format a number as US currency
13552 * @param {Number/String} value The numeric value to format
13553 * @return {String} The formatted currency string
13555 usMoney : function(v){
13556 return '$' + Roo.util.Format.number(v);
13561 * eventually this should probably emulate php's number_format
13562 * @param {Number/String} value The numeric value to format
13563 * @param {Number} decimals number of decimal places
13564 * @return {String} The formatted currency string
13566 number : function(v,decimals)
13568 // multiply and round.
13569 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13570 var mul = Math.pow(10, decimals);
13571 var zero = String(mul).substring(1);
13572 v = (Math.round((v-0)*mul))/mul;
13574 // if it's '0' number.. then
13576 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13578 var ps = v.split('.');
13582 var r = /(\d+)(\d{3})/;
13584 while (r.test(whole)) {
13585 whole = whole.replace(r, '$1' + ',' + '$2');
13591 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13592 // does not have decimals
13593 (decimals ? ('.' + zero) : '');
13596 return whole + sub ;
13600 * Parse a value into a formatted date using the specified format pattern.
13601 * @param {Mixed} value The value to format
13602 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13603 * @return {String} The formatted date string
13605 date : function(v, format){
13609 if(!(v instanceof Date)){
13610 v = new Date(Date.parse(v));
13612 return v.dateFormat(format || Roo.util.Format.defaults.date);
13616 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13617 * @param {String} format Any valid date format string
13618 * @return {Function} The date formatting function
13620 dateRenderer : function(format){
13621 return function(v){
13622 return Roo.util.Format.date(v, format);
13627 stripTagsRE : /<\/?[^>]+>/gi,
13630 * Strips all HTML tags
13631 * @param {Mixed} value The text from which to strip tags
13632 * @return {String} The stripped text
13634 stripTags : function(v){
13635 return !v ? v : String(v).replace(this.stripTagsRE, "");
13639 Roo.util.Format.defaults = {
13643 * Ext JS Library 1.1.1
13644 * Copyright(c) 2006-2007, Ext JS, LLC.
13646 * Originally Released Under LGPL - original licence link has changed is not relivant.
13649 * <script type="text/javascript">
13656 * @class Roo.MasterTemplate
13657 * @extends Roo.Template
13658 * Provides a template that can have child templates. The syntax is:
13660 var t = new Roo.MasterTemplate(
13661 '<select name="{name}">',
13662 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13665 t.add('options', {value: 'foo', text: 'bar'});
13666 // or you can add multiple child elements in one shot
13667 t.addAll('options', [
13668 {value: 'foo', text: 'bar'},
13669 {value: 'foo2', text: 'bar2'},
13670 {value: 'foo3', text: 'bar3'}
13672 // then append, applying the master template values
13673 t.append('my-form', {name: 'my-select'});
13675 * A name attribute for the child template is not required if you have only one child
13676 * template or you want to refer to them by index.
13678 Roo.MasterTemplate = function(){
13679 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13680 this.originalHtml = this.html;
13682 var m, re = this.subTemplateRe;
13685 while(m = re.exec(this.html)){
13686 var name = m[1], content = m[2];
13691 tpl : new Roo.Template(content)
13694 st[name] = st[subIndex];
13696 st[subIndex].tpl.compile();
13697 st[subIndex].tpl.call = this.call.createDelegate(this);
13700 this.subCount = subIndex;
13703 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13705 * The regular expression used to match sub templates
13709 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13712 * Applies the passed values to a child template.
13713 * @param {String/Number} name (optional) The name or index of the child template
13714 * @param {Array/Object} values The values to be applied to the template
13715 * @return {MasterTemplate} this
13717 add : function(name, values){
13718 if(arguments.length == 1){
13719 values = arguments[0];
13722 var s = this.subs[name];
13723 s.buffer[s.buffer.length] = s.tpl.apply(values);
13728 * Applies all the passed values to a child template.
13729 * @param {String/Number} name (optional) The name or index of the child template
13730 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13731 * @param {Boolean} reset (optional) True to reset the template first
13732 * @return {MasterTemplate} this
13734 fill : function(name, values, reset){
13736 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13744 for(var i = 0, len = values.length; i < len; i++){
13745 this.add(name, values[i]);
13751 * Resets the template for reuse
13752 * @return {MasterTemplate} this
13754 reset : function(){
13756 for(var i = 0; i < this.subCount; i++){
13762 applyTemplate : function(values){
13764 var replaceIndex = -1;
13765 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13766 return s[++replaceIndex].buffer.join("");
13768 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13771 apply : function(){
13772 return this.applyTemplate.apply(this, arguments);
13775 compile : function(){return this;}
13779 * Alias for fill().
13782 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13784 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13785 * var tpl = Roo.MasterTemplate.from('element-id');
13786 * @param {String/HTMLElement} el
13787 * @param {Object} config
13790 Roo.MasterTemplate.from = function(el, config){
13791 el = Roo.getDom(el);
13792 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13795 * Ext JS Library 1.1.1
13796 * Copyright(c) 2006-2007, Ext JS, LLC.
13798 * Originally Released Under LGPL - original licence link has changed is not relivant.
13801 * <script type="text/javascript">
13806 * @class Roo.util.CSS
13807 * Utility class for manipulating CSS rules
13810 Roo.util.CSS = function(){
13812 var doc = document;
13814 var camelRe = /(-[a-z])/gi;
13815 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13819 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13820 * tag and appended to the HEAD of the document.
13821 * @param {String|Object} cssText The text containing the css rules
13822 * @param {String} id An id to add to the stylesheet for later removal
13823 * @return {StyleSheet}
13825 createStyleSheet : function(cssText, id){
13827 var head = doc.getElementsByTagName("head")[0];
13828 var nrules = doc.createElement("style");
13829 nrules.setAttribute("type", "text/css");
13831 nrules.setAttribute("id", id);
13833 if (typeof(cssText) != 'string') {
13834 // support object maps..
13835 // not sure if this a good idea..
13836 // perhaps it should be merged with the general css handling
13837 // and handle js style props.
13838 var cssTextNew = [];
13839 for(var n in cssText) {
13841 for(var k in cssText[n]) {
13842 citems.push( k + ' : ' +cssText[n][k] + ';' );
13844 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13847 cssText = cssTextNew.join("\n");
13853 head.appendChild(nrules);
13854 ss = nrules.styleSheet;
13855 ss.cssText = cssText;
13858 nrules.appendChild(doc.createTextNode(cssText));
13860 nrules.cssText = cssText;
13862 head.appendChild(nrules);
13863 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13865 this.cacheStyleSheet(ss);
13870 * Removes a style or link tag by id
13871 * @param {String} id The id of the tag
13873 removeStyleSheet : function(id){
13874 var existing = doc.getElementById(id);
13876 existing.parentNode.removeChild(existing);
13881 * Dynamically swaps an existing stylesheet reference for a new one
13882 * @param {String} id The id of an existing link tag to remove
13883 * @param {String} url The href of the new stylesheet to include
13885 swapStyleSheet : function(id, url){
13886 this.removeStyleSheet(id);
13887 var ss = doc.createElement("link");
13888 ss.setAttribute("rel", "stylesheet");
13889 ss.setAttribute("type", "text/css");
13890 ss.setAttribute("id", id);
13891 ss.setAttribute("href", url);
13892 doc.getElementsByTagName("head")[0].appendChild(ss);
13896 * Refresh the rule cache if you have dynamically added stylesheets
13897 * @return {Object} An object (hash) of rules indexed by selector
13899 refreshCache : function(){
13900 return this.getRules(true);
13904 cacheStyleSheet : function(stylesheet){
13908 try{// try catch for cross domain access issue
13909 var ssRules = stylesheet.cssRules || stylesheet.rules;
13910 for(var j = ssRules.length-1; j >= 0; --j){
13911 rules[ssRules[j].selectorText] = ssRules[j];
13917 * Gets all css rules for the document
13918 * @param {Boolean} refreshCache true to refresh the internal cache
13919 * @return {Object} An object (hash) of rules indexed by selector
13921 getRules : function(refreshCache){
13922 if(rules == null || refreshCache){
13924 var ds = doc.styleSheets;
13925 for(var i =0, len = ds.length; i < len; i++){
13927 this.cacheStyleSheet(ds[i]);
13935 * Gets an an individual CSS rule by selector(s)
13936 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13937 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13938 * @return {CSSRule} The CSS rule or null if one is not found
13940 getRule : function(selector, refreshCache){
13941 var rs = this.getRules(refreshCache);
13942 if(!(selector instanceof Array)){
13943 return rs[selector];
13945 for(var i = 0; i < selector.length; i++){
13946 if(rs[selector[i]]){
13947 return rs[selector[i]];
13955 * Updates a rule property
13956 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13957 * @param {String} property The css property
13958 * @param {String} value The new value for the property
13959 * @return {Boolean} true If a rule was found and updated
13961 updateRule : function(selector, property, value){
13962 if(!(selector instanceof Array)){
13963 var rule = this.getRule(selector);
13965 rule.style[property.replace(camelRe, camelFn)] = value;
13969 for(var i = 0; i < selector.length; i++){
13970 if(this.updateRule(selector[i], property, value)){
13980 * Ext JS Library 1.1.1
13981 * Copyright(c) 2006-2007, Ext JS, LLC.
13983 * Originally Released Under LGPL - original licence link has changed is not relivant.
13986 * <script type="text/javascript">
13992 * @class Roo.util.ClickRepeater
13993 * @extends Roo.util.Observable
13995 * A wrapper class which can be applied to any element. Fires a "click" event while the
13996 * mouse is pressed. The interval between firings may be specified in the config but
13997 * defaults to 10 milliseconds.
13999 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14001 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14002 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14003 * Similar to an autorepeat key delay.
14004 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14005 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14006 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14007 * "interval" and "delay" are ignored. "immediate" is honored.
14008 * @cfg {Boolean} preventDefault True to prevent the default click event
14009 * @cfg {Boolean} stopDefault True to stop the default click event
14012 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14013 * 2007-02-02 jvs Renamed to ClickRepeater
14014 * 2007-02-03 jvs Modifications for FF Mac and Safari
14017 * @param {String/HTMLElement/Element} el The element to listen on
14018 * @param {Object} config
14020 Roo.util.ClickRepeater = function(el, config)
14022 this.el = Roo.get(el);
14023 this.el.unselectable();
14025 Roo.apply(this, config);
14030 * Fires when the mouse button is depressed.
14031 * @param {Roo.util.ClickRepeater} this
14033 "mousedown" : true,
14036 * Fires on a specified interval during the time the element is pressed.
14037 * @param {Roo.util.ClickRepeater} this
14042 * Fires when the mouse key is released.
14043 * @param {Roo.util.ClickRepeater} this
14048 this.el.on("mousedown", this.handleMouseDown, this);
14049 if(this.preventDefault || this.stopDefault){
14050 this.el.on("click", function(e){
14051 if(this.preventDefault){
14052 e.preventDefault();
14054 if(this.stopDefault){
14060 // allow inline handler
14062 this.on("click", this.handler, this.scope || this);
14065 Roo.util.ClickRepeater.superclass.constructor.call(this);
14068 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14071 preventDefault : true,
14072 stopDefault : false,
14076 handleMouseDown : function(){
14077 clearTimeout(this.timer);
14079 if(this.pressClass){
14080 this.el.addClass(this.pressClass);
14082 this.mousedownTime = new Date();
14084 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14085 this.el.on("mouseout", this.handleMouseOut, this);
14087 this.fireEvent("mousedown", this);
14088 this.fireEvent("click", this);
14090 this.timer = this.click.defer(this.delay || this.interval, this);
14094 click : function(){
14095 this.fireEvent("click", this);
14096 this.timer = this.click.defer(this.getInterval(), this);
14100 getInterval: function(){
14101 if(!this.accelerate){
14102 return this.interval;
14104 var pressTime = this.mousedownTime.getElapsed();
14105 if(pressTime < 500){
14107 }else if(pressTime < 1700){
14109 }else if(pressTime < 2600){
14111 }else if(pressTime < 3500){
14113 }else if(pressTime < 4400){
14115 }else if(pressTime < 5300){
14117 }else if(pressTime < 6200){
14125 handleMouseOut : function(){
14126 clearTimeout(this.timer);
14127 if(this.pressClass){
14128 this.el.removeClass(this.pressClass);
14130 this.el.on("mouseover", this.handleMouseReturn, this);
14134 handleMouseReturn : function(){
14135 this.el.un("mouseover", this.handleMouseReturn);
14136 if(this.pressClass){
14137 this.el.addClass(this.pressClass);
14143 handleMouseUp : function(){
14144 clearTimeout(this.timer);
14145 this.el.un("mouseover", this.handleMouseReturn);
14146 this.el.un("mouseout", this.handleMouseOut);
14147 Roo.get(document).un("mouseup", this.handleMouseUp);
14148 this.el.removeClass(this.pressClass);
14149 this.fireEvent("mouseup", this);
14153 * Ext JS Library 1.1.1
14154 * Copyright(c) 2006-2007, Ext JS, LLC.
14156 * Originally Released Under LGPL - original licence link has changed is not relivant.
14159 * <script type="text/javascript">
14164 * @class Roo.KeyNav
14165 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14166 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14167 * way to implement custom navigation schemes for any UI component.</p>
14168 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14169 * pageUp, pageDown, del, home, end. Usage:</p>
14171 var nav = new Roo.KeyNav("my-element", {
14172 "left" : function(e){
14173 this.moveLeft(e.ctrlKey);
14175 "right" : function(e){
14176 this.moveRight(e.ctrlKey);
14178 "enter" : function(e){
14185 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14186 * @param {Object} config The config
14188 Roo.KeyNav = function(el, config){
14189 this.el = Roo.get(el);
14190 Roo.apply(this, config);
14191 if(!this.disabled){
14192 this.disabled = true;
14197 Roo.KeyNav.prototype = {
14199 * @cfg {Boolean} disabled
14200 * True to disable this KeyNav instance (defaults to false)
14204 * @cfg {String} defaultEventAction
14205 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14206 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14207 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14209 defaultEventAction: "stopEvent",
14211 * @cfg {Boolean} forceKeyDown
14212 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14213 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14214 * handle keydown instead of keypress.
14216 forceKeyDown : false,
14219 prepareEvent : function(e){
14220 var k = e.getKey();
14221 var h = this.keyToHandler[k];
14222 //if(h && this[h]){
14223 // e.stopPropagation();
14225 if(Roo.isSafari && h && k >= 37 && k <= 40){
14231 relay : function(e){
14232 var k = e.getKey();
14233 var h = this.keyToHandler[k];
14235 if(this.doRelay(e, this[h], h) !== true){
14236 e[this.defaultEventAction]();
14242 doRelay : function(e, h, hname){
14243 return h.call(this.scope || this, e);
14246 // possible handlers
14260 // quick lookup hash
14277 * Enable this KeyNav
14279 enable: function(){
14281 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14282 // the EventObject will normalize Safari automatically
14283 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14284 this.el.on("keydown", this.relay, this);
14286 this.el.on("keydown", this.prepareEvent, this);
14287 this.el.on("keypress", this.relay, this);
14289 this.disabled = false;
14294 * Disable this KeyNav
14296 disable: function(){
14297 if(!this.disabled){
14298 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14299 this.el.un("keydown", this.relay);
14301 this.el.un("keydown", this.prepareEvent);
14302 this.el.un("keypress", this.relay);
14304 this.disabled = true;
14309 * Ext JS Library 1.1.1
14310 * Copyright(c) 2006-2007, Ext JS, LLC.
14312 * Originally Released Under LGPL - original licence link has changed is not relivant.
14315 * <script type="text/javascript">
14320 * @class Roo.KeyMap
14321 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14322 * The constructor accepts the same config object as defined by {@link #addBinding}.
14323 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14324 * combination it will call the function with this signature (if the match is a multi-key
14325 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14326 * A KeyMap can also handle a string representation of keys.<br />
14329 // map one key by key code
14330 var map = new Roo.KeyMap("my-element", {
14331 key: 13, // or Roo.EventObject.ENTER
14336 // map multiple keys to one action by string
14337 var map = new Roo.KeyMap("my-element", {
14343 // map multiple keys to multiple actions by strings and array of codes
14344 var map = new Roo.KeyMap("my-element", [
14347 fn: function(){ alert("Return was pressed"); }
14350 fn: function(){ alert('a, b or c was pressed'); }
14355 fn: function(){ alert('Control + shift + tab was pressed.'); }
14359 * <b>Note: A KeyMap starts enabled</b>
14361 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14362 * @param {Object} config The config (see {@link #addBinding})
14363 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14365 Roo.KeyMap = function(el, config, eventName){
14366 this.el = Roo.get(el);
14367 this.eventName = eventName || "keydown";
14368 this.bindings = [];
14370 this.addBinding(config);
14375 Roo.KeyMap.prototype = {
14377 * True to stop the event from bubbling and prevent the default browser action if the
14378 * key was handled by the KeyMap (defaults to false)
14384 * Add a new binding to this KeyMap. The following config object properties are supported:
14386 Property Type Description
14387 ---------- --------------- ----------------------------------------------------------------------
14388 key String/Array A single keycode or an array of keycodes to handle
14389 shift Boolean True to handle key only when shift is pressed (defaults to false)
14390 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14391 alt Boolean True to handle key only when alt is pressed (defaults to false)
14392 fn Function The function to call when KeyMap finds the expected key combination
14393 scope Object The scope of the callback function
14399 var map = new Roo.KeyMap(document, {
14400 key: Roo.EventObject.ENTER,
14405 //Add a new binding to the existing KeyMap later
14413 * @param {Object/Array} config A single KeyMap config or an array of configs
14415 addBinding : function(config){
14416 if(config instanceof Array){
14417 for(var i = 0, len = config.length; i < len; i++){
14418 this.addBinding(config[i]);
14422 var keyCode = config.key,
14423 shift = config.shift,
14424 ctrl = config.ctrl,
14427 scope = config.scope;
14428 if(typeof keyCode == "string"){
14430 var keyString = keyCode.toUpperCase();
14431 for(var j = 0, len = keyString.length; j < len; j++){
14432 ks.push(keyString.charCodeAt(j));
14436 var keyArray = keyCode instanceof Array;
14437 var handler = function(e){
14438 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14439 var k = e.getKey();
14441 for(var i = 0, len = keyCode.length; i < len; i++){
14442 if(keyCode[i] == k){
14443 if(this.stopEvent){
14446 fn.call(scope || window, k, e);
14452 if(this.stopEvent){
14455 fn.call(scope || window, k, e);
14460 this.bindings.push(handler);
14464 * Shorthand for adding a single key listener
14465 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14466 * following options:
14467 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14468 * @param {Function} fn The function to call
14469 * @param {Object} scope (optional) The scope of the function
14471 on : function(key, fn, scope){
14472 var keyCode, shift, ctrl, alt;
14473 if(typeof key == "object" && !(key instanceof Array)){
14492 handleKeyDown : function(e){
14493 if(this.enabled){ //just in case
14494 var b = this.bindings;
14495 for(var i = 0, len = b.length; i < len; i++){
14496 b[i].call(this, e);
14502 * Returns true if this KeyMap is enabled
14503 * @return {Boolean}
14505 isEnabled : function(){
14506 return this.enabled;
14510 * Enables this KeyMap
14512 enable: function(){
14514 this.el.on(this.eventName, this.handleKeyDown, this);
14515 this.enabled = true;
14520 * Disable this KeyMap
14522 disable: function(){
14524 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14525 this.enabled = false;
14530 * Ext JS Library 1.1.1
14531 * Copyright(c) 2006-2007, Ext JS, LLC.
14533 * Originally Released Under LGPL - original licence link has changed is not relivant.
14536 * <script type="text/javascript">
14541 * @class Roo.util.TextMetrics
14542 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14543 * wide, in pixels, a given block of text will be.
14546 Roo.util.TextMetrics = function(){
14550 * Measures the size of the specified text
14551 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14552 * that can affect the size of the rendered text
14553 * @param {String} text The text to measure
14554 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14555 * in order to accurately measure the text height
14556 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14558 measure : function(el, text, fixedWidth){
14560 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14563 shared.setFixedWidth(fixedWidth || 'auto');
14564 return shared.getSize(text);
14568 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14569 * the overhead of multiple calls to initialize the style properties on each measurement.
14570 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14571 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14572 * in order to accurately measure the text height
14573 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14575 createInstance : function(el, fixedWidth){
14576 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14583 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14584 var ml = new Roo.Element(document.createElement('div'));
14585 document.body.appendChild(ml.dom);
14586 ml.position('absolute');
14587 ml.setLeftTop(-1000, -1000);
14591 ml.setWidth(fixedWidth);
14596 * Returns the size of the specified text based on the internal element's style and width properties
14597 * @memberOf Roo.util.TextMetrics.Instance#
14598 * @param {String} text The text to measure
14599 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14601 getSize : function(text){
14603 var s = ml.getSize();
14609 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14610 * that can affect the size of the rendered text
14611 * @memberOf Roo.util.TextMetrics.Instance#
14612 * @param {String/HTMLElement} el The element, dom node or id
14614 bind : function(el){
14616 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14621 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14622 * to set a fixed width in order to accurately measure the text height.
14623 * @memberOf Roo.util.TextMetrics.Instance#
14624 * @param {Number} width The width to set on the element
14626 setFixedWidth : function(width){
14627 ml.setWidth(width);
14631 * Returns the measured width of the specified text
14632 * @memberOf Roo.util.TextMetrics.Instance#
14633 * @param {String} text The text to measure
14634 * @return {Number} width The width in pixels
14636 getWidth : function(text){
14637 ml.dom.style.width = 'auto';
14638 return this.getSize(text).width;
14642 * Returns the measured height of the specified text. For multiline text, be sure to call
14643 * {@link #setFixedWidth} if necessary.
14644 * @memberOf Roo.util.TextMetrics.Instance#
14645 * @param {String} text The text to measure
14646 * @return {Number} height The height in pixels
14648 getHeight : function(text){
14649 return this.getSize(text).height;
14653 instance.bind(bindTo);
14658 // backwards compat
14659 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14661 * Ext JS Library 1.1.1
14662 * Copyright(c) 2006-2007, Ext JS, LLC.
14664 * Originally Released Under LGPL - original licence link has changed is not relivant.
14667 * <script type="text/javascript">
14671 * @class Roo.state.Provider
14672 * Abstract base class for state provider implementations. This class provides methods
14673 * for encoding and decoding <b>typed</b> variables including dates and defines the
14674 * Provider interface.
14676 Roo.state.Provider = function(){
14678 * @event statechange
14679 * Fires when a state change occurs.
14680 * @param {Provider} this This state provider
14681 * @param {String} key The state key which was changed
14682 * @param {String} value The encoded value for the state
14685 "statechange": true
14688 Roo.state.Provider.superclass.constructor.call(this);
14690 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14692 * Returns the current value for a key
14693 * @param {String} name The key name
14694 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14695 * @return {Mixed} The state data
14697 get : function(name, defaultValue){
14698 return typeof this.state[name] == "undefined" ?
14699 defaultValue : this.state[name];
14703 * Clears a value from the state
14704 * @param {String} name The key name
14706 clear : function(name){
14707 delete this.state[name];
14708 this.fireEvent("statechange", this, name, null);
14712 * Sets the value for a key
14713 * @param {String} name The key name
14714 * @param {Mixed} value The value to set
14716 set : function(name, value){
14717 this.state[name] = value;
14718 this.fireEvent("statechange", this, name, value);
14722 * Decodes a string previously encoded with {@link #encodeValue}.
14723 * @param {String} value The value to decode
14724 * @return {Mixed} The decoded value
14726 decodeValue : function(cookie){
14727 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14728 var matches = re.exec(unescape(cookie));
14729 if(!matches || !matches[1]) return; // non state cookie
14730 var type = matches[1];
14731 var v = matches[2];
14734 return parseFloat(v);
14736 return new Date(Date.parse(v));
14741 var values = v.split("^");
14742 for(var i = 0, len = values.length; i < len; i++){
14743 all.push(this.decodeValue(values[i]));
14748 var values = v.split("^");
14749 for(var i = 0, len = values.length; i < len; i++){
14750 var kv = values[i].split("=");
14751 all[kv[0]] = this.decodeValue(kv[1]);
14760 * Encodes a value including type information. Decode with {@link #decodeValue}.
14761 * @param {Mixed} value The value to encode
14762 * @return {String} The encoded value
14764 encodeValue : function(v){
14766 if(typeof v == "number"){
14768 }else if(typeof v == "boolean"){
14769 enc = "b:" + (v ? "1" : "0");
14770 }else if(v instanceof Date){
14771 enc = "d:" + v.toGMTString();
14772 }else if(v instanceof Array){
14774 for(var i = 0, len = v.length; i < len; i++){
14775 flat += this.encodeValue(v[i]);
14776 if(i != len-1) flat += "^";
14779 }else if(typeof v == "object"){
14782 if(typeof v[key] != "function"){
14783 flat += key + "=" + this.encodeValue(v[key]) + "^";
14786 enc = "o:" + flat.substring(0, flat.length-1);
14790 return escape(enc);
14796 * Ext JS Library 1.1.1
14797 * Copyright(c) 2006-2007, Ext JS, LLC.
14799 * Originally Released Under LGPL - original licence link has changed is not relivant.
14802 * <script type="text/javascript">
14805 * @class Roo.state.Manager
14806 * This is the global state manager. By default all components that are "state aware" check this class
14807 * for state information if you don't pass them a custom state provider. In order for this class
14808 * to be useful, it must be initialized with a provider when your application initializes.
14810 // in your initialization function
14812 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14814 // supposed you have a {@link Roo.BorderLayout}
14815 var layout = new Roo.BorderLayout(...);
14816 layout.restoreState();
14817 // or a {Roo.BasicDialog}
14818 var dialog = new Roo.BasicDialog(...);
14819 dialog.restoreState();
14823 Roo.state.Manager = function(){
14824 var provider = new Roo.state.Provider();
14828 * Configures the default state provider for your application
14829 * @param {Provider} stateProvider The state provider to set
14831 setProvider : function(stateProvider){
14832 provider = stateProvider;
14836 * Returns the current value for a key
14837 * @param {String} name The key name
14838 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14839 * @return {Mixed} The state data
14841 get : function(key, defaultValue){
14842 return provider.get(key, defaultValue);
14846 * Sets the value for a key
14847 * @param {String} name The key name
14848 * @param {Mixed} value The state data
14850 set : function(key, value){
14851 provider.set(key, value);
14855 * Clears a value from the state
14856 * @param {String} name The key name
14858 clear : function(key){
14859 provider.clear(key);
14863 * Gets the currently configured state provider
14864 * @return {Provider} The state provider
14866 getProvider : function(){
14873 * Ext JS Library 1.1.1
14874 * Copyright(c) 2006-2007, Ext JS, LLC.
14876 * Originally Released Under LGPL - original licence link has changed is not relivant.
14879 * <script type="text/javascript">
14882 * @class Roo.state.CookieProvider
14883 * @extends Roo.state.Provider
14884 * The default Provider implementation which saves state via cookies.
14887 var cp = new Roo.state.CookieProvider({
14889 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14890 domain: "roojs.com"
14892 Roo.state.Manager.setProvider(cp);
14894 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14895 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14896 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14897 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14898 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14899 * domain the page is running on including the 'www' like 'www.roojs.com')
14900 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14902 * Create a new CookieProvider
14903 * @param {Object} config The configuration object
14905 Roo.state.CookieProvider = function(config){
14906 Roo.state.CookieProvider.superclass.constructor.call(this);
14908 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14909 this.domain = null;
14910 this.secure = false;
14911 Roo.apply(this, config);
14912 this.state = this.readCookies();
14915 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14917 set : function(name, value){
14918 if(typeof value == "undefined" || value === null){
14922 this.setCookie(name, value);
14923 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14927 clear : function(name){
14928 this.clearCookie(name);
14929 Roo.state.CookieProvider.superclass.clear.call(this, name);
14933 readCookies : function(){
14935 var c = document.cookie + ";";
14936 var re = /\s?(.*?)=(.*?);/g;
14938 while((matches = re.exec(c)) != null){
14939 var name = matches[1];
14940 var value = matches[2];
14941 if(name && name.substring(0,3) == "ys-"){
14942 cookies[name.substr(3)] = this.decodeValue(value);
14949 setCookie : function(name, value){
14950 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14951 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14952 ((this.path == null) ? "" : ("; path=" + this.path)) +
14953 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14954 ((this.secure == true) ? "; secure" : "");
14958 clearCookie : function(name){
14959 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14960 ((this.path == null) ? "" : ("; path=" + this.path)) +
14961 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14962 ((this.secure == true) ? "; secure" : "");
14966 * Ext JS Library 1.1.1
14967 * Copyright(c) 2006-2007, Ext JS, LLC.
14969 * Originally Released Under LGPL - original licence link has changed is not relivant.
14972 * <script type="text/javascript">
14977 * @class Roo.ComponentMgr
14978 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14981 Roo.ComponentMgr = function(){
14982 var all = new Roo.util.MixedCollection();
14986 * Registers a component.
14987 * @param {Roo.Component} c The component
14989 register : function(c){
14994 * Unregisters a component.
14995 * @param {Roo.Component} c The component
14997 unregister : function(c){
15002 * Returns a component by id
15003 * @param {String} id The component id
15005 get : function(id){
15006 return all.get(id);
15010 * Registers a function that will be called when a specified component is added to ComponentMgr
15011 * @param {String} id The component id
15012 * @param {Funtction} fn The callback function
15013 * @param {Object} scope The scope of the callback
15015 onAvailable : function(id, fn, scope){
15016 all.on("add", function(index, o){
15018 fn.call(scope || o, o);
15019 all.un("add", fn, scope);
15026 * Ext JS Library 1.1.1
15027 * Copyright(c) 2006-2007, Ext JS, LLC.
15029 * Originally Released Under LGPL - original licence link has changed is not relivant.
15032 * <script type="text/javascript">
15036 * @class Roo.Component
15037 * @extends Roo.util.Observable
15038 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15039 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15040 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15041 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15042 * All visual components (widgets) that require rendering into a layout should subclass Component.
15044 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15045 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
15046 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15048 Roo.Component = function(config){
15049 config = config || {};
15050 if(config.tagName || config.dom || typeof config == "string"){ // element object
15051 config = {el: config, id: config.id || config};
15053 this.initialConfig = config;
15055 Roo.apply(this, config);
15059 * Fires after the component is disabled.
15060 * @param {Roo.Component} this
15065 * Fires after the component is enabled.
15066 * @param {Roo.Component} this
15070 * @event beforeshow
15071 * Fires before the component is shown. Return false to stop the show.
15072 * @param {Roo.Component} this
15077 * Fires after the component is shown.
15078 * @param {Roo.Component} this
15082 * @event beforehide
15083 * Fires before the component is hidden. Return false to stop the hide.
15084 * @param {Roo.Component} this
15089 * Fires after the component is hidden.
15090 * @param {Roo.Component} this
15094 * @event beforerender
15095 * Fires before the component is rendered. Return false to stop the render.
15096 * @param {Roo.Component} this
15098 beforerender : true,
15101 * Fires after the component is rendered.
15102 * @param {Roo.Component} this
15106 * @event beforedestroy
15107 * Fires before the component is destroyed. Return false to stop the destroy.
15108 * @param {Roo.Component} this
15110 beforedestroy : true,
15113 * Fires after the component is destroyed.
15114 * @param {Roo.Component} this
15119 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15121 Roo.ComponentMgr.register(this);
15122 Roo.Component.superclass.constructor.call(this);
15123 this.initComponent();
15124 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15125 this.render(this.renderTo);
15126 delete this.renderTo;
15131 Roo.Component.AUTO_ID = 1000;
15133 Roo.extend(Roo.Component, Roo.util.Observable, {
15135 * @scope Roo.Component.prototype
15137 * true if this component is hidden. Read-only.
15142 * true if this component is disabled. Read-only.
15147 * true if this component has been rendered. Read-only.
15151 /** @cfg {String} disableClass
15152 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15154 disabledClass : "x-item-disabled",
15155 /** @cfg {Boolean} allowDomMove
15156 * Whether the component can move the Dom node when rendering (defaults to true).
15158 allowDomMove : true,
15159 /** @cfg {String} hideMode
15160 * How this component should hidden. Supported values are
15161 * "visibility" (css visibility), "offsets" (negative offset position) and
15162 * "display" (css display) - defaults to "display".
15164 hideMode: 'display',
15167 ctype : "Roo.Component",
15170 * @cfg {String} actionMode
15171 * which property holds the element that used for hide() / show() / disable() / enable()
15177 getActionEl : function(){
15178 return this[this.actionMode];
15181 initComponent : Roo.emptyFn,
15183 * If this is a lazy rendering component, render it to its container element.
15184 * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
15186 render : function(container, position){
15187 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15188 if(!container && this.el){
15189 this.el = Roo.get(this.el);
15190 container = this.el.dom.parentNode;
15191 this.allowDomMove = false;
15193 this.container = Roo.get(container);
15194 this.rendered = true;
15195 if(position !== undefined){
15196 if(typeof position == 'number'){
15197 position = this.container.dom.childNodes[position];
15199 position = Roo.getDom(position);
15202 this.onRender(this.container, position || null);
15204 this.el.addClass(this.cls);
15208 this.el.applyStyles(this.style);
15211 this.fireEvent("render", this);
15212 this.afterRender(this.container);
15224 // default function is not really useful
15225 onRender : function(ct, position){
15227 this.el = Roo.get(this.el);
15228 if(this.allowDomMove !== false){
15229 ct.dom.insertBefore(this.el.dom, position);
15235 getAutoCreate : function(){
15236 var cfg = typeof this.autoCreate == "object" ?
15237 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15238 if(this.id && !cfg.id){
15245 afterRender : Roo.emptyFn,
15248 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15249 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15251 destroy : function(){
15252 if(this.fireEvent("beforedestroy", this) !== false){
15253 this.purgeListeners();
15254 this.beforeDestroy();
15256 this.el.removeAllListeners();
15258 if(this.actionMode == "container"){
15259 this.container.remove();
15263 Roo.ComponentMgr.unregister(this);
15264 this.fireEvent("destroy", this);
15269 beforeDestroy : function(){
15274 onDestroy : function(){
15279 * Returns the underlying {@link Roo.Element}.
15280 * @return {Roo.Element} The element
15282 getEl : function(){
15287 * Returns the id of this component.
15290 getId : function(){
15295 * Try to focus this component.
15296 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15297 * @return {Roo.Component} this
15299 focus : function(selectText){
15302 if(selectText === true){
15303 this.el.dom.select();
15318 * Disable this component.
15319 * @return {Roo.Component} this
15321 disable : function(){
15325 this.disabled = true;
15326 this.fireEvent("disable", this);
15331 onDisable : function(){
15332 this.getActionEl().addClass(this.disabledClass);
15333 this.el.dom.disabled = true;
15337 * Enable this component.
15338 * @return {Roo.Component} this
15340 enable : function(){
15344 this.disabled = false;
15345 this.fireEvent("enable", this);
15350 onEnable : function(){
15351 this.getActionEl().removeClass(this.disabledClass);
15352 this.el.dom.disabled = false;
15356 * Convenience function for setting disabled/enabled by boolean.
15357 * @param {Boolean} disabled
15359 setDisabled : function(disabled){
15360 this[disabled ? "disable" : "enable"]();
15364 * Show this component.
15365 * @return {Roo.Component} this
15368 if(this.fireEvent("beforeshow", this) !== false){
15369 this.hidden = false;
15373 this.fireEvent("show", this);
15379 onShow : function(){
15380 var ae = this.getActionEl();
15381 if(this.hideMode == 'visibility'){
15382 ae.dom.style.visibility = "visible";
15383 }else if(this.hideMode == 'offsets'){
15384 ae.removeClass('x-hidden');
15386 ae.dom.style.display = "";
15391 * Hide this component.
15392 * @return {Roo.Component} this
15395 if(this.fireEvent("beforehide", this) !== false){
15396 this.hidden = true;
15400 this.fireEvent("hide", this);
15406 onHide : function(){
15407 var ae = this.getActionEl();
15408 if(this.hideMode == 'visibility'){
15409 ae.dom.style.visibility = "hidden";
15410 }else if(this.hideMode == 'offsets'){
15411 ae.addClass('x-hidden');
15413 ae.dom.style.display = "none";
15418 * Convenience function to hide or show this component by boolean.
15419 * @param {Boolean} visible True to show, false to hide
15420 * @return {Roo.Component} this
15422 setVisible: function(visible){
15432 * Returns true if this component is visible.
15434 isVisible : function(){
15435 return this.getActionEl().isVisible();
15438 cloneConfig : function(overrides){
15439 overrides = overrides || {};
15440 var id = overrides.id || Roo.id();
15441 var cfg = Roo.applyIf(overrides, this.initialConfig);
15442 cfg.id = id; // prevent dup id
15443 return new this.constructor(cfg);
15447 * Ext JS Library 1.1.1
15448 * Copyright(c) 2006-2007, Ext JS, LLC.
15450 * Originally Released Under LGPL - original licence link has changed is not relivant.
15453 * <script type="text/javascript">
15457 * @class Roo.BoxComponent
15458 * @extends Roo.Component
15459 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15460 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15461 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15462 * layout containers.
15464 * @param {Roo.Element/String/Object} config The configuration options.
15466 Roo.BoxComponent = function(config){
15467 Roo.Component.call(this, config);
15471 * Fires after the component is resized.
15472 * @param {Roo.Component} this
15473 * @param {Number} adjWidth The box-adjusted width that was set
15474 * @param {Number} adjHeight The box-adjusted height that was set
15475 * @param {Number} rawWidth The width that was originally specified
15476 * @param {Number} rawHeight The height that was originally specified
15481 * Fires after the component is moved.
15482 * @param {Roo.Component} this
15483 * @param {Number} x The new x position
15484 * @param {Number} y The new y position
15490 Roo.extend(Roo.BoxComponent, Roo.Component, {
15491 // private, set in afterRender to signify that the component has been rendered
15493 // private, used to defer height settings to subclasses
15494 deferHeight: false,
15495 /** @cfg {Number} width
15496 * width (optional) size of component
15498 /** @cfg {Number} height
15499 * height (optional) size of component
15503 * Sets the width and height of the component. This method fires the resize event. This method can accept
15504 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15505 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15506 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15507 * @return {Roo.BoxComponent} this
15509 setSize : function(w, h){
15510 // support for standard size objects
15511 if(typeof w == 'object'){
15516 if(!this.boxReady){
15522 // prevent recalcs when not needed
15523 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15526 this.lastSize = {width: w, height: h};
15528 var adj = this.adjustSize(w, h);
15529 var aw = adj.width, ah = adj.height;
15530 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15531 var rz = this.getResizeEl();
15532 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15533 rz.setSize(aw, ah);
15534 }else if(!this.deferHeight && ah !== undefined){
15536 }else if(aw !== undefined){
15539 this.onResize(aw, ah, w, h);
15540 this.fireEvent('resize', this, aw, ah, w, h);
15546 * Gets the current size of the component's underlying element.
15547 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15549 getSize : function(){
15550 return this.el.getSize();
15554 * Gets the current XY position of the component's underlying element.
15555 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15556 * @return {Array} The XY position of the element (e.g., [100, 200])
15558 getPosition : function(local){
15559 if(local === true){
15560 return [this.el.getLeft(true), this.el.getTop(true)];
15562 return this.xy || this.el.getXY();
15566 * Gets the current box measurements of the component's underlying element.
15567 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15568 * @returns {Object} box An object in the format {x, y, width, height}
15570 getBox : function(local){
15571 var s = this.el.getSize();
15573 s.x = this.el.getLeft(true);
15574 s.y = this.el.getTop(true);
15576 var xy = this.xy || this.el.getXY();
15584 * Sets the current box measurements of the component's underlying element.
15585 * @param {Object} box An object in the format {x, y, width, height}
15586 * @returns {Roo.BoxComponent} this
15588 updateBox : function(box){
15589 this.setSize(box.width, box.height);
15590 this.setPagePosition(box.x, box.y);
15595 getResizeEl : function(){
15596 return this.resizeEl || this.el;
15600 getPositionEl : function(){
15601 return this.positionEl || this.el;
15605 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15606 * This method fires the move event.
15607 * @param {Number} left The new left
15608 * @param {Number} top The new top
15609 * @returns {Roo.BoxComponent} this
15611 setPosition : function(x, y){
15614 if(!this.boxReady){
15617 var adj = this.adjustPosition(x, y);
15618 var ax = adj.x, ay = adj.y;
15620 var el = this.getPositionEl();
15621 if(ax !== undefined || ay !== undefined){
15622 if(ax !== undefined && ay !== undefined){
15623 el.setLeftTop(ax, ay);
15624 }else if(ax !== undefined){
15626 }else if(ay !== undefined){
15629 this.onPosition(ax, ay);
15630 this.fireEvent('move', this, ax, ay);
15636 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15637 * This method fires the move event.
15638 * @param {Number} x The new x position
15639 * @param {Number} y The new y position
15640 * @returns {Roo.BoxComponent} this
15642 setPagePosition : function(x, y){
15645 if(!this.boxReady){
15648 if(x === undefined || y === undefined){ // cannot translate undefined points
15651 var p = this.el.translatePoints(x, y);
15652 this.setPosition(p.left, p.top);
15657 onRender : function(ct, position){
15658 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15660 this.resizeEl = Roo.get(this.resizeEl);
15662 if(this.positionEl){
15663 this.positionEl = Roo.get(this.positionEl);
15668 afterRender : function(){
15669 Roo.BoxComponent.superclass.afterRender.call(this);
15670 this.boxReady = true;
15671 this.setSize(this.width, this.height);
15672 if(this.x || this.y){
15673 this.setPosition(this.x, this.y);
15675 if(this.pageX || this.pageY){
15676 this.setPagePosition(this.pageX, this.pageY);
15681 * Force the component's size to recalculate based on the underlying element's current height and width.
15682 * @returns {Roo.BoxComponent} this
15684 syncSize : function(){
15685 delete this.lastSize;
15686 this.setSize(this.el.getWidth(), this.el.getHeight());
15691 * Called after the component is resized, this method is empty by default but can be implemented by any
15692 * subclass that needs to perform custom logic after a resize occurs.
15693 * @param {Number} adjWidth The box-adjusted width that was set
15694 * @param {Number} adjHeight The box-adjusted height that was set
15695 * @param {Number} rawWidth The width that was originally specified
15696 * @param {Number} rawHeight The height that was originally specified
15698 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15703 * Called after the component is moved, this method is empty by default but can be implemented by any
15704 * subclass that needs to perform custom logic after a move occurs.
15705 * @param {Number} x The new x position
15706 * @param {Number} y The new y position
15708 onPosition : function(x, y){
15713 adjustSize : function(w, h){
15714 if(this.autoWidth){
15717 if(this.autoHeight){
15720 return {width : w, height: h};
15724 adjustPosition : function(x, y){
15725 return {x : x, y: y};
15728 * Original code for Roojs - LGPL
15729 * <script type="text/javascript">
15733 * @class Roo.XComponent
15734 * A delayed Element creator...
15735 * Or a way to group chunks of interface together.
15737 * Mypart.xyx = new Roo.XComponent({
15739 parent : 'Mypart.xyz', // empty == document.element.!!
15743 disabled : function() {}
15745 tree : function() { // return an tree of xtype declared components
15749 xtype : 'NestedLayoutPanel',
15756 * It can be used to build a big heiracy, with parent etc.
15757 * or you can just use this to render a single compoent to a dom element
15758 * MYPART.render(Roo.Element | String(id) | dom_element )
15760 * @extends Roo.util.Observable
15762 * @param cfg {Object} configuration of component
15765 Roo.XComponent = function(cfg) {
15766 Roo.apply(this, cfg);
15770 * Fires when this the componnt is built
15771 * @param {Roo.XComponent} c the component
15776 this.region = this.region || 'center'; // default..
15777 Roo.XComponent.register(this);
15778 this.modules = false;
15779 this.el = false; // where the layout goes..
15783 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15786 * The created element (with Roo.factory())
15787 * @type {Roo.Layout}
15793 * for BC - use el in new code
15794 * @type {Roo.Layout}
15800 * for BC - use el in new code
15801 * @type {Roo.Layout}
15806 * @cfg {Function|boolean} disabled
15807 * If this module is disabled by some rule, return true from the funtion
15812 * @cfg {String} parent
15813 * Name of parent element which it get xtype added to..
15818 * @cfg {String} order
15819 * Used to set the order in which elements are created (usefull for multiple tabs)
15824 * @cfg {String} name
15825 * String to display while loading.
15829 * @cfg {String} region
15830 * Region to render component to (defaults to center)
15835 * @cfg {Array} items
15836 * A single item array - the first element is the root of the tree..
15837 * It's done this way to stay compatible with the Xtype system...
15843 * The method that retuns the tree of parts that make up this compoennt
15850 * render element to dom or tree
15851 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15854 render : function(el)
15858 var hp = this.parent ? 1 : 0;
15860 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15861 // if parent is a '#.....' string, then let's use that..
15862 var ename = this.parent.substr(1)
15863 this.parent = (this.parent == '#bootstrap') ? { el : true} : false; // flags it as a top module...
15864 el = Roo.get(ename);
15865 if (!el && !this.parent) {
15866 Roo.log("Warning - element can not be found :#" + ename );
15870 var tree = this._tree ? this._tree() : this.tree();
15873 if (!this.parent && typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) {
15874 //el = Roo.get(document.body);
15875 this.parent = { el : true };
15880 if (!this.parent) {
15882 Roo.log("no parent - creating one");
15884 el = el ? Roo.get(el) : false;
15886 // it's a top level one..
15888 el : new Roo.BorderLayout(el || document.body, {
15894 tabPosition: 'top',
15895 //resizeTabs: true,
15896 alwaysShowTabs: el && hp? false : true,
15897 hideTabs: el || !hp ? true : false,
15904 if (!this.parent.el) {
15905 // probably an old style ctor, which has been disabled.
15909 // The 'tree' method is '_tree now'
15911 tree.region = tree.region || this.region;
15913 if (this.parent.el === true) {
15914 // bootstrap... - body..
15915 this.parent.el = Roo.factory(tree);
15918 this.el = this.parent.el.addxtype(tree);
15919 this.fireEvent('built', this);
15921 this.panel = this.el;
15922 this.layout = this.panel.layout;
15923 this.parentLayout = this.parent.layout || false;
15929 Roo.apply(Roo.XComponent, {
15931 * @property hideProgress
15932 * true to disable the building progress bar.. usefull on single page renders.
15935 hideProgress : false,
15937 * @property buildCompleted
15938 * True when the builder has completed building the interface.
15941 buildCompleted : false,
15944 * @property topModule
15945 * the upper most module - uses document.element as it's constructor.
15952 * @property modules
15953 * array of modules to be created by registration system.
15954 * @type {Array} of Roo.XComponent
15959 * @property elmodules
15960 * array of modules to be created by which use #ID
15961 * @type {Array} of Roo.XComponent
15967 * @property build_from_html
15968 * Build elements from html - used by bootstrap HTML stuff
15969 * - this is cleared after build is completed
15970 * @type {boolean} true (default false)
15973 build_from_html : false,
15976 * Register components to be built later.
15978 * This solves the following issues
15979 * - Building is not done on page load, but after an authentication process has occured.
15980 * - Interface elements are registered on page load
15981 * - Parent Interface elements may not be loaded before child, so this handles that..
15988 module : 'Pman.Tab.projectMgr',
15990 parent : 'Pman.layout',
15991 disabled : false, // or use a function..
15994 * * @param {Object} details about module
15996 register : function(obj) {
15998 Roo.XComponent.event.fireEvent('register', obj);
15999 switch(typeof(obj.disabled) ) {
16005 if ( obj.disabled() ) {
16011 if (obj.disabled) {
16017 this.modules.push(obj);
16021 * convert a string to an object..
16022 * eg. 'AAA.BBB' -> finds AAA.BBB
16026 toObject : function(str)
16028 if (!str || typeof(str) == 'object') {
16031 if (str.substring(0,1) == '#') {
16035 var ar = str.split('.');
16040 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16042 throw "Module not found : " + str;
16046 throw "Module not found : " + str;
16048 Roo.each(ar, function(e) {
16049 if (typeof(o[e]) == 'undefined') {
16050 throw "Module not found : " + str;
16061 * move modules into their correct place in the tree..
16064 preBuild : function ()
16067 Roo.each(this.modules , function (obj)
16069 Roo.XComponent.event.fireEvent('beforebuild', obj);
16071 var opar = obj.parent;
16073 obj.parent = this.toObject(opar);
16075 Roo.log("parent:toObject failed: " + e.toString());
16080 Roo.debug && Roo.log("GOT top level module");
16081 Roo.debug && Roo.log(obj);
16082 obj.modules = new Roo.util.MixedCollection(false,
16083 function(o) { return o.order + '' }
16085 this.topModule = obj;
16088 // parent is a string (usually a dom element name..)
16089 if (typeof(obj.parent) == 'string') {
16090 this.elmodules.push(obj);
16093 if (obj.parent.constructor != Roo.XComponent) {
16094 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16096 if (!obj.parent.modules) {
16097 obj.parent.modules = new Roo.util.MixedCollection(false,
16098 function(o) { return o.order + '' }
16101 if (obj.parent.disabled) {
16102 obj.disabled = true;
16104 obj.parent.modules.add(obj);
16109 * make a list of modules to build.
16110 * @return {Array} list of modules.
16113 buildOrder : function()
16116 var cmp = function(a,b) {
16117 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16119 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16120 throw "No top level modules to build";
16123 // make a flat list in order of modules to build.
16124 var mods = this.topModule ? [ this.topModule ] : [];
16127 // elmodules (is a list of DOM based modules )
16128 Roo.each(this.elmodules, function(e) {
16130 if (!this.topModule &&
16131 typeof(e.parent) == 'string' &&
16132 e.parent.substring(0,1) == '#' &&
16133 Roo.get(e.parent.substr(1))
16136 _this.topModule = e;
16142 // add modules to their parents..
16143 var addMod = function(m) {
16144 Roo.debug && Roo.log("build Order: add: " + m.name);
16147 if (m.modules && !m.disabled) {
16148 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16149 m.modules.keySort('ASC', cmp );
16150 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16152 m.modules.each(addMod);
16154 Roo.debug && Roo.log("build Order: no child modules");
16156 // not sure if this is used any more..
16158 m.finalize.name = m.name + " (clean up) ";
16159 mods.push(m.finalize);
16163 if (this.topModule && this.topModule.modules) {
16164 this.topModule.modules.keySort('ASC', cmp );
16165 this.topModule.modules.each(addMod);
16171 * Build the registered modules.
16172 * @param {Object} parent element.
16173 * @param {Function} optional method to call after module has been added.
16177 build : function(opts)
16180 if (typeof(opts) != 'undefined') {
16181 Roo.apply(this,opts);
16185 var mods = this.buildOrder();
16187 //this.allmods = mods;
16188 //Roo.debug && Roo.log(mods);
16190 if (!mods.length) { // should not happen
16191 throw "NO modules!!!";
16195 var msg = "Building Interface...";
16196 // flash it up as modal - so we store the mask!?
16197 if (!this.hideProgress && Roo.MessageBox) {
16198 Roo.MessageBox.show({ title: 'loading' });
16199 Roo.MessageBox.show({
16200 title: "Please wait...",
16209 var total = mods.length;
16212 var progressRun = function() {
16213 if (!mods.length) {
16214 Roo.debug && Roo.log('hide?');
16215 if (!this.hideProgress && Roo.MessageBox) {
16216 Roo.MessageBox.hide();
16218 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16220 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16226 var m = mods.shift();
16229 Roo.debug && Roo.log(m);
16230 // not sure if this is supported any more.. - modules that are are just function
16231 if (typeof(m) == 'function') {
16233 return progressRun.defer(10, _this);
16237 msg = "Building Interface " + (total - mods.length) +
16239 (m.name ? (' - ' + m.name) : '');
16240 Roo.debug && Roo.log(msg);
16241 if (!this.hideProgress && Roo.MessageBox) {
16242 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16246 // is the module disabled?
16247 var disabled = (typeof(m.disabled) == 'function') ?
16248 m.disabled.call(m.module.disabled) : m.disabled;
16252 return progressRun(); // we do not update the display!
16260 // it's 10 on top level, and 1 on others??? why...
16261 return progressRun.defer(10, _this);
16264 progressRun.defer(1, _this);
16278 * wrapper for event.on - aliased later..
16279 * Typically use to register a event handler for register:
16281 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16290 Roo.XComponent.event = new Roo.util.Observable({
16294 * Fires when an Component is registered,
16295 * set the disable property on the Component to stop registration.
16296 * @param {Roo.XComponent} c the component being registerd.
16301 * @event beforebuild
16302 * Fires before each Component is built
16303 * can be used to apply permissions.
16304 * @param {Roo.XComponent} c the component being registerd.
16307 'beforebuild' : true,
16309 * @event buildcomplete
16310 * Fires on the top level element when all elements have been built
16311 * @param {Roo.XComponent} the top level component.
16313 'buildcomplete' : true
16318 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16321 * Ext JS Library 1.1.1
16322 * Copyright(c) 2006-2007, Ext JS, LLC.
16324 * Originally Released Under LGPL - original licence link has changed is not relivant.
16327 * <script type="text/javascript">
16333 * These classes are derivatives of the similarly named classes in the YUI Library.
16334 * The original license:
16335 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16336 * Code licensed under the BSD License:
16337 * http://developer.yahoo.net/yui/license.txt
16342 var Event=Roo.EventManager;
16343 var Dom=Roo.lib.Dom;
16346 * @class Roo.dd.DragDrop
16347 * @extends Roo.util.Observable
16348 * Defines the interface and base operation of items that that can be
16349 * dragged or can be drop targets. It was designed to be extended, overriding
16350 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16351 * Up to three html elements can be associated with a DragDrop instance:
16353 * <li>linked element: the element that is passed into the constructor.
16354 * This is the element which defines the boundaries for interaction with
16355 * other DragDrop objects.</li>
16356 * <li>handle element(s): The drag operation only occurs if the element that
16357 * was clicked matches a handle element. By default this is the linked
16358 * element, but there are times that you will want only a portion of the
16359 * linked element to initiate the drag operation, and the setHandleElId()
16360 * method provides a way to define this.</li>
16361 * <li>drag element: this represents the element that would be moved along
16362 * with the cursor during a drag operation. By default, this is the linked
16363 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16364 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16367 * This class should not be instantiated until the onload event to ensure that
16368 * the associated elements are available.
16369 * The following would define a DragDrop obj that would interact with any
16370 * other DragDrop obj in the "group1" group:
16372 * dd = new Roo.dd.DragDrop("div1", "group1");
16374 * Since none of the event handlers have been implemented, nothing would
16375 * actually happen if you were to run the code above. Normally you would
16376 * override this class or one of the default implementations, but you can
16377 * also override the methods you want on an instance of the class...
16379 * dd.onDragDrop = function(e, id) {
16380 * alert("dd was dropped on " + id);
16384 * @param {String} id of the element that is linked to this instance
16385 * @param {String} sGroup the group of related DragDrop objects
16386 * @param {object} config an object containing configurable attributes
16387 * Valid properties for DragDrop:
16388 * padding, isTarget, maintainOffset, primaryButtonOnly
16390 Roo.dd.DragDrop = function(id, sGroup, config) {
16392 this.init(id, sGroup, config);
16397 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16400 * The id of the element associated with this object. This is what we
16401 * refer to as the "linked element" because the size and position of
16402 * this element is used to determine when the drag and drop objects have
16410 * Configuration attributes passed into the constructor
16417 * The id of the element that will be dragged. By default this is same
16418 * as the linked element , but could be changed to another element. Ex:
16420 * @property dragElId
16427 * the id of the element that initiates the drag operation. By default
16428 * this is the linked element, but could be changed to be a child of this
16429 * element. This lets us do things like only starting the drag when the
16430 * header element within the linked html element is clicked.
16431 * @property handleElId
16438 * An associative array of HTML tags that will be ignored if clicked.
16439 * @property invalidHandleTypes
16440 * @type {string: string}
16442 invalidHandleTypes: null,
16445 * An associative array of ids for elements that will be ignored if clicked
16446 * @property invalidHandleIds
16447 * @type {string: string}
16449 invalidHandleIds: null,
16452 * An indexted array of css class names for elements that will be ignored
16454 * @property invalidHandleClasses
16457 invalidHandleClasses: null,
16460 * The linked element's absolute X position at the time the drag was
16462 * @property startPageX
16469 * The linked element's absolute X position at the time the drag was
16471 * @property startPageY
16478 * The group defines a logical collection of DragDrop objects that are
16479 * related. Instances only get events when interacting with other
16480 * DragDrop object in the same group. This lets us define multiple
16481 * groups using a single DragDrop subclass if we want.
16483 * @type {string: string}
16488 * Individual drag/drop instances can be locked. This will prevent
16489 * onmousedown start drag.
16497 * Lock this instance
16500 lock: function() { this.locked = true; },
16503 * Unlock this instace
16506 unlock: function() { this.locked = false; },
16509 * By default, all insances can be a drop target. This can be disabled by
16510 * setting isTarget to false.
16517 * The padding configured for this drag and drop object for calculating
16518 * the drop zone intersection with this object.
16525 * Cached reference to the linked element
16526 * @property _domRef
16532 * Internal typeof flag
16533 * @property __ygDragDrop
16536 __ygDragDrop: true,
16539 * Set to true when horizontal contraints are applied
16540 * @property constrainX
16547 * Set to true when vertical contraints are applied
16548 * @property constrainY
16555 * The left constraint
16563 * The right constraint
16571 * The up constraint
16580 * The down constraint
16588 * Maintain offsets when we resetconstraints. Set to true when you want
16589 * the position of the element relative to its parent to stay the same
16590 * when the page changes
16592 * @property maintainOffset
16595 maintainOffset: false,
16598 * Array of pixel locations the element will snap to if we specified a
16599 * horizontal graduation/interval. This array is generated automatically
16600 * when you define a tick interval.
16607 * Array of pixel locations the element will snap to if we specified a
16608 * vertical graduation/interval. This array is generated automatically
16609 * when you define a tick interval.
16616 * By default the drag and drop instance will only respond to the primary
16617 * button click (left button for a right-handed mouse). Set to true to
16618 * allow drag and drop to start with any mouse click that is propogated
16620 * @property primaryButtonOnly
16623 primaryButtonOnly: true,
16626 * The availabe property is false until the linked dom element is accessible.
16627 * @property available
16633 * By default, drags can only be initiated if the mousedown occurs in the
16634 * region the linked element is. This is done in part to work around a
16635 * bug in some browsers that mis-report the mousedown if the previous
16636 * mouseup happened outside of the window. This property is set to true
16637 * if outer handles are defined.
16639 * @property hasOuterHandles
16643 hasOuterHandles: false,
16646 * Code that executes immediately before the startDrag event
16647 * @method b4StartDrag
16650 b4StartDrag: function(x, y) { },
16653 * Abstract method called after a drag/drop object is clicked
16654 * and the drag or mousedown time thresholds have beeen met.
16655 * @method startDrag
16656 * @param {int} X click location
16657 * @param {int} Y click location
16659 startDrag: function(x, y) { /* override this */ },
16662 * Code that executes immediately before the onDrag event
16666 b4Drag: function(e) { },
16669 * Abstract method called during the onMouseMove event while dragging an
16672 * @param {Event} e the mousemove event
16674 onDrag: function(e) { /* override this */ },
16677 * Abstract method called when this element fist begins hovering over
16678 * another DragDrop obj
16679 * @method onDragEnter
16680 * @param {Event} e the mousemove event
16681 * @param {String|DragDrop[]} id In POINT mode, the element
16682 * id this is hovering over. In INTERSECT mode, an array of one or more
16683 * dragdrop items being hovered over.
16685 onDragEnter: function(e, id) { /* override this */ },
16688 * Code that executes immediately before the onDragOver event
16689 * @method b4DragOver
16692 b4DragOver: function(e) { },
16695 * Abstract method called when this element is hovering over another
16697 * @method onDragOver
16698 * @param {Event} e the mousemove event
16699 * @param {String|DragDrop[]} id In POINT mode, the element
16700 * id this is hovering over. In INTERSECT mode, an array of dd items
16701 * being hovered over.
16703 onDragOver: function(e, id) { /* override this */ },
16706 * Code that executes immediately before the onDragOut event
16707 * @method b4DragOut
16710 b4DragOut: function(e) { },
16713 * Abstract method called when we are no longer hovering over an element
16714 * @method onDragOut
16715 * @param {Event} e the mousemove event
16716 * @param {String|DragDrop[]} id In POINT mode, the element
16717 * id this was hovering over. In INTERSECT mode, an array of dd items
16718 * that the mouse is no longer over.
16720 onDragOut: function(e, id) { /* override this */ },
16723 * Code that executes immediately before the onDragDrop event
16724 * @method b4DragDrop
16727 b4DragDrop: function(e) { },
16730 * Abstract method called when this item is dropped on another DragDrop
16732 * @method onDragDrop
16733 * @param {Event} e the mouseup event
16734 * @param {String|DragDrop[]} id In POINT mode, the element
16735 * id this was dropped on. In INTERSECT mode, an array of dd items this
16738 onDragDrop: function(e, id) { /* override this */ },
16741 * Abstract method called when this item is dropped on an area with no
16743 * @method onInvalidDrop
16744 * @param {Event} e the mouseup event
16746 onInvalidDrop: function(e) { /* override this */ },
16749 * Code that executes immediately before the endDrag event
16750 * @method b4EndDrag
16753 b4EndDrag: function(e) { },
16756 * Fired when we are done dragging the object
16758 * @param {Event} e the mouseup event
16760 endDrag: function(e) { /* override this */ },
16763 * Code executed immediately before the onMouseDown event
16764 * @method b4MouseDown
16765 * @param {Event} e the mousedown event
16768 b4MouseDown: function(e) { },
16771 * Event handler that fires when a drag/drop obj gets a mousedown
16772 * @method onMouseDown
16773 * @param {Event} e the mousedown event
16775 onMouseDown: function(e) { /* override this */ },
16778 * Event handler that fires when a drag/drop obj gets a mouseup
16779 * @method onMouseUp
16780 * @param {Event} e the mouseup event
16782 onMouseUp: function(e) { /* override this */ },
16785 * Override the onAvailable method to do what is needed after the initial
16786 * position was determined.
16787 * @method onAvailable
16789 onAvailable: function () {
16793 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16796 defaultPadding : {left:0, right:0, top:0, bottom:0},
16799 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16803 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16804 { dragElId: "existingProxyDiv" });
16805 dd.startDrag = function(){
16806 this.constrainTo("parent-id");
16809 * Or you can initalize it using the {@link Roo.Element} object:
16811 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16812 startDrag : function(){
16813 this.constrainTo("parent-id");
16817 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16818 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16819 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16820 * an object containing the sides to pad. For example: {right:10, bottom:10}
16821 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16823 constrainTo : function(constrainTo, pad, inContent){
16824 if(typeof pad == "number"){
16825 pad = {left: pad, right:pad, top:pad, bottom:pad};
16827 pad = pad || this.defaultPadding;
16828 var b = Roo.get(this.getEl()).getBox();
16829 var ce = Roo.get(constrainTo);
16830 var s = ce.getScroll();
16831 var c, cd = ce.dom;
16832 if(cd == document.body){
16833 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16836 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16840 var topSpace = b.y - c.y;
16841 var leftSpace = b.x - c.x;
16843 this.resetConstraints();
16844 this.setXConstraint(leftSpace - (pad.left||0), // left
16845 c.width - leftSpace - b.width - (pad.right||0) //right
16847 this.setYConstraint(topSpace - (pad.top||0), //top
16848 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16853 * Returns a reference to the linked element
16855 * @return {HTMLElement} the html element
16857 getEl: function() {
16858 if (!this._domRef) {
16859 this._domRef = Roo.getDom(this.id);
16862 return this._domRef;
16866 * Returns a reference to the actual element to drag. By default this is
16867 * the same as the html element, but it can be assigned to another
16868 * element. An example of this can be found in Roo.dd.DDProxy
16869 * @method getDragEl
16870 * @return {HTMLElement} the html element
16872 getDragEl: function() {
16873 return Roo.getDom(this.dragElId);
16877 * Sets up the DragDrop object. Must be called in the constructor of any
16878 * Roo.dd.DragDrop subclass
16880 * @param id the id of the linked element
16881 * @param {String} sGroup the group of related items
16882 * @param {object} config configuration attributes
16884 init: function(id, sGroup, config) {
16885 this.initTarget(id, sGroup, config);
16886 if (!Roo.isTouch) {
16887 Event.on(this.id, "mousedown", this.handleMouseDown, this);
16889 Event.on(this.id, "touchstart", this.handleMouseDown, this);
16890 // Event.on(this.id, "selectstart", Event.preventDefault);
16894 * Initializes Targeting functionality only... the object does not
16895 * get a mousedown handler.
16896 * @method initTarget
16897 * @param id the id of the linked element
16898 * @param {String} sGroup the group of related items
16899 * @param {object} config configuration attributes
16901 initTarget: function(id, sGroup, config) {
16903 // configuration attributes
16904 this.config = config || {};
16906 // create a local reference to the drag and drop manager
16907 this.DDM = Roo.dd.DDM;
16908 // initialize the groups array
16911 // assume that we have an element reference instead of an id if the
16912 // parameter is not a string
16913 if (typeof id !== "string") {
16920 // add to an interaction group
16921 this.addToGroup((sGroup) ? sGroup : "default");
16923 // We don't want to register this as the handle with the manager
16924 // so we just set the id rather than calling the setter.
16925 this.handleElId = id;
16927 // the linked element is the element that gets dragged by default
16928 this.setDragElId(id);
16930 // by default, clicked anchors will not start drag operations.
16931 this.invalidHandleTypes = { A: "A" };
16932 this.invalidHandleIds = {};
16933 this.invalidHandleClasses = [];
16935 this.applyConfig();
16937 this.handleOnAvailable();
16941 * Applies the configuration parameters that were passed into the constructor.
16942 * This is supposed to happen at each level through the inheritance chain. So
16943 * a DDProxy implentation will execute apply config on DDProxy, DD, and
16944 * DragDrop in order to get all of the parameters that are available in
16946 * @method applyConfig
16948 applyConfig: function() {
16950 // configurable properties:
16951 // padding, isTarget, maintainOffset, primaryButtonOnly
16952 this.padding = this.config.padding || [0, 0, 0, 0];
16953 this.isTarget = (this.config.isTarget !== false);
16954 this.maintainOffset = (this.config.maintainOffset);
16955 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
16960 * Executed when the linked element is available
16961 * @method handleOnAvailable
16964 handleOnAvailable: function() {
16965 this.available = true;
16966 this.resetConstraints();
16967 this.onAvailable();
16971 * Configures the padding for the target zone in px. Effectively expands
16972 * (or reduces) the virtual object size for targeting calculations.
16973 * Supports css-style shorthand; if only one parameter is passed, all sides
16974 * will have that padding, and if only two are passed, the top and bottom
16975 * will have the first param, the left and right the second.
16976 * @method setPadding
16977 * @param {int} iTop Top pad
16978 * @param {int} iRight Right pad
16979 * @param {int} iBot Bot pad
16980 * @param {int} iLeft Left pad
16982 setPadding: function(iTop, iRight, iBot, iLeft) {
16983 // this.padding = [iLeft, iRight, iTop, iBot];
16984 if (!iRight && 0 !== iRight) {
16985 this.padding = [iTop, iTop, iTop, iTop];
16986 } else if (!iBot && 0 !== iBot) {
16987 this.padding = [iTop, iRight, iTop, iRight];
16989 this.padding = [iTop, iRight, iBot, iLeft];
16994 * Stores the initial placement of the linked element.
16995 * @method setInitialPosition
16996 * @param {int} diffX the X offset, default 0
16997 * @param {int} diffY the Y offset, default 0
16999 setInitPosition: function(diffX, diffY) {
17000 var el = this.getEl();
17002 if (!this.DDM.verifyEl(el)) {
17006 var dx = diffX || 0;
17007 var dy = diffY || 0;
17009 var p = Dom.getXY( el );
17011 this.initPageX = p[0] - dx;
17012 this.initPageY = p[1] - dy;
17014 this.lastPageX = p[0];
17015 this.lastPageY = p[1];
17018 this.setStartPosition(p);
17022 * Sets the start position of the element. This is set when the obj
17023 * is initialized, the reset when a drag is started.
17024 * @method setStartPosition
17025 * @param pos current position (from previous lookup)
17028 setStartPosition: function(pos) {
17029 var p = pos || Dom.getXY( this.getEl() );
17030 this.deltaSetXY = null;
17032 this.startPageX = p[0];
17033 this.startPageY = p[1];
17037 * Add this instance to a group of related drag/drop objects. All
17038 * instances belong to at least one group, and can belong to as many
17039 * groups as needed.
17040 * @method addToGroup
17041 * @param sGroup {string} the name of the group
17043 addToGroup: function(sGroup) {
17044 this.groups[sGroup] = true;
17045 this.DDM.regDragDrop(this, sGroup);
17049 * Remove's this instance from the supplied interaction group
17050 * @method removeFromGroup
17051 * @param {string} sGroup The group to drop
17053 removeFromGroup: function(sGroup) {
17054 if (this.groups[sGroup]) {
17055 delete this.groups[sGroup];
17058 this.DDM.removeDDFromGroup(this, sGroup);
17062 * Allows you to specify that an element other than the linked element
17063 * will be moved with the cursor during a drag
17064 * @method setDragElId
17065 * @param id {string} the id of the element that will be used to initiate the drag
17067 setDragElId: function(id) {
17068 this.dragElId = id;
17072 * Allows you to specify a child of the linked element that should be
17073 * used to initiate the drag operation. An example of this would be if
17074 * you have a content div with text and links. Clicking anywhere in the
17075 * content area would normally start the drag operation. Use this method
17076 * to specify that an element inside of the content div is the element
17077 * that starts the drag operation.
17078 * @method setHandleElId
17079 * @param id {string} the id of the element that will be used to
17080 * initiate the drag.
17082 setHandleElId: function(id) {
17083 if (typeof id !== "string") {
17086 this.handleElId = id;
17087 this.DDM.regHandle(this.id, id);
17091 * Allows you to set an element outside of the linked element as a drag
17093 * @method setOuterHandleElId
17094 * @param id the id of the element that will be used to initiate the drag
17096 setOuterHandleElId: function(id) {
17097 if (typeof id !== "string") {
17100 Event.on(id, "mousedown",
17101 this.handleMouseDown, this);
17102 this.setHandleElId(id);
17104 this.hasOuterHandles = true;
17108 * Remove all drag and drop hooks for this element
17111 unreg: function() {
17112 Event.un(this.id, "mousedown",
17113 this.handleMouseDown);
17114 Event.un(this.id, "touchstart",
17115 this.handleMouseDown);
17116 this._domRef = null;
17117 this.DDM._remove(this);
17120 destroy : function(){
17125 * Returns true if this instance is locked, or the drag drop mgr is locked
17126 * (meaning that all drag/drop is disabled on the page.)
17128 * @return {boolean} true if this obj or all drag/drop is locked, else
17131 isLocked: function() {
17132 return (this.DDM.isLocked() || this.locked);
17136 * Fired when this object is clicked
17137 * @method handleMouseDown
17139 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17142 handleMouseDown: function(e, oDD){
17144 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17145 //Roo.log('not touch/ button !=0');
17148 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17149 return; // double touch..
17153 if (this.isLocked()) {
17154 //Roo.log('locked');
17158 this.DDM.refreshCache(this.groups);
17159 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17160 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17161 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17162 //Roo.log('no outer handes or not over target');
17165 // Roo.log('check validator');
17166 if (this.clickValidator(e)) {
17167 // Roo.log('validate success');
17168 // set the initial element position
17169 this.setStartPosition();
17172 this.b4MouseDown(e);
17173 this.onMouseDown(e);
17175 this.DDM.handleMouseDown(e, this);
17177 this.DDM.stopEvent(e);
17185 clickValidator: function(e) {
17186 var target = e.getTarget();
17187 return ( this.isValidHandleChild(target) &&
17188 (this.id == this.handleElId ||
17189 this.DDM.handleWasClicked(target, this.id)) );
17193 * Allows you to specify a tag name that should not start a drag operation
17194 * when clicked. This is designed to facilitate embedding links within a
17195 * drag handle that do something other than start the drag.
17196 * @method addInvalidHandleType
17197 * @param {string} tagName the type of element to exclude
17199 addInvalidHandleType: function(tagName) {
17200 var type = tagName.toUpperCase();
17201 this.invalidHandleTypes[type] = type;
17205 * Lets you to specify an element id for a child of a drag handle
17206 * that should not initiate a drag
17207 * @method addInvalidHandleId
17208 * @param {string} id the element id of the element you wish to ignore
17210 addInvalidHandleId: function(id) {
17211 if (typeof id !== "string") {
17214 this.invalidHandleIds[id] = id;
17218 * Lets you specify a css class of elements that will not initiate a drag
17219 * @method addInvalidHandleClass
17220 * @param {string} cssClass the class of the elements you wish to ignore
17222 addInvalidHandleClass: function(cssClass) {
17223 this.invalidHandleClasses.push(cssClass);
17227 * Unsets an excluded tag name set by addInvalidHandleType
17228 * @method removeInvalidHandleType
17229 * @param {string} tagName the type of element to unexclude
17231 removeInvalidHandleType: function(tagName) {
17232 var type = tagName.toUpperCase();
17233 // this.invalidHandleTypes[type] = null;
17234 delete this.invalidHandleTypes[type];
17238 * Unsets an invalid handle id
17239 * @method removeInvalidHandleId
17240 * @param {string} id the id of the element to re-enable
17242 removeInvalidHandleId: function(id) {
17243 if (typeof id !== "string") {
17246 delete this.invalidHandleIds[id];
17250 * Unsets an invalid css class
17251 * @method removeInvalidHandleClass
17252 * @param {string} cssClass the class of the element(s) you wish to
17255 removeInvalidHandleClass: function(cssClass) {
17256 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17257 if (this.invalidHandleClasses[i] == cssClass) {
17258 delete this.invalidHandleClasses[i];
17264 * Checks the tag exclusion list to see if this click should be ignored
17265 * @method isValidHandleChild
17266 * @param {HTMLElement} node the HTMLElement to evaluate
17267 * @return {boolean} true if this is a valid tag type, false if not
17269 isValidHandleChild: function(node) {
17272 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17275 nodeName = node.nodeName.toUpperCase();
17277 nodeName = node.nodeName;
17279 valid = valid && !this.invalidHandleTypes[nodeName];
17280 valid = valid && !this.invalidHandleIds[node.id];
17282 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17283 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17292 * Create the array of horizontal tick marks if an interval was specified
17293 * in setXConstraint().
17294 * @method setXTicks
17297 setXTicks: function(iStartX, iTickSize) {
17299 this.xTickSize = iTickSize;
17303 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17305 this.xTicks[this.xTicks.length] = i;
17310 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17312 this.xTicks[this.xTicks.length] = i;
17317 this.xTicks.sort(this.DDM.numericSort) ;
17321 * Create the array of vertical tick marks if an interval was specified in
17322 * setYConstraint().
17323 * @method setYTicks
17326 setYTicks: function(iStartY, iTickSize) {
17328 this.yTickSize = iTickSize;
17332 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17334 this.yTicks[this.yTicks.length] = i;
17339 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17341 this.yTicks[this.yTicks.length] = i;
17346 this.yTicks.sort(this.DDM.numericSort) ;
17350 * By default, the element can be dragged any place on the screen. Use
17351 * this method to limit the horizontal travel of the element. Pass in
17352 * 0,0 for the parameters if you want to lock the drag to the y axis.
17353 * @method setXConstraint
17354 * @param {int} iLeft the number of pixels the element can move to the left
17355 * @param {int} iRight the number of pixels the element can move to the
17357 * @param {int} iTickSize optional parameter for specifying that the
17359 * should move iTickSize pixels at a time.
17361 setXConstraint: function(iLeft, iRight, iTickSize) {
17362 this.leftConstraint = iLeft;
17363 this.rightConstraint = iRight;
17365 this.minX = this.initPageX - iLeft;
17366 this.maxX = this.initPageX + iRight;
17367 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17369 this.constrainX = true;
17373 * Clears any constraints applied to this instance. Also clears ticks
17374 * since they can't exist independent of a constraint at this time.
17375 * @method clearConstraints
17377 clearConstraints: function() {
17378 this.constrainX = false;
17379 this.constrainY = false;
17384 * Clears any tick interval defined for this instance
17385 * @method clearTicks
17387 clearTicks: function() {
17388 this.xTicks = null;
17389 this.yTicks = null;
17390 this.xTickSize = 0;
17391 this.yTickSize = 0;
17395 * By default, the element can be dragged any place on the screen. Set
17396 * this to limit the vertical travel of the element. Pass in 0,0 for the
17397 * parameters if you want to lock the drag to the x axis.
17398 * @method setYConstraint
17399 * @param {int} iUp the number of pixels the element can move up
17400 * @param {int} iDown the number of pixels the element can move down
17401 * @param {int} iTickSize optional parameter for specifying that the
17402 * element should move iTickSize pixels at a time.
17404 setYConstraint: function(iUp, iDown, iTickSize) {
17405 this.topConstraint = iUp;
17406 this.bottomConstraint = iDown;
17408 this.minY = this.initPageY - iUp;
17409 this.maxY = this.initPageY + iDown;
17410 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17412 this.constrainY = true;
17417 * resetConstraints must be called if you manually reposition a dd element.
17418 * @method resetConstraints
17419 * @param {boolean} maintainOffset
17421 resetConstraints: function() {
17424 // Maintain offsets if necessary
17425 if (this.initPageX || this.initPageX === 0) {
17426 // figure out how much this thing has moved
17427 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17428 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17430 this.setInitPosition(dx, dy);
17432 // This is the first time we have detected the element's position
17434 this.setInitPosition();
17437 if (this.constrainX) {
17438 this.setXConstraint( this.leftConstraint,
17439 this.rightConstraint,
17443 if (this.constrainY) {
17444 this.setYConstraint( this.topConstraint,
17445 this.bottomConstraint,
17451 * Normally the drag element is moved pixel by pixel, but we can specify
17452 * that it move a number of pixels at a time. This method resolves the
17453 * location when we have it set up like this.
17455 * @param {int} val where we want to place the object
17456 * @param {int[]} tickArray sorted array of valid points
17457 * @return {int} the closest tick
17460 getTick: function(val, tickArray) {
17463 // If tick interval is not defined, it is effectively 1 pixel,
17464 // so we return the value passed to us.
17466 } else if (tickArray[0] >= val) {
17467 // The value is lower than the first tick, so we return the first
17469 return tickArray[0];
17471 for (var i=0, len=tickArray.length; i<len; ++i) {
17473 if (tickArray[next] && tickArray[next] >= val) {
17474 var diff1 = val - tickArray[i];
17475 var diff2 = tickArray[next] - val;
17476 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17480 // The value is larger than the last tick, so we return the last
17482 return tickArray[tickArray.length - 1];
17489 * @return {string} string representation of the dd obj
17491 toString: function() {
17492 return ("DragDrop " + this.id);
17500 * Ext JS Library 1.1.1
17501 * Copyright(c) 2006-2007, Ext JS, LLC.
17503 * Originally Released Under LGPL - original licence link has changed is not relivant.
17506 * <script type="text/javascript">
17511 * The drag and drop utility provides a framework for building drag and drop
17512 * applications. In addition to enabling drag and drop for specific elements,
17513 * the drag and drop elements are tracked by the manager class, and the
17514 * interactions between the various elements are tracked during the drag and
17515 * the implementing code is notified about these important moments.
17518 // Only load the library once. Rewriting the manager class would orphan
17519 // existing drag and drop instances.
17520 if (!Roo.dd.DragDropMgr) {
17523 * @class Roo.dd.DragDropMgr
17524 * DragDropMgr is a singleton that tracks the element interaction for
17525 * all DragDrop items in the window. Generally, you will not call
17526 * this class directly, but it does have helper methods that could
17527 * be useful in your DragDrop implementations.
17530 Roo.dd.DragDropMgr = function() {
17532 var Event = Roo.EventManager;
17537 * Two dimensional Array of registered DragDrop objects. The first
17538 * dimension is the DragDrop item group, the second the DragDrop
17541 * @type {string: string}
17548 * Array of element ids defined as drag handles. Used to determine
17549 * if the element that generated the mousedown event is actually the
17550 * handle and not the html element itself.
17551 * @property handleIds
17552 * @type {string: string}
17559 * the DragDrop object that is currently being dragged
17560 * @property dragCurrent
17568 * the DragDrop object(s) that are being hovered over
17569 * @property dragOvers
17577 * the X distance between the cursor and the object being dragged
17586 * the Y distance between the cursor and the object being dragged
17595 * Flag to determine if we should prevent the default behavior of the
17596 * events we define. By default this is true, but this can be set to
17597 * false if you need the default behavior (not recommended)
17598 * @property preventDefault
17602 preventDefault: true,
17605 * Flag to determine if we should stop the propagation of the events
17606 * we generate. This is true by default but you may want to set it to
17607 * false if the html element contains other features that require the
17609 * @property stopPropagation
17613 stopPropagation: true,
17616 * Internal flag that is set to true when drag and drop has been
17618 * @property initialized
17625 * All drag and drop can be disabled.
17633 * Called the first time an element is registered.
17639 this.initialized = true;
17643 * In point mode, drag and drop interaction is defined by the
17644 * location of the cursor during the drag/drop
17652 * In intersect mode, drag and drop interactio nis defined by the
17653 * overlap of two or more drag and drop objects.
17654 * @property INTERSECT
17661 * The current drag and drop mode. Default: POINT
17669 * Runs method on all drag and drop objects
17670 * @method _execOnAll
17674 _execOnAll: function(sMethod, args) {
17675 for (var i in this.ids) {
17676 for (var j in this.ids[i]) {
17677 var oDD = this.ids[i][j];
17678 if (! this.isTypeOfDD(oDD)) {
17681 oDD[sMethod].apply(oDD, args);
17687 * Drag and drop initialization. Sets up the global event handlers
17692 _onLoad: function() {
17696 if (!Roo.isTouch) {
17697 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17698 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17700 Event.on(document, "touchend", this.handleMouseUp, this, true);
17701 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17703 Event.on(window, "unload", this._onUnload, this, true);
17704 Event.on(window, "resize", this._onResize, this, true);
17705 // Event.on(window, "mouseout", this._test);
17710 * Reset constraints on all drag and drop objs
17711 * @method _onResize
17715 _onResize: function(e) {
17716 this._execOnAll("resetConstraints", []);
17720 * Lock all drag and drop functionality
17724 lock: function() { this.locked = true; },
17727 * Unlock all drag and drop functionality
17731 unlock: function() { this.locked = false; },
17734 * Is drag and drop locked?
17736 * @return {boolean} True if drag and drop is locked, false otherwise.
17739 isLocked: function() { return this.locked; },
17742 * Location cache that is set for all drag drop objects when a drag is
17743 * initiated, cleared when the drag is finished.
17744 * @property locationCache
17751 * Set useCache to false if you want to force object the lookup of each
17752 * drag and drop linked element constantly during a drag.
17753 * @property useCache
17760 * The number of pixels that the mouse needs to move after the
17761 * mousedown before the drag is initiated. Default=3;
17762 * @property clickPixelThresh
17766 clickPixelThresh: 3,
17769 * The number of milliseconds after the mousedown event to initiate the
17770 * drag if we don't get a mouseup event. Default=1000
17771 * @property clickTimeThresh
17775 clickTimeThresh: 350,
17778 * Flag that indicates that either the drag pixel threshold or the
17779 * mousdown time threshold has been met
17780 * @property dragThreshMet
17785 dragThreshMet: false,
17788 * Timeout used for the click time threshold
17789 * @property clickTimeout
17794 clickTimeout: null,
17797 * The X position of the mousedown event stored for later use when a
17798 * drag threshold is met.
17807 * The Y position of the mousedown event stored for later use when a
17808 * drag threshold is met.
17817 * Each DragDrop instance must be registered with the DragDropMgr.
17818 * This is executed in DragDrop.init()
17819 * @method regDragDrop
17820 * @param {DragDrop} oDD the DragDrop object to register
17821 * @param {String} sGroup the name of the group this element belongs to
17824 regDragDrop: function(oDD, sGroup) {
17825 if (!this.initialized) { this.init(); }
17827 if (!this.ids[sGroup]) {
17828 this.ids[sGroup] = {};
17830 this.ids[sGroup][oDD.id] = oDD;
17834 * Removes the supplied dd instance from the supplied group. Executed
17835 * by DragDrop.removeFromGroup, so don't call this function directly.
17836 * @method removeDDFromGroup
17840 removeDDFromGroup: function(oDD, sGroup) {
17841 if (!this.ids[sGroup]) {
17842 this.ids[sGroup] = {};
17845 var obj = this.ids[sGroup];
17846 if (obj && obj[oDD.id]) {
17847 delete obj[oDD.id];
17852 * Unregisters a drag and drop item. This is executed in
17853 * DragDrop.unreg, use that method instead of calling this directly.
17858 _remove: function(oDD) {
17859 for (var g in oDD.groups) {
17860 if (g && this.ids[g][oDD.id]) {
17861 delete this.ids[g][oDD.id];
17864 delete this.handleIds[oDD.id];
17868 * Each DragDrop handle element must be registered. This is done
17869 * automatically when executing DragDrop.setHandleElId()
17870 * @method regHandle
17871 * @param {String} sDDId the DragDrop id this element is a handle for
17872 * @param {String} sHandleId the id of the element that is the drag
17876 regHandle: function(sDDId, sHandleId) {
17877 if (!this.handleIds[sDDId]) {
17878 this.handleIds[sDDId] = {};
17880 this.handleIds[sDDId][sHandleId] = sHandleId;
17884 * Utility function to determine if a given element has been
17885 * registered as a drag drop item.
17886 * @method isDragDrop
17887 * @param {String} id the element id to check
17888 * @return {boolean} true if this element is a DragDrop item,
17892 isDragDrop: function(id) {
17893 return ( this.getDDById(id) ) ? true : false;
17897 * Returns the drag and drop instances that are in all groups the
17898 * passed in instance belongs to.
17899 * @method getRelated
17900 * @param {DragDrop} p_oDD the obj to get related data for
17901 * @param {boolean} bTargetsOnly if true, only return targetable objs
17902 * @return {DragDrop[]} the related instances
17905 getRelated: function(p_oDD, bTargetsOnly) {
17907 for (var i in p_oDD.groups) {
17908 for (j in this.ids[i]) {
17909 var dd = this.ids[i][j];
17910 if (! this.isTypeOfDD(dd)) {
17913 if (!bTargetsOnly || dd.isTarget) {
17914 oDDs[oDDs.length] = dd;
17923 * Returns true if the specified dd target is a legal target for
17924 * the specifice drag obj
17925 * @method isLegalTarget
17926 * @param {DragDrop} the drag obj
17927 * @param {DragDrop} the target
17928 * @return {boolean} true if the target is a legal target for the
17932 isLegalTarget: function (oDD, oTargetDD) {
17933 var targets = this.getRelated(oDD, true);
17934 for (var i=0, len=targets.length;i<len;++i) {
17935 if (targets[i].id == oTargetDD.id) {
17944 * My goal is to be able to transparently determine if an object is
17945 * typeof DragDrop, and the exact subclass of DragDrop. typeof
17946 * returns "object", oDD.constructor.toString() always returns
17947 * "DragDrop" and not the name of the subclass. So for now it just
17948 * evaluates a well-known variable in DragDrop.
17949 * @method isTypeOfDD
17950 * @param {Object} the object to evaluate
17951 * @return {boolean} true if typeof oDD = DragDrop
17954 isTypeOfDD: function (oDD) {
17955 return (oDD && oDD.__ygDragDrop);
17959 * Utility function to determine if a given element has been
17960 * registered as a drag drop handle for the given Drag Drop object.
17962 * @param {String} id the element id to check
17963 * @return {boolean} true if this element is a DragDrop handle, false
17967 isHandle: function(sDDId, sHandleId) {
17968 return ( this.handleIds[sDDId] &&
17969 this.handleIds[sDDId][sHandleId] );
17973 * Returns the DragDrop instance for a given id
17974 * @method getDDById
17975 * @param {String} id the id of the DragDrop object
17976 * @return {DragDrop} the drag drop object, null if it is not found
17979 getDDById: function(id) {
17980 for (var i in this.ids) {
17981 if (this.ids[i][id]) {
17982 return this.ids[i][id];
17989 * Fired after a registered DragDrop object gets the mousedown event.
17990 * Sets up the events required to track the object being dragged
17991 * @method handleMouseDown
17992 * @param {Event} e the event
17993 * @param oDD the DragDrop object being dragged
17997 handleMouseDown: function(e, oDD) {
17999 Roo.QuickTips.disable();
18001 this.currentTarget = e.getTarget();
18003 this.dragCurrent = oDD;
18005 var el = oDD.getEl();
18007 // track start position
18008 this.startX = e.getPageX();
18009 this.startY = e.getPageY();
18011 this.deltaX = this.startX - el.offsetLeft;
18012 this.deltaY = this.startY - el.offsetTop;
18014 this.dragThreshMet = false;
18016 this.clickTimeout = setTimeout(
18018 var DDM = Roo.dd.DDM;
18019 DDM.startDrag(DDM.startX, DDM.startY);
18021 this.clickTimeThresh );
18025 * Fired when either the drag pixel threshol or the mousedown hold
18026 * time threshold has been met.
18027 * @method startDrag
18028 * @param x {int} the X position of the original mousedown
18029 * @param y {int} the Y position of the original mousedown
18032 startDrag: function(x, y) {
18033 clearTimeout(this.clickTimeout);
18034 if (this.dragCurrent) {
18035 this.dragCurrent.b4StartDrag(x, y);
18036 this.dragCurrent.startDrag(x, y);
18038 this.dragThreshMet = true;
18042 * Internal function to handle the mouseup event. Will be invoked
18043 * from the context of the document.
18044 * @method handleMouseUp
18045 * @param {Event} e the event
18049 handleMouseUp: function(e) {
18052 Roo.QuickTips.enable();
18054 if (! this.dragCurrent) {
18058 clearTimeout(this.clickTimeout);
18060 if (this.dragThreshMet) {
18061 this.fireEvents(e, true);
18071 * Utility to stop event propagation and event default, if these
18072 * features are turned on.
18073 * @method stopEvent
18074 * @param {Event} e the event as returned by this.getEvent()
18077 stopEvent: function(e){
18078 if(this.stopPropagation) {
18079 e.stopPropagation();
18082 if (this.preventDefault) {
18083 e.preventDefault();
18088 * Internal function to clean up event handlers after the drag
18089 * operation is complete
18091 * @param {Event} e the event
18095 stopDrag: function(e) {
18096 // Fire the drag end event for the item that was dragged
18097 if (this.dragCurrent) {
18098 if (this.dragThreshMet) {
18099 this.dragCurrent.b4EndDrag(e);
18100 this.dragCurrent.endDrag(e);
18103 this.dragCurrent.onMouseUp(e);
18106 this.dragCurrent = null;
18107 this.dragOvers = {};
18111 * Internal function to handle the mousemove event. Will be invoked
18112 * from the context of the html element.
18114 * @TODO figure out what we can do about mouse events lost when the
18115 * user drags objects beyond the window boundary. Currently we can
18116 * detect this in internet explorer by verifying that the mouse is
18117 * down during the mousemove event. Firefox doesn't give us the
18118 * button state on the mousemove event.
18119 * @method handleMouseMove
18120 * @param {Event} e the event
18124 handleMouseMove: function(e) {
18125 if (! this.dragCurrent) {
18129 // var button = e.which || e.button;
18131 // check for IE mouseup outside of page boundary
18132 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18134 return this.handleMouseUp(e);
18137 if (!this.dragThreshMet) {
18138 var diffX = Math.abs(this.startX - e.getPageX());
18139 var diffY = Math.abs(this.startY - e.getPageY());
18140 if (diffX > this.clickPixelThresh ||
18141 diffY > this.clickPixelThresh) {
18142 this.startDrag(this.startX, this.startY);
18146 if (this.dragThreshMet) {
18147 this.dragCurrent.b4Drag(e);
18148 this.dragCurrent.onDrag(e);
18149 if(!this.dragCurrent.moveOnly){
18150 this.fireEvents(e, false);
18160 * Iterates over all of the DragDrop elements to find ones we are
18161 * hovering over or dropping on
18162 * @method fireEvents
18163 * @param {Event} e the event
18164 * @param {boolean} isDrop is this a drop op or a mouseover op?
18168 fireEvents: function(e, isDrop) {
18169 var dc = this.dragCurrent;
18171 // If the user did the mouse up outside of the window, we could
18172 // get here even though we have ended the drag.
18173 if (!dc || dc.isLocked()) {
18177 var pt = e.getPoint();
18179 // cache the previous dragOver array
18185 var enterEvts = [];
18187 // Check to see if the object(s) we were hovering over is no longer
18188 // being hovered over so we can fire the onDragOut event
18189 for (var i in this.dragOvers) {
18191 var ddo = this.dragOvers[i];
18193 if (! this.isTypeOfDD(ddo)) {
18197 if (! this.isOverTarget(pt, ddo, this.mode)) {
18198 outEvts.push( ddo );
18201 oldOvers[i] = true;
18202 delete this.dragOvers[i];
18205 for (var sGroup in dc.groups) {
18207 if ("string" != typeof sGroup) {
18211 for (i in this.ids[sGroup]) {
18212 var oDD = this.ids[sGroup][i];
18213 if (! this.isTypeOfDD(oDD)) {
18217 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18218 if (this.isOverTarget(pt, oDD, this.mode)) {
18219 // look for drop interactions
18221 dropEvts.push( oDD );
18222 // look for drag enter and drag over interactions
18225 // initial drag over: dragEnter fires
18226 if (!oldOvers[oDD.id]) {
18227 enterEvts.push( oDD );
18228 // subsequent drag overs: dragOver fires
18230 overEvts.push( oDD );
18233 this.dragOvers[oDD.id] = oDD;
18241 if (outEvts.length) {
18242 dc.b4DragOut(e, outEvts);
18243 dc.onDragOut(e, outEvts);
18246 if (enterEvts.length) {
18247 dc.onDragEnter(e, enterEvts);
18250 if (overEvts.length) {
18251 dc.b4DragOver(e, overEvts);
18252 dc.onDragOver(e, overEvts);
18255 if (dropEvts.length) {
18256 dc.b4DragDrop(e, dropEvts);
18257 dc.onDragDrop(e, dropEvts);
18261 // fire dragout events
18263 for (i=0, len=outEvts.length; i<len; ++i) {
18264 dc.b4DragOut(e, outEvts[i].id);
18265 dc.onDragOut(e, outEvts[i].id);
18268 // fire enter events
18269 for (i=0,len=enterEvts.length; i<len; ++i) {
18270 // dc.b4DragEnter(e, oDD.id);
18271 dc.onDragEnter(e, enterEvts[i].id);
18274 // fire over events
18275 for (i=0,len=overEvts.length; i<len; ++i) {
18276 dc.b4DragOver(e, overEvts[i].id);
18277 dc.onDragOver(e, overEvts[i].id);
18280 // fire drop events
18281 for (i=0, len=dropEvts.length; i<len; ++i) {
18282 dc.b4DragDrop(e, dropEvts[i].id);
18283 dc.onDragDrop(e, dropEvts[i].id);
18288 // notify about a drop that did not find a target
18289 if (isDrop && !dropEvts.length) {
18290 dc.onInvalidDrop(e);
18296 * Helper function for getting the best match from the list of drag
18297 * and drop objects returned by the drag and drop events when we are
18298 * in INTERSECT mode. It returns either the first object that the
18299 * cursor is over, or the object that has the greatest overlap with
18300 * the dragged element.
18301 * @method getBestMatch
18302 * @param {DragDrop[]} dds The array of drag and drop objects
18304 * @return {DragDrop} The best single match
18307 getBestMatch: function(dds) {
18309 // Return null if the input is not what we expect
18310 //if (!dds || !dds.length || dds.length == 0) {
18312 // If there is only one item, it wins
18313 //} else if (dds.length == 1) {
18315 var len = dds.length;
18320 // Loop through the targeted items
18321 for (var i=0; i<len; ++i) {
18323 // If the cursor is over the object, it wins. If the
18324 // cursor is over multiple matches, the first one we come
18326 if (dd.cursorIsOver) {
18329 // Otherwise the object with the most overlap wins
18332 winner.overlap.getArea() < dd.overlap.getArea()) {
18343 * Refreshes the cache of the top-left and bottom-right points of the
18344 * drag and drop objects in the specified group(s). This is in the
18345 * format that is stored in the drag and drop instance, so typical
18348 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18352 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18354 * @TODO this really should be an indexed array. Alternatively this
18355 * method could accept both.
18356 * @method refreshCache
18357 * @param {Object} groups an associative array of groups to refresh
18360 refreshCache: function(groups) {
18361 for (var sGroup in groups) {
18362 if ("string" != typeof sGroup) {
18365 for (var i in this.ids[sGroup]) {
18366 var oDD = this.ids[sGroup][i];
18368 if (this.isTypeOfDD(oDD)) {
18369 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18370 var loc = this.getLocation(oDD);
18372 this.locationCache[oDD.id] = loc;
18374 delete this.locationCache[oDD.id];
18375 // this will unregister the drag and drop object if
18376 // the element is not in a usable state
18385 * This checks to make sure an element exists and is in the DOM. The
18386 * main purpose is to handle cases where innerHTML is used to remove
18387 * drag and drop objects from the DOM. IE provides an 'unspecified
18388 * error' when trying to access the offsetParent of such an element
18390 * @param {HTMLElement} el the element to check
18391 * @return {boolean} true if the element looks usable
18394 verifyEl: function(el) {
18399 parent = el.offsetParent;
18402 parent = el.offsetParent;
18413 * Returns a Region object containing the drag and drop element's position
18414 * and size, including the padding configured for it
18415 * @method getLocation
18416 * @param {DragDrop} oDD the drag and drop object to get the
18418 * @return {Roo.lib.Region} a Region object representing the total area
18419 * the element occupies, including any padding
18420 * the instance is configured for.
18423 getLocation: function(oDD) {
18424 if (! this.isTypeOfDD(oDD)) {
18428 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18431 pos= Roo.lib.Dom.getXY(el);
18439 x2 = x1 + el.offsetWidth;
18441 y2 = y1 + el.offsetHeight;
18443 t = y1 - oDD.padding[0];
18444 r = x2 + oDD.padding[1];
18445 b = y2 + oDD.padding[2];
18446 l = x1 - oDD.padding[3];
18448 return new Roo.lib.Region( t, r, b, l );
18452 * Checks the cursor location to see if it over the target
18453 * @method isOverTarget
18454 * @param {Roo.lib.Point} pt The point to evaluate
18455 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18456 * @return {boolean} true if the mouse is over the target
18460 isOverTarget: function(pt, oTarget, intersect) {
18461 // use cache if available
18462 var loc = this.locationCache[oTarget.id];
18463 if (!loc || !this.useCache) {
18464 loc = this.getLocation(oTarget);
18465 this.locationCache[oTarget.id] = loc;
18473 oTarget.cursorIsOver = loc.contains( pt );
18475 // DragDrop is using this as a sanity check for the initial mousedown
18476 // in this case we are done. In POINT mode, if the drag obj has no
18477 // contraints, we are also done. Otherwise we need to evaluate the
18478 // location of the target as related to the actual location of the
18479 // dragged element.
18480 var dc = this.dragCurrent;
18481 if (!dc || !dc.getTargetCoord ||
18482 (!intersect && !dc.constrainX && !dc.constrainY)) {
18483 return oTarget.cursorIsOver;
18486 oTarget.overlap = null;
18488 // Get the current location of the drag element, this is the
18489 // location of the mouse event less the delta that represents
18490 // where the original mousedown happened on the element. We
18491 // need to consider constraints and ticks as well.
18492 var pos = dc.getTargetCoord(pt.x, pt.y);
18494 var el = dc.getDragEl();
18495 var curRegion = new Roo.lib.Region( pos.y,
18496 pos.x + el.offsetWidth,
18497 pos.y + el.offsetHeight,
18500 var overlap = curRegion.intersect(loc);
18503 oTarget.overlap = overlap;
18504 return (intersect) ? true : oTarget.cursorIsOver;
18511 * unload event handler
18512 * @method _onUnload
18516 _onUnload: function(e, me) {
18517 Roo.dd.DragDropMgr.unregAll();
18521 * Cleans up the drag and drop events and objects.
18526 unregAll: function() {
18528 if (this.dragCurrent) {
18530 this.dragCurrent = null;
18533 this._execOnAll("unreg", []);
18535 for (i in this.elementCache) {
18536 delete this.elementCache[i];
18539 this.elementCache = {};
18544 * A cache of DOM elements
18545 * @property elementCache
18552 * Get the wrapper for the DOM element specified
18553 * @method getElWrapper
18554 * @param {String} id the id of the element to get
18555 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18557 * @deprecated This wrapper isn't that useful
18560 getElWrapper: function(id) {
18561 var oWrapper = this.elementCache[id];
18562 if (!oWrapper || !oWrapper.el) {
18563 oWrapper = this.elementCache[id] =
18564 new this.ElementWrapper(Roo.getDom(id));
18570 * Returns the actual DOM element
18571 * @method getElement
18572 * @param {String} id the id of the elment to get
18573 * @return {Object} The element
18574 * @deprecated use Roo.getDom instead
18577 getElement: function(id) {
18578 return Roo.getDom(id);
18582 * Returns the style property for the DOM element (i.e.,
18583 * document.getElById(id).style)
18585 * @param {String} id the id of the elment to get
18586 * @return {Object} The style property of the element
18587 * @deprecated use Roo.getDom instead
18590 getCss: function(id) {
18591 var el = Roo.getDom(id);
18592 return (el) ? el.style : null;
18596 * Inner class for cached elements
18597 * @class DragDropMgr.ElementWrapper
18602 ElementWrapper: function(el) {
18607 this.el = el || null;
18612 this.id = this.el && el.id;
18614 * A reference to the style property
18617 this.css = this.el && el.style;
18621 * Returns the X position of an html element
18623 * @param el the element for which to get the position
18624 * @return {int} the X coordinate
18626 * @deprecated use Roo.lib.Dom.getX instead
18629 getPosX: function(el) {
18630 return Roo.lib.Dom.getX(el);
18634 * Returns the Y position of an html element
18636 * @param el the element for which to get the position
18637 * @return {int} the Y coordinate
18638 * @deprecated use Roo.lib.Dom.getY instead
18641 getPosY: function(el) {
18642 return Roo.lib.Dom.getY(el);
18646 * Swap two nodes. In IE, we use the native method, for others we
18647 * emulate the IE behavior
18649 * @param n1 the first node to swap
18650 * @param n2 the other node to swap
18653 swapNode: function(n1, n2) {
18657 var p = n2.parentNode;
18658 var s = n2.nextSibling;
18661 p.insertBefore(n1, n2);
18662 } else if (n2 == n1.nextSibling) {
18663 p.insertBefore(n2, n1);
18665 n1.parentNode.replaceChild(n2, n1);
18666 p.insertBefore(n1, s);
18672 * Returns the current scroll position
18673 * @method getScroll
18677 getScroll: function () {
18678 var t, l, dde=document.documentElement, db=document.body;
18679 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18681 l = dde.scrollLeft;
18688 return { top: t, left: l };
18692 * Returns the specified element style property
18694 * @param {HTMLElement} el the element
18695 * @param {string} styleProp the style property
18696 * @return {string} The value of the style property
18697 * @deprecated use Roo.lib.Dom.getStyle
18700 getStyle: function(el, styleProp) {
18701 return Roo.fly(el).getStyle(styleProp);
18705 * Gets the scrollTop
18706 * @method getScrollTop
18707 * @return {int} the document's scrollTop
18710 getScrollTop: function () { return this.getScroll().top; },
18713 * Gets the scrollLeft
18714 * @method getScrollLeft
18715 * @return {int} the document's scrollTop
18718 getScrollLeft: function () { return this.getScroll().left; },
18721 * Sets the x/y position of an element to the location of the
18724 * @param {HTMLElement} moveEl The element to move
18725 * @param {HTMLElement} targetEl The position reference element
18728 moveToEl: function (moveEl, targetEl) {
18729 var aCoord = Roo.lib.Dom.getXY(targetEl);
18730 Roo.lib.Dom.setXY(moveEl, aCoord);
18734 * Numeric array sort function
18735 * @method numericSort
18738 numericSort: function(a, b) { return (a - b); },
18742 * @property _timeoutCount
18749 * Trying to make the load order less important. Without this we get
18750 * an error if this file is loaded before the Event Utility.
18751 * @method _addListeners
18755 _addListeners: function() {
18756 var DDM = Roo.dd.DDM;
18757 if ( Roo.lib.Event && document ) {
18760 if (DDM._timeoutCount > 2000) {
18762 setTimeout(DDM._addListeners, 10);
18763 if (document && document.body) {
18764 DDM._timeoutCount += 1;
18771 * Recursively searches the immediate parent and all child nodes for
18772 * the handle element in order to determine wheter or not it was
18774 * @method handleWasClicked
18775 * @param node the html element to inspect
18778 handleWasClicked: function(node, id) {
18779 if (this.isHandle(id, node.id)) {
18782 // check to see if this is a text node child of the one we want
18783 var p = node.parentNode;
18786 if (this.isHandle(id, p.id)) {
18801 // shorter alias, save a few bytes
18802 Roo.dd.DDM = Roo.dd.DragDropMgr;
18803 Roo.dd.DDM._addListeners();
18807 * Ext JS Library 1.1.1
18808 * Copyright(c) 2006-2007, Ext JS, LLC.
18810 * Originally Released Under LGPL - original licence link has changed is not relivant.
18813 * <script type="text/javascript">
18818 * A DragDrop implementation where the linked element follows the
18819 * mouse cursor during a drag.
18820 * @extends Roo.dd.DragDrop
18822 * @param {String} id the id of the linked element
18823 * @param {String} sGroup the group of related DragDrop items
18824 * @param {object} config an object containing configurable attributes
18825 * Valid properties for DD:
18828 Roo.dd.DD = function(id, sGroup, config) {
18830 this.init(id, sGroup, config);
18834 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18837 * When set to true, the utility automatically tries to scroll the browser
18838 * window wehn a drag and drop element is dragged near the viewport boundary.
18839 * Defaults to true.
18846 * Sets the pointer offset to the distance between the linked element's top
18847 * left corner and the location the element was clicked
18848 * @method autoOffset
18849 * @param {int} iPageX the X coordinate of the click
18850 * @param {int} iPageY the Y coordinate of the click
18852 autoOffset: function(iPageX, iPageY) {
18853 var x = iPageX - this.startPageX;
18854 var y = iPageY - this.startPageY;
18855 this.setDelta(x, y);
18859 * Sets the pointer offset. You can call this directly to force the
18860 * offset to be in a particular location (e.g., pass in 0,0 to set it
18861 * to the center of the object)
18863 * @param {int} iDeltaX the distance from the left
18864 * @param {int} iDeltaY the distance from the top
18866 setDelta: function(iDeltaX, iDeltaY) {
18867 this.deltaX = iDeltaX;
18868 this.deltaY = iDeltaY;
18872 * Sets the drag element to the location of the mousedown or click event,
18873 * maintaining the cursor location relative to the location on the element
18874 * that was clicked. Override this if you want to place the element in a
18875 * location other than where the cursor is.
18876 * @method setDragElPos
18877 * @param {int} iPageX the X coordinate of the mousedown or drag event
18878 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18880 setDragElPos: function(iPageX, iPageY) {
18881 // the first time we do this, we are going to check to make sure
18882 // the element has css positioning
18884 var el = this.getDragEl();
18885 this.alignElWithMouse(el, iPageX, iPageY);
18889 * Sets the element to the location of the mousedown or click event,
18890 * maintaining the cursor location relative to the location on the element
18891 * that was clicked. Override this if you want to place the element in a
18892 * location other than where the cursor is.
18893 * @method alignElWithMouse
18894 * @param {HTMLElement} el the element to move
18895 * @param {int} iPageX the X coordinate of the mousedown or drag event
18896 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18898 alignElWithMouse: function(el, iPageX, iPageY) {
18899 var oCoord = this.getTargetCoord(iPageX, iPageY);
18900 var fly = el.dom ? el : Roo.fly(el);
18901 if (!this.deltaSetXY) {
18902 var aCoord = [oCoord.x, oCoord.y];
18904 var newLeft = fly.getLeft(true);
18905 var newTop = fly.getTop(true);
18906 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
18908 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
18911 this.cachePosition(oCoord.x, oCoord.y);
18912 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
18917 * Saves the most recent position so that we can reset the constraints and
18918 * tick marks on-demand. We need to know this so that we can calculate the
18919 * number of pixels the element is offset from its original position.
18920 * @method cachePosition
18921 * @param iPageX the current x position (optional, this just makes it so we
18922 * don't have to look it up again)
18923 * @param iPageY the current y position (optional, this just makes it so we
18924 * don't have to look it up again)
18926 cachePosition: function(iPageX, iPageY) {
18928 this.lastPageX = iPageX;
18929 this.lastPageY = iPageY;
18931 var aCoord = Roo.lib.Dom.getXY(this.getEl());
18932 this.lastPageX = aCoord[0];
18933 this.lastPageY = aCoord[1];
18938 * Auto-scroll the window if the dragged object has been moved beyond the
18939 * visible window boundary.
18940 * @method autoScroll
18941 * @param {int} x the drag element's x position
18942 * @param {int} y the drag element's y position
18943 * @param {int} h the height of the drag element
18944 * @param {int} w the width of the drag element
18947 autoScroll: function(x, y, h, w) {
18950 // The client height
18951 var clientH = Roo.lib.Dom.getViewWidth();
18953 // The client width
18954 var clientW = Roo.lib.Dom.getViewHeight();
18956 // The amt scrolled down
18957 var st = this.DDM.getScrollTop();
18959 // The amt scrolled right
18960 var sl = this.DDM.getScrollLeft();
18962 // Location of the bottom of the element
18965 // Location of the right of the element
18968 // The distance from the cursor to the bottom of the visible area,
18969 // adjusted so that we don't scroll if the cursor is beyond the
18970 // element drag constraints
18971 var toBot = (clientH + st - y - this.deltaY);
18973 // The distance from the cursor to the right of the visible area
18974 var toRight = (clientW + sl - x - this.deltaX);
18977 // How close to the edge the cursor must be before we scroll
18978 // var thresh = (document.all) ? 100 : 40;
18981 // How many pixels to scroll per autoscroll op. This helps to reduce
18982 // clunky scrolling. IE is more sensitive about this ... it needs this
18983 // value to be higher.
18984 var scrAmt = (document.all) ? 80 : 30;
18986 // Scroll down if we are near the bottom of the visible page and the
18987 // obj extends below the crease
18988 if ( bot > clientH && toBot < thresh ) {
18989 window.scrollTo(sl, st + scrAmt);
18992 // Scroll up if the window is scrolled down and the top of the object
18993 // goes above the top border
18994 if ( y < st && st > 0 && y - st < thresh ) {
18995 window.scrollTo(sl, st - scrAmt);
18998 // Scroll right if the obj is beyond the right border and the cursor is
18999 // near the border.
19000 if ( right > clientW && toRight < thresh ) {
19001 window.scrollTo(sl + scrAmt, st);
19004 // Scroll left if the window has been scrolled to the right and the obj
19005 // extends past the left border
19006 if ( x < sl && sl > 0 && x - sl < thresh ) {
19007 window.scrollTo(sl - scrAmt, st);
19013 * Finds the location the element should be placed if we want to move
19014 * it to where the mouse location less the click offset would place us.
19015 * @method getTargetCoord
19016 * @param {int} iPageX the X coordinate of the click
19017 * @param {int} iPageY the Y coordinate of the click
19018 * @return an object that contains the coordinates (Object.x and Object.y)
19021 getTargetCoord: function(iPageX, iPageY) {
19024 var x = iPageX - this.deltaX;
19025 var y = iPageY - this.deltaY;
19027 if (this.constrainX) {
19028 if (x < this.minX) { x = this.minX; }
19029 if (x > this.maxX) { x = this.maxX; }
19032 if (this.constrainY) {
19033 if (y < this.minY) { y = this.minY; }
19034 if (y > this.maxY) { y = this.maxY; }
19037 x = this.getTick(x, this.xTicks);
19038 y = this.getTick(y, this.yTicks);
19045 * Sets up config options specific to this class. Overrides
19046 * Roo.dd.DragDrop, but all versions of this method through the
19047 * inheritance chain are called
19049 applyConfig: function() {
19050 Roo.dd.DD.superclass.applyConfig.call(this);
19051 this.scroll = (this.config.scroll !== false);
19055 * Event that fires prior to the onMouseDown event. Overrides
19058 b4MouseDown: function(e) {
19059 // this.resetConstraints();
19060 this.autoOffset(e.getPageX(),
19065 * Event that fires prior to the onDrag event. Overrides
19068 b4Drag: function(e) {
19069 this.setDragElPos(e.getPageX(),
19073 toString: function() {
19074 return ("DD " + this.id);
19077 //////////////////////////////////////////////////////////////////////////
19078 // Debugging ygDragDrop events that can be overridden
19079 //////////////////////////////////////////////////////////////////////////
19081 startDrag: function(x, y) {
19084 onDrag: function(e) {
19087 onDragEnter: function(e, id) {
19090 onDragOver: function(e, id) {
19093 onDragOut: function(e, id) {
19096 onDragDrop: function(e, id) {
19099 endDrag: function(e) {
19106 * Ext JS Library 1.1.1
19107 * Copyright(c) 2006-2007, Ext JS, LLC.
19109 * Originally Released Under LGPL - original licence link has changed is not relivant.
19112 * <script type="text/javascript">
19116 * @class Roo.dd.DDProxy
19117 * A DragDrop implementation that inserts an empty, bordered div into
19118 * the document that follows the cursor during drag operations. At the time of
19119 * the click, the frame div is resized to the dimensions of the linked html
19120 * element, and moved to the exact location of the linked element.
19122 * References to the "frame" element refer to the single proxy element that
19123 * was created to be dragged in place of all DDProxy elements on the
19126 * @extends Roo.dd.DD
19128 * @param {String} id the id of the linked html element
19129 * @param {String} sGroup the group of related DragDrop objects
19130 * @param {object} config an object containing configurable attributes
19131 * Valid properties for DDProxy in addition to those in DragDrop:
19132 * resizeFrame, centerFrame, dragElId
19134 Roo.dd.DDProxy = function(id, sGroup, config) {
19136 this.init(id, sGroup, config);
19142 * The default drag frame div id
19143 * @property Roo.dd.DDProxy.dragElId
19147 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19149 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19152 * By default we resize the drag frame to be the same size as the element
19153 * we want to drag (this is to get the frame effect). We can turn it off
19154 * if we want a different behavior.
19155 * @property resizeFrame
19161 * By default the frame is positioned exactly where the drag element is, so
19162 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19163 * you do not have constraints on the obj is to have the drag frame centered
19164 * around the cursor. Set centerFrame to true for this effect.
19165 * @property centerFrame
19168 centerFrame: false,
19171 * Creates the proxy element if it does not yet exist
19172 * @method createFrame
19174 createFrame: function() {
19176 var body = document.body;
19178 if (!body || !body.firstChild) {
19179 setTimeout( function() { self.createFrame(); }, 50 );
19183 var div = this.getDragEl();
19186 div = document.createElement("div");
19187 div.id = this.dragElId;
19190 s.position = "absolute";
19191 s.visibility = "hidden";
19193 s.border = "2px solid #aaa";
19196 // appendChild can blow up IE if invoked prior to the window load event
19197 // while rendering a table. It is possible there are other scenarios
19198 // that would cause this to happen as well.
19199 body.insertBefore(div, body.firstChild);
19204 * Initialization for the drag frame element. Must be called in the
19205 * constructor of all subclasses
19206 * @method initFrame
19208 initFrame: function() {
19209 this.createFrame();
19212 applyConfig: function() {
19213 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19215 this.resizeFrame = (this.config.resizeFrame !== false);
19216 this.centerFrame = (this.config.centerFrame);
19217 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19221 * Resizes the drag frame to the dimensions of the clicked object, positions
19222 * it over the object, and finally displays it
19223 * @method showFrame
19224 * @param {int} iPageX X click position
19225 * @param {int} iPageY Y click position
19228 showFrame: function(iPageX, iPageY) {
19229 var el = this.getEl();
19230 var dragEl = this.getDragEl();
19231 var s = dragEl.style;
19233 this._resizeProxy();
19235 if (this.centerFrame) {
19236 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19237 Math.round(parseInt(s.height, 10)/2) );
19240 this.setDragElPos(iPageX, iPageY);
19242 Roo.fly(dragEl).show();
19246 * The proxy is automatically resized to the dimensions of the linked
19247 * element when a drag is initiated, unless resizeFrame is set to false
19248 * @method _resizeProxy
19251 _resizeProxy: function() {
19252 if (this.resizeFrame) {
19253 var el = this.getEl();
19254 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19258 // overrides Roo.dd.DragDrop
19259 b4MouseDown: function(e) {
19260 var x = e.getPageX();
19261 var y = e.getPageY();
19262 this.autoOffset(x, y);
19263 this.setDragElPos(x, y);
19266 // overrides Roo.dd.DragDrop
19267 b4StartDrag: function(x, y) {
19268 // show the drag frame
19269 this.showFrame(x, y);
19272 // overrides Roo.dd.DragDrop
19273 b4EndDrag: function(e) {
19274 Roo.fly(this.getDragEl()).hide();
19277 // overrides Roo.dd.DragDrop
19278 // By default we try to move the element to the last location of the frame.
19279 // This is so that the default behavior mirrors that of Roo.dd.DD.
19280 endDrag: function(e) {
19282 var lel = this.getEl();
19283 var del = this.getDragEl();
19285 // Show the drag frame briefly so we can get its position
19286 del.style.visibility = "";
19289 // Hide the linked element before the move to get around a Safari
19291 lel.style.visibility = "hidden";
19292 Roo.dd.DDM.moveToEl(lel, del);
19293 del.style.visibility = "hidden";
19294 lel.style.visibility = "";
19299 beforeMove : function(){
19303 afterDrag : function(){
19307 toString: function() {
19308 return ("DDProxy " + this.id);
19314 * Ext JS Library 1.1.1
19315 * Copyright(c) 2006-2007, Ext JS, LLC.
19317 * Originally Released Under LGPL - original licence link has changed is not relivant.
19320 * <script type="text/javascript">
19324 * @class Roo.dd.DDTarget
19325 * A DragDrop implementation that does not move, but can be a drop
19326 * target. You would get the same result by simply omitting implementation
19327 * for the event callbacks, but this way we reduce the processing cost of the
19328 * event listener and the callbacks.
19329 * @extends Roo.dd.DragDrop
19331 * @param {String} id the id of the element that is a drop target
19332 * @param {String} sGroup the group of related DragDrop objects
19333 * @param {object} config an object containing configurable attributes
19334 * Valid properties for DDTarget in addition to those in
19338 Roo.dd.DDTarget = function(id, sGroup, config) {
19340 this.initTarget(id, sGroup, config);
19342 if (config.listeners || config.events) {
19343 Roo.dd.DragDrop.superclass.constructor.call(this, {
19344 listeners : config.listeners || {},
19345 events : config.events || {}
19350 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19351 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19352 toString: function() {
19353 return ("DDTarget " + this.id);
19358 * Ext JS Library 1.1.1
19359 * Copyright(c) 2006-2007, Ext JS, LLC.
19361 * Originally Released Under LGPL - original licence link has changed is not relivant.
19364 * <script type="text/javascript">
19369 * @class Roo.dd.ScrollManager
19370 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19371 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19374 Roo.dd.ScrollManager = function(){
19375 var ddm = Roo.dd.DragDropMgr;
19382 var onStop = function(e){
19387 var triggerRefresh = function(){
19388 if(ddm.dragCurrent){
19389 ddm.refreshCache(ddm.dragCurrent.groups);
19393 var doScroll = function(){
19394 if(ddm.dragCurrent){
19395 var dds = Roo.dd.ScrollManager;
19397 if(proc.el.scroll(proc.dir, dds.increment)){
19401 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19406 var clearProc = function(){
19408 clearInterval(proc.id);
19415 var startProc = function(el, dir){
19416 Roo.log('scroll startproc');
19420 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19423 var onFire = function(e, isDrop){
19425 if(isDrop || !ddm.dragCurrent){ return; }
19426 var dds = Roo.dd.ScrollManager;
19427 if(!dragEl || dragEl != ddm.dragCurrent){
19428 dragEl = ddm.dragCurrent;
19429 // refresh regions on drag start
19430 dds.refreshCache();
19433 var xy = Roo.lib.Event.getXY(e);
19434 var pt = new Roo.lib.Point(xy[0], xy[1]);
19435 for(var id in els){
19436 var el = els[id], r = el._region;
19437 if(r && r.contains(pt) && el.isScrollable()){
19438 if(r.bottom - pt.y <= dds.thresh){
19440 startProc(el, "down");
19443 }else if(r.right - pt.x <= dds.thresh){
19445 startProc(el, "left");
19448 }else if(pt.y - r.top <= dds.thresh){
19450 startProc(el, "up");
19453 }else if(pt.x - r.left <= dds.thresh){
19455 startProc(el, "right");
19464 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19465 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19469 * Registers new overflow element(s) to auto scroll
19470 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19472 register : function(el){
19473 if(el instanceof Array){
19474 for(var i = 0, len = el.length; i < len; i++) {
19475 this.register(el[i]);
19481 Roo.dd.ScrollManager.els = els;
19485 * Unregisters overflow element(s) so they are no longer scrolled
19486 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19488 unregister : function(el){
19489 if(el instanceof Array){
19490 for(var i = 0, len = el.length; i < len; i++) {
19491 this.unregister(el[i]);
19500 * The number of pixels from the edge of a container the pointer needs to be to
19501 * trigger scrolling (defaults to 25)
19507 * The number of pixels to scroll in each scroll increment (defaults to 50)
19513 * The frequency of scrolls in milliseconds (defaults to 500)
19519 * True to animate the scroll (defaults to true)
19525 * The animation duration in seconds -
19526 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19532 * Manually trigger a cache refresh.
19534 refreshCache : function(){
19535 for(var id in els){
19536 if(typeof els[id] == 'object'){ // for people extending the object prototype
19537 els[id]._region = els[id].getRegion();
19544 * Ext JS Library 1.1.1
19545 * Copyright(c) 2006-2007, Ext JS, LLC.
19547 * Originally Released Under LGPL - original licence link has changed is not relivant.
19550 * <script type="text/javascript">
19555 * @class Roo.dd.Registry
19556 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19557 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19560 Roo.dd.Registry = function(){
19563 var autoIdSeed = 0;
19565 var getId = function(el, autogen){
19566 if(typeof el == "string"){
19570 if(!id && autogen !== false){
19571 id = "roodd-" + (++autoIdSeed);
19579 * Register a drag drop element
19580 * @param {String|HTMLElement} element The id or DOM node to register
19581 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19582 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19583 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19584 * populated in the data object (if applicable):
19586 Value Description<br />
19587 --------- ------------------------------------------<br />
19588 handles Array of DOM nodes that trigger dragging<br />
19589 for the element being registered<br />
19590 isHandle True if the element passed in triggers<br />
19591 dragging itself, else false
19594 register : function(el, data){
19596 if(typeof el == "string"){
19597 el = document.getElementById(el);
19600 elements[getId(el)] = data;
19601 if(data.isHandle !== false){
19602 handles[data.ddel.id] = data;
19605 var hs = data.handles;
19606 for(var i = 0, len = hs.length; i < len; i++){
19607 handles[getId(hs[i])] = data;
19613 * Unregister a drag drop element
19614 * @param {String|HTMLElement} element The id or DOM node to unregister
19616 unregister : function(el){
19617 var id = getId(el, false);
19618 var data = elements[id];
19620 delete elements[id];
19622 var hs = data.handles;
19623 for(var i = 0, len = hs.length; i < len; i++){
19624 delete handles[getId(hs[i], false)];
19631 * Returns the handle registered for a DOM Node by id
19632 * @param {String|HTMLElement} id The DOM node or id to look up
19633 * @return {Object} handle The custom handle data
19635 getHandle : function(id){
19636 if(typeof id != "string"){ // must be element?
19639 return handles[id];
19643 * Returns the handle that is registered for the DOM node that is the target of the event
19644 * @param {Event} e The event
19645 * @return {Object} handle The custom handle data
19647 getHandleFromEvent : function(e){
19648 var t = Roo.lib.Event.getTarget(e);
19649 return t ? handles[t.id] : null;
19653 * Returns a custom data object that is registered for a DOM node by id
19654 * @param {String|HTMLElement} id The DOM node or id to look up
19655 * @return {Object} data The custom data
19657 getTarget : function(id){
19658 if(typeof id != "string"){ // must be element?
19661 return elements[id];
19665 * Returns a custom data object that is registered for the DOM node that is the target of the event
19666 * @param {Event} e The event
19667 * @return {Object} data The custom data
19669 getTargetFromEvent : function(e){
19670 var t = Roo.lib.Event.getTarget(e);
19671 return t ? elements[t.id] || handles[t.id] : null;
19676 * Ext JS Library 1.1.1
19677 * Copyright(c) 2006-2007, Ext JS, LLC.
19679 * Originally Released Under LGPL - original licence link has changed is not relivant.
19682 * <script type="text/javascript">
19687 * @class Roo.dd.StatusProxy
19688 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19689 * default drag proxy used by all Roo.dd components.
19691 * @param {Object} config
19693 Roo.dd.StatusProxy = function(config){
19694 Roo.apply(this, config);
19695 this.id = this.id || Roo.id();
19696 this.el = new Roo.Layer({
19698 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19699 {tag: "div", cls: "x-dd-drop-icon"},
19700 {tag: "div", cls: "x-dd-drag-ghost"}
19703 shadow: !config || config.shadow !== false
19705 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19706 this.dropStatus = this.dropNotAllowed;
19709 Roo.dd.StatusProxy.prototype = {
19711 * @cfg {String} dropAllowed
19712 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19714 dropAllowed : "x-dd-drop-ok",
19716 * @cfg {String} dropNotAllowed
19717 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19719 dropNotAllowed : "x-dd-drop-nodrop",
19722 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19723 * over the current target element.
19724 * @param {String} cssClass The css class for the new drop status indicator image
19726 setStatus : function(cssClass){
19727 cssClass = cssClass || this.dropNotAllowed;
19728 if(this.dropStatus != cssClass){
19729 this.el.replaceClass(this.dropStatus, cssClass);
19730 this.dropStatus = cssClass;
19735 * Resets the status indicator to the default dropNotAllowed value
19736 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19738 reset : function(clearGhost){
19739 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19740 this.dropStatus = this.dropNotAllowed;
19742 this.ghost.update("");
19747 * Updates the contents of the ghost element
19748 * @param {String} html The html that will replace the current innerHTML of the ghost element
19750 update : function(html){
19751 if(typeof html == "string"){
19752 this.ghost.update(html);
19754 this.ghost.update("");
19755 html.style.margin = "0";
19756 this.ghost.dom.appendChild(html);
19758 // ensure float = none set?? cant remember why though.
19759 var el = this.ghost.dom.firstChild;
19761 Roo.fly(el).setStyle('float', 'none');
19766 * Returns the underlying proxy {@link Roo.Layer}
19767 * @return {Roo.Layer} el
19769 getEl : function(){
19774 * Returns the ghost element
19775 * @return {Roo.Element} el
19777 getGhost : function(){
19783 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19785 hide : function(clear){
19793 * Stops the repair animation if it's currently running
19796 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19802 * Displays this proxy
19809 * Force the Layer to sync its shadow and shim positions to the element
19816 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19817 * invalid drop operation by the item being dragged.
19818 * @param {Array} xy The XY position of the element ([x, y])
19819 * @param {Function} callback The function to call after the repair is complete
19820 * @param {Object} scope The scope in which to execute the callback
19822 repair : function(xy, callback, scope){
19823 this.callback = callback;
19824 this.scope = scope;
19825 if(xy && this.animRepair !== false){
19826 this.el.addClass("x-dd-drag-repair");
19827 this.el.hideUnders(true);
19828 this.anim = this.el.shift({
19829 duration: this.repairDuration || .5,
19833 callback: this.afterRepair,
19837 this.afterRepair();
19842 afterRepair : function(){
19844 if(typeof this.callback == "function"){
19845 this.callback.call(this.scope || this);
19847 this.callback = null;
19852 * Ext JS Library 1.1.1
19853 * Copyright(c) 2006-2007, Ext JS, LLC.
19855 * Originally Released Under LGPL - original licence link has changed is not relivant.
19858 * <script type="text/javascript">
19862 * @class Roo.dd.DragSource
19863 * @extends Roo.dd.DDProxy
19864 * A simple class that provides the basic implementation needed to make any element draggable.
19866 * @param {String/HTMLElement/Element} el The container element
19867 * @param {Object} config
19869 Roo.dd.DragSource = function(el, config){
19870 this.el = Roo.get(el);
19871 this.dragData = {};
19873 Roo.apply(this, config);
19876 this.proxy = new Roo.dd.StatusProxy();
19879 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
19880 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
19882 this.dragging = false;
19885 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
19887 * @cfg {String} dropAllowed
19888 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
19890 dropAllowed : "x-dd-drop-ok",
19892 * @cfg {String} dropNotAllowed
19893 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
19895 dropNotAllowed : "x-dd-drop-nodrop",
19898 * Returns the data object associated with this drag source
19899 * @return {Object} data An object containing arbitrary data
19901 getDragData : function(e){
19902 return this.dragData;
19906 onDragEnter : function(e, id){
19907 var target = Roo.dd.DragDropMgr.getDDById(id);
19908 this.cachedTarget = target;
19909 if(this.beforeDragEnter(target, e, id) !== false){
19910 if(target.isNotifyTarget){
19911 var status = target.notifyEnter(this, e, this.dragData);
19912 this.proxy.setStatus(status);
19914 this.proxy.setStatus(this.dropAllowed);
19917 if(this.afterDragEnter){
19919 * An empty function by default, but provided so that you can perform a custom action
19920 * when the dragged item enters the drop target by providing an implementation.
19921 * @param {Roo.dd.DragDrop} target The drop target
19922 * @param {Event} e The event object
19923 * @param {String} id The id of the dragged element
19924 * @method afterDragEnter
19926 this.afterDragEnter(target, e, id);
19932 * An empty function by default, but provided so that you can perform a custom action
19933 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
19934 * @param {Roo.dd.DragDrop} target The drop target
19935 * @param {Event} e The event object
19936 * @param {String} id The id of the dragged element
19937 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19939 beforeDragEnter : function(target, e, id){
19944 alignElWithMouse: function() {
19945 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
19950 onDragOver : function(e, id){
19951 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19952 if(this.beforeDragOver(target, e, id) !== false){
19953 if(target.isNotifyTarget){
19954 var status = target.notifyOver(this, e, this.dragData);
19955 this.proxy.setStatus(status);
19958 if(this.afterDragOver){
19960 * An empty function by default, but provided so that you can perform a custom action
19961 * while the dragged item is over the drop target by providing an implementation.
19962 * @param {Roo.dd.DragDrop} target The drop target
19963 * @param {Event} e The event object
19964 * @param {String} id The id of the dragged element
19965 * @method afterDragOver
19967 this.afterDragOver(target, e, id);
19973 * An empty function by default, but provided so that you can perform a custom action
19974 * while the dragged item is over the drop target and optionally cancel the onDragOver.
19975 * @param {Roo.dd.DragDrop} target The drop target
19976 * @param {Event} e The event object
19977 * @param {String} id The id of the dragged element
19978 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19980 beforeDragOver : function(target, e, id){
19985 onDragOut : function(e, id){
19986 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19987 if(this.beforeDragOut(target, e, id) !== false){
19988 if(target.isNotifyTarget){
19989 target.notifyOut(this, e, this.dragData);
19991 this.proxy.reset();
19992 if(this.afterDragOut){
19994 * An empty function by default, but provided so that you can perform a custom action
19995 * after the dragged item is dragged out of the target without dropping.
19996 * @param {Roo.dd.DragDrop} target The drop target
19997 * @param {Event} e The event object
19998 * @param {String} id The id of the dragged element
19999 * @method afterDragOut
20001 this.afterDragOut(target, e, id);
20004 this.cachedTarget = null;
20008 * An empty function by default, but provided so that you can perform a custom action before the dragged
20009 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20010 * @param {Roo.dd.DragDrop} target The drop target
20011 * @param {Event} e The event object
20012 * @param {String} id The id of the dragged element
20013 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20015 beforeDragOut : function(target, e, id){
20020 onDragDrop : function(e, id){
20021 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20022 if(this.beforeDragDrop(target, e, id) !== false){
20023 if(target.isNotifyTarget){
20024 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20025 this.onValidDrop(target, e, id);
20027 this.onInvalidDrop(target, e, id);
20030 this.onValidDrop(target, e, id);
20033 if(this.afterDragDrop){
20035 * An empty function by default, but provided so that you can perform a custom action
20036 * after a valid drag drop has occurred by providing an implementation.
20037 * @param {Roo.dd.DragDrop} target The drop target
20038 * @param {Event} e The event object
20039 * @param {String} id The id of the dropped element
20040 * @method afterDragDrop
20042 this.afterDragDrop(target, e, id);
20045 delete this.cachedTarget;
20049 * An empty function by default, but provided so that you can perform a custom action before the dragged
20050 * item is dropped onto the target and optionally cancel the onDragDrop.
20051 * @param {Roo.dd.DragDrop} target The drop target
20052 * @param {Event} e The event object
20053 * @param {String} id The id of the dragged element
20054 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20056 beforeDragDrop : function(target, e, id){
20061 onValidDrop : function(target, e, id){
20063 if(this.afterValidDrop){
20065 * An empty function by default, but provided so that you can perform a custom action
20066 * after a valid drop has occurred by providing an implementation.
20067 * @param {Object} target The target DD
20068 * @param {Event} e The event object
20069 * @param {String} id The id of the dropped element
20070 * @method afterInvalidDrop
20072 this.afterValidDrop(target, e, id);
20077 getRepairXY : function(e, data){
20078 return this.el.getXY();
20082 onInvalidDrop : function(target, e, id){
20083 this.beforeInvalidDrop(target, e, id);
20084 if(this.cachedTarget){
20085 if(this.cachedTarget.isNotifyTarget){
20086 this.cachedTarget.notifyOut(this, e, this.dragData);
20088 this.cacheTarget = null;
20090 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20092 if(this.afterInvalidDrop){
20094 * An empty function by default, but provided so that you can perform a custom action
20095 * after an invalid drop has occurred by providing an implementation.
20096 * @param {Event} e The event object
20097 * @param {String} id The id of the dropped element
20098 * @method afterInvalidDrop
20100 this.afterInvalidDrop(e, id);
20105 afterRepair : function(){
20107 this.el.highlight(this.hlColor || "c3daf9");
20109 this.dragging = false;
20113 * An empty function by default, but provided so that you can perform a custom action after an invalid
20114 * drop has occurred.
20115 * @param {Roo.dd.DragDrop} target The drop target
20116 * @param {Event} e The event object
20117 * @param {String} id The id of the dragged element
20118 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20120 beforeInvalidDrop : function(target, e, id){
20125 handleMouseDown : function(e){
20126 if(this.dragging) {
20129 var data = this.getDragData(e);
20130 if(data && this.onBeforeDrag(data, e) !== false){
20131 this.dragData = data;
20133 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20138 * An empty function by default, but provided so that you can perform a custom action before the initial
20139 * drag event begins and optionally cancel it.
20140 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20141 * @param {Event} e The event object
20142 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20144 onBeforeDrag : function(data, e){
20149 * An empty function by default, but provided so that you can perform a custom action once the initial
20150 * drag event has begun. The drag cannot be canceled from this function.
20151 * @param {Number} x The x position of the click on the dragged object
20152 * @param {Number} y The y position of the click on the dragged object
20154 onStartDrag : Roo.emptyFn,
20156 // private - YUI override
20157 startDrag : function(x, y){
20158 this.proxy.reset();
20159 this.dragging = true;
20160 this.proxy.update("");
20161 this.onInitDrag(x, y);
20166 onInitDrag : function(x, y){
20167 var clone = this.el.dom.cloneNode(true);
20168 clone.id = Roo.id(); // prevent duplicate ids
20169 this.proxy.update(clone);
20170 this.onStartDrag(x, y);
20175 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20176 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20178 getProxy : function(){
20183 * Hides the drag source's {@link Roo.dd.StatusProxy}
20185 hideProxy : function(){
20187 this.proxy.reset(true);
20188 this.dragging = false;
20192 triggerCacheRefresh : function(){
20193 Roo.dd.DDM.refreshCache(this.groups);
20196 // private - override to prevent hiding
20197 b4EndDrag: function(e) {
20200 // private - override to prevent moving
20201 endDrag : function(e){
20202 this.onEndDrag(this.dragData, e);
20206 onEndDrag : function(data, e){
20209 // private - pin to cursor
20210 autoOffset : function(x, y) {
20211 this.setDelta(-12, -20);
20215 * Ext JS Library 1.1.1
20216 * Copyright(c) 2006-2007, Ext JS, LLC.
20218 * Originally Released Under LGPL - original licence link has changed is not relivant.
20221 * <script type="text/javascript">
20226 * @class Roo.dd.DropTarget
20227 * @extends Roo.dd.DDTarget
20228 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20229 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20231 * @param {String/HTMLElement/Element} el The container element
20232 * @param {Object} config
20234 Roo.dd.DropTarget = function(el, config){
20235 this.el = Roo.get(el);
20237 var listeners = false; ;
20238 if (config && config.listeners) {
20239 listeners= config.listeners;
20240 delete config.listeners;
20242 Roo.apply(this, config);
20244 if(this.containerScroll){
20245 Roo.dd.ScrollManager.register(this.el);
20249 * @scope Roo.dd.DropTarget
20254 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20255 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20256 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20258 * IMPORTANT : it should set this.overClass and this.dropAllowed
20260 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20261 * @param {Event} e The event
20262 * @param {Object} data An object containing arbitrary data supplied by the drag source
20268 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20269 * This method will be called on every mouse movement while the drag source is over the drop target.
20270 * This default implementation simply returns the dropAllowed config value.
20272 * IMPORTANT : it should set this.dropAllowed
20274 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20275 * @param {Event} e The event
20276 * @param {Object} data An object containing arbitrary data supplied by the drag source
20282 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20283 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20284 * overClass (if any) from the drop element.
20286 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20287 * @param {Event} e The event
20288 * @param {Object} data An object containing arbitrary data supplied by the drag source
20294 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20295 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20296 * implementation that does something to process the drop event and returns true so that the drag source's
20297 * repair action does not run.
20299 * IMPORTANT : it should set this.success
20301 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20302 * @param {Event} e The event
20303 * @param {Object} data An object containing arbitrary data supplied by the drag source
20309 Roo.dd.DropTarget.superclass.constructor.call( this,
20311 this.ddGroup || this.group,
20314 listeners : listeners || {}
20322 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20324 * @cfg {String} overClass
20325 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20328 * @cfg {String} ddGroup
20329 * The drag drop group to handle drop events for
20333 * @cfg {String} dropAllowed
20334 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20336 dropAllowed : "x-dd-drop-ok",
20338 * @cfg {String} dropNotAllowed
20339 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20341 dropNotAllowed : "x-dd-drop-nodrop",
20343 * @cfg {boolean} success
20344 * set this after drop listener..
20348 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20349 * if the drop point is valid for over/enter..
20356 isNotifyTarget : true,
20361 notifyEnter : function(dd, e, data)
20364 this.fireEvent('enter', dd, e, data);
20365 if(this.overClass){
20366 this.el.addClass(this.overClass);
20368 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20369 this.valid ? this.dropAllowed : this.dropNotAllowed
20376 notifyOver : function(dd, e, data)
20379 this.fireEvent('over', dd, e, data);
20380 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20381 this.valid ? this.dropAllowed : this.dropNotAllowed
20388 notifyOut : function(dd, e, data)
20390 this.fireEvent('out', dd, e, data);
20391 if(this.overClass){
20392 this.el.removeClass(this.overClass);
20399 notifyDrop : function(dd, e, data)
20401 this.success = false;
20402 this.fireEvent('drop', dd, e, data);
20403 return this.success;
20407 * Ext JS Library 1.1.1
20408 * Copyright(c) 2006-2007, Ext JS, LLC.
20410 * Originally Released Under LGPL - original licence link has changed is not relivant.
20413 * <script type="text/javascript">
20418 * @class Roo.dd.DragZone
20419 * @extends Roo.dd.DragSource
20420 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20421 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20423 * @param {String/HTMLElement/Element} el The container element
20424 * @param {Object} config
20426 Roo.dd.DragZone = function(el, config){
20427 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20428 if(this.containerScroll){
20429 Roo.dd.ScrollManager.register(this.el);
20433 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20435 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20436 * for auto scrolling during drag operations.
20439 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20440 * method after a failed drop (defaults to "c3daf9" - light blue)
20444 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20445 * for a valid target to drag based on the mouse down. Override this method
20446 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20447 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20448 * @param {EventObject} e The mouse down event
20449 * @return {Object} The dragData
20451 getDragData : function(e){
20452 return Roo.dd.Registry.getHandleFromEvent(e);
20456 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20457 * this.dragData.ddel
20458 * @param {Number} x The x position of the click on the dragged object
20459 * @param {Number} y The y position of the click on the dragged object
20460 * @return {Boolean} true to continue the drag, false to cancel
20462 onInitDrag : function(x, y){
20463 this.proxy.update(this.dragData.ddel.cloneNode(true));
20464 this.onStartDrag(x, y);
20469 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20471 afterRepair : function(){
20473 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20475 this.dragging = false;
20479 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20480 * the XY of this.dragData.ddel
20481 * @param {EventObject} e The mouse up event
20482 * @return {Array} The xy location (e.g. [100, 200])
20484 getRepairXY : function(e){
20485 return Roo.Element.fly(this.dragData.ddel).getXY();
20489 * Ext JS Library 1.1.1
20490 * Copyright(c) 2006-2007, Ext JS, LLC.
20492 * Originally Released Under LGPL - original licence link has changed is not relivant.
20495 * <script type="text/javascript">
20498 * @class Roo.dd.DropZone
20499 * @extends Roo.dd.DropTarget
20500 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20501 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20503 * @param {String/HTMLElement/Element} el The container element
20504 * @param {Object} config
20506 Roo.dd.DropZone = function(el, config){
20507 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20510 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20512 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20513 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20514 * provide your own custom lookup.
20515 * @param {Event} e The event
20516 * @return {Object} data The custom data
20518 getTargetFromEvent : function(e){
20519 return Roo.dd.Registry.getTargetFromEvent(e);
20523 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20524 * that it has registered. This method has no default implementation and should be overridden to provide
20525 * node-specific processing if necessary.
20526 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20527 * {@link #getTargetFromEvent} for this node)
20528 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20529 * @param {Event} e The event
20530 * @param {Object} data An object containing arbitrary data supplied by the drag source
20532 onNodeEnter : function(n, dd, e, data){
20537 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20538 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20539 * overridden to provide the proper feedback.
20540 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20541 * {@link #getTargetFromEvent} for this node)
20542 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20543 * @param {Event} e The event
20544 * @param {Object} data An object containing arbitrary data supplied by the drag source
20545 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20546 * underlying {@link Roo.dd.StatusProxy} can be updated
20548 onNodeOver : function(n, dd, e, data){
20549 return this.dropAllowed;
20553 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20554 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20555 * node-specific processing if necessary.
20556 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20557 * {@link #getTargetFromEvent} for this node)
20558 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20559 * @param {Event} e The event
20560 * @param {Object} data An object containing arbitrary data supplied by the drag source
20562 onNodeOut : function(n, dd, e, data){
20567 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20568 * the drop node. The default implementation returns false, so it should be overridden to provide the
20569 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20570 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20571 * {@link #getTargetFromEvent} for this node)
20572 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20573 * @param {Event} e The event
20574 * @param {Object} data An object containing arbitrary data supplied by the drag source
20575 * @return {Boolean} True if the drop was valid, else false
20577 onNodeDrop : function(n, dd, e, data){
20582 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20583 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20584 * it should be overridden to provide the proper feedback if necessary.
20585 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20586 * @param {Event} e The event
20587 * @param {Object} data An object containing arbitrary data supplied by the drag source
20588 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20589 * underlying {@link Roo.dd.StatusProxy} can be updated
20591 onContainerOver : function(dd, e, data){
20592 return this.dropNotAllowed;
20596 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20597 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20598 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20599 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20600 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20601 * @param {Event} e The event
20602 * @param {Object} data An object containing arbitrary data supplied by the drag source
20603 * @return {Boolean} True if the drop was valid, else false
20605 onContainerDrop : function(dd, e, data){
20610 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20611 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20612 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20613 * you should override this method and provide a custom implementation.
20614 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20615 * @param {Event} e The event
20616 * @param {Object} data An object containing arbitrary data supplied by the drag source
20617 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20618 * underlying {@link Roo.dd.StatusProxy} can be updated
20620 notifyEnter : function(dd, e, data){
20621 return this.dropNotAllowed;
20625 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20626 * This method will be called on every mouse movement while the drag source is over the drop zone.
20627 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20628 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20629 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20630 * registered node, it will call {@link #onContainerOver}.
20631 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20632 * @param {Event} e The event
20633 * @param {Object} data An object containing arbitrary data supplied by the drag source
20634 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20635 * underlying {@link Roo.dd.StatusProxy} can be updated
20637 notifyOver : function(dd, e, data){
20638 var n = this.getTargetFromEvent(e);
20639 if(!n){ // not over valid drop target
20640 if(this.lastOverNode){
20641 this.onNodeOut(this.lastOverNode, dd, e, data);
20642 this.lastOverNode = null;
20644 return this.onContainerOver(dd, e, data);
20646 if(this.lastOverNode != n){
20647 if(this.lastOverNode){
20648 this.onNodeOut(this.lastOverNode, dd, e, data);
20650 this.onNodeEnter(n, dd, e, data);
20651 this.lastOverNode = n;
20653 return this.onNodeOver(n, dd, e, data);
20657 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20658 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20659 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20660 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20661 * @param {Event} e The event
20662 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20664 notifyOut : function(dd, e, data){
20665 if(this.lastOverNode){
20666 this.onNodeOut(this.lastOverNode, dd, e, data);
20667 this.lastOverNode = null;
20672 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20673 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20674 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20675 * otherwise it will call {@link #onContainerDrop}.
20676 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20677 * @param {Event} e The event
20678 * @param {Object} data An object containing arbitrary data supplied by the drag source
20679 * @return {Boolean} True if the drop was valid, else false
20681 notifyDrop : function(dd, e, data){
20682 if(this.lastOverNode){
20683 this.onNodeOut(this.lastOverNode, dd, e, data);
20684 this.lastOverNode = null;
20686 var n = this.getTargetFromEvent(e);
20688 this.onNodeDrop(n, dd, e, data) :
20689 this.onContainerDrop(dd, e, data);
20693 triggerCacheRefresh : function(){
20694 Roo.dd.DDM.refreshCache(this.groups);
20698 * Ext JS Library 1.1.1
20699 * Copyright(c) 2006-2007, Ext JS, LLC.
20701 * Originally Released Under LGPL - original licence link has changed is not relivant.
20704 * <script type="text/javascript">
20709 * @class Roo.data.SortTypes
20711 * Defines the default sorting (casting?) comparison functions used when sorting data.
20713 Roo.data.SortTypes = {
20715 * Default sort that does nothing
20716 * @param {Mixed} s The value being converted
20717 * @return {Mixed} The comparison value
20719 none : function(s){
20724 * The regular expression used to strip tags
20728 stripTagsRE : /<\/?[^>]+>/gi,
20731 * Strips all HTML tags to sort on text only
20732 * @param {Mixed} s The value being converted
20733 * @return {String} The comparison value
20735 asText : function(s){
20736 return String(s).replace(this.stripTagsRE, "");
20740 * Strips all HTML tags to sort on text only - Case insensitive
20741 * @param {Mixed} s The value being converted
20742 * @return {String} The comparison value
20744 asUCText : function(s){
20745 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20749 * Case insensitive string
20750 * @param {Mixed} s The value being converted
20751 * @return {String} The comparison value
20753 asUCString : function(s) {
20754 return String(s).toUpperCase();
20759 * @param {Mixed} s The value being converted
20760 * @return {Number} The comparison value
20762 asDate : function(s) {
20766 if(s instanceof Date){
20767 return s.getTime();
20769 return Date.parse(String(s));
20774 * @param {Mixed} s The value being converted
20775 * @return {Float} The comparison value
20777 asFloat : function(s) {
20778 var val = parseFloat(String(s).replace(/,/g, ""));
20779 if(isNaN(val)) val = 0;
20785 * @param {Mixed} s The value being converted
20786 * @return {Number} The comparison value
20788 asInt : function(s) {
20789 var val = parseInt(String(s).replace(/,/g, ""));
20790 if(isNaN(val)) val = 0;
20795 * Ext JS Library 1.1.1
20796 * Copyright(c) 2006-2007, Ext JS, LLC.
20798 * Originally Released Under LGPL - original licence link has changed is not relivant.
20801 * <script type="text/javascript">
20805 * @class Roo.data.Record
20806 * Instances of this class encapsulate both record <em>definition</em> information, and record
20807 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20808 * to access Records cached in an {@link Roo.data.Store} object.<br>
20810 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20811 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20814 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20816 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20817 * {@link #create}. The parameters are the same.
20818 * @param {Array} data An associative Array of data values keyed by the field name.
20819 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20820 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20821 * not specified an integer id is generated.
20823 Roo.data.Record = function(data, id){
20824 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20829 * Generate a constructor for a specific record layout.
20830 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20831 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20832 * Each field definition object may contain the following properties: <ul>
20833 * <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,
20834 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20835 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20836 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20837 * is being used, then this is a string containing the javascript expression to reference the data relative to
20838 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20839 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20840 * this may be omitted.</p></li>
20841 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20842 * <ul><li>auto (Default, implies no conversion)</li>
20847 * <li>date</li></ul></p></li>
20848 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20849 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20850 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20851 * by the Reader into an object that will be stored in the Record. It is passed the
20852 * following parameters:<ul>
20853 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20855 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20857 * <br>usage:<br><pre><code>
20858 var TopicRecord = Roo.data.Record.create(
20859 {name: 'title', mapping: 'topic_title'},
20860 {name: 'author', mapping: 'username'},
20861 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20862 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20863 {name: 'lastPoster', mapping: 'user2'},
20864 {name: 'excerpt', mapping: 'post_text'}
20867 var myNewRecord = new TopicRecord({
20868 title: 'Do my job please',
20871 lastPost: new Date(),
20872 lastPoster: 'Animal',
20873 excerpt: 'No way dude!'
20875 myStore.add(myNewRecord);
20880 Roo.data.Record.create = function(o){
20881 var f = function(){
20882 f.superclass.constructor.apply(this, arguments);
20884 Roo.extend(f, Roo.data.Record);
20885 var p = f.prototype;
20886 p.fields = new Roo.util.MixedCollection(false, function(field){
20889 for(var i = 0, len = o.length; i < len; i++){
20890 p.fields.add(new Roo.data.Field(o[i]));
20892 f.getField = function(name){
20893 return p.fields.get(name);
20898 Roo.data.Record.AUTO_ID = 1000;
20899 Roo.data.Record.EDIT = 'edit';
20900 Roo.data.Record.REJECT = 'reject';
20901 Roo.data.Record.COMMIT = 'commit';
20903 Roo.data.Record.prototype = {
20905 * Readonly flag - true if this record has been modified.
20914 join : function(store){
20915 this.store = store;
20919 * Set the named field to the specified value.
20920 * @param {String} name The name of the field to set.
20921 * @param {Object} value The value to set the field to.
20923 set : function(name, value){
20924 if(this.data[name] == value){
20928 if(!this.modified){
20929 this.modified = {};
20931 if(typeof this.modified[name] == 'undefined'){
20932 this.modified[name] = this.data[name];
20934 this.data[name] = value;
20935 if(!this.editing && this.store){
20936 this.store.afterEdit(this);
20941 * Get the value of the named field.
20942 * @param {String} name The name of the field to get the value of.
20943 * @return {Object} The value of the field.
20945 get : function(name){
20946 return this.data[name];
20950 beginEdit : function(){
20951 this.editing = true;
20952 this.modified = {};
20956 cancelEdit : function(){
20957 this.editing = false;
20958 delete this.modified;
20962 endEdit : function(){
20963 this.editing = false;
20964 if(this.dirty && this.store){
20965 this.store.afterEdit(this);
20970 * Usually called by the {@link Roo.data.Store} which owns the Record.
20971 * Rejects all changes made to the Record since either creation, or the last commit operation.
20972 * Modified fields are reverted to their original values.
20974 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20975 * of reject operations.
20977 reject : function(){
20978 var m = this.modified;
20980 if(typeof m[n] != "function"){
20981 this.data[n] = m[n];
20984 this.dirty = false;
20985 delete this.modified;
20986 this.editing = false;
20988 this.store.afterReject(this);
20993 * Usually called by the {@link Roo.data.Store} which owns the Record.
20994 * Commits all changes made to the Record since either creation, or the last commit operation.
20996 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20997 * of commit operations.
20999 commit : function(){
21000 this.dirty = false;
21001 delete this.modified;
21002 this.editing = false;
21004 this.store.afterCommit(this);
21009 hasError : function(){
21010 return this.error != null;
21014 clearError : function(){
21019 * Creates a copy of this record.
21020 * @param {String} id (optional) A new record id if you don't want to use this record's id
21023 copy : function(newId) {
21024 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21028 * Ext JS Library 1.1.1
21029 * Copyright(c) 2006-2007, Ext JS, LLC.
21031 * Originally Released Under LGPL - original licence link has changed is not relivant.
21034 * <script type="text/javascript">
21040 * @class Roo.data.Store
21041 * @extends Roo.util.Observable
21042 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21043 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21045 * 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
21046 * has no knowledge of the format of the data returned by the Proxy.<br>
21048 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21049 * instances from the data object. These records are cached and made available through accessor functions.
21051 * Creates a new Store.
21052 * @param {Object} config A config object containing the objects needed for the Store to access data,
21053 * and read the data into Records.
21055 Roo.data.Store = function(config){
21056 this.data = new Roo.util.MixedCollection(false);
21057 this.data.getKey = function(o){
21060 this.baseParams = {};
21062 this.paramNames = {
21067 "multisort" : "_multisort"
21070 if(config && config.data){
21071 this.inlineData = config.data;
21072 delete config.data;
21075 Roo.apply(this, config);
21077 if(this.reader){ // reader passed
21078 this.reader = Roo.factory(this.reader, Roo.data);
21079 this.reader.xmodule = this.xmodule || false;
21080 if(!this.recordType){
21081 this.recordType = this.reader.recordType;
21083 if(this.reader.onMetaChange){
21084 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21088 if(this.recordType){
21089 this.fields = this.recordType.prototype.fields;
21091 this.modified = [];
21095 * @event datachanged
21096 * Fires when the data cache has changed, and a widget which is using this Store
21097 * as a Record cache should refresh its view.
21098 * @param {Store} this
21100 datachanged : true,
21102 * @event metachange
21103 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21104 * @param {Store} this
21105 * @param {Object} meta The JSON metadata
21110 * Fires when Records have been added to the Store
21111 * @param {Store} this
21112 * @param {Roo.data.Record[]} records The array of Records added
21113 * @param {Number} index The index at which the record(s) were added
21118 * Fires when a Record has been removed from the Store
21119 * @param {Store} this
21120 * @param {Roo.data.Record} record The Record that was removed
21121 * @param {Number} index The index at which the record was removed
21126 * Fires when a Record has been updated
21127 * @param {Store} this
21128 * @param {Roo.data.Record} record The Record that was updated
21129 * @param {String} operation The update operation being performed. Value may be one of:
21131 Roo.data.Record.EDIT
21132 Roo.data.Record.REJECT
21133 Roo.data.Record.COMMIT
21139 * Fires when the data cache has been cleared.
21140 * @param {Store} this
21144 * @event beforeload
21145 * Fires before a request is made for a new data object. If the beforeload handler returns false
21146 * the load action will be canceled.
21147 * @param {Store} this
21148 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21152 * @event beforeloadadd
21153 * Fires after a new set of Records has been loaded.
21154 * @param {Store} this
21155 * @param {Roo.data.Record[]} records The Records that were loaded
21156 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21158 beforeloadadd : true,
21161 * Fires after a new set of Records has been loaded, before they are added to the store.
21162 * @param {Store} this
21163 * @param {Roo.data.Record[]} records The Records that were loaded
21164 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21165 * @params {Object} return from reader
21169 * @event loadexception
21170 * Fires if an exception occurs in the Proxy during loading.
21171 * Called with the signature of the Proxy's "loadexception" event.
21172 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21175 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21176 * @param {Object} load options
21177 * @param {Object} jsonData from your request (normally this contains the Exception)
21179 loadexception : true
21183 this.proxy = Roo.factory(this.proxy, Roo.data);
21184 this.proxy.xmodule = this.xmodule || false;
21185 this.relayEvents(this.proxy, ["loadexception"]);
21187 this.sortToggle = {};
21188 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21190 Roo.data.Store.superclass.constructor.call(this);
21192 if(this.inlineData){
21193 this.loadData(this.inlineData);
21194 delete this.inlineData;
21198 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21200 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21201 * without a remote query - used by combo/forms at present.
21205 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21208 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21211 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21212 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21215 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21216 * on any HTTP request
21219 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21222 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21226 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21227 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21229 remoteSort : false,
21232 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21233 * loaded or when a record is removed. (defaults to false).
21235 pruneModifiedRecords : false,
21238 lastOptions : null,
21241 * Add Records to the Store and fires the add event.
21242 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21244 add : function(records){
21245 records = [].concat(records);
21246 for(var i = 0, len = records.length; i < len; i++){
21247 records[i].join(this);
21249 var index = this.data.length;
21250 this.data.addAll(records);
21251 this.fireEvent("add", this, records, index);
21255 * Remove a Record from the Store and fires the remove event.
21256 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21258 remove : function(record){
21259 var index = this.data.indexOf(record);
21260 this.data.removeAt(index);
21261 if(this.pruneModifiedRecords){
21262 this.modified.remove(record);
21264 this.fireEvent("remove", this, record, index);
21268 * Remove all Records from the Store and fires the clear event.
21270 removeAll : function(){
21272 if(this.pruneModifiedRecords){
21273 this.modified = [];
21275 this.fireEvent("clear", this);
21279 * Inserts Records to the Store at the given index and fires the add event.
21280 * @param {Number} index The start index at which to insert the passed Records.
21281 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21283 insert : function(index, records){
21284 records = [].concat(records);
21285 for(var i = 0, len = records.length; i < len; i++){
21286 this.data.insert(index, records[i]);
21287 records[i].join(this);
21289 this.fireEvent("add", this, records, index);
21293 * Get the index within the cache of the passed Record.
21294 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21295 * @return {Number} The index of the passed Record. Returns -1 if not found.
21297 indexOf : function(record){
21298 return this.data.indexOf(record);
21302 * Get the index within the cache of the Record with the passed id.
21303 * @param {String} id The id of the Record to find.
21304 * @return {Number} The index of the Record. Returns -1 if not found.
21306 indexOfId : function(id){
21307 return this.data.indexOfKey(id);
21311 * Get the Record with the specified id.
21312 * @param {String} id The id of the Record to find.
21313 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21315 getById : function(id){
21316 return this.data.key(id);
21320 * Get the Record at the specified index.
21321 * @param {Number} index The index of the Record to find.
21322 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21324 getAt : function(index){
21325 return this.data.itemAt(index);
21329 * Returns a range of Records between specified indices.
21330 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21331 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21332 * @return {Roo.data.Record[]} An array of Records
21334 getRange : function(start, end){
21335 return this.data.getRange(start, end);
21339 storeOptions : function(o){
21340 o = Roo.apply({}, o);
21343 this.lastOptions = o;
21347 * Loads the Record cache from the configured Proxy using the configured Reader.
21349 * If using remote paging, then the first load call must specify the <em>start</em>
21350 * and <em>limit</em> properties in the options.params property to establish the initial
21351 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21353 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21354 * and this call will return before the new data has been loaded. Perform any post-processing
21355 * in a callback function, or in a "load" event handler.</strong>
21357 * @param {Object} options An object containing properties which control loading options:<ul>
21358 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21359 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21360 * passed the following arguments:<ul>
21361 * <li>r : Roo.data.Record[]</li>
21362 * <li>options: Options object from the load call</li>
21363 * <li>success: Boolean success indicator</li></ul></li>
21364 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21365 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21368 load : function(options){
21369 options = options || {};
21370 if(this.fireEvent("beforeload", this, options) !== false){
21371 this.storeOptions(options);
21372 var p = Roo.apply(options.params || {}, this.baseParams);
21373 // if meta was not loaded from remote source.. try requesting it.
21374 if (!this.reader.metaFromRemote) {
21375 p._requestMeta = 1;
21377 if(this.sortInfo && this.remoteSort){
21378 var pn = this.paramNames;
21379 p[pn["sort"]] = this.sortInfo.field;
21380 p[pn["dir"]] = this.sortInfo.direction;
21382 if (this.multiSort) {
21383 var pn = this.paramNames;
21384 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21387 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21392 * Reloads the Record cache from the configured Proxy using the configured Reader and
21393 * the options from the last load operation performed.
21394 * @param {Object} options (optional) An object containing properties which may override the options
21395 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21396 * the most recently used options are reused).
21398 reload : function(options){
21399 this.load(Roo.applyIf(options||{}, this.lastOptions));
21403 // Called as a callback by the Reader during a load operation.
21404 loadRecords : function(o, options, success){
21405 if(!o || success === false){
21406 if(success !== false){
21407 this.fireEvent("load", this, [], options, o);
21409 if(options.callback){
21410 options.callback.call(options.scope || this, [], options, false);
21414 // if data returned failure - throw an exception.
21415 if (o.success === false) {
21416 // show a message if no listener is registered.
21417 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21418 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21420 // loadmask wil be hooked into this..
21421 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21424 var r = o.records, t = o.totalRecords || r.length;
21426 this.fireEvent("beforeloadadd", this, r, options, o);
21428 if(!options || options.add !== true){
21429 if(this.pruneModifiedRecords){
21430 this.modified = [];
21432 for(var i = 0, len = r.length; i < len; i++){
21436 this.data = this.snapshot;
21437 delete this.snapshot;
21440 this.data.addAll(r);
21441 this.totalLength = t;
21443 this.fireEvent("datachanged", this);
21445 this.totalLength = Math.max(t, this.data.length+r.length);
21448 this.fireEvent("load", this, r, options, o);
21449 if(options.callback){
21450 options.callback.call(options.scope || this, r, options, true);
21456 * Loads data from a passed data block. A Reader which understands the format of the data
21457 * must have been configured in the constructor.
21458 * @param {Object} data The data block from which to read the Records. The format of the data expected
21459 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21460 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21462 loadData : function(o, append){
21463 var r = this.reader.readRecords(o);
21464 this.loadRecords(r, {add: append}, true);
21468 * Gets the number of cached records.
21470 * <em>If using paging, this may not be the total size of the dataset. If the data object
21471 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21472 * the data set size</em>
21474 getCount : function(){
21475 return this.data.length || 0;
21479 * Gets the total number of records in the dataset as returned by the server.
21481 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21482 * the dataset size</em>
21484 getTotalCount : function(){
21485 return this.totalLength || 0;
21489 * Returns the sort state of the Store as an object with two properties:
21491 field {String} The name of the field by which the Records are sorted
21492 direction {String} The sort order, "ASC" or "DESC"
21495 getSortState : function(){
21496 return this.sortInfo;
21500 applySort : function(){
21501 if(this.sortInfo && !this.remoteSort){
21502 var s = this.sortInfo, f = s.field;
21503 var st = this.fields.get(f).sortType;
21504 var fn = function(r1, r2){
21505 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21506 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21508 this.data.sort(s.direction, fn);
21509 if(this.snapshot && this.snapshot != this.data){
21510 this.snapshot.sort(s.direction, fn);
21516 * Sets the default sort column and order to be used by the next load operation.
21517 * @param {String} fieldName The name of the field to sort by.
21518 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21520 setDefaultSort : function(field, dir){
21521 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21525 * Sort the Records.
21526 * If remote sorting is used, the sort is performed on the server, and the cache is
21527 * reloaded. If local sorting is used, the cache is sorted internally.
21528 * @param {String} fieldName The name of the field to sort by.
21529 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21531 sort : function(fieldName, dir){
21532 var f = this.fields.get(fieldName);
21534 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21536 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21537 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21542 this.sortToggle[f.name] = dir;
21543 this.sortInfo = {field: f.name, direction: dir};
21544 if(!this.remoteSort){
21546 this.fireEvent("datachanged", this);
21548 this.load(this.lastOptions);
21553 * Calls the specified function for each of the Records in the cache.
21554 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21555 * Returning <em>false</em> aborts and exits the iteration.
21556 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21558 each : function(fn, scope){
21559 this.data.each(fn, scope);
21563 * Gets all records modified since the last commit. Modified records are persisted across load operations
21564 * (e.g., during paging).
21565 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21567 getModifiedRecords : function(){
21568 return this.modified;
21572 createFilterFn : function(property, value, anyMatch){
21573 if(!value.exec){ // not a regex
21574 value = String(value);
21575 if(value.length == 0){
21578 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21580 return function(r){
21581 return value.test(r.data[property]);
21586 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21587 * @param {String} property A field on your records
21588 * @param {Number} start The record index to start at (defaults to 0)
21589 * @param {Number} end The last record index to include (defaults to length - 1)
21590 * @return {Number} The sum
21592 sum : function(property, start, end){
21593 var rs = this.data.items, v = 0;
21594 start = start || 0;
21595 end = (end || end === 0) ? end : rs.length-1;
21597 for(var i = start; i <= end; i++){
21598 v += (rs[i].data[property] || 0);
21604 * Filter the records by a specified property.
21605 * @param {String} field A field on your records
21606 * @param {String/RegExp} value Either a string that the field
21607 * should start with or a RegExp to test against the field
21608 * @param {Boolean} anyMatch True to match any part not just the beginning
21610 filter : function(property, value, anyMatch){
21611 var fn = this.createFilterFn(property, value, anyMatch);
21612 return fn ? this.filterBy(fn) : this.clearFilter();
21616 * Filter by a function. The specified function will be called with each
21617 * record in this data source. If the function returns true the record is included,
21618 * otherwise it is filtered.
21619 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21620 * @param {Object} scope (optional) The scope of the function (defaults to this)
21622 filterBy : function(fn, scope){
21623 this.snapshot = this.snapshot || this.data;
21624 this.data = this.queryBy(fn, scope||this);
21625 this.fireEvent("datachanged", this);
21629 * Query the records by a specified property.
21630 * @param {String} field A field on your records
21631 * @param {String/RegExp} value Either a string that the field
21632 * should start with or a RegExp to test against the field
21633 * @param {Boolean} anyMatch True to match any part not just the beginning
21634 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21636 query : function(property, value, anyMatch){
21637 var fn = this.createFilterFn(property, value, anyMatch);
21638 return fn ? this.queryBy(fn) : this.data.clone();
21642 * Query by a function. The specified function will be called with each
21643 * record in this data source. If the function returns true the record is included
21645 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21646 * @param {Object} scope (optional) The scope of the function (defaults to this)
21647 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21649 queryBy : function(fn, scope){
21650 var data = this.snapshot || this.data;
21651 return data.filterBy(fn, scope||this);
21655 * Collects unique values for a particular dataIndex from this store.
21656 * @param {String} dataIndex The property to collect
21657 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21658 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21659 * @return {Array} An array of the unique values
21661 collect : function(dataIndex, allowNull, bypassFilter){
21662 var d = (bypassFilter === true && this.snapshot) ?
21663 this.snapshot.items : this.data.items;
21664 var v, sv, r = [], l = {};
21665 for(var i = 0, len = d.length; i < len; i++){
21666 v = d[i].data[dataIndex];
21668 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21677 * Revert to a view of the Record cache with no filtering applied.
21678 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21680 clearFilter : function(suppressEvent){
21681 if(this.snapshot && this.snapshot != this.data){
21682 this.data = this.snapshot;
21683 delete this.snapshot;
21684 if(suppressEvent !== true){
21685 this.fireEvent("datachanged", this);
21691 afterEdit : function(record){
21692 if(this.modified.indexOf(record) == -1){
21693 this.modified.push(record);
21695 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21699 afterReject : function(record){
21700 this.modified.remove(record);
21701 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21705 afterCommit : function(record){
21706 this.modified.remove(record);
21707 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21711 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21712 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21714 commitChanges : function(){
21715 var m = this.modified.slice(0);
21716 this.modified = [];
21717 for(var i = 0, len = m.length; i < len; i++){
21723 * Cancel outstanding changes on all changed records.
21725 rejectChanges : function(){
21726 var m = this.modified.slice(0);
21727 this.modified = [];
21728 for(var i = 0, len = m.length; i < len; i++){
21733 onMetaChange : function(meta, rtype, o){
21734 this.recordType = rtype;
21735 this.fields = rtype.prototype.fields;
21736 delete this.snapshot;
21737 this.sortInfo = meta.sortInfo || this.sortInfo;
21738 this.modified = [];
21739 this.fireEvent('metachange', this, this.reader.meta);
21742 moveIndex : function(data, type)
21744 var index = this.indexOf(data);
21746 var newIndex = index + type;
21750 this.insert(newIndex, data);
21755 * Ext JS Library 1.1.1
21756 * Copyright(c) 2006-2007, Ext JS, LLC.
21758 * Originally Released Under LGPL - original licence link has changed is not relivant.
21761 * <script type="text/javascript">
21765 * @class Roo.data.SimpleStore
21766 * @extends Roo.data.Store
21767 * Small helper class to make creating Stores from Array data easier.
21768 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21769 * @cfg {Array} fields An array of field definition objects, or field name strings.
21770 * @cfg {Array} data The multi-dimensional array of data
21772 * @param {Object} config
21774 Roo.data.SimpleStore = function(config){
21775 Roo.data.SimpleStore.superclass.constructor.call(this, {
21777 reader: new Roo.data.ArrayReader({
21780 Roo.data.Record.create(config.fields)
21782 proxy : new Roo.data.MemoryProxy(config.data)
21786 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21788 * Ext JS Library 1.1.1
21789 * Copyright(c) 2006-2007, Ext JS, LLC.
21791 * Originally Released Under LGPL - original licence link has changed is not relivant.
21794 * <script type="text/javascript">
21799 * @extends Roo.data.Store
21800 * @class Roo.data.JsonStore
21801 * Small helper class to make creating Stores for JSON data easier. <br/>
21803 var store = new Roo.data.JsonStore({
21804 url: 'get-images.php',
21806 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21809 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21810 * JsonReader and HttpProxy (unless inline data is provided).</b>
21811 * @cfg {Array} fields An array of field definition objects, or field name strings.
21813 * @param {Object} config
21815 Roo.data.JsonStore = function(c){
21816 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21817 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21818 reader: new Roo.data.JsonReader(c, c.fields)
21821 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21823 * Ext JS Library 1.1.1
21824 * Copyright(c) 2006-2007, Ext JS, LLC.
21826 * Originally Released Under LGPL - original licence link has changed is not relivant.
21829 * <script type="text/javascript">
21833 Roo.data.Field = function(config){
21834 if(typeof config == "string"){
21835 config = {name: config};
21837 Roo.apply(this, config);
21840 this.type = "auto";
21843 var st = Roo.data.SortTypes;
21844 // named sortTypes are supported, here we look them up
21845 if(typeof this.sortType == "string"){
21846 this.sortType = st[this.sortType];
21849 // set default sortType for strings and dates
21850 if(!this.sortType){
21853 this.sortType = st.asUCString;
21856 this.sortType = st.asDate;
21859 this.sortType = st.none;
21864 var stripRe = /[\$,%]/g;
21866 // prebuilt conversion function for this field, instead of
21867 // switching every time we're reading a value
21869 var cv, dateFormat = this.dateFormat;
21874 cv = function(v){ return v; };
21877 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
21881 return v !== undefined && v !== null && v !== '' ?
21882 parseInt(String(v).replace(stripRe, ""), 10) : '';
21887 return v !== undefined && v !== null && v !== '' ?
21888 parseFloat(String(v).replace(stripRe, ""), 10) : '';
21893 cv = function(v){ return v === true || v === "true" || v == 1; };
21900 if(v instanceof Date){
21904 if(dateFormat == "timestamp"){
21905 return new Date(v*1000);
21907 return Date.parseDate(v, dateFormat);
21909 var parsed = Date.parse(v);
21910 return parsed ? new Date(parsed) : null;
21919 Roo.data.Field.prototype = {
21927 * Ext JS Library 1.1.1
21928 * Copyright(c) 2006-2007, Ext JS, LLC.
21930 * Originally Released Under LGPL - original licence link has changed is not relivant.
21933 * <script type="text/javascript">
21936 // Base class for reading structured data from a data source. This class is intended to be
21937 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
21940 * @class Roo.data.DataReader
21941 * Base class for reading structured data from a data source. This class is intended to be
21942 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
21945 Roo.data.DataReader = function(meta, recordType){
21949 this.recordType = recordType instanceof Array ?
21950 Roo.data.Record.create(recordType) : recordType;
21953 Roo.data.DataReader.prototype = {
21955 * Create an empty record
21956 * @param {Object} data (optional) - overlay some values
21957 * @return {Roo.data.Record} record created.
21959 newRow : function(d) {
21961 this.recordType.prototype.fields.each(function(c) {
21963 case 'int' : da[c.name] = 0; break;
21964 case 'date' : da[c.name] = new Date(); break;
21965 case 'float' : da[c.name] = 0.0; break;
21966 case 'boolean' : da[c.name] = false; break;
21967 default : da[c.name] = ""; break;
21971 return new this.recordType(Roo.apply(da, d));
21976 * Ext JS Library 1.1.1
21977 * Copyright(c) 2006-2007, Ext JS, LLC.
21979 * Originally Released Under LGPL - original licence link has changed is not relivant.
21982 * <script type="text/javascript">
21986 * @class Roo.data.DataProxy
21987 * @extends Roo.data.Observable
21988 * This class is an abstract base class for implementations which provide retrieval of
21989 * unformatted data objects.<br>
21991 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
21992 * (of the appropriate type which knows how to parse the data object) to provide a block of
21993 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
21995 * Custom implementations must implement the load method as described in
21996 * {@link Roo.data.HttpProxy#load}.
21998 Roo.data.DataProxy = function(){
22001 * @event beforeload
22002 * Fires before a network request is made to retrieve a data object.
22003 * @param {Object} This DataProxy object.
22004 * @param {Object} params The params parameter to the load function.
22009 * Fires before the load method's callback is called.
22010 * @param {Object} This DataProxy object.
22011 * @param {Object} o The data object.
22012 * @param {Object} arg The callback argument object passed to the load function.
22016 * @event loadexception
22017 * Fires if an Exception occurs during data retrieval.
22018 * @param {Object} This DataProxy object.
22019 * @param {Object} o The data object.
22020 * @param {Object} arg The callback argument object passed to the load function.
22021 * @param {Object} e The Exception.
22023 loadexception : true
22025 Roo.data.DataProxy.superclass.constructor.call(this);
22028 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22031 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22035 * Ext JS Library 1.1.1
22036 * Copyright(c) 2006-2007, Ext JS, LLC.
22038 * Originally Released Under LGPL - original licence link has changed is not relivant.
22041 * <script type="text/javascript">
22044 * @class Roo.data.MemoryProxy
22045 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22046 * to the Reader when its load method is called.
22048 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22050 Roo.data.MemoryProxy = function(data){
22054 Roo.data.MemoryProxy.superclass.constructor.call(this);
22058 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22060 * Load data from the requested source (in this case an in-memory
22061 * data object passed to the constructor), read the data object into
22062 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22063 * process that block using the passed callback.
22064 * @param {Object} params This parameter is not used by the MemoryProxy class.
22065 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22066 * object into a block of Roo.data.Records.
22067 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22068 * The function must be passed <ul>
22069 * <li>The Record block object</li>
22070 * <li>The "arg" argument from the load function</li>
22071 * <li>A boolean success indicator</li>
22073 * @param {Object} scope The scope in which to call the callback
22074 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22076 load : function(params, reader, callback, scope, arg){
22077 params = params || {};
22080 result = reader.readRecords(this.data);
22082 this.fireEvent("loadexception", this, arg, null, e);
22083 callback.call(scope, null, arg, false);
22086 callback.call(scope, result, arg, true);
22090 update : function(params, records){
22095 * Ext JS Library 1.1.1
22096 * Copyright(c) 2006-2007, Ext JS, LLC.
22098 * Originally Released Under LGPL - original licence link has changed is not relivant.
22101 * <script type="text/javascript">
22104 * @class Roo.data.HttpProxy
22105 * @extends Roo.data.DataProxy
22106 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22107 * configured to reference a certain URL.<br><br>
22109 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22110 * from which the running page was served.<br><br>
22112 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22114 * Be aware that to enable the browser to parse an XML document, the server must set
22115 * the Content-Type header in the HTTP response to "text/xml".
22117 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22118 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22119 * will be used to make the request.
22121 Roo.data.HttpProxy = function(conn){
22122 Roo.data.HttpProxy.superclass.constructor.call(this);
22123 // is conn a conn config or a real conn?
22125 this.useAjax = !conn || !conn.events;
22129 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22130 // thse are take from connection...
22133 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22136 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22137 * extra parameters to each request made by this object. (defaults to undefined)
22140 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22141 * to each request made by this object. (defaults to undefined)
22144 * @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)
22147 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22150 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22156 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22160 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22161 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22162 * a finer-grained basis than the DataProxy events.
22164 getConnection : function(){
22165 return this.useAjax ? Roo.Ajax : this.conn;
22169 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22170 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22171 * process that block using the passed callback.
22172 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22173 * for the request to the remote server.
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 if(this.fireEvent("beforeload", this, params) !== false){
22188 params : params || {},
22190 callback : callback,
22195 callback : this.loadResponse,
22199 Roo.applyIf(o, this.conn);
22200 if(this.activeRequest){
22201 Roo.Ajax.abort(this.activeRequest);
22203 this.activeRequest = Roo.Ajax.request(o);
22205 this.conn.request(o);
22208 callback.call(scope||this, null, arg, false);
22213 loadResponse : function(o, success, response){
22214 delete this.activeRequest;
22216 this.fireEvent("loadexception", this, o, response);
22217 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22222 result = o.reader.read(response);
22224 this.fireEvent("loadexception", this, o, response, e);
22225 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22229 this.fireEvent("load", this, o, o.request.arg);
22230 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22234 update : function(dataSet){
22239 updateResponse : function(dataSet){
22244 * Ext JS Library 1.1.1
22245 * Copyright(c) 2006-2007, Ext JS, LLC.
22247 * Originally Released Under LGPL - original licence link has changed is not relivant.
22250 * <script type="text/javascript">
22254 * @class Roo.data.ScriptTagProxy
22255 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22256 * other than the originating domain of the running page.<br><br>
22258 * <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
22259 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22261 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22262 * source code that is used as the source inside a <script> tag.<br><br>
22264 * In order for the browser to process the returned data, the server must wrap the data object
22265 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22266 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22267 * depending on whether the callback name was passed:
22270 boolean scriptTag = false;
22271 String cb = request.getParameter("callback");
22274 response.setContentType("text/javascript");
22276 response.setContentType("application/x-json");
22278 Writer out = response.getWriter();
22280 out.write(cb + "(");
22282 out.print(dataBlock.toJsonString());
22289 * @param {Object} config A configuration object.
22291 Roo.data.ScriptTagProxy = function(config){
22292 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22293 Roo.apply(this, config);
22294 this.head = document.getElementsByTagName("head")[0];
22297 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22299 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22301 * @cfg {String} url The URL from which to request the data object.
22304 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22308 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22309 * the server the name of the callback function set up by the load call to process the returned data object.
22310 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22311 * javascript output which calls this named function passing the data object as its only parameter.
22313 callbackParam : "callback",
22315 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22316 * name to the request.
22321 * Load data from the configured URL, read the data object into
22322 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22323 * process that block using the passed callback.
22324 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22325 * for the request to the remote server.
22326 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22327 * object into a block of Roo.data.Records.
22328 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22329 * The function must be passed <ul>
22330 * <li>The Record block object</li>
22331 * <li>The "arg" argument from the load function</li>
22332 * <li>A boolean success indicator</li>
22334 * @param {Object} scope The scope in which to call the callback
22335 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22337 load : function(params, reader, callback, scope, arg){
22338 if(this.fireEvent("beforeload", this, params) !== false){
22340 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22342 var url = this.url;
22343 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22345 url += "&_dc=" + (new Date().getTime());
22347 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22350 cb : "stcCallback"+transId,
22351 scriptId : "stcScript"+transId,
22355 callback : callback,
22361 window[trans.cb] = function(o){
22362 conn.handleResponse(o, trans);
22365 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22367 if(this.autoAbort !== false){
22371 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22373 var script = document.createElement("script");
22374 script.setAttribute("src", url);
22375 script.setAttribute("type", "text/javascript");
22376 script.setAttribute("id", trans.scriptId);
22377 this.head.appendChild(script);
22379 this.trans = trans;
22381 callback.call(scope||this, null, arg, false);
22386 isLoading : function(){
22387 return this.trans ? true : false;
22391 * Abort the current server request.
22393 abort : function(){
22394 if(this.isLoading()){
22395 this.destroyTrans(this.trans);
22400 destroyTrans : function(trans, isLoaded){
22401 this.head.removeChild(document.getElementById(trans.scriptId));
22402 clearTimeout(trans.timeoutId);
22404 window[trans.cb] = undefined;
22406 delete window[trans.cb];
22409 // if hasn't been loaded, wait for load to remove it to prevent script error
22410 window[trans.cb] = function(){
22411 window[trans.cb] = undefined;
22413 delete window[trans.cb];
22420 handleResponse : function(o, trans){
22421 this.trans = false;
22422 this.destroyTrans(trans, true);
22425 result = trans.reader.readRecords(o);
22427 this.fireEvent("loadexception", this, o, trans.arg, e);
22428 trans.callback.call(trans.scope||window, null, trans.arg, false);
22431 this.fireEvent("load", this, o, trans.arg);
22432 trans.callback.call(trans.scope||window, result, trans.arg, true);
22436 handleFailure : function(trans){
22437 this.trans = false;
22438 this.destroyTrans(trans, false);
22439 this.fireEvent("loadexception", this, null, trans.arg);
22440 trans.callback.call(trans.scope||window, null, trans.arg, false);
22444 * Ext JS Library 1.1.1
22445 * Copyright(c) 2006-2007, Ext JS, LLC.
22447 * Originally Released Under LGPL - original licence link has changed is not relivant.
22450 * <script type="text/javascript">
22454 * @class Roo.data.JsonReader
22455 * @extends Roo.data.DataReader
22456 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22457 * based on mappings in a provided Roo.data.Record constructor.
22459 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22460 * in the reply previously.
22465 var RecordDef = Roo.data.Record.create([
22466 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22467 {name: 'occupation'} // This field will use "occupation" as the mapping.
22469 var myReader = new Roo.data.JsonReader({
22470 totalProperty: "results", // The property which contains the total dataset size (optional)
22471 root: "rows", // The property which contains an Array of row objects
22472 id: "id" // The property within each row object that provides an ID for the record (optional)
22476 * This would consume a JSON file like this:
22478 { 'results': 2, 'rows': [
22479 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22480 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22483 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22484 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22485 * paged from the remote server.
22486 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22487 * @cfg {String} root name of the property which contains the Array of row objects.
22488 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22490 * Create a new JsonReader
22491 * @param {Object} meta Metadata configuration options
22492 * @param {Object} recordType Either an Array of field definition objects,
22493 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22495 Roo.data.JsonReader = function(meta, recordType){
22498 // set some defaults:
22499 Roo.applyIf(meta, {
22500 totalProperty: 'total',
22501 successProperty : 'success',
22506 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22508 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22511 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22512 * Used by Store query builder to append _requestMeta to params.
22515 metaFromRemote : false,
22517 * This method is only used by a DataProxy which has retrieved data from a remote server.
22518 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22519 * @return {Object} data A data block which is used by an Roo.data.Store object as
22520 * a cache of Roo.data.Records.
22522 read : function(response){
22523 var json = response.responseText;
22525 var o = /* eval:var:o */ eval("("+json+")");
22527 throw {message: "JsonReader.read: Json object not found"};
22533 this.metaFromRemote = true;
22534 this.meta = o.metaData;
22535 this.recordType = Roo.data.Record.create(o.metaData.fields);
22536 this.onMetaChange(this.meta, this.recordType, o);
22538 return this.readRecords(o);
22541 // private function a store will implement
22542 onMetaChange : function(meta, recordType, o){
22549 simpleAccess: function(obj, subsc) {
22556 getJsonAccessor: function(){
22558 return function(expr) {
22560 return(re.test(expr))
22561 ? new Function("obj", "return obj." + expr)
22566 return Roo.emptyFn;
22571 * Create a data block containing Roo.data.Records from an XML document.
22572 * @param {Object} o An object which contains an Array of row objects in the property specified
22573 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22574 * which contains the total size of the dataset.
22575 * @return {Object} data A data block which is used by an Roo.data.Store object as
22576 * a cache of Roo.data.Records.
22578 readRecords : function(o){
22580 * After any data loads, the raw JSON data is available for further custom processing.
22584 var s = this.meta, Record = this.recordType,
22585 f = Record.prototype.fields, fi = f.items, fl = f.length;
22587 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22589 if(s.totalProperty) {
22590 this.getTotal = this.getJsonAccessor(s.totalProperty);
22592 if(s.successProperty) {
22593 this.getSuccess = this.getJsonAccessor(s.successProperty);
22595 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22597 var g = this.getJsonAccessor(s.id);
22598 this.getId = function(rec) {
22600 return (r === undefined || r === "") ? null : r;
22603 this.getId = function(){return null;};
22606 for(var jj = 0; jj < fl; jj++){
22608 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22609 this.ef[jj] = this.getJsonAccessor(map);
22613 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22614 if(s.totalProperty){
22615 var vt = parseInt(this.getTotal(o), 10);
22620 if(s.successProperty){
22621 var vs = this.getSuccess(o);
22622 if(vs === false || vs === 'false'){
22627 for(var i = 0; i < c; i++){
22630 var id = this.getId(n);
22631 for(var j = 0; j < fl; j++){
22633 var v = this.ef[j](n);
22635 Roo.log('missing convert for ' + f.name);
22639 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22641 var record = new Record(values, id);
22643 records[i] = record;
22649 totalRecords : totalRecords
22654 * Ext JS Library 1.1.1
22655 * Copyright(c) 2006-2007, Ext JS, LLC.
22657 * Originally Released Under LGPL - original licence link has changed is not relivant.
22660 * <script type="text/javascript">
22664 * @class Roo.data.XmlReader
22665 * @extends Roo.data.DataReader
22666 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22667 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22669 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22670 * header in the HTTP response must be set to "text/xml".</em>
22674 var RecordDef = Roo.data.Record.create([
22675 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22676 {name: 'occupation'} // This field will use "occupation" as the mapping.
22678 var myReader = new Roo.data.XmlReader({
22679 totalRecords: "results", // The element which contains the total dataset size (optional)
22680 record: "row", // The repeated element which contains row information
22681 id: "id" // The element within the row that provides an ID for the record (optional)
22685 * This would consume an XML file like this:
22689 <results>2</results>
22692 <name>Bill</name>
22693 <occupation>Gardener</occupation>
22697 <name>Ben</name>
22698 <occupation>Horticulturalist</occupation>
22702 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22703 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22704 * paged from the remote server.
22705 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22706 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22707 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22708 * a record identifier value.
22710 * Create a new XmlReader
22711 * @param {Object} meta Metadata configuration options
22712 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22713 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22714 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22716 Roo.data.XmlReader = function(meta, recordType){
22718 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22720 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22722 * This method is only used by a DataProxy which has retrieved data from a remote server.
22723 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22724 * to contain a method called 'responseXML' that returns an XML document object.
22725 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22726 * a cache of Roo.data.Records.
22728 read : function(response){
22729 var doc = response.responseXML;
22731 throw {message: "XmlReader.read: XML Document not available"};
22733 return this.readRecords(doc);
22737 * Create a data block containing Roo.data.Records from an XML document.
22738 * @param {Object} doc A parsed XML document.
22739 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22740 * a cache of Roo.data.Records.
22742 readRecords : function(doc){
22744 * After any data loads/reads, the raw XML Document is available for further custom processing.
22745 * @type XMLDocument
22747 this.xmlData = doc;
22748 var root = doc.documentElement || doc;
22749 var q = Roo.DomQuery;
22750 var recordType = this.recordType, fields = recordType.prototype.fields;
22751 var sid = this.meta.id;
22752 var totalRecords = 0, success = true;
22753 if(this.meta.totalRecords){
22754 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22757 if(this.meta.success){
22758 var sv = q.selectValue(this.meta.success, root, true);
22759 success = sv !== false && sv !== 'false';
22762 var ns = q.select(this.meta.record, root);
22763 for(var i = 0, len = ns.length; i < len; i++) {
22766 var id = sid ? q.selectValue(sid, n) : undefined;
22767 for(var j = 0, jlen = fields.length; j < jlen; j++){
22768 var f = fields.items[j];
22769 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22771 values[f.name] = v;
22773 var record = new recordType(values, id);
22775 records[records.length] = record;
22781 totalRecords : totalRecords || records.length
22786 * Ext JS Library 1.1.1
22787 * Copyright(c) 2006-2007, Ext JS, LLC.
22789 * Originally Released Under LGPL - original licence link has changed is not relivant.
22792 * <script type="text/javascript">
22796 * @class Roo.data.ArrayReader
22797 * @extends Roo.data.DataReader
22798 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22799 * Each element of that Array represents a row of data fields. The
22800 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22801 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22805 var RecordDef = Roo.data.Record.create([
22806 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22807 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22809 var myReader = new Roo.data.ArrayReader({
22810 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22814 * This would consume an Array like this:
22816 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22818 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22820 * Create a new JsonReader
22821 * @param {Object} meta Metadata configuration options.
22822 * @param {Object} recordType Either an Array of field definition objects
22823 * as specified to {@link Roo.data.Record#create},
22824 * or an {@link Roo.data.Record} object
22825 * created using {@link Roo.data.Record#create}.
22827 Roo.data.ArrayReader = function(meta, recordType){
22828 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22831 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22833 * Create a data block containing Roo.data.Records from an XML document.
22834 * @param {Object} o An Array of row objects which represents the dataset.
22835 * @return {Object} data A data block which is used by an Roo.data.Store object as
22836 * a cache of Roo.data.Records.
22838 readRecords : function(o){
22839 var sid = this.meta ? this.meta.id : null;
22840 var recordType = this.recordType, fields = recordType.prototype.fields;
22843 for(var i = 0; i < root.length; i++){
22846 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22847 for(var j = 0, jlen = fields.length; j < jlen; j++){
22848 var f = fields.items[j];
22849 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22850 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22852 values[f.name] = v;
22854 var record = new recordType(values, id);
22856 records[records.length] = record;
22860 totalRecords : records.length
22865 * Ext JS Library 1.1.1
22866 * Copyright(c) 2006-2007, Ext JS, LLC.
22868 * Originally Released Under LGPL - original licence link has changed is not relivant.
22871 * <script type="text/javascript">
22876 * @class Roo.data.Tree
22877 * @extends Roo.util.Observable
22878 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
22879 * in the tree have most standard DOM functionality.
22881 * @param {Node} root (optional) The root node
22883 Roo.data.Tree = function(root){
22884 this.nodeHash = {};
22886 * The root node for this tree
22891 this.setRootNode(root);
22896 * Fires when a new child node is appended to a node in this tree.
22897 * @param {Tree} tree The owner tree
22898 * @param {Node} parent The parent node
22899 * @param {Node} node The newly appended node
22900 * @param {Number} index The index of the newly appended node
22905 * Fires when a child node is removed from a node in this tree.
22906 * @param {Tree} tree The owner tree
22907 * @param {Node} parent The parent node
22908 * @param {Node} node The child node removed
22913 * Fires when a node is moved to a new location in the tree
22914 * @param {Tree} tree The owner tree
22915 * @param {Node} node The node moved
22916 * @param {Node} oldParent The old parent of this node
22917 * @param {Node} newParent The new parent of this node
22918 * @param {Number} index The index it was moved to
22923 * Fires when a new child node is inserted in a node in this tree.
22924 * @param {Tree} tree The owner tree
22925 * @param {Node} parent The parent node
22926 * @param {Node} node The child node inserted
22927 * @param {Node} refNode The child node the node was inserted before
22931 * @event beforeappend
22932 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
22933 * @param {Tree} tree The owner tree
22934 * @param {Node} parent The parent node
22935 * @param {Node} node The child node to be appended
22937 "beforeappend" : true,
22939 * @event beforeremove
22940 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
22941 * @param {Tree} tree The owner tree
22942 * @param {Node} parent The parent node
22943 * @param {Node} node The child node to be removed
22945 "beforeremove" : true,
22947 * @event beforemove
22948 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
22949 * @param {Tree} tree The owner tree
22950 * @param {Node} node The node being moved
22951 * @param {Node} oldParent The parent of the node
22952 * @param {Node} newParent The new parent the node is moving to
22953 * @param {Number} index The index it is being moved to
22955 "beforemove" : true,
22957 * @event beforeinsert
22958 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
22959 * @param {Tree} tree The owner tree
22960 * @param {Node} parent The parent node
22961 * @param {Node} node The child node to be inserted
22962 * @param {Node} refNode The child node the node is being inserted before
22964 "beforeinsert" : true
22967 Roo.data.Tree.superclass.constructor.call(this);
22970 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
22971 pathSeparator: "/",
22973 proxyNodeEvent : function(){
22974 return this.fireEvent.apply(this, arguments);
22978 * Returns the root node for this tree.
22981 getRootNode : function(){
22986 * Sets the root node for this tree.
22987 * @param {Node} node
22990 setRootNode : function(node){
22992 node.ownerTree = this;
22993 node.isRoot = true;
22994 this.registerNode(node);
22999 * Gets a node in this tree by its id.
23000 * @param {String} id
23003 getNodeById : function(id){
23004 return this.nodeHash[id];
23007 registerNode : function(node){
23008 this.nodeHash[node.id] = node;
23011 unregisterNode : function(node){
23012 delete this.nodeHash[node.id];
23015 toString : function(){
23016 return "[Tree"+(this.id?" "+this.id:"")+"]";
23021 * @class Roo.data.Node
23022 * @extends Roo.util.Observable
23023 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23024 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23026 * @param {Object} attributes The attributes/config for the node
23028 Roo.data.Node = function(attributes){
23030 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23033 this.attributes = attributes || {};
23034 this.leaf = this.attributes.leaf;
23036 * The node id. @type String
23038 this.id = this.attributes.id;
23040 this.id = Roo.id(null, "ynode-");
23041 this.attributes.id = this.id;
23046 * All child nodes of this node. @type Array
23048 this.childNodes = [];
23049 if(!this.childNodes.indexOf){ // indexOf is a must
23050 this.childNodes.indexOf = function(o){
23051 for(var i = 0, len = this.length; i < len; i++){
23060 * The parent node for this node. @type Node
23062 this.parentNode = null;
23064 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23066 this.firstChild = null;
23068 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23070 this.lastChild = null;
23072 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23074 this.previousSibling = null;
23076 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23078 this.nextSibling = null;
23083 * Fires when a new child node is appended
23084 * @param {Tree} tree The owner tree
23085 * @param {Node} this This node
23086 * @param {Node} node The newly appended node
23087 * @param {Number} index The index of the newly appended node
23092 * Fires when a child node is removed
23093 * @param {Tree} tree The owner tree
23094 * @param {Node} this This node
23095 * @param {Node} node The removed node
23100 * Fires when this node is moved to a new location in the tree
23101 * @param {Tree} tree The owner tree
23102 * @param {Node} this This node
23103 * @param {Node} oldParent The old parent of this node
23104 * @param {Node} newParent The new parent of this node
23105 * @param {Number} index The index it was moved to
23110 * Fires when a new child node is inserted.
23111 * @param {Tree} tree The owner tree
23112 * @param {Node} this This node
23113 * @param {Node} node The child node inserted
23114 * @param {Node} refNode The child node the node was inserted before
23118 * @event beforeappend
23119 * Fires before a new child is appended, return false to cancel the append.
23120 * @param {Tree} tree The owner tree
23121 * @param {Node} this This node
23122 * @param {Node} node The child node to be appended
23124 "beforeappend" : true,
23126 * @event beforeremove
23127 * Fires before a child is removed, return false to cancel the remove.
23128 * @param {Tree} tree The owner tree
23129 * @param {Node} this This node
23130 * @param {Node} node The child node to be removed
23132 "beforeremove" : true,
23134 * @event beforemove
23135 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23136 * @param {Tree} tree The owner tree
23137 * @param {Node} this This node
23138 * @param {Node} oldParent The parent of this node
23139 * @param {Node} newParent The new parent this node is moving to
23140 * @param {Number} index The index it is being moved to
23142 "beforemove" : true,
23144 * @event beforeinsert
23145 * Fires before a new child is inserted, return false to cancel the insert.
23146 * @param {Tree} tree The owner tree
23147 * @param {Node} this This node
23148 * @param {Node} node The child node to be inserted
23149 * @param {Node} refNode The child node the node is being inserted before
23151 "beforeinsert" : true
23153 this.listeners = this.attributes.listeners;
23154 Roo.data.Node.superclass.constructor.call(this);
23157 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23158 fireEvent : function(evtName){
23159 // first do standard event for this node
23160 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23163 // then bubble it up to the tree if the event wasn't cancelled
23164 var ot = this.getOwnerTree();
23166 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23174 * Returns true if this node is a leaf
23175 * @return {Boolean}
23177 isLeaf : function(){
23178 return this.leaf === true;
23182 setFirstChild : function(node){
23183 this.firstChild = node;
23187 setLastChild : function(node){
23188 this.lastChild = node;
23193 * Returns true if this node is the last child of its parent
23194 * @return {Boolean}
23196 isLast : function(){
23197 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23201 * Returns true if this node is the first child of its parent
23202 * @return {Boolean}
23204 isFirst : function(){
23205 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23208 hasChildNodes : function(){
23209 return !this.isLeaf() && this.childNodes.length > 0;
23213 * Insert node(s) as the last child node of this node.
23214 * @param {Node/Array} node The node or Array of nodes to append
23215 * @return {Node} The appended node if single append, or null if an array was passed
23217 appendChild : function(node){
23219 if(node instanceof Array){
23221 }else if(arguments.length > 1){
23224 // if passed an array or multiple args do them one by one
23226 for(var i = 0, len = multi.length; i < len; i++) {
23227 this.appendChild(multi[i]);
23230 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23233 var index = this.childNodes.length;
23234 var oldParent = node.parentNode;
23235 // it's a move, make sure we move it cleanly
23237 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23240 oldParent.removeChild(node);
23242 index = this.childNodes.length;
23244 this.setFirstChild(node);
23246 this.childNodes.push(node);
23247 node.parentNode = this;
23248 var ps = this.childNodes[index-1];
23250 node.previousSibling = ps;
23251 ps.nextSibling = node;
23253 node.previousSibling = null;
23255 node.nextSibling = null;
23256 this.setLastChild(node);
23257 node.setOwnerTree(this.getOwnerTree());
23258 this.fireEvent("append", this.ownerTree, this, node, index);
23260 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23267 * Removes a child node from this node.
23268 * @param {Node} node The node to remove
23269 * @return {Node} The removed node
23271 removeChild : function(node){
23272 var index = this.childNodes.indexOf(node);
23276 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23280 // remove it from childNodes collection
23281 this.childNodes.splice(index, 1);
23284 if(node.previousSibling){
23285 node.previousSibling.nextSibling = node.nextSibling;
23287 if(node.nextSibling){
23288 node.nextSibling.previousSibling = node.previousSibling;
23291 // update child refs
23292 if(this.firstChild == node){
23293 this.setFirstChild(node.nextSibling);
23295 if(this.lastChild == node){
23296 this.setLastChild(node.previousSibling);
23299 node.setOwnerTree(null);
23300 // clear any references from the node
23301 node.parentNode = null;
23302 node.previousSibling = null;
23303 node.nextSibling = null;
23304 this.fireEvent("remove", this.ownerTree, this, node);
23309 * Inserts the first node before the second node in this nodes childNodes collection.
23310 * @param {Node} node The node to insert
23311 * @param {Node} refNode The node to insert before (if null the node is appended)
23312 * @return {Node} The inserted node
23314 insertBefore : function(node, refNode){
23315 if(!refNode){ // like standard Dom, refNode can be null for append
23316 return this.appendChild(node);
23319 if(node == refNode){
23323 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23326 var index = this.childNodes.indexOf(refNode);
23327 var oldParent = node.parentNode;
23328 var refIndex = index;
23330 // when moving internally, indexes will change after remove
23331 if(oldParent == this && this.childNodes.indexOf(node) < index){
23335 // it's a move, make sure we move it cleanly
23337 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23340 oldParent.removeChild(node);
23343 this.setFirstChild(node);
23345 this.childNodes.splice(refIndex, 0, node);
23346 node.parentNode = this;
23347 var ps = this.childNodes[refIndex-1];
23349 node.previousSibling = ps;
23350 ps.nextSibling = node;
23352 node.previousSibling = null;
23354 node.nextSibling = refNode;
23355 refNode.previousSibling = node;
23356 node.setOwnerTree(this.getOwnerTree());
23357 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23359 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23365 * Returns the child node at the specified index.
23366 * @param {Number} index
23369 item : function(index){
23370 return this.childNodes[index];
23374 * Replaces one child node in this node with another.
23375 * @param {Node} newChild The replacement node
23376 * @param {Node} oldChild The node to replace
23377 * @return {Node} The replaced node
23379 replaceChild : function(newChild, oldChild){
23380 this.insertBefore(newChild, oldChild);
23381 this.removeChild(oldChild);
23386 * Returns the index of a child node
23387 * @param {Node} node
23388 * @return {Number} The index of the node or -1 if it was not found
23390 indexOf : function(child){
23391 return this.childNodes.indexOf(child);
23395 * Returns the tree this node is in.
23398 getOwnerTree : function(){
23399 // if it doesn't have one, look for one
23400 if(!this.ownerTree){
23404 this.ownerTree = p.ownerTree;
23410 return this.ownerTree;
23414 * Returns depth of this node (the root node has a depth of 0)
23417 getDepth : function(){
23420 while(p.parentNode){
23428 setOwnerTree : function(tree){
23429 // if it's move, we need to update everyone
23430 if(tree != this.ownerTree){
23431 if(this.ownerTree){
23432 this.ownerTree.unregisterNode(this);
23434 this.ownerTree = tree;
23435 var cs = this.childNodes;
23436 for(var i = 0, len = cs.length; i < len; i++) {
23437 cs[i].setOwnerTree(tree);
23440 tree.registerNode(this);
23446 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23447 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23448 * @return {String} The path
23450 getPath : function(attr){
23451 attr = attr || "id";
23452 var p = this.parentNode;
23453 var b = [this.attributes[attr]];
23455 b.unshift(p.attributes[attr]);
23458 var sep = this.getOwnerTree().pathSeparator;
23459 return sep + b.join(sep);
23463 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23464 * function call will be the scope provided or the current node. The arguments to the function
23465 * will be the args provided or the current node. If the function returns false at any point,
23466 * the bubble is stopped.
23467 * @param {Function} fn The function to call
23468 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23469 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23471 bubble : function(fn, scope, args){
23474 if(fn.call(scope || p, args || p) === false){
23482 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23483 * function call will be the scope provided or the current node. The arguments to the function
23484 * will be the args provided or the current node. If the function returns false at any point,
23485 * the cascade is stopped on that branch.
23486 * @param {Function} fn The function to call
23487 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23488 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23490 cascade : function(fn, scope, args){
23491 if(fn.call(scope || this, args || this) !== false){
23492 var cs = this.childNodes;
23493 for(var i = 0, len = cs.length; i < len; i++) {
23494 cs[i].cascade(fn, scope, args);
23500 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23501 * function call will be the scope provided or the current node. The arguments to the function
23502 * will be the args provided or the current node. If the function returns false at any point,
23503 * the iteration stops.
23504 * @param {Function} fn The function to call
23505 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23506 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23508 eachChild : function(fn, scope, args){
23509 var cs = this.childNodes;
23510 for(var i = 0, len = cs.length; i < len; i++) {
23511 if(fn.call(scope || this, args || cs[i]) === false){
23518 * Finds the first child that has the attribute with the specified value.
23519 * @param {String} attribute The attribute name
23520 * @param {Mixed} value The value to search for
23521 * @return {Node} The found child or null if none was found
23523 findChild : function(attribute, value){
23524 var cs = this.childNodes;
23525 for(var i = 0, len = cs.length; i < len; i++) {
23526 if(cs[i].attributes[attribute] == value){
23534 * Finds the first child by a custom function. The child matches if the function passed
23536 * @param {Function} fn
23537 * @param {Object} scope (optional)
23538 * @return {Node} The found child or null if none was found
23540 findChildBy : function(fn, scope){
23541 var cs = this.childNodes;
23542 for(var i = 0, len = cs.length; i < len; i++) {
23543 if(fn.call(scope||cs[i], cs[i]) === true){
23551 * Sorts this nodes children using the supplied sort function
23552 * @param {Function} fn
23553 * @param {Object} scope (optional)
23555 sort : function(fn, scope){
23556 var cs = this.childNodes;
23557 var len = cs.length;
23559 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23561 for(var i = 0; i < len; i++){
23563 n.previousSibling = cs[i-1];
23564 n.nextSibling = cs[i+1];
23566 this.setFirstChild(n);
23569 this.setLastChild(n);
23576 * Returns true if this node is an ancestor (at any point) of the passed node.
23577 * @param {Node} node
23578 * @return {Boolean}
23580 contains : function(node){
23581 return node.isAncestor(this);
23585 * Returns true if the passed node is an ancestor (at any point) of this node.
23586 * @param {Node} node
23587 * @return {Boolean}
23589 isAncestor : function(node){
23590 var p = this.parentNode;
23600 toString : function(){
23601 return "[Node"+(this.id?" "+this.id:"")+"]";
23605 * Ext JS Library 1.1.1
23606 * Copyright(c) 2006-2007, Ext JS, LLC.
23608 * Originally Released Under LGPL - original licence link has changed is not relivant.
23611 * <script type="text/javascript">
23616 * @extends Roo.Element
23617 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23618 * automatic maintaining of shadow/shim positions.
23619 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23620 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23621 * you can pass a string with a CSS class name. False turns off the shadow.
23622 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23623 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23624 * @cfg {String} cls CSS class to add to the element
23625 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23626 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23628 * @param {Object} config An object with config options.
23629 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23632 Roo.Layer = function(config, existingEl){
23633 config = config || {};
23634 var dh = Roo.DomHelper;
23635 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23637 this.dom = Roo.getDom(existingEl);
23640 var o = config.dh || {tag: "div", cls: "x-layer"};
23641 this.dom = dh.append(pel, o);
23644 this.addClass(config.cls);
23646 this.constrain = config.constrain !== false;
23647 this.visibilityMode = Roo.Element.VISIBILITY;
23649 this.id = this.dom.id = config.id;
23651 this.id = Roo.id(this.dom);
23653 this.zindex = config.zindex || this.getZIndex();
23654 this.position("absolute", this.zindex);
23656 this.shadowOffset = config.shadowOffset || 4;
23657 this.shadow = new Roo.Shadow({
23658 offset : this.shadowOffset,
23659 mode : config.shadow
23662 this.shadowOffset = 0;
23664 this.useShim = config.shim !== false && Roo.useShims;
23665 this.useDisplay = config.useDisplay;
23669 var supr = Roo.Element.prototype;
23671 // shims are shared among layer to keep from having 100 iframes
23674 Roo.extend(Roo.Layer, Roo.Element, {
23676 getZIndex : function(){
23677 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23680 getShim : function(){
23687 var shim = shims.shift();
23689 shim = this.createShim();
23690 shim.enableDisplayMode('block');
23691 shim.dom.style.display = 'none';
23692 shim.dom.style.visibility = 'visible';
23694 var pn = this.dom.parentNode;
23695 if(shim.dom.parentNode != pn){
23696 pn.insertBefore(shim.dom, this.dom);
23698 shim.setStyle('z-index', this.getZIndex()-2);
23703 hideShim : function(){
23705 this.shim.setDisplayed(false);
23706 shims.push(this.shim);
23711 disableShadow : function(){
23713 this.shadowDisabled = true;
23714 this.shadow.hide();
23715 this.lastShadowOffset = this.shadowOffset;
23716 this.shadowOffset = 0;
23720 enableShadow : function(show){
23722 this.shadowDisabled = false;
23723 this.shadowOffset = this.lastShadowOffset;
23724 delete this.lastShadowOffset;
23732 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23733 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23734 sync : function(doShow){
23735 var sw = this.shadow;
23736 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23737 var sh = this.getShim();
23739 var w = this.getWidth(),
23740 h = this.getHeight();
23742 var l = this.getLeft(true),
23743 t = this.getTop(true);
23745 if(sw && !this.shadowDisabled){
23746 if(doShow && !sw.isVisible()){
23749 sw.realign(l, t, w, h);
23755 // fit the shim behind the shadow, so it is shimmed too
23756 var a = sw.adjusts, s = sh.dom.style;
23757 s.left = (Math.min(l, l+a.l))+"px";
23758 s.top = (Math.min(t, t+a.t))+"px";
23759 s.width = (w+a.w)+"px";
23760 s.height = (h+a.h)+"px";
23767 sh.setLeftTop(l, t);
23774 destroy : function(){
23777 this.shadow.hide();
23779 this.removeAllListeners();
23780 var pn = this.dom.parentNode;
23782 pn.removeChild(this.dom);
23784 Roo.Element.uncache(this.id);
23787 remove : function(){
23792 beginUpdate : function(){
23793 this.updating = true;
23797 endUpdate : function(){
23798 this.updating = false;
23803 hideUnders : function(negOffset){
23805 this.shadow.hide();
23811 constrainXY : function(){
23812 if(this.constrain){
23813 var vw = Roo.lib.Dom.getViewWidth(),
23814 vh = Roo.lib.Dom.getViewHeight();
23815 var s = Roo.get(document).getScroll();
23817 var xy = this.getXY();
23818 var x = xy[0], y = xy[1];
23819 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23820 // only move it if it needs it
23822 // first validate right/bottom
23823 if((x + w) > vw+s.left){
23824 x = vw - w - this.shadowOffset;
23827 if((y + h) > vh+s.top){
23828 y = vh - h - this.shadowOffset;
23831 // then make sure top/left isn't negative
23842 var ay = this.avoidY;
23843 if(y <= ay && (y+h) >= ay){
23849 supr.setXY.call(this, xy);
23855 isVisible : function(){
23856 return this.visible;
23860 showAction : function(){
23861 this.visible = true; // track visibility to prevent getStyle calls
23862 if(this.useDisplay === true){
23863 this.setDisplayed("");
23864 }else if(this.lastXY){
23865 supr.setXY.call(this, this.lastXY);
23866 }else if(this.lastLT){
23867 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23872 hideAction : function(){
23873 this.visible = false;
23874 if(this.useDisplay === true){
23875 this.setDisplayed(false);
23877 this.setLeftTop(-10000,-10000);
23881 // overridden Element method
23882 setVisible : function(v, a, d, c, e){
23887 var cb = function(){
23892 }.createDelegate(this);
23893 supr.setVisible.call(this, true, true, d, cb, e);
23896 this.hideUnders(true);
23905 }.createDelegate(this);
23907 supr.setVisible.call(this, v, a, d, cb, e);
23916 storeXY : function(xy){
23917 delete this.lastLT;
23921 storeLeftTop : function(left, top){
23922 delete this.lastXY;
23923 this.lastLT = [left, top];
23927 beforeFx : function(){
23928 this.beforeAction();
23929 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23933 afterFx : function(){
23934 Roo.Layer.superclass.afterFx.apply(this, arguments);
23935 this.sync(this.isVisible());
23939 beforeAction : function(){
23940 if(!this.updating && this.shadow){
23941 this.shadow.hide();
23945 // overridden Element method
23946 setLeft : function(left){
23947 this.storeLeftTop(left, this.getTop(true));
23948 supr.setLeft.apply(this, arguments);
23952 setTop : function(top){
23953 this.storeLeftTop(this.getLeft(true), top);
23954 supr.setTop.apply(this, arguments);
23958 setLeftTop : function(left, top){
23959 this.storeLeftTop(left, top);
23960 supr.setLeftTop.apply(this, arguments);
23964 setXY : function(xy, a, d, c, e){
23966 this.beforeAction();
23968 var cb = this.createCB(c);
23969 supr.setXY.call(this, xy, a, d, cb, e);
23976 createCB : function(c){
23987 // overridden Element method
23988 setX : function(x, a, d, c, e){
23989 this.setXY([x, this.getY()], a, d, c, e);
23992 // overridden Element method
23993 setY : function(y, a, d, c, e){
23994 this.setXY([this.getX(), y], a, d, c, e);
23997 // overridden Element method
23998 setSize : function(w, h, a, d, c, e){
23999 this.beforeAction();
24000 var cb = this.createCB(c);
24001 supr.setSize.call(this, w, h, a, d, cb, e);
24007 // overridden Element method
24008 setWidth : function(w, a, d, c, e){
24009 this.beforeAction();
24010 var cb = this.createCB(c);
24011 supr.setWidth.call(this, w, a, d, cb, e);
24017 // overridden Element method
24018 setHeight : function(h, a, d, c, e){
24019 this.beforeAction();
24020 var cb = this.createCB(c);
24021 supr.setHeight.call(this, h, a, d, cb, e);
24027 // overridden Element method
24028 setBounds : function(x, y, w, h, a, d, c, e){
24029 this.beforeAction();
24030 var cb = this.createCB(c);
24032 this.storeXY([x, y]);
24033 supr.setXY.call(this, [x, y]);
24034 supr.setSize.call(this, w, h, a, d, cb, e);
24037 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24043 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24044 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24045 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24046 * @param {Number} zindex The new z-index to set
24047 * @return {this} The Layer
24049 setZIndex : function(zindex){
24050 this.zindex = zindex;
24051 this.setStyle("z-index", zindex + 2);
24053 this.shadow.setZIndex(zindex + 1);
24056 this.shim.setStyle("z-index", zindex);
24062 * Ext JS Library 1.1.1
24063 * Copyright(c) 2006-2007, Ext JS, LLC.
24065 * Originally Released Under LGPL - original licence link has changed is not relivant.
24068 * <script type="text/javascript">
24073 * @class Roo.Shadow
24074 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24075 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24076 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24078 * Create a new Shadow
24079 * @param {Object} config The config object
24081 Roo.Shadow = function(config){
24082 Roo.apply(this, config);
24083 if(typeof this.mode != "string"){
24084 this.mode = this.defaultMode;
24086 var o = this.offset, a = {h: 0};
24087 var rad = Math.floor(this.offset/2);
24088 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24094 a.l -= this.offset + rad;
24095 a.t -= this.offset + rad;
24106 a.l -= (this.offset - rad);
24107 a.t -= this.offset + rad;
24109 a.w -= (this.offset - rad)*2;
24120 a.l -= (this.offset - rad);
24121 a.t -= (this.offset - rad);
24123 a.w -= (this.offset + rad + 1);
24124 a.h -= (this.offset + rad);
24133 Roo.Shadow.prototype = {
24135 * @cfg {String} mode
24136 * The shadow display mode. Supports the following options:<br />
24137 * sides: Shadow displays on both sides and bottom only<br />
24138 * frame: Shadow displays equally on all four sides<br />
24139 * drop: Traditional bottom-right drop shadow (default)
24142 * @cfg {String} offset
24143 * The number of pixels to offset the shadow from the element (defaults to 4)
24148 defaultMode: "drop",
24151 * Displays the shadow under the target element
24152 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24154 show : function(target){
24155 target = Roo.get(target);
24157 this.el = Roo.Shadow.Pool.pull();
24158 if(this.el.dom.nextSibling != target.dom){
24159 this.el.insertBefore(target);
24162 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24164 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24167 target.getLeft(true),
24168 target.getTop(true),
24172 this.el.dom.style.display = "block";
24176 * Returns true if the shadow is visible, else false
24178 isVisible : function(){
24179 return this.el ? true : false;
24183 * Direct alignment when values are already available. Show must be called at least once before
24184 * calling this method to ensure it is initialized.
24185 * @param {Number} left The target element left position
24186 * @param {Number} top The target element top position
24187 * @param {Number} width The target element width
24188 * @param {Number} height The target element height
24190 realign : function(l, t, w, h){
24194 var a = this.adjusts, d = this.el.dom, s = d.style;
24196 s.left = (l+a.l)+"px";
24197 s.top = (t+a.t)+"px";
24198 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24200 if(s.width != sws || s.height != shs){
24204 var cn = d.childNodes;
24205 var sww = Math.max(0, (sw-12))+"px";
24206 cn[0].childNodes[1].style.width = sww;
24207 cn[1].childNodes[1].style.width = sww;
24208 cn[2].childNodes[1].style.width = sww;
24209 cn[1].style.height = Math.max(0, (sh-12))+"px";
24215 * Hides this shadow
24219 this.el.dom.style.display = "none";
24220 Roo.Shadow.Pool.push(this.el);
24226 * Adjust the z-index of this shadow
24227 * @param {Number} zindex The new z-index
24229 setZIndex : function(z){
24232 this.el.setStyle("z-index", z);
24237 // Private utility class that manages the internal Shadow cache
24238 Roo.Shadow.Pool = function(){
24240 var markup = Roo.isIE ?
24241 '<div class="x-ie-shadow"></div>' :
24242 '<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>';
24245 var sh = p.shift();
24247 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24248 sh.autoBoxAdjust = false;
24253 push : function(sh){
24259 * Ext JS Library 1.1.1
24260 * Copyright(c) 2006-2007, Ext JS, LLC.
24262 * Originally Released Under LGPL - original licence link has changed is not relivant.
24265 * <script type="text/javascript">
24270 * @class Roo.SplitBar
24271 * @extends Roo.util.Observable
24272 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24276 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24277 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24278 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24279 split.minSize = 100;
24280 split.maxSize = 600;
24281 split.animate = true;
24282 split.on('moved', splitterMoved);
24285 * Create a new SplitBar
24286 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24287 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24288 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24289 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24290 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24291 position of the SplitBar).
24293 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24296 this.el = Roo.get(dragElement, true);
24297 this.el.dom.unselectable = "on";
24299 this.resizingEl = Roo.get(resizingElement, true);
24303 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24304 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24307 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24310 * The minimum size of the resizing element. (Defaults to 0)
24316 * The maximum size of the resizing element. (Defaults to 2000)
24319 this.maxSize = 2000;
24322 * Whether to animate the transition to the new size
24325 this.animate = false;
24328 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24331 this.useShim = false;
24336 if(!existingProxy){
24338 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24340 this.proxy = Roo.get(existingProxy).dom;
24343 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24346 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24349 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24352 this.dragSpecs = {};
24355 * @private The adapter to use to positon and resize elements
24357 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24358 this.adapter.init(this);
24360 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24362 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24363 this.el.addClass("x-splitbar-h");
24366 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24367 this.el.addClass("x-splitbar-v");
24373 * Fires when the splitter is moved (alias for {@link #event-moved})
24374 * @param {Roo.SplitBar} this
24375 * @param {Number} newSize the new width or height
24380 * Fires when the splitter is moved
24381 * @param {Roo.SplitBar} this
24382 * @param {Number} newSize the new width or height
24386 * @event beforeresize
24387 * Fires before the splitter is dragged
24388 * @param {Roo.SplitBar} this
24390 "beforeresize" : true,
24392 "beforeapply" : true
24395 Roo.util.Observable.call(this);
24398 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24399 onStartProxyDrag : function(x, y){
24400 this.fireEvent("beforeresize", this);
24402 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24404 o.enableDisplayMode("block");
24405 // all splitbars share the same overlay
24406 Roo.SplitBar.prototype.overlay = o;
24408 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24409 this.overlay.show();
24410 Roo.get(this.proxy).setDisplayed("block");
24411 var size = this.adapter.getElementSize(this);
24412 this.activeMinSize = this.getMinimumSize();;
24413 this.activeMaxSize = this.getMaximumSize();;
24414 var c1 = size - this.activeMinSize;
24415 var c2 = Math.max(this.activeMaxSize - size, 0);
24416 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24417 this.dd.resetConstraints();
24418 this.dd.setXConstraint(
24419 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24420 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24422 this.dd.setYConstraint(0, 0);
24424 this.dd.resetConstraints();
24425 this.dd.setXConstraint(0, 0);
24426 this.dd.setYConstraint(
24427 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24428 this.placement == Roo.SplitBar.TOP ? c2 : c1
24431 this.dragSpecs.startSize = size;
24432 this.dragSpecs.startPoint = [x, y];
24433 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24437 * @private Called after the drag operation by the DDProxy
24439 onEndProxyDrag : function(e){
24440 Roo.get(this.proxy).setDisplayed(false);
24441 var endPoint = Roo.lib.Event.getXY(e);
24443 this.overlay.hide();
24446 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24447 newSize = this.dragSpecs.startSize +
24448 (this.placement == Roo.SplitBar.LEFT ?
24449 endPoint[0] - this.dragSpecs.startPoint[0] :
24450 this.dragSpecs.startPoint[0] - endPoint[0]
24453 newSize = this.dragSpecs.startSize +
24454 (this.placement == Roo.SplitBar.TOP ?
24455 endPoint[1] - this.dragSpecs.startPoint[1] :
24456 this.dragSpecs.startPoint[1] - endPoint[1]
24459 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24460 if(newSize != this.dragSpecs.startSize){
24461 if(this.fireEvent('beforeapply', this, newSize) !== false){
24462 this.adapter.setElementSize(this, newSize);
24463 this.fireEvent("moved", this, newSize);
24464 this.fireEvent("resize", this, newSize);
24470 * Get the adapter this SplitBar uses
24471 * @return The adapter object
24473 getAdapter : function(){
24474 return this.adapter;
24478 * Set the adapter this SplitBar uses
24479 * @param {Object} adapter A SplitBar adapter object
24481 setAdapter : function(adapter){
24482 this.adapter = adapter;
24483 this.adapter.init(this);
24487 * Gets the minimum size for the resizing element
24488 * @return {Number} The minimum size
24490 getMinimumSize : function(){
24491 return this.minSize;
24495 * Sets the minimum size for the resizing element
24496 * @param {Number} minSize The minimum size
24498 setMinimumSize : function(minSize){
24499 this.minSize = minSize;
24503 * Gets the maximum size for the resizing element
24504 * @return {Number} The maximum size
24506 getMaximumSize : function(){
24507 return this.maxSize;
24511 * Sets the maximum size for the resizing element
24512 * @param {Number} maxSize The maximum size
24514 setMaximumSize : function(maxSize){
24515 this.maxSize = maxSize;
24519 * Sets the initialize size for the resizing element
24520 * @param {Number} size The initial size
24522 setCurrentSize : function(size){
24523 var oldAnimate = this.animate;
24524 this.animate = false;
24525 this.adapter.setElementSize(this, size);
24526 this.animate = oldAnimate;
24530 * Destroy this splitbar.
24531 * @param {Boolean} removeEl True to remove the element
24533 destroy : function(removeEl){
24535 this.shim.remove();
24538 this.proxy.parentNode.removeChild(this.proxy);
24546 * @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.
24548 Roo.SplitBar.createProxy = function(dir){
24549 var proxy = new Roo.Element(document.createElement("div"));
24550 proxy.unselectable();
24551 var cls = 'x-splitbar-proxy';
24552 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24553 document.body.appendChild(proxy.dom);
24558 * @class Roo.SplitBar.BasicLayoutAdapter
24559 * Default Adapter. It assumes the splitter and resizing element are not positioned
24560 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24562 Roo.SplitBar.BasicLayoutAdapter = function(){
24565 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24566 // do nothing for now
24567 init : function(s){
24571 * Called before drag operations to get the current size of the resizing element.
24572 * @param {Roo.SplitBar} s The SplitBar using this adapter
24574 getElementSize : function(s){
24575 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24576 return s.resizingEl.getWidth();
24578 return s.resizingEl.getHeight();
24583 * Called after drag operations to set the size of the resizing element.
24584 * @param {Roo.SplitBar} s The SplitBar using this adapter
24585 * @param {Number} newSize The new size to set
24586 * @param {Function} onComplete A function to be invoked when resizing is complete
24588 setElementSize : function(s, newSize, onComplete){
24589 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24591 s.resizingEl.setWidth(newSize);
24593 onComplete(s, newSize);
24596 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24601 s.resizingEl.setHeight(newSize);
24603 onComplete(s, newSize);
24606 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24613 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24614 * @extends Roo.SplitBar.BasicLayoutAdapter
24615 * Adapter that moves the splitter element to align with the resized sizing element.
24616 * Used with an absolute positioned SplitBar.
24617 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24618 * document.body, make sure you assign an id to the body element.
24620 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24621 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24622 this.container = Roo.get(container);
24625 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24626 init : function(s){
24627 this.basic.init(s);
24630 getElementSize : function(s){
24631 return this.basic.getElementSize(s);
24634 setElementSize : function(s, newSize, onComplete){
24635 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24638 moveSplitter : function(s){
24639 var yes = Roo.SplitBar;
24640 switch(s.placement){
24642 s.el.setX(s.resizingEl.getRight());
24645 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24648 s.el.setY(s.resizingEl.getBottom());
24651 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24658 * Orientation constant - Create a vertical SplitBar
24662 Roo.SplitBar.VERTICAL = 1;
24665 * Orientation constant - Create a horizontal SplitBar
24669 Roo.SplitBar.HORIZONTAL = 2;
24672 * Placement constant - The resizing element is to the left of the splitter element
24676 Roo.SplitBar.LEFT = 1;
24679 * Placement constant - The resizing element is to the right of the splitter element
24683 Roo.SplitBar.RIGHT = 2;
24686 * Placement constant - The resizing element is positioned above the splitter element
24690 Roo.SplitBar.TOP = 3;
24693 * Placement constant - The resizing element is positioned under splitter element
24697 Roo.SplitBar.BOTTOM = 4;
24700 * Ext JS Library 1.1.1
24701 * Copyright(c) 2006-2007, Ext JS, LLC.
24703 * Originally Released Under LGPL - original licence link has changed is not relivant.
24706 * <script type="text/javascript">
24711 * @extends Roo.util.Observable
24712 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24713 * This class also supports single and multi selection modes. <br>
24714 * Create a data model bound view:
24716 var store = new Roo.data.Store(...);
24718 var view = new Roo.View({
24720 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24722 singleSelect: true,
24723 selectedClass: "ydataview-selected",
24727 // listen for node click?
24728 view.on("click", function(vw, index, node, e){
24729 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24733 dataModel.load("foobar.xml");
24735 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24737 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24738 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24740 * Note: old style constructor is still suported (container, template, config)
24743 * Create a new View
24744 * @param {Object} config The config object
24747 Roo.View = function(config, depreciated_tpl, depreciated_config){
24749 if (typeof(depreciated_tpl) == 'undefined') {
24750 // new way.. - universal constructor.
24751 Roo.apply(this, config);
24752 this.el = Roo.get(this.el);
24755 this.el = Roo.get(config);
24756 this.tpl = depreciated_tpl;
24757 Roo.apply(this, depreciated_config);
24759 this.wrapEl = this.el.wrap().wrap();
24760 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24763 if(typeof(this.tpl) == "string"){
24764 this.tpl = new Roo.Template(this.tpl);
24766 // support xtype ctors..
24767 this.tpl = new Roo.factory(this.tpl, Roo);
24771 this.tpl.compile();
24779 * @event beforeclick
24780 * Fires before a click is processed. Returns false to cancel the default action.
24781 * @param {Roo.View} this
24782 * @param {Number} index The index of the target node
24783 * @param {HTMLElement} node The target node
24784 * @param {Roo.EventObject} e The raw event object
24786 "beforeclick" : true,
24789 * Fires when a template node is clicked.
24790 * @param {Roo.View} this
24791 * @param {Number} index The index of the target node
24792 * @param {HTMLElement} node The target node
24793 * @param {Roo.EventObject} e The raw event object
24798 * Fires when a template node is double clicked.
24799 * @param {Roo.View} this
24800 * @param {Number} index The index of the target node
24801 * @param {HTMLElement} node The target node
24802 * @param {Roo.EventObject} e The raw event object
24806 * @event contextmenu
24807 * Fires when a template node is right clicked.
24808 * @param {Roo.View} this
24809 * @param {Number} index The index of the target node
24810 * @param {HTMLElement} node The target node
24811 * @param {Roo.EventObject} e The raw event object
24813 "contextmenu" : true,
24815 * @event selectionchange
24816 * Fires when the selected nodes change.
24817 * @param {Roo.View} this
24818 * @param {Array} selections Array of the selected nodes
24820 "selectionchange" : true,
24823 * @event beforeselect
24824 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24825 * @param {Roo.View} this
24826 * @param {HTMLElement} node The node to be selected
24827 * @param {Array} selections Array of currently selected nodes
24829 "beforeselect" : true,
24831 * @event preparedata
24832 * Fires on every row to render, to allow you to change the data.
24833 * @param {Roo.View} this
24834 * @param {Object} data to be rendered (change this)
24836 "preparedata" : true
24844 "click": this.onClick,
24845 "dblclick": this.onDblClick,
24846 "contextmenu": this.onContextMenu,
24850 this.selections = [];
24852 this.cmp = new Roo.CompositeElementLite([]);
24854 this.store = Roo.factory(this.store, Roo.data);
24855 this.setStore(this.store, true);
24858 if ( this.footer && this.footer.xtype) {
24860 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24862 this.footer.dataSource = this.store
24863 this.footer.container = fctr;
24864 this.footer = Roo.factory(this.footer, Roo);
24865 fctr.insertFirst(this.el);
24867 // this is a bit insane - as the paging toolbar seems to detach the el..
24868 // dom.parentNode.parentNode.parentNode
24869 // they get detached?
24873 Roo.View.superclass.constructor.call(this);
24878 Roo.extend(Roo.View, Roo.util.Observable, {
24881 * @cfg {Roo.data.Store} store Data store to load data from.
24886 * @cfg {String|Roo.Element} el The container element.
24891 * @cfg {String|Roo.Template} tpl The template used by this View
24895 * @cfg {String} dataName the named area of the template to use as the data area
24896 * Works with domtemplates roo-name="name"
24900 * @cfg {String} selectedClass The css class to add to selected nodes
24902 selectedClass : "x-view-selected",
24904 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24909 * @cfg {String} text to display on mask (default Loading)
24913 * @cfg {Boolean} multiSelect Allow multiple selection
24915 multiSelect : false,
24917 * @cfg {Boolean} singleSelect Allow single selection
24919 singleSelect: false,
24922 * @cfg {Boolean} toggleSelect - selecting
24924 toggleSelect : false,
24927 * Returns the element this view is bound to.
24928 * @return {Roo.Element}
24930 getEl : function(){
24931 return this.wrapEl;
24937 * Refreshes the view. - called by datachanged on the store. - do not call directly.
24939 refresh : function(){
24940 Roo.log('refresh');
24943 // if we are using something like 'domtemplate', then
24944 // the what gets used is:
24945 // t.applySubtemplate(NAME, data, wrapping data..)
24946 // the outer template then get' applied with
24947 // the store 'extra data'
24948 // and the body get's added to the
24949 // roo-name="data" node?
24950 // <span class='roo-tpl-{name}'></span> ?????
24954 this.clearSelections();
24955 this.el.update("");
24957 var records = this.store.getRange();
24958 if(records.length < 1) {
24960 // is this valid?? = should it render a template??
24962 this.el.update(this.emptyText);
24966 if (this.dataName) {
24967 this.el.update(t.apply(this.store.meta)); //????
24968 el = this.el.child('.roo-tpl-' + this.dataName);
24971 for(var i = 0, len = records.length; i < len; i++){
24972 var data = this.prepareData(records[i].data, i, records[i]);
24973 this.fireEvent("preparedata", this, data, i, records[i]);
24974 html[html.length] = Roo.util.Format.trim(
24976 t.applySubtemplate(this.dataName, data, this.store.meta) :
24983 el.update(html.join(""));
24984 this.nodes = el.dom.childNodes;
24985 this.updateIndexes(0);
24990 * Function to override to reformat the data that is sent to
24991 * the template for each node.
24992 * DEPRICATED - use the preparedata event handler.
24993 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
24994 * a JSON object for an UpdateManager bound view).
24996 prepareData : function(data, index, record)
24998 this.fireEvent("preparedata", this, data, index, record);
25002 onUpdate : function(ds, record){
25003 Roo.log('on update');
25004 this.clearSelections();
25005 var index = this.store.indexOf(record);
25006 var n = this.nodes[index];
25007 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25008 n.parentNode.removeChild(n);
25009 this.updateIndexes(index, index);
25015 onAdd : function(ds, records, index)
25017 Roo.log(['on Add', ds, records, index] );
25018 this.clearSelections();
25019 if(this.nodes.length == 0){
25023 var n = this.nodes[index];
25024 for(var i = 0, len = records.length; i < len; i++){
25025 var d = this.prepareData(records[i].data, i, records[i]);
25027 this.tpl.insertBefore(n, d);
25030 this.tpl.append(this.el, d);
25033 this.updateIndexes(index);
25036 onRemove : function(ds, record, index){
25037 Roo.log('onRemove');
25038 this.clearSelections();
25039 var el = this.dataName ?
25040 this.el.child('.roo-tpl-' + this.dataName) :
25043 el.dom.removeChild(this.nodes[index]);
25044 this.updateIndexes(index);
25048 * Refresh an individual node.
25049 * @param {Number} index
25051 refreshNode : function(index){
25052 this.onUpdate(this.store, this.store.getAt(index));
25055 updateIndexes : function(startIndex, endIndex){
25056 var ns = this.nodes;
25057 startIndex = startIndex || 0;
25058 endIndex = endIndex || ns.length - 1;
25059 for(var i = startIndex; i <= endIndex; i++){
25060 ns[i].nodeIndex = i;
25065 * Changes the data store this view uses and refresh the view.
25066 * @param {Store} store
25068 setStore : function(store, initial){
25069 if(!initial && this.store){
25070 this.store.un("datachanged", this.refresh);
25071 this.store.un("add", this.onAdd);
25072 this.store.un("remove", this.onRemove);
25073 this.store.un("update", this.onUpdate);
25074 this.store.un("clear", this.refresh);
25075 this.store.un("beforeload", this.onBeforeLoad);
25076 this.store.un("load", this.onLoad);
25077 this.store.un("loadexception", this.onLoad);
25081 store.on("datachanged", this.refresh, this);
25082 store.on("add", this.onAdd, this);
25083 store.on("remove", this.onRemove, this);
25084 store.on("update", this.onUpdate, this);
25085 store.on("clear", this.refresh, this);
25086 store.on("beforeload", this.onBeforeLoad, this);
25087 store.on("load", this.onLoad, this);
25088 store.on("loadexception", this.onLoad, this);
25096 * onbeforeLoad - masks the loading area.
25099 onBeforeLoad : function(store,opts)
25101 Roo.log('onBeforeLoad');
25103 this.el.update("");
25105 this.el.mask(this.mask ? this.mask : "Loading" );
25107 onLoad : function ()
25114 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25115 * @param {HTMLElement} node
25116 * @return {HTMLElement} The template node
25118 findItemFromChild : function(node){
25119 var el = this.dataName ?
25120 this.el.child('.roo-tpl-' + this.dataName,true) :
25123 if(!node || node.parentNode == el){
25126 var p = node.parentNode;
25127 while(p && p != el){
25128 if(p.parentNode == el){
25137 onClick : function(e){
25138 var item = this.findItemFromChild(e.getTarget());
25140 var index = this.indexOf(item);
25141 if(this.onItemClick(item, index, e) !== false){
25142 this.fireEvent("click", this, index, item, e);
25145 this.clearSelections();
25150 onContextMenu : function(e){
25151 var item = this.findItemFromChild(e.getTarget());
25153 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25158 onDblClick : function(e){
25159 var item = this.findItemFromChild(e.getTarget());
25161 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25165 onItemClick : function(item, index, e)
25167 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25170 if (this.toggleSelect) {
25171 var m = this.isSelected(item) ? 'unselect' : 'select';
25174 _t[m](item, true, false);
25177 if(this.multiSelect || this.singleSelect){
25178 if(this.multiSelect && e.shiftKey && this.lastSelection){
25179 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25181 this.select(item, this.multiSelect && e.ctrlKey);
25182 this.lastSelection = item;
25184 e.preventDefault();
25190 * Get the number of selected nodes.
25193 getSelectionCount : function(){
25194 return this.selections.length;
25198 * Get the currently selected nodes.
25199 * @return {Array} An array of HTMLElements
25201 getSelectedNodes : function(){
25202 return this.selections;
25206 * Get the indexes of the selected nodes.
25209 getSelectedIndexes : function(){
25210 var indexes = [], s = this.selections;
25211 for(var i = 0, len = s.length; i < len; i++){
25212 indexes.push(s[i].nodeIndex);
25218 * Clear all selections
25219 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25221 clearSelections : function(suppressEvent){
25222 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25223 this.cmp.elements = this.selections;
25224 this.cmp.removeClass(this.selectedClass);
25225 this.selections = [];
25226 if(!suppressEvent){
25227 this.fireEvent("selectionchange", this, this.selections);
25233 * Returns true if the passed node is selected
25234 * @param {HTMLElement/Number} node The node or node index
25235 * @return {Boolean}
25237 isSelected : function(node){
25238 var s = this.selections;
25242 node = this.getNode(node);
25243 return s.indexOf(node) !== -1;
25248 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
25249 * @param {Boolean} keepExisting (optional) true to keep existing selections
25250 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25252 select : function(nodeInfo, keepExisting, suppressEvent){
25253 if(nodeInfo instanceof Array){
25255 this.clearSelections(true);
25257 for(var i = 0, len = nodeInfo.length; i < len; i++){
25258 this.select(nodeInfo[i], true, true);
25262 var node = this.getNode(nodeInfo);
25263 if(!node || this.isSelected(node)){
25264 return; // already selected.
25267 this.clearSelections(true);
25269 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25270 Roo.fly(node).addClass(this.selectedClass);
25271 this.selections.push(node);
25272 if(!suppressEvent){
25273 this.fireEvent("selectionchange", this, this.selections);
25281 * @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
25282 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25283 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25285 unselect : function(nodeInfo, keepExisting, suppressEvent)
25287 if(nodeInfo instanceof Array){
25288 Roo.each(this.selections, function(s) {
25289 this.unselect(s, nodeInfo);
25293 var node = this.getNode(nodeInfo);
25294 if(!node || !this.isSelected(node)){
25295 Roo.log("not selected");
25296 return; // not selected.
25300 Roo.each(this.selections, function(s) {
25302 Roo.fly(node).removeClass(this.selectedClass);
25309 this.selections= ns;
25310 this.fireEvent("selectionchange", this, this.selections);
25314 * Gets a template node.
25315 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25316 * @return {HTMLElement} The node or null if it wasn't found
25318 getNode : function(nodeInfo){
25319 if(typeof nodeInfo == "string"){
25320 return document.getElementById(nodeInfo);
25321 }else if(typeof nodeInfo == "number"){
25322 return this.nodes[nodeInfo];
25328 * Gets a range template nodes.
25329 * @param {Number} startIndex
25330 * @param {Number} endIndex
25331 * @return {Array} An array of nodes
25333 getNodes : function(start, end){
25334 var ns = this.nodes;
25335 start = start || 0;
25336 end = typeof end == "undefined" ? ns.length - 1 : end;
25339 for(var i = start; i <= end; i++){
25343 for(var i = start; i >= end; i--){
25351 * Finds the index of the passed node
25352 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25353 * @return {Number} The index of the node or -1
25355 indexOf : function(node){
25356 node = this.getNode(node);
25357 if(typeof node.nodeIndex == "number"){
25358 return node.nodeIndex;
25360 var ns = this.nodes;
25361 for(var i = 0, len = ns.length; i < len; i++){
25371 * Ext JS Library 1.1.1
25372 * Copyright(c) 2006-2007, Ext JS, LLC.
25374 * Originally Released Under LGPL - original licence link has changed is not relivant.
25377 * <script type="text/javascript">
25381 * @class Roo.JsonView
25382 * @extends Roo.View
25383 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25385 var view = new Roo.JsonView({
25386 container: "my-element",
25387 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25392 // listen for node click?
25393 view.on("click", function(vw, index, node, e){
25394 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25397 // direct load of JSON data
25398 view.load("foobar.php");
25400 // Example from my blog list
25401 var tpl = new Roo.Template(
25402 '<div class="entry">' +
25403 '<a class="entry-title" href="{link}">{title}</a>' +
25404 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25405 "</div><hr />"
25408 var moreView = new Roo.JsonView({
25409 container : "entry-list",
25413 moreView.on("beforerender", this.sortEntries, this);
25415 url: "/blog/get-posts.php",
25416 params: "allposts=true",
25417 text: "Loading Blog Entries..."
25421 * Note: old code is supported with arguments : (container, template, config)
25425 * Create a new JsonView
25427 * @param {Object} config The config object
25430 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25433 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25435 var um = this.el.getUpdateManager();
25436 um.setRenderer(this);
25437 um.on("update", this.onLoad, this);
25438 um.on("failure", this.onLoadException, this);
25441 * @event beforerender
25442 * Fires before rendering of the downloaded JSON data.
25443 * @param {Roo.JsonView} this
25444 * @param {Object} data The JSON data loaded
25448 * Fires when data is loaded.
25449 * @param {Roo.JsonView} this
25450 * @param {Object} data The JSON data loaded
25451 * @param {Object} response The raw Connect response object
25454 * @event loadexception
25455 * Fires when loading fails.
25456 * @param {Roo.JsonView} this
25457 * @param {Object} response The raw Connect response object
25460 'beforerender' : true,
25462 'loadexception' : true
25465 Roo.extend(Roo.JsonView, Roo.View, {
25467 * @type {String} The root property in the loaded JSON object that contains the data
25472 * Refreshes the view.
25474 refresh : function(){
25475 this.clearSelections();
25476 this.el.update("");
25478 var o = this.jsonData;
25479 if(o && o.length > 0){
25480 for(var i = 0, len = o.length; i < len; i++){
25481 var data = this.prepareData(o[i], i, o);
25482 html[html.length] = this.tpl.apply(data);
25485 html.push(this.emptyText);
25487 this.el.update(html.join(""));
25488 this.nodes = this.el.dom.childNodes;
25489 this.updateIndexes(0);
25493 * 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.
25494 * @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:
25497 url: "your-url.php",
25498 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25499 callback: yourFunction,
25500 scope: yourObject, //(optional scope)
25503 text: "Loading...",
25508 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25509 * 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.
25510 * @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}
25511 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25512 * @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.
25515 var um = this.el.getUpdateManager();
25516 um.update.apply(um, arguments);
25519 render : function(el, response){
25520 this.clearSelections();
25521 this.el.update("");
25524 o = Roo.util.JSON.decode(response.responseText);
25527 o = o[this.jsonRoot];
25532 * The current JSON data or null
25535 this.beforeRender();
25540 * Get the number of records in the current JSON dataset
25543 getCount : function(){
25544 return this.jsonData ? this.jsonData.length : 0;
25548 * Returns the JSON object for the specified node(s)
25549 * @param {HTMLElement/Array} node The node or an array of nodes
25550 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25551 * you get the JSON object for the node
25553 getNodeData : function(node){
25554 if(node instanceof Array){
25556 for(var i = 0, len = node.length; i < len; i++){
25557 data.push(this.getNodeData(node[i]));
25561 return this.jsonData[this.indexOf(node)] || null;
25564 beforeRender : function(){
25565 this.snapshot = this.jsonData;
25567 this.sort.apply(this, this.sortInfo);
25569 this.fireEvent("beforerender", this, this.jsonData);
25572 onLoad : function(el, o){
25573 this.fireEvent("load", this, this.jsonData, o);
25576 onLoadException : function(el, o){
25577 this.fireEvent("loadexception", this, o);
25581 * Filter the data by a specific property.
25582 * @param {String} property A property on your JSON objects
25583 * @param {String/RegExp} value Either string that the property values
25584 * should start with, or a RegExp to test against the property
25586 filter : function(property, value){
25589 var ss = this.snapshot;
25590 if(typeof value == "string"){
25591 var vlen = value.length;
25593 this.clearFilter();
25596 value = value.toLowerCase();
25597 for(var i = 0, len = ss.length; i < len; i++){
25599 if(o[property].substr(0, vlen).toLowerCase() == value){
25603 } else if(value.exec){ // regex?
25604 for(var i = 0, len = ss.length; i < len; i++){
25606 if(value.test(o[property])){
25613 this.jsonData = data;
25619 * Filter by a function. The passed function will be called with each
25620 * object in the current dataset. If the function returns true the value is kept,
25621 * otherwise it is filtered.
25622 * @param {Function} fn
25623 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25625 filterBy : function(fn, scope){
25628 var ss = this.snapshot;
25629 for(var i = 0, len = ss.length; i < len; i++){
25631 if(fn.call(scope || this, o)){
25635 this.jsonData = data;
25641 * Clears the current filter.
25643 clearFilter : function(){
25644 if(this.snapshot && this.jsonData != this.snapshot){
25645 this.jsonData = this.snapshot;
25652 * Sorts the data for this view and refreshes it.
25653 * @param {String} property A property on your JSON objects to sort on
25654 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25655 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25657 sort : function(property, dir, sortType){
25658 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25661 var dsc = dir && dir.toLowerCase() == "desc";
25662 var f = function(o1, o2){
25663 var v1 = sortType ? sortType(o1[p]) : o1[p];
25664 var v2 = sortType ? sortType(o2[p]) : o2[p];
25667 return dsc ? +1 : -1;
25668 } else if(v1 > v2){
25669 return dsc ? -1 : +1;
25674 this.jsonData.sort(f);
25676 if(this.jsonData != this.snapshot){
25677 this.snapshot.sort(f);
25683 * Ext JS Library 1.1.1
25684 * Copyright(c) 2006-2007, Ext JS, LLC.
25686 * Originally Released Under LGPL - original licence link has changed is not relivant.
25689 * <script type="text/javascript">
25694 * @class Roo.ColorPalette
25695 * @extends Roo.Component
25696 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25697 * Here's an example of typical usage:
25699 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25700 cp.render('my-div');
25702 cp.on('select', function(palette, selColor){
25703 // do something with selColor
25707 * Create a new ColorPalette
25708 * @param {Object} config The config object
25710 Roo.ColorPalette = function(config){
25711 Roo.ColorPalette.superclass.constructor.call(this, config);
25715 * Fires when a color is selected
25716 * @param {ColorPalette} this
25717 * @param {String} color The 6-digit color hex code (without the # symbol)
25723 this.on("select", this.handler, this.scope, true);
25726 Roo.extend(Roo.ColorPalette, Roo.Component, {
25728 * @cfg {String} itemCls
25729 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25731 itemCls : "x-color-palette",
25733 * @cfg {String} value
25734 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25735 * the hex codes are case-sensitive.
25738 clickEvent:'click',
25740 ctype: "Roo.ColorPalette",
25743 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25745 allowReselect : false,
25748 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25749 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25750 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25751 * of colors with the width setting until the box is symmetrical.</p>
25752 * <p>You can override individual colors if needed:</p>
25754 var cp = new Roo.ColorPalette();
25755 cp.colors[0] = "FF0000"; // change the first box to red
25758 Or you can provide a custom array of your own for complete control:
25760 var cp = new Roo.ColorPalette();
25761 cp.colors = ["000000", "993300", "333300"];
25766 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25767 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25768 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25769 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25770 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25774 onRender : function(container, position){
25775 var t = new Roo.MasterTemplate(
25776 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25778 var c = this.colors;
25779 for(var i = 0, len = c.length; i < len; i++){
25782 var el = document.createElement("div");
25783 el.className = this.itemCls;
25785 container.dom.insertBefore(el, position);
25786 this.el = Roo.get(el);
25787 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25788 if(this.clickEvent != 'click'){
25789 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25794 afterRender : function(){
25795 Roo.ColorPalette.superclass.afterRender.call(this);
25797 var s = this.value;
25804 handleClick : function(e, t){
25805 e.preventDefault();
25806 if(!this.disabled){
25807 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25808 this.select(c.toUpperCase());
25813 * Selects the specified color in the palette (fires the select event)
25814 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25816 select : function(color){
25817 color = color.replace("#", "");
25818 if(color != this.value || this.allowReselect){
25821 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25823 el.child("a.color-"+color).addClass("x-color-palette-sel");
25824 this.value = color;
25825 this.fireEvent("select", this, color);
25830 * Ext JS Library 1.1.1
25831 * Copyright(c) 2006-2007, Ext JS, LLC.
25833 * Originally Released Under LGPL - original licence link has changed is not relivant.
25836 * <script type="text/javascript">
25840 * @class Roo.DatePicker
25841 * @extends Roo.Component
25842 * Simple date picker class.
25844 * Create a new DatePicker
25845 * @param {Object} config The config object
25847 Roo.DatePicker = function(config){
25848 Roo.DatePicker.superclass.constructor.call(this, config);
25850 this.value = config && config.value ?
25851 config.value.clearTime() : new Date().clearTime();
25856 * Fires when a date is selected
25857 * @param {DatePicker} this
25858 * @param {Date} date The selected date
25862 * @event monthchange
25863 * Fires when the displayed month changes
25864 * @param {DatePicker} this
25865 * @param {Date} date The selected month
25867 'monthchange': true
25871 this.on("select", this.handler, this.scope || this);
25873 // build the disabledDatesRE
25874 if(!this.disabledDatesRE && this.disabledDates){
25875 var dd = this.disabledDates;
25877 for(var i = 0; i < dd.length; i++){
25879 if(i != dd.length-1) re += "|";
25881 this.disabledDatesRE = new RegExp(re + ")");
25885 Roo.extend(Roo.DatePicker, Roo.Component, {
25887 * @cfg {String} todayText
25888 * The text to display on the button that selects the current date (defaults to "Today")
25890 todayText : "Today",
25892 * @cfg {String} okText
25893 * The text to display on the ok button
25895 okText : " OK ", //   to give the user extra clicking room
25897 * @cfg {String} cancelText
25898 * The text to display on the cancel button
25900 cancelText : "Cancel",
25902 * @cfg {String} todayTip
25903 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25905 todayTip : "{0} (Spacebar)",
25907 * @cfg {Date} minDate
25908 * Minimum allowable date (JavaScript date object, defaults to null)
25912 * @cfg {Date} maxDate
25913 * Maximum allowable date (JavaScript date object, defaults to null)
25917 * @cfg {String} minText
25918 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25920 minText : "This date is before the minimum date",
25922 * @cfg {String} maxText
25923 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25925 maxText : "This date is after the maximum date",
25927 * @cfg {String} format
25928 * The default date format string which can be overriden for localization support. The format must be
25929 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25933 * @cfg {Array} disabledDays
25934 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25936 disabledDays : null,
25938 * @cfg {String} disabledDaysText
25939 * The tooltip to display when the date falls on a disabled day (defaults to "")
25941 disabledDaysText : "",
25943 * @cfg {RegExp} disabledDatesRE
25944 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25946 disabledDatesRE : null,
25948 * @cfg {String} disabledDatesText
25949 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25951 disabledDatesText : "",
25953 * @cfg {Boolean} constrainToViewport
25954 * True to constrain the date picker to the viewport (defaults to true)
25956 constrainToViewport : true,
25958 * @cfg {Array} monthNames
25959 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25961 monthNames : Date.monthNames,
25963 * @cfg {Array} dayNames
25964 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25966 dayNames : Date.dayNames,
25968 * @cfg {String} nextText
25969 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25971 nextText: 'Next Month (Control+Right)',
25973 * @cfg {String} prevText
25974 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25976 prevText: 'Previous Month (Control+Left)',
25978 * @cfg {String} monthYearText
25979 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25981 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25983 * @cfg {Number} startDay
25984 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25988 * @cfg {Bool} showClear
25989 * Show a clear button (usefull for date form elements that can be blank.)
25995 * Sets the value of the date field
25996 * @param {Date} value The date to set
25998 setValue : function(value){
25999 var old = this.value;
26001 if (typeof(value) == 'string') {
26003 value = Date.parseDate(value, this.format);
26006 value = new Date();
26009 this.value = value.clearTime(true);
26011 this.update(this.value);
26016 * Gets the current selected value of the date field
26017 * @return {Date} The selected date
26019 getValue : function(){
26024 focus : function(){
26026 this.update(this.activeDate);
26031 onRender : function(container, position){
26034 '<table cellspacing="0">',
26035 '<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>',
26036 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26037 var dn = this.dayNames;
26038 for(var i = 0; i < 7; i++){
26039 var d = this.startDay+i;
26043 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26045 m[m.length] = "</tr></thead><tbody><tr>";
26046 for(var i = 0; i < 42; i++) {
26047 if(i % 7 == 0 && i != 0){
26048 m[m.length] = "</tr><tr>";
26050 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26052 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26053 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26055 var el = document.createElement("div");
26056 el.className = "x-date-picker";
26057 el.innerHTML = m.join("");
26059 container.dom.insertBefore(el, position);
26061 this.el = Roo.get(el);
26062 this.eventEl = Roo.get(el.firstChild);
26064 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26065 handler: this.showPrevMonth,
26067 preventDefault:true,
26071 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26072 handler: this.showNextMonth,
26074 preventDefault:true,
26078 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26080 this.monthPicker = this.el.down('div.x-date-mp');
26081 this.monthPicker.enableDisplayMode('block');
26083 var kn = new Roo.KeyNav(this.eventEl, {
26084 "left" : function(e){
26086 this.showPrevMonth() :
26087 this.update(this.activeDate.add("d", -1));
26090 "right" : function(e){
26092 this.showNextMonth() :
26093 this.update(this.activeDate.add("d", 1));
26096 "up" : function(e){
26098 this.showNextYear() :
26099 this.update(this.activeDate.add("d", -7));
26102 "down" : function(e){
26104 this.showPrevYear() :
26105 this.update(this.activeDate.add("d", 7));
26108 "pageUp" : function(e){
26109 this.showNextMonth();
26112 "pageDown" : function(e){
26113 this.showPrevMonth();
26116 "enter" : function(e){
26117 e.stopPropagation();
26124 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26126 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26128 this.el.unselectable();
26130 this.cells = this.el.select("table.x-date-inner tbody td");
26131 this.textNodes = this.el.query("table.x-date-inner tbody span");
26133 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26135 tooltip: this.monthYearText
26138 this.mbtn.on('click', this.showMonthPicker, this);
26139 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26142 var today = (new Date()).dateFormat(this.format);
26144 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26145 if (this.showClear) {
26146 baseTb.add( new Roo.Toolbar.Fill());
26149 text: String.format(this.todayText, today),
26150 tooltip: String.format(this.todayTip, today),
26151 handler: this.selectToday,
26155 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26158 if (this.showClear) {
26160 baseTb.add( new Roo.Toolbar.Fill());
26163 cls: 'x-btn-icon x-btn-clear',
26164 handler: function() {
26166 this.fireEvent("select", this, '');
26176 this.update(this.value);
26179 createMonthPicker : function(){
26180 if(!this.monthPicker.dom.firstChild){
26181 var buf = ['<table border="0" cellspacing="0">'];
26182 for(var i = 0; i < 6; i++){
26184 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26185 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26187 '<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>' :
26188 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26192 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26194 '</button><button type="button" class="x-date-mp-cancel">',
26196 '</button></td></tr>',
26199 this.monthPicker.update(buf.join(''));
26200 this.monthPicker.on('click', this.onMonthClick, this);
26201 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26203 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26204 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26206 this.mpMonths.each(function(m, a, i){
26209 m.dom.xmonth = 5 + Math.round(i * .5);
26211 m.dom.xmonth = Math.round((i-1) * .5);
26217 showMonthPicker : function(){
26218 this.createMonthPicker();
26219 var size = this.el.getSize();
26220 this.monthPicker.setSize(size);
26221 this.monthPicker.child('table').setSize(size);
26223 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26224 this.updateMPMonth(this.mpSelMonth);
26225 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26226 this.updateMPYear(this.mpSelYear);
26228 this.monthPicker.slideIn('t', {duration:.2});
26231 updateMPYear : function(y){
26233 var ys = this.mpYears.elements;
26234 for(var i = 1; i <= 10; i++){
26235 var td = ys[i-1], y2;
26237 y2 = y + Math.round(i * .5);
26238 td.firstChild.innerHTML = y2;
26241 y2 = y - (5-Math.round(i * .5));
26242 td.firstChild.innerHTML = y2;
26245 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26249 updateMPMonth : function(sm){
26250 this.mpMonths.each(function(m, a, i){
26251 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26255 selectMPMonth: function(m){
26259 onMonthClick : function(e, t){
26261 var el = new Roo.Element(t), pn;
26262 if(el.is('button.x-date-mp-cancel')){
26263 this.hideMonthPicker();
26265 else if(el.is('button.x-date-mp-ok')){
26266 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26267 this.hideMonthPicker();
26269 else if(pn = el.up('td.x-date-mp-month', 2)){
26270 this.mpMonths.removeClass('x-date-mp-sel');
26271 pn.addClass('x-date-mp-sel');
26272 this.mpSelMonth = pn.dom.xmonth;
26274 else if(pn = el.up('td.x-date-mp-year', 2)){
26275 this.mpYears.removeClass('x-date-mp-sel');
26276 pn.addClass('x-date-mp-sel');
26277 this.mpSelYear = pn.dom.xyear;
26279 else if(el.is('a.x-date-mp-prev')){
26280 this.updateMPYear(this.mpyear-10);
26282 else if(el.is('a.x-date-mp-next')){
26283 this.updateMPYear(this.mpyear+10);
26287 onMonthDblClick : function(e, t){
26289 var el = new Roo.Element(t), pn;
26290 if(pn = el.up('td.x-date-mp-month', 2)){
26291 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26292 this.hideMonthPicker();
26294 else if(pn = el.up('td.x-date-mp-year', 2)){
26295 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26296 this.hideMonthPicker();
26300 hideMonthPicker : function(disableAnim){
26301 if(this.monthPicker){
26302 if(disableAnim === true){
26303 this.monthPicker.hide();
26305 this.monthPicker.slideOut('t', {duration:.2});
26311 showPrevMonth : function(e){
26312 this.update(this.activeDate.add("mo", -1));
26316 showNextMonth : function(e){
26317 this.update(this.activeDate.add("mo", 1));
26321 showPrevYear : function(){
26322 this.update(this.activeDate.add("y", -1));
26326 showNextYear : function(){
26327 this.update(this.activeDate.add("y", 1));
26331 handleMouseWheel : function(e){
26332 var delta = e.getWheelDelta();
26334 this.showPrevMonth();
26336 } else if(delta < 0){
26337 this.showNextMonth();
26343 handleDateClick : function(e, t){
26345 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26346 this.setValue(new Date(t.dateValue));
26347 this.fireEvent("select", this, this.value);
26352 selectToday : function(){
26353 this.setValue(new Date().clearTime());
26354 this.fireEvent("select", this, this.value);
26358 update : function(date)
26360 var vd = this.activeDate;
26361 this.activeDate = date;
26363 var t = date.getTime();
26364 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26365 this.cells.removeClass("x-date-selected");
26366 this.cells.each(function(c){
26367 if(c.dom.firstChild.dateValue == t){
26368 c.addClass("x-date-selected");
26369 setTimeout(function(){
26370 try{c.dom.firstChild.focus();}catch(e){}
26379 var days = date.getDaysInMonth();
26380 var firstOfMonth = date.getFirstDateOfMonth();
26381 var startingPos = firstOfMonth.getDay()-this.startDay;
26383 if(startingPos <= this.startDay){
26387 var pm = date.add("mo", -1);
26388 var prevStart = pm.getDaysInMonth()-startingPos;
26390 var cells = this.cells.elements;
26391 var textEls = this.textNodes;
26392 days += startingPos;
26394 // convert everything to numbers so it's fast
26395 var day = 86400000;
26396 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26397 var today = new Date().clearTime().getTime();
26398 var sel = date.clearTime().getTime();
26399 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26400 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26401 var ddMatch = this.disabledDatesRE;
26402 var ddText = this.disabledDatesText;
26403 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26404 var ddaysText = this.disabledDaysText;
26405 var format = this.format;
26407 var setCellClass = function(cal, cell){
26409 var t = d.getTime();
26410 cell.firstChild.dateValue = t;
26412 cell.className += " x-date-today";
26413 cell.title = cal.todayText;
26416 cell.className += " x-date-selected";
26417 setTimeout(function(){
26418 try{cell.firstChild.focus();}catch(e){}
26423 cell.className = " x-date-disabled";
26424 cell.title = cal.minText;
26428 cell.className = " x-date-disabled";
26429 cell.title = cal.maxText;
26433 if(ddays.indexOf(d.getDay()) != -1){
26434 cell.title = ddaysText;
26435 cell.className = " x-date-disabled";
26438 if(ddMatch && format){
26439 var fvalue = d.dateFormat(format);
26440 if(ddMatch.test(fvalue)){
26441 cell.title = ddText.replace("%0", fvalue);
26442 cell.className = " x-date-disabled";
26448 for(; i < startingPos; i++) {
26449 textEls[i].innerHTML = (++prevStart);
26450 d.setDate(d.getDate()+1);
26451 cells[i].className = "x-date-prevday";
26452 setCellClass(this, cells[i]);
26454 for(; i < days; i++){
26455 intDay = i - startingPos + 1;
26456 textEls[i].innerHTML = (intDay);
26457 d.setDate(d.getDate()+1);
26458 cells[i].className = "x-date-active";
26459 setCellClass(this, cells[i]);
26462 for(; i < 42; i++) {
26463 textEls[i].innerHTML = (++extraDays);
26464 d.setDate(d.getDate()+1);
26465 cells[i].className = "x-date-nextday";
26466 setCellClass(this, cells[i]);
26469 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26470 this.fireEvent('monthchange', this, date);
26472 if(!this.internalRender){
26473 var main = this.el.dom.firstChild;
26474 var w = main.offsetWidth;
26475 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26476 Roo.fly(main).setWidth(w);
26477 this.internalRender = true;
26478 // opera does not respect the auto grow header center column
26479 // then, after it gets a width opera refuses to recalculate
26480 // without a second pass
26481 if(Roo.isOpera && !this.secondPass){
26482 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26483 this.secondPass = true;
26484 this.update.defer(10, this, [date]);
26492 * Ext JS Library 1.1.1
26493 * Copyright(c) 2006-2007, Ext JS, LLC.
26495 * Originally Released Under LGPL - original licence link has changed is not relivant.
26498 * <script type="text/javascript">
26501 * @class Roo.TabPanel
26502 * @extends Roo.util.Observable
26503 * A lightweight tab container.
26507 // basic tabs 1, built from existing content
26508 var tabs = new Roo.TabPanel("tabs1");
26509 tabs.addTab("script", "View Script");
26510 tabs.addTab("markup", "View Markup");
26511 tabs.activate("script");
26513 // more advanced tabs, built from javascript
26514 var jtabs = new Roo.TabPanel("jtabs");
26515 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26517 // set up the UpdateManager
26518 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26519 var updater = tab2.getUpdateManager();
26520 updater.setDefaultUrl("ajax1.htm");
26521 tab2.on('activate', updater.refresh, updater, true);
26523 // Use setUrl for Ajax loading
26524 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26525 tab3.setUrl("ajax2.htm", null, true);
26528 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26531 jtabs.activate("jtabs-1");
26534 * Create a new TabPanel.
26535 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26536 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26538 Roo.TabPanel = function(container, config){
26540 * The container element for this TabPanel.
26541 * @type Roo.Element
26543 this.el = Roo.get(container, true);
26545 if(typeof config == "boolean"){
26546 this.tabPosition = config ? "bottom" : "top";
26548 Roo.apply(this, config);
26551 if(this.tabPosition == "bottom"){
26552 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26553 this.el.addClass("x-tabs-bottom");
26555 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26556 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26557 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26559 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26561 if(this.tabPosition != "bottom"){
26562 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26563 * @type Roo.Element
26565 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26566 this.el.addClass("x-tabs-top");
26570 this.bodyEl.setStyle("position", "relative");
26572 this.active = null;
26573 this.activateDelegate = this.activate.createDelegate(this);
26578 * Fires when the active tab changes
26579 * @param {Roo.TabPanel} this
26580 * @param {Roo.TabPanelItem} activePanel The new active tab
26584 * @event beforetabchange
26585 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26586 * @param {Roo.TabPanel} this
26587 * @param {Object} e Set cancel to true on this object to cancel the tab change
26588 * @param {Roo.TabPanelItem} tab The tab being changed to
26590 "beforetabchange" : true
26593 Roo.EventManager.onWindowResize(this.onResize, this);
26594 this.cpad = this.el.getPadding("lr");
26595 this.hiddenCount = 0;
26598 // toolbar on the tabbar support...
26599 if (this.toolbar) {
26600 var tcfg = this.toolbar;
26601 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26602 this.toolbar = new Roo.Toolbar(tcfg);
26603 if (Roo.isSafari) {
26604 var tbl = tcfg.container.child('table', true);
26605 tbl.setAttribute('width', '100%');
26612 Roo.TabPanel.superclass.constructor.call(this);
26615 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26617 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26619 tabPosition : "top",
26621 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26623 currentTabWidth : 0,
26625 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26629 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26633 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26635 preferredTabWidth : 175,
26637 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26639 resizeTabs : false,
26641 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26643 monitorResize : true,
26645 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26650 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26651 * @param {String} id The id of the div to use <b>or create</b>
26652 * @param {String} text The text for the tab
26653 * @param {String} content (optional) Content to put in the TabPanelItem body
26654 * @param {Boolean} closable (optional) True to create a close icon on the tab
26655 * @return {Roo.TabPanelItem} The created TabPanelItem
26657 addTab : function(id, text, content, closable){
26658 var item = new Roo.TabPanelItem(this, id, text, closable);
26659 this.addTabItem(item);
26661 item.setContent(content);
26667 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26668 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26669 * @return {Roo.TabPanelItem}
26671 getTab : function(id){
26672 return this.items[id];
26676 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26677 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26679 hideTab : function(id){
26680 var t = this.items[id];
26683 this.hiddenCount++;
26684 this.autoSizeTabs();
26689 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26690 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26692 unhideTab : function(id){
26693 var t = this.items[id];
26695 t.setHidden(false);
26696 this.hiddenCount--;
26697 this.autoSizeTabs();
26702 * Adds an existing {@link Roo.TabPanelItem}.
26703 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26705 addTabItem : function(item){
26706 this.items[item.id] = item;
26707 this.items.push(item);
26708 if(this.resizeTabs){
26709 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26710 this.autoSizeTabs();
26717 * Removes a {@link Roo.TabPanelItem}.
26718 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26720 removeTab : function(id){
26721 var items = this.items;
26722 var tab = items[id];
26723 if(!tab) { return; }
26724 var index = items.indexOf(tab);
26725 if(this.active == tab && items.length > 1){
26726 var newTab = this.getNextAvailable(index);
26731 this.stripEl.dom.removeChild(tab.pnode.dom);
26732 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26733 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26735 items.splice(index, 1);
26736 delete this.items[tab.id];
26737 tab.fireEvent("close", tab);
26738 tab.purgeListeners();
26739 this.autoSizeTabs();
26742 getNextAvailable : function(start){
26743 var items = this.items;
26745 // look for a next tab that will slide over to
26746 // replace the one being removed
26747 while(index < items.length){
26748 var item = items[++index];
26749 if(item && !item.isHidden()){
26753 // if one isn't found select the previous tab (on the left)
26756 var item = items[--index];
26757 if(item && !item.isHidden()){
26765 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26766 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26768 disableTab : function(id){
26769 var tab = this.items[id];
26770 if(tab && this.active != tab){
26776 * Enables a {@link Roo.TabPanelItem} that is disabled.
26777 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26779 enableTab : function(id){
26780 var tab = this.items[id];
26785 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26786 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26787 * @return {Roo.TabPanelItem} The TabPanelItem.
26789 activate : function(id){
26790 var tab = this.items[id];
26794 if(tab == this.active || tab.disabled){
26798 this.fireEvent("beforetabchange", this, e, tab);
26799 if(e.cancel !== true && !tab.disabled){
26801 this.active.hide();
26803 this.active = this.items[id];
26804 this.active.show();
26805 this.fireEvent("tabchange", this, this.active);
26811 * Gets the active {@link Roo.TabPanelItem}.
26812 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26814 getActiveTab : function(){
26815 return this.active;
26819 * Updates the tab body element to fit the height of the container element
26820 * for overflow scrolling
26821 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26823 syncHeight : function(targetHeight){
26824 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26825 var bm = this.bodyEl.getMargins();
26826 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26827 this.bodyEl.setHeight(newHeight);
26831 onResize : function(){
26832 if(this.monitorResize){
26833 this.autoSizeTabs();
26838 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26840 beginUpdate : function(){
26841 this.updating = true;
26845 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26847 endUpdate : function(){
26848 this.updating = false;
26849 this.autoSizeTabs();
26853 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26855 autoSizeTabs : function(){
26856 var count = this.items.length;
26857 var vcount = count - this.hiddenCount;
26858 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26859 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26860 var availWidth = Math.floor(w / vcount);
26861 var b = this.stripBody;
26862 if(b.getWidth() > w){
26863 var tabs = this.items;
26864 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26865 if(availWidth < this.minTabWidth){
26866 /*if(!this.sleft){ // incomplete scrolling code
26867 this.createScrollButtons();
26870 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26873 if(this.currentTabWidth < this.preferredTabWidth){
26874 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26880 * Returns the number of tabs in this TabPanel.
26883 getCount : function(){
26884 return this.items.length;
26888 * Resizes all the tabs to the passed width
26889 * @param {Number} The new width
26891 setTabWidth : function(width){
26892 this.currentTabWidth = width;
26893 for(var i = 0, len = this.items.length; i < len; i++) {
26894 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26899 * Destroys this TabPanel
26900 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26902 destroy : function(removeEl){
26903 Roo.EventManager.removeResizeListener(this.onResize, this);
26904 for(var i = 0, len = this.items.length; i < len; i++){
26905 this.items[i].purgeListeners();
26907 if(removeEl === true){
26908 this.el.update("");
26915 * @class Roo.TabPanelItem
26916 * @extends Roo.util.Observable
26917 * Represents an individual item (tab plus body) in a TabPanel.
26918 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26919 * @param {String} id The id of this TabPanelItem
26920 * @param {String} text The text for the tab of this TabPanelItem
26921 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26923 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26925 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26926 * @type Roo.TabPanel
26928 this.tabPanel = tabPanel;
26930 * The id for this TabPanelItem
26935 this.disabled = false;
26939 this.loaded = false;
26940 this.closable = closable;
26943 * The body element for this TabPanelItem.
26944 * @type Roo.Element
26946 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26947 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26948 this.bodyEl.setStyle("display", "block");
26949 this.bodyEl.setStyle("zoom", "1");
26952 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26954 this.el = Roo.get(els.el, true);
26955 this.inner = Roo.get(els.inner, true);
26956 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26957 this.pnode = Roo.get(els.el.parentNode, true);
26958 this.el.on("mousedown", this.onTabMouseDown, this);
26959 this.el.on("click", this.onTabClick, this);
26962 var c = Roo.get(els.close, true);
26963 c.dom.title = this.closeText;
26964 c.addClassOnOver("close-over");
26965 c.on("click", this.closeClick, this);
26971 * Fires when this tab becomes the active tab.
26972 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26973 * @param {Roo.TabPanelItem} this
26977 * @event beforeclose
26978 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26979 * @param {Roo.TabPanelItem} this
26980 * @param {Object} e Set cancel to true on this object to cancel the close.
26982 "beforeclose": true,
26985 * Fires when this tab is closed.
26986 * @param {Roo.TabPanelItem} this
26990 * @event deactivate
26991 * Fires when this tab is no longer the active tab.
26992 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26993 * @param {Roo.TabPanelItem} this
26995 "deactivate" : true
26997 this.hidden = false;
26999 Roo.TabPanelItem.superclass.constructor.call(this);
27002 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27003 purgeListeners : function(){
27004 Roo.util.Observable.prototype.purgeListeners.call(this);
27005 this.el.removeAllListeners();
27008 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27011 this.pnode.addClass("on");
27014 this.tabPanel.stripWrap.repaint();
27016 this.fireEvent("activate", this.tabPanel, this);
27020 * Returns true if this tab is the active tab.
27021 * @return {Boolean}
27023 isActive : function(){
27024 return this.tabPanel.getActiveTab() == this;
27028 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27031 this.pnode.removeClass("on");
27033 this.fireEvent("deactivate", this.tabPanel, this);
27036 hideAction : function(){
27037 this.bodyEl.hide();
27038 this.bodyEl.setStyle("position", "absolute");
27039 this.bodyEl.setLeft("-20000px");
27040 this.bodyEl.setTop("-20000px");
27043 showAction : function(){
27044 this.bodyEl.setStyle("position", "relative");
27045 this.bodyEl.setTop("");
27046 this.bodyEl.setLeft("");
27047 this.bodyEl.show();
27051 * Set the tooltip for the tab.
27052 * @param {String} tooltip The tab's tooltip
27054 setTooltip : function(text){
27055 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27056 this.textEl.dom.qtip = text;
27057 this.textEl.dom.removeAttribute('title');
27059 this.textEl.dom.title = text;
27063 onTabClick : function(e){
27064 e.preventDefault();
27065 this.tabPanel.activate(this.id);
27068 onTabMouseDown : function(e){
27069 e.preventDefault();
27070 this.tabPanel.activate(this.id);
27073 getWidth : function(){
27074 return this.inner.getWidth();
27077 setWidth : function(width){
27078 var iwidth = width - this.pnode.getPadding("lr");
27079 this.inner.setWidth(iwidth);
27080 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27081 this.pnode.setWidth(width);
27085 * Show or hide the tab
27086 * @param {Boolean} hidden True to hide or false to show.
27088 setHidden : function(hidden){
27089 this.hidden = hidden;
27090 this.pnode.setStyle("display", hidden ? "none" : "");
27094 * Returns true if this tab is "hidden"
27095 * @return {Boolean}
27097 isHidden : function(){
27098 return this.hidden;
27102 * Returns the text for this tab
27105 getText : function(){
27109 autoSize : function(){
27110 //this.el.beginMeasure();
27111 this.textEl.setWidth(1);
27112 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
27113 //this.el.endMeasure();
27117 * Sets the text for the tab (Note: this also sets the tooltip text)
27118 * @param {String} text The tab's text and tooltip
27120 setText : function(text){
27122 this.textEl.update(text);
27123 this.setTooltip(text);
27124 if(!this.tabPanel.resizeTabs){
27129 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27131 activate : function(){
27132 this.tabPanel.activate(this.id);
27136 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27138 disable : function(){
27139 if(this.tabPanel.active != this){
27140 this.disabled = true;
27141 this.pnode.addClass("disabled");
27146 * Enables this TabPanelItem if it was previously disabled.
27148 enable : function(){
27149 this.disabled = false;
27150 this.pnode.removeClass("disabled");
27154 * Sets the content for this TabPanelItem.
27155 * @param {String} content The content
27156 * @param {Boolean} loadScripts true to look for and load scripts
27158 setContent : function(content, loadScripts){
27159 this.bodyEl.update(content, loadScripts);
27163 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27164 * @return {Roo.UpdateManager} The UpdateManager
27166 getUpdateManager : function(){
27167 return this.bodyEl.getUpdateManager();
27171 * Set a URL to be used to load the content for this TabPanelItem.
27172 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27173 * @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)
27174 * @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)
27175 * @return {Roo.UpdateManager} The UpdateManager
27177 setUrl : function(url, params, loadOnce){
27178 if(this.refreshDelegate){
27179 this.un('activate', this.refreshDelegate);
27181 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27182 this.on("activate", this.refreshDelegate);
27183 return this.bodyEl.getUpdateManager();
27187 _handleRefresh : function(url, params, loadOnce){
27188 if(!loadOnce || !this.loaded){
27189 var updater = this.bodyEl.getUpdateManager();
27190 updater.update(url, params, this._setLoaded.createDelegate(this));
27195 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27196 * Will fail silently if the setUrl method has not been called.
27197 * This does not activate the panel, just updates its content.
27199 refresh : function(){
27200 if(this.refreshDelegate){
27201 this.loaded = false;
27202 this.refreshDelegate();
27207 _setLoaded : function(){
27208 this.loaded = true;
27212 closeClick : function(e){
27215 this.fireEvent("beforeclose", this, o);
27216 if(o.cancel !== true){
27217 this.tabPanel.removeTab(this.id);
27221 * The text displayed in the tooltip for the close icon.
27224 closeText : "Close this tab"
27228 Roo.TabPanel.prototype.createStrip = function(container){
27229 var strip = document.createElement("div");
27230 strip.className = "x-tabs-wrap";
27231 container.appendChild(strip);
27235 Roo.TabPanel.prototype.createStripList = function(strip){
27236 // div wrapper for retard IE
27237 // returns the "tr" element.
27238 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27239 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27240 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27241 return strip.firstChild.firstChild.firstChild.firstChild;
27244 Roo.TabPanel.prototype.createBody = function(container){
27245 var body = document.createElement("div");
27246 Roo.id(body, "tab-body");
27247 Roo.fly(body).addClass("x-tabs-body");
27248 container.appendChild(body);
27252 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27253 var body = Roo.getDom(id);
27255 body = document.createElement("div");
27258 Roo.fly(body).addClass("x-tabs-item-body");
27259 bodyEl.insertBefore(body, bodyEl.firstChild);
27263 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27264 var td = document.createElement("td");
27265 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27266 //stripEl.appendChild(td);
27268 td.className = "x-tabs-closable";
27269 if(!this.closeTpl){
27270 this.closeTpl = new Roo.Template(
27271 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27272 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27273 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27276 var el = this.closeTpl.overwrite(td, {"text": text});
27277 var close = el.getElementsByTagName("div")[0];
27278 var inner = el.getElementsByTagName("em")[0];
27279 return {"el": el, "close": close, "inner": inner};
27282 this.tabTpl = new Roo.Template(
27283 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27284 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27287 var el = this.tabTpl.overwrite(td, {"text": text});
27288 var inner = el.getElementsByTagName("em")[0];
27289 return {"el": el, "inner": inner};
27293 * Ext JS Library 1.1.1
27294 * Copyright(c) 2006-2007, Ext JS, LLC.
27296 * Originally Released Under LGPL - original licence link has changed is not relivant.
27299 * <script type="text/javascript">
27303 * @class Roo.Button
27304 * @extends Roo.util.Observable
27305 * Simple Button class
27306 * @cfg {String} text The button text
27307 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27308 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27309 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27310 * @cfg {Object} scope The scope of the handler
27311 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27312 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27313 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27314 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27315 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27316 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27317 applies if enableToggle = true)
27318 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27319 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27320 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27322 * Create a new button
27323 * @param {Object} config The config object
27325 Roo.Button = function(renderTo, config)
27329 renderTo = config.renderTo || false;
27332 Roo.apply(this, config);
27336 * Fires when this button is clicked
27337 * @param {Button} this
27338 * @param {EventObject} e The click event
27343 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27344 * @param {Button} this
27345 * @param {Boolean} pressed
27350 * Fires when the mouse hovers over the button
27351 * @param {Button} this
27352 * @param {Event} e The event object
27354 'mouseover' : true,
27357 * Fires when the mouse exits the button
27358 * @param {Button} this
27359 * @param {Event} e The event object
27364 * Fires when the button is rendered
27365 * @param {Button} this
27370 this.menu = Roo.menu.MenuMgr.get(this.menu);
27372 // register listeners first!! - so render can be captured..
27373 Roo.util.Observable.call(this);
27375 this.render(renderTo);
27381 Roo.extend(Roo.Button, Roo.util.Observable, {
27387 * Read-only. True if this button is hidden
27392 * Read-only. True if this button is disabled
27397 * Read-only. True if this button is pressed (only if enableToggle = true)
27403 * @cfg {Number} tabIndex
27404 * The DOM tabIndex for this button (defaults to undefined)
27406 tabIndex : undefined,
27409 * @cfg {Boolean} enableToggle
27410 * True to enable pressed/not pressed toggling (defaults to false)
27412 enableToggle: false,
27414 * @cfg {Mixed} menu
27415 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27419 * @cfg {String} menuAlign
27420 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27422 menuAlign : "tl-bl?",
27425 * @cfg {String} iconCls
27426 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27428 iconCls : undefined,
27430 * @cfg {String} type
27431 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27436 menuClassTarget: 'tr',
27439 * @cfg {String} clickEvent
27440 * The type of event to map to the button's event handler (defaults to 'click')
27442 clickEvent : 'click',
27445 * @cfg {Boolean} handleMouseEvents
27446 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27448 handleMouseEvents : true,
27451 * @cfg {String} tooltipType
27452 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27454 tooltipType : 'qtip',
27457 * @cfg {String} cls
27458 * A CSS class to apply to the button's main element.
27462 * @cfg {Roo.Template} template (Optional)
27463 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27464 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27465 * require code modifications if required elements (e.g. a button) aren't present.
27469 render : function(renderTo){
27471 if(this.hideParent){
27472 this.parentEl = Roo.get(renderTo);
27474 if(!this.dhconfig){
27475 if(!this.template){
27476 if(!Roo.Button.buttonTemplate){
27477 // hideous table template
27478 Roo.Button.buttonTemplate = new Roo.Template(
27479 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27480 '<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>',
27481 "</tr></tbody></table>");
27483 this.template = Roo.Button.buttonTemplate;
27485 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27486 var btnEl = btn.child("button:first");
27487 btnEl.on('focus', this.onFocus, this);
27488 btnEl.on('blur', this.onBlur, this);
27490 btn.addClass(this.cls);
27493 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27496 btnEl.addClass(this.iconCls);
27498 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27501 if(this.tabIndex !== undefined){
27502 btnEl.dom.tabIndex = this.tabIndex;
27505 if(typeof this.tooltip == 'object'){
27506 Roo.QuickTips.tips(Roo.apply({
27510 btnEl.dom[this.tooltipType] = this.tooltip;
27514 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27518 this.el.dom.id = this.el.id = this.id;
27521 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27522 this.menu.on("show", this.onMenuShow, this);
27523 this.menu.on("hide", this.onMenuHide, this);
27525 btn.addClass("x-btn");
27526 if(Roo.isIE && !Roo.isIE7){
27527 this.autoWidth.defer(1, this);
27531 if(this.handleMouseEvents){
27532 btn.on("mouseover", this.onMouseOver, this);
27533 btn.on("mouseout", this.onMouseOut, this);
27534 btn.on("mousedown", this.onMouseDown, this);
27536 btn.on(this.clickEvent, this.onClick, this);
27537 //btn.on("mouseup", this.onMouseUp, this);
27544 Roo.ButtonToggleMgr.register(this);
27546 this.el.addClass("x-btn-pressed");
27549 var repeater = new Roo.util.ClickRepeater(btn,
27550 typeof this.repeat == "object" ? this.repeat : {}
27552 repeater.on("click", this.onClick, this);
27555 this.fireEvent('render', this);
27559 * Returns the button's underlying element
27560 * @return {Roo.Element} The element
27562 getEl : function(){
27567 * Destroys this Button and removes any listeners.
27569 destroy : function(){
27570 Roo.ButtonToggleMgr.unregister(this);
27571 this.el.removeAllListeners();
27572 this.purgeListeners();
27577 autoWidth : function(){
27579 this.el.setWidth("auto");
27580 if(Roo.isIE7 && Roo.isStrict){
27581 var ib = this.el.child('button');
27582 if(ib && ib.getWidth() > 20){
27584 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27589 this.el.beginMeasure();
27591 if(this.el.getWidth() < this.minWidth){
27592 this.el.setWidth(this.minWidth);
27595 this.el.endMeasure();
27602 * Assigns this button's click handler
27603 * @param {Function} handler The function to call when the button is clicked
27604 * @param {Object} scope (optional) Scope for the function passed in
27606 setHandler : function(handler, scope){
27607 this.handler = handler;
27608 this.scope = scope;
27612 * Sets this button's text
27613 * @param {String} text The button text
27615 setText : function(text){
27618 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27624 * Gets the text for this button
27625 * @return {String} The button text
27627 getText : function(){
27635 this.hidden = false;
27637 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27645 this.hidden = true;
27647 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27652 * Convenience function for boolean show/hide
27653 * @param {Boolean} visible True to show, false to hide
27655 setVisible: function(visible){
27664 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27665 * @param {Boolean} state (optional) Force a particular state
27667 toggle : function(state){
27668 state = state === undefined ? !this.pressed : state;
27669 if(state != this.pressed){
27671 this.el.addClass("x-btn-pressed");
27672 this.pressed = true;
27673 this.fireEvent("toggle", this, true);
27675 this.el.removeClass("x-btn-pressed");
27676 this.pressed = false;
27677 this.fireEvent("toggle", this, false);
27679 if(this.toggleHandler){
27680 this.toggleHandler.call(this.scope || this, this, state);
27688 focus : function(){
27689 this.el.child('button:first').focus();
27693 * Disable this button
27695 disable : function(){
27697 this.el.addClass("x-btn-disabled");
27699 this.disabled = true;
27703 * Enable this button
27705 enable : function(){
27707 this.el.removeClass("x-btn-disabled");
27709 this.disabled = false;
27713 * Convenience function for boolean enable/disable
27714 * @param {Boolean} enabled True to enable, false to disable
27716 setDisabled : function(v){
27717 this[v !== true ? "enable" : "disable"]();
27721 onClick : function(e){
27723 e.preventDefault();
27728 if(!this.disabled){
27729 if(this.enableToggle){
27732 if(this.menu && !this.menu.isVisible()){
27733 this.menu.show(this.el, this.menuAlign);
27735 this.fireEvent("click", this, e);
27737 this.el.removeClass("x-btn-over");
27738 this.handler.call(this.scope || this, this, e);
27743 onMouseOver : function(e){
27744 if(!this.disabled){
27745 this.el.addClass("x-btn-over");
27746 this.fireEvent('mouseover', this, e);
27750 onMouseOut : function(e){
27751 if(!e.within(this.el, true)){
27752 this.el.removeClass("x-btn-over");
27753 this.fireEvent('mouseout', this, e);
27757 onFocus : function(e){
27758 if(!this.disabled){
27759 this.el.addClass("x-btn-focus");
27763 onBlur : function(e){
27764 this.el.removeClass("x-btn-focus");
27767 onMouseDown : function(e){
27768 if(!this.disabled && e.button == 0){
27769 this.el.addClass("x-btn-click");
27770 Roo.get(document).on('mouseup', this.onMouseUp, this);
27774 onMouseUp : function(e){
27776 this.el.removeClass("x-btn-click");
27777 Roo.get(document).un('mouseup', this.onMouseUp, this);
27781 onMenuShow : function(e){
27782 this.el.addClass("x-btn-menu-active");
27785 onMenuHide : function(e){
27786 this.el.removeClass("x-btn-menu-active");
27790 // Private utility class used by Button
27791 Roo.ButtonToggleMgr = function(){
27794 function toggleGroup(btn, state){
27796 var g = groups[btn.toggleGroup];
27797 for(var i = 0, l = g.length; i < l; i++){
27799 g[i].toggle(false);
27806 register : function(btn){
27807 if(!btn.toggleGroup){
27810 var g = groups[btn.toggleGroup];
27812 g = groups[btn.toggleGroup] = [];
27815 btn.on("toggle", toggleGroup);
27818 unregister : function(btn){
27819 if(!btn.toggleGroup){
27822 var g = groups[btn.toggleGroup];
27825 btn.un("toggle", toggleGroup);
27831 * Ext JS Library 1.1.1
27832 * Copyright(c) 2006-2007, Ext JS, LLC.
27834 * Originally Released Under LGPL - original licence link has changed is not relivant.
27837 * <script type="text/javascript">
27841 * @class Roo.SplitButton
27842 * @extends Roo.Button
27843 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27844 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27845 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27846 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27847 * @cfg {String} arrowTooltip The title attribute of the arrow
27849 * Create a new menu button
27850 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27851 * @param {Object} config The config object
27853 Roo.SplitButton = function(renderTo, config){
27854 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27856 * @event arrowclick
27857 * Fires when this button's arrow is clicked
27858 * @param {SplitButton} this
27859 * @param {EventObject} e The click event
27861 this.addEvents({"arrowclick":true});
27864 Roo.extend(Roo.SplitButton, Roo.Button, {
27865 render : function(renderTo){
27866 // this is one sweet looking template!
27867 var tpl = new Roo.Template(
27868 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27869 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27870 '<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>',
27871 "</tbody></table></td><td>",
27872 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27873 '<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>',
27874 "</tbody></table></td></tr></table>"
27876 var btn = tpl.append(renderTo, [this.text, this.type], true);
27877 var btnEl = btn.child("button");
27879 btn.addClass(this.cls);
27882 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27885 btnEl.addClass(this.iconCls);
27887 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27891 if(this.handleMouseEvents){
27892 btn.on("mouseover", this.onMouseOver, this);
27893 btn.on("mouseout", this.onMouseOut, this);
27894 btn.on("mousedown", this.onMouseDown, this);
27895 btn.on("mouseup", this.onMouseUp, this);
27897 btn.on(this.clickEvent, this.onClick, this);
27899 if(typeof this.tooltip == 'object'){
27900 Roo.QuickTips.tips(Roo.apply({
27904 btnEl.dom[this.tooltipType] = this.tooltip;
27907 if(this.arrowTooltip){
27908 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27917 this.el.addClass("x-btn-pressed");
27919 if(Roo.isIE && !Roo.isIE7){
27920 this.autoWidth.defer(1, this);
27925 this.menu.on("show", this.onMenuShow, this);
27926 this.menu.on("hide", this.onMenuHide, this);
27928 this.fireEvent('render', this);
27932 autoWidth : function(){
27934 var tbl = this.el.child("table:first");
27935 var tbl2 = this.el.child("table:last");
27936 this.el.setWidth("auto");
27937 tbl.setWidth("auto");
27938 if(Roo.isIE7 && Roo.isStrict){
27939 var ib = this.el.child('button:first');
27940 if(ib && ib.getWidth() > 20){
27942 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27947 this.el.beginMeasure();
27949 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27950 tbl.setWidth(this.minWidth-tbl2.getWidth());
27953 this.el.endMeasure();
27956 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27960 * Sets this button's click handler
27961 * @param {Function} handler The function to call when the button is clicked
27962 * @param {Object} scope (optional) Scope for the function passed above
27964 setHandler : function(handler, scope){
27965 this.handler = handler;
27966 this.scope = scope;
27970 * Sets this button's arrow click handler
27971 * @param {Function} handler The function to call when the arrow is clicked
27972 * @param {Object} scope (optional) Scope for the function passed above
27974 setArrowHandler : function(handler, scope){
27975 this.arrowHandler = handler;
27976 this.scope = scope;
27982 focus : function(){
27984 this.el.child("button:first").focus();
27989 onClick : function(e){
27990 e.preventDefault();
27991 if(!this.disabled){
27992 if(e.getTarget(".x-btn-menu-arrow-wrap")){
27993 if(this.menu && !this.menu.isVisible()){
27994 this.menu.show(this.el, this.menuAlign);
27996 this.fireEvent("arrowclick", this, e);
27997 if(this.arrowHandler){
27998 this.arrowHandler.call(this.scope || this, this, e);
28001 this.fireEvent("click", this, e);
28003 this.handler.call(this.scope || this, this, e);
28009 onMouseDown : function(e){
28010 if(!this.disabled){
28011 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28015 onMouseUp : function(e){
28016 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28021 // backwards compat
28022 Roo.MenuButton = Roo.SplitButton;/*
28024 * Ext JS Library 1.1.1
28025 * Copyright(c) 2006-2007, Ext JS, LLC.
28027 * Originally Released Under LGPL - original licence link has changed is not relivant.
28030 * <script type="text/javascript">
28034 * @class Roo.Toolbar
28035 * Basic Toolbar class.
28037 * Creates a new Toolbar
28038 * @param {Object} container The config object
28040 Roo.Toolbar = function(container, buttons, config)
28042 /// old consturctor format still supported..
28043 if(container instanceof Array){ // omit the container for later rendering
28044 buttons = container;
28048 if (typeof(container) == 'object' && container.xtype) {
28049 config = container;
28050 container = config.container;
28051 buttons = config.buttons || []; // not really - use items!!
28054 if (config && config.items) {
28055 xitems = config.items;
28056 delete config.items;
28058 Roo.apply(this, config);
28059 this.buttons = buttons;
28062 this.render(container);
28064 this.xitems = xitems;
28065 Roo.each(xitems, function(b) {
28071 Roo.Toolbar.prototype = {
28073 * @cfg {Array} items
28074 * array of button configs or elements to add (will be converted to a MixedCollection)
28078 * @cfg {String/HTMLElement/Element} container
28079 * The id or element that will contain the toolbar
28082 render : function(ct){
28083 this.el = Roo.get(ct);
28085 this.el.addClass(this.cls);
28087 // using a table allows for vertical alignment
28088 // 100% width is needed by Safari...
28089 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28090 this.tr = this.el.child("tr", true);
28092 this.items = new Roo.util.MixedCollection(false, function(o){
28093 return o.id || ("item" + (++autoId));
28096 this.add.apply(this, this.buttons);
28097 delete this.buttons;
28102 * Adds element(s) to the toolbar -- this function takes a variable number of
28103 * arguments of mixed type and adds them to the toolbar.
28104 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28106 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28107 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28108 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28109 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28110 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28111 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28112 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28113 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28114 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28116 * @param {Mixed} arg2
28117 * @param {Mixed} etc.
28120 var a = arguments, l = a.length;
28121 for(var i = 0; i < l; i++){
28126 _add : function(el) {
28129 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28132 if (el.applyTo){ // some kind of form field
28133 return this.addField(el);
28135 if (el.render){ // some kind of Toolbar.Item
28136 return this.addItem(el);
28138 if (typeof el == "string"){ // string
28139 if(el == "separator" || el == "-"){
28140 return this.addSeparator();
28143 return this.addSpacer();
28146 return this.addFill();
28148 return this.addText(el);
28151 if(el.tagName){ // element
28152 return this.addElement(el);
28154 if(typeof el == "object"){ // must be button config?
28155 return this.addButton(el);
28157 // and now what?!?!
28163 * Add an Xtype element
28164 * @param {Object} xtype Xtype Object
28165 * @return {Object} created Object
28167 addxtype : function(e){
28168 return this.add(e);
28172 * Returns the Element for this toolbar.
28173 * @return {Roo.Element}
28175 getEl : function(){
28181 * @return {Roo.Toolbar.Item} The separator item
28183 addSeparator : function(){
28184 return this.addItem(new Roo.Toolbar.Separator());
28188 * Adds a spacer element
28189 * @return {Roo.Toolbar.Spacer} The spacer item
28191 addSpacer : function(){
28192 return this.addItem(new Roo.Toolbar.Spacer());
28196 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28197 * @return {Roo.Toolbar.Fill} The fill item
28199 addFill : function(){
28200 return this.addItem(new Roo.Toolbar.Fill());
28204 * Adds any standard HTML element to the toolbar
28205 * @param {String/HTMLElement/Element} el The element or id of the element to add
28206 * @return {Roo.Toolbar.Item} The element's item
28208 addElement : function(el){
28209 return this.addItem(new Roo.Toolbar.Item(el));
28212 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28213 * @type Roo.util.MixedCollection
28218 * Adds any Toolbar.Item or subclass
28219 * @param {Roo.Toolbar.Item} item
28220 * @return {Roo.Toolbar.Item} The item
28222 addItem : function(item){
28223 var td = this.nextBlock();
28225 this.items.add(item);
28230 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28231 * @param {Object/Array} config A button config or array of configs
28232 * @return {Roo.Toolbar.Button/Array}
28234 addButton : function(config){
28235 if(config instanceof Array){
28237 for(var i = 0, len = config.length; i < len; i++) {
28238 buttons.push(this.addButton(config[i]));
28243 if(!(config instanceof Roo.Toolbar.Button)){
28245 new Roo.Toolbar.SplitButton(config) :
28246 new Roo.Toolbar.Button(config);
28248 var td = this.nextBlock();
28255 * Adds text to the toolbar
28256 * @param {String} text The text to add
28257 * @return {Roo.Toolbar.Item} The element's item
28259 addText : function(text){
28260 return this.addItem(new Roo.Toolbar.TextItem(text));
28264 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28265 * @param {Number} index The index where the item is to be inserted
28266 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28267 * @return {Roo.Toolbar.Button/Item}
28269 insertButton : function(index, item){
28270 if(item instanceof Array){
28272 for(var i = 0, len = item.length; i < len; i++) {
28273 buttons.push(this.insertButton(index + i, item[i]));
28277 if (!(item instanceof Roo.Toolbar.Button)){
28278 item = new Roo.Toolbar.Button(item);
28280 var td = document.createElement("td");
28281 this.tr.insertBefore(td, this.tr.childNodes[index]);
28283 this.items.insert(index, item);
28288 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28289 * @param {Object} config
28290 * @return {Roo.Toolbar.Item} The element's item
28292 addDom : function(config, returnEl){
28293 var td = this.nextBlock();
28294 Roo.DomHelper.overwrite(td, config);
28295 var ti = new Roo.Toolbar.Item(td.firstChild);
28297 this.items.add(ti);
28302 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28303 * @type Roo.util.MixedCollection
28308 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28309 * Note: the field should not have been rendered yet. For a field that has already been
28310 * rendered, use {@link #addElement}.
28311 * @param {Roo.form.Field} field
28312 * @return {Roo.ToolbarItem}
28316 addField : function(field) {
28317 if (!this.fields) {
28319 this.fields = new Roo.util.MixedCollection(false, function(o){
28320 return o.id || ("item" + (++autoId));
28325 var td = this.nextBlock();
28327 var ti = new Roo.Toolbar.Item(td.firstChild);
28329 this.items.add(ti);
28330 this.fields.add(field);
28341 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28342 this.el.child('div').hide();
28350 this.el.child('div').show();
28354 nextBlock : function(){
28355 var td = document.createElement("td");
28356 this.tr.appendChild(td);
28361 destroy : function(){
28362 if(this.items){ // rendered?
28363 Roo.destroy.apply(Roo, this.items.items);
28365 if(this.fields){ // rendered?
28366 Roo.destroy.apply(Roo, this.fields.items);
28368 Roo.Element.uncache(this.el, this.tr);
28373 * @class Roo.Toolbar.Item
28374 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28376 * Creates a new Item
28377 * @param {HTMLElement} el
28379 Roo.Toolbar.Item = function(el){
28380 this.el = Roo.getDom(el);
28381 this.id = Roo.id(this.el);
28382 this.hidden = false;
28385 Roo.Toolbar.Item.prototype = {
28388 * Get this item's HTML Element
28389 * @return {HTMLElement}
28391 getEl : function(){
28396 render : function(td){
28398 td.appendChild(this.el);
28402 * Removes and destroys this item.
28404 destroy : function(){
28405 this.td.parentNode.removeChild(this.td);
28412 this.hidden = false;
28413 this.td.style.display = "";
28420 this.hidden = true;
28421 this.td.style.display = "none";
28425 * Convenience function for boolean show/hide.
28426 * @param {Boolean} visible true to show/false to hide
28428 setVisible: function(visible){
28437 * Try to focus this item.
28439 focus : function(){
28440 Roo.fly(this.el).focus();
28444 * Disables this item.
28446 disable : function(){
28447 Roo.fly(this.td).addClass("x-item-disabled");
28448 this.disabled = true;
28449 this.el.disabled = true;
28453 * Enables this item.
28455 enable : function(){
28456 Roo.fly(this.td).removeClass("x-item-disabled");
28457 this.disabled = false;
28458 this.el.disabled = false;
28464 * @class Roo.Toolbar.Separator
28465 * @extends Roo.Toolbar.Item
28466 * A simple toolbar separator class
28468 * Creates a new Separator
28470 Roo.Toolbar.Separator = function(){
28471 var s = document.createElement("span");
28472 s.className = "ytb-sep";
28473 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
28475 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28476 enable:Roo.emptyFn,
28477 disable:Roo.emptyFn,
28482 * @class Roo.Toolbar.Spacer
28483 * @extends Roo.Toolbar.Item
28484 * A simple element that adds extra horizontal space to a toolbar.
28486 * Creates a new Spacer
28488 Roo.Toolbar.Spacer = function(){
28489 var s = document.createElement("div");
28490 s.className = "ytb-spacer";
28491 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
28493 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28494 enable:Roo.emptyFn,
28495 disable:Roo.emptyFn,
28500 * @class Roo.Toolbar.Fill
28501 * @extends Roo.Toolbar.Spacer
28502 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28504 * Creates a new Spacer
28506 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28508 render : function(td){
28509 td.style.width = '100%';
28510 Roo.Toolbar.Fill.superclass.render.call(this, td);
28515 * @class Roo.Toolbar.TextItem
28516 * @extends Roo.Toolbar.Item
28517 * A simple class that renders text directly into a toolbar.
28519 * Creates a new TextItem
28520 * @param {String} text
28522 Roo.Toolbar.TextItem = function(text){
28523 if (typeof(text) == 'object') {
28526 var s = document.createElement("span");
28527 s.className = "ytb-text";
28528 s.innerHTML = text;
28529 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28531 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28532 enable:Roo.emptyFn,
28533 disable:Roo.emptyFn,
28538 * @class Roo.Toolbar.Button
28539 * @extends Roo.Button
28540 * A button that renders into a toolbar.
28542 * Creates a new Button
28543 * @param {Object} config A standard {@link Roo.Button} config object
28545 Roo.Toolbar.Button = function(config){
28546 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28548 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28549 render : function(td){
28551 Roo.Toolbar.Button.superclass.render.call(this, td);
28555 * Removes and destroys this button
28557 destroy : function(){
28558 Roo.Toolbar.Button.superclass.destroy.call(this);
28559 this.td.parentNode.removeChild(this.td);
28563 * Shows this button
28566 this.hidden = false;
28567 this.td.style.display = "";
28571 * Hides this button
28574 this.hidden = true;
28575 this.td.style.display = "none";
28579 * Disables this item
28581 disable : function(){
28582 Roo.fly(this.td).addClass("x-item-disabled");
28583 this.disabled = true;
28587 * Enables this item
28589 enable : function(){
28590 Roo.fly(this.td).removeClass("x-item-disabled");
28591 this.disabled = false;
28594 // backwards compat
28595 Roo.ToolbarButton = Roo.Toolbar.Button;
28598 * @class Roo.Toolbar.SplitButton
28599 * @extends Roo.SplitButton
28600 * A menu button that renders into a toolbar.
28602 * Creates a new SplitButton
28603 * @param {Object} config A standard {@link Roo.SplitButton} config object
28605 Roo.Toolbar.SplitButton = function(config){
28606 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28608 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28609 render : function(td){
28611 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28615 * Removes and destroys this button
28617 destroy : function(){
28618 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28619 this.td.parentNode.removeChild(this.td);
28623 * Shows this button
28626 this.hidden = false;
28627 this.td.style.display = "";
28631 * Hides this button
28634 this.hidden = true;
28635 this.td.style.display = "none";
28639 // backwards compat
28640 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28642 * Ext JS Library 1.1.1
28643 * Copyright(c) 2006-2007, Ext JS, LLC.
28645 * Originally Released Under LGPL - original licence link has changed is not relivant.
28648 * <script type="text/javascript">
28652 * @class Roo.PagingToolbar
28653 * @extends Roo.Toolbar
28654 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28656 * Create a new PagingToolbar
28657 * @param {Object} config The config object
28659 Roo.PagingToolbar = function(el, ds, config)
28661 // old args format still supported... - xtype is prefered..
28662 if (typeof(el) == 'object' && el.xtype) {
28663 // created from xtype...
28665 ds = el.dataSource;
28666 el = config.container;
28669 if (config.items) {
28670 items = config.items;
28674 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28677 this.renderButtons(this.el);
28680 // supprot items array.
28682 Roo.each(items, function(e) {
28683 this.add(Roo.factory(e));
28688 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28690 * @cfg {Roo.data.Store} dataSource
28691 * The underlying data store providing the paged data
28694 * @cfg {String/HTMLElement/Element} container
28695 * container The id or element that will contain the toolbar
28698 * @cfg {Boolean} displayInfo
28699 * True to display the displayMsg (defaults to false)
28702 * @cfg {Number} pageSize
28703 * The number of records to display per page (defaults to 20)
28707 * @cfg {String} displayMsg
28708 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28710 displayMsg : 'Displaying {0} - {1} of {2}',
28712 * @cfg {String} emptyMsg
28713 * The message to display when no records are found (defaults to "No data to display")
28715 emptyMsg : 'No data to display',
28717 * Customizable piece of the default paging text (defaults to "Page")
28720 beforePageText : "Page",
28722 * Customizable piece of the default paging text (defaults to "of %0")
28725 afterPageText : "of {0}",
28727 * Customizable piece of the default paging text (defaults to "First Page")
28730 firstText : "First Page",
28732 * Customizable piece of the default paging text (defaults to "Previous Page")
28735 prevText : "Previous Page",
28737 * Customizable piece of the default paging text (defaults to "Next Page")
28740 nextText : "Next Page",
28742 * Customizable piece of the default paging text (defaults to "Last Page")
28745 lastText : "Last Page",
28747 * Customizable piece of the default paging text (defaults to "Refresh")
28750 refreshText : "Refresh",
28753 renderButtons : function(el){
28754 Roo.PagingToolbar.superclass.render.call(this, el);
28755 this.first = this.addButton({
28756 tooltip: this.firstText,
28757 cls: "x-btn-icon x-grid-page-first",
28759 handler: this.onClick.createDelegate(this, ["first"])
28761 this.prev = this.addButton({
28762 tooltip: this.prevText,
28763 cls: "x-btn-icon x-grid-page-prev",
28765 handler: this.onClick.createDelegate(this, ["prev"])
28767 //this.addSeparator();
28768 this.add(this.beforePageText);
28769 this.field = Roo.get(this.addDom({
28774 cls: "x-grid-page-number"
28776 this.field.on("keydown", this.onPagingKeydown, this);
28777 this.field.on("focus", function(){this.dom.select();});
28778 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28779 this.field.setHeight(18);
28780 //this.addSeparator();
28781 this.next = this.addButton({
28782 tooltip: this.nextText,
28783 cls: "x-btn-icon x-grid-page-next",
28785 handler: this.onClick.createDelegate(this, ["next"])
28787 this.last = this.addButton({
28788 tooltip: this.lastText,
28789 cls: "x-btn-icon x-grid-page-last",
28791 handler: this.onClick.createDelegate(this, ["last"])
28793 //this.addSeparator();
28794 this.loading = this.addButton({
28795 tooltip: this.refreshText,
28796 cls: "x-btn-icon x-grid-loading",
28797 handler: this.onClick.createDelegate(this, ["refresh"])
28800 if(this.displayInfo){
28801 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28806 updateInfo : function(){
28807 if(this.displayEl){
28808 var count = this.ds.getCount();
28809 var msg = count == 0 ?
28813 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28815 this.displayEl.update(msg);
28820 onLoad : function(ds, r, o){
28821 this.cursor = o.params ? o.params.start : 0;
28822 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28824 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28825 this.field.dom.value = ap;
28826 this.first.setDisabled(ap == 1);
28827 this.prev.setDisabled(ap == 1);
28828 this.next.setDisabled(ap == ps);
28829 this.last.setDisabled(ap == ps);
28830 this.loading.enable();
28835 getPageData : function(){
28836 var total = this.ds.getTotalCount();
28839 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28840 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28845 onLoadError : function(){
28846 this.loading.enable();
28850 onPagingKeydown : function(e){
28851 var k = e.getKey();
28852 var d = this.getPageData();
28854 var v = this.field.dom.value, pageNum;
28855 if(!v || isNaN(pageNum = parseInt(v, 10))){
28856 this.field.dom.value = d.activePage;
28859 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28860 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28863 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))
28865 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28866 this.field.dom.value = pageNum;
28867 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28870 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28872 var v = this.field.dom.value, pageNum;
28873 var increment = (e.shiftKey) ? 10 : 1;
28874 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28876 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28877 this.field.dom.value = d.activePage;
28880 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28882 this.field.dom.value = parseInt(v, 10) + increment;
28883 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28884 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28891 beforeLoad : function(){
28893 this.loading.disable();
28898 onClick : function(which){
28902 ds.load({params:{start: 0, limit: this.pageSize}});
28905 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28908 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28911 var total = ds.getTotalCount();
28912 var extra = total % this.pageSize;
28913 var lastStart = extra ? (total - extra) : total-this.pageSize;
28914 ds.load({params:{start: lastStart, limit: this.pageSize}});
28917 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28923 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28924 * @param {Roo.data.Store} store The data store to unbind
28926 unbind : function(ds){
28927 ds.un("beforeload", this.beforeLoad, this);
28928 ds.un("load", this.onLoad, this);
28929 ds.un("loadexception", this.onLoadError, this);
28930 ds.un("remove", this.updateInfo, this);
28931 ds.un("add", this.updateInfo, this);
28932 this.ds = undefined;
28936 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28937 * @param {Roo.data.Store} store The data store to bind
28939 bind : function(ds){
28940 ds.on("beforeload", this.beforeLoad, this);
28941 ds.on("load", this.onLoad, this);
28942 ds.on("loadexception", this.onLoadError, this);
28943 ds.on("remove", this.updateInfo, this);
28944 ds.on("add", this.updateInfo, this);
28949 * Ext JS Library 1.1.1
28950 * Copyright(c) 2006-2007, Ext JS, LLC.
28952 * Originally Released Under LGPL - original licence link has changed is not relivant.
28955 * <script type="text/javascript">
28959 * @class Roo.Resizable
28960 * @extends Roo.util.Observable
28961 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28962 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28963 * 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
28964 * the element will be wrapped for you automatically.</p>
28965 * <p>Here is the list of valid resize handles:</p>
28968 ------ -------------------
28977 'hd' horizontal drag
28980 * <p>Here's an example showing the creation of a typical Resizable:</p>
28982 var resizer = new Roo.Resizable("element-id", {
28990 resizer.on("resize", myHandler);
28992 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
28993 * resizer.east.setDisplayed(false);</p>
28994 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
28995 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
28996 * resize operation's new size (defaults to [0, 0])
28997 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
28998 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
28999 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29000 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29001 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29002 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29003 * @cfg {Number} width The width of the element in pixels (defaults to null)
29004 * @cfg {Number} height The height of the element in pixels (defaults to null)
29005 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29006 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29007 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29008 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29009 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29010 * in favor of the handles config option (defaults to false)
29011 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29012 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29013 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29014 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29015 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29016 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29017 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29018 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29019 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29020 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29021 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29023 * Create a new resizable component
29024 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29025 * @param {Object} config configuration options
29027 Roo.Resizable = function(el, config)
29029 this.el = Roo.get(el);
29031 if(config && config.wrap){
29032 config.resizeChild = this.el;
29033 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29034 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29035 this.el.setStyle("overflow", "hidden");
29036 this.el.setPositioning(config.resizeChild.getPositioning());
29037 config.resizeChild.clearPositioning();
29038 if(!config.width || !config.height){
29039 var csize = config.resizeChild.getSize();
29040 this.el.setSize(csize.width, csize.height);
29042 if(config.pinned && !config.adjustments){
29043 config.adjustments = "auto";
29047 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29048 this.proxy.unselectable();
29049 this.proxy.enableDisplayMode('block');
29051 Roo.apply(this, config);
29054 this.disableTrackOver = true;
29055 this.el.addClass("x-resizable-pinned");
29057 // if the element isn't positioned, make it relative
29058 var position = this.el.getStyle("position");
29059 if(position != "absolute" && position != "fixed"){
29060 this.el.setStyle("position", "relative");
29062 if(!this.handles){ // no handles passed, must be legacy style
29063 this.handles = 's,e,se';
29064 if(this.multiDirectional){
29065 this.handles += ',n,w';
29068 if(this.handles == "all"){
29069 this.handles = "n s e w ne nw se sw";
29071 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29072 var ps = Roo.Resizable.positions;
29073 for(var i = 0, len = hs.length; i < len; i++){
29074 if(hs[i] && ps[hs[i]]){
29075 var pos = ps[hs[i]];
29076 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29080 this.corner = this.southeast;
29082 // updateBox = the box can move..
29083 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29084 this.updateBox = true;
29087 this.activeHandle = null;
29089 if(this.resizeChild){
29090 if(typeof this.resizeChild == "boolean"){
29091 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29093 this.resizeChild = Roo.get(this.resizeChild, true);
29097 if(this.adjustments == "auto"){
29098 var rc = this.resizeChild;
29099 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29100 if(rc && (hw || hn)){
29101 rc.position("relative");
29102 rc.setLeft(hw ? hw.el.getWidth() : 0);
29103 rc.setTop(hn ? hn.el.getHeight() : 0);
29105 this.adjustments = [
29106 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29107 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29111 if(this.draggable){
29112 this.dd = this.dynamic ?
29113 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29114 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29120 * @event beforeresize
29121 * Fired before resize is allowed. Set enabled to false to cancel resize.
29122 * @param {Roo.Resizable} this
29123 * @param {Roo.EventObject} e The mousedown event
29125 "beforeresize" : true,
29128 * Fired a resizing.
29129 * @param {Roo.Resizable} this
29130 * @param {Number} x The new x position
29131 * @param {Number} y The new y position
29132 * @param {Number} w The new w width
29133 * @param {Number} h The new h hight
29134 * @param {Roo.EventObject} e The mouseup event
29139 * Fired after a resize.
29140 * @param {Roo.Resizable} this
29141 * @param {Number} width The new width
29142 * @param {Number} height The new height
29143 * @param {Roo.EventObject} e The mouseup event
29148 if(this.width !== null && this.height !== null){
29149 this.resizeTo(this.width, this.height);
29151 this.updateChildSize();
29154 this.el.dom.style.zoom = 1;
29156 Roo.Resizable.superclass.constructor.call(this);
29159 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29160 resizeChild : false,
29161 adjustments : [0, 0],
29171 multiDirectional : false,
29172 disableTrackOver : false,
29173 easing : 'easeOutStrong',
29174 widthIncrement : 0,
29175 heightIncrement : 0,
29179 preserveRatio : false,
29180 transparent: false,
29186 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29188 constrainTo: undefined,
29190 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29192 resizeRegion: undefined,
29196 * Perform a manual resize
29197 * @param {Number} width
29198 * @param {Number} height
29200 resizeTo : function(width, height){
29201 this.el.setSize(width, height);
29202 this.updateChildSize();
29203 this.fireEvent("resize", this, width, height, null);
29207 startSizing : function(e, handle){
29208 this.fireEvent("beforeresize", this, e);
29209 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29212 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29213 this.overlay.unselectable();
29214 this.overlay.enableDisplayMode("block");
29215 this.overlay.on("mousemove", this.onMouseMove, this);
29216 this.overlay.on("mouseup", this.onMouseUp, this);
29218 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29220 this.resizing = true;
29221 this.startBox = this.el.getBox();
29222 this.startPoint = e.getXY();
29223 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29224 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29226 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29227 this.overlay.show();
29229 if(this.constrainTo) {
29230 var ct = Roo.get(this.constrainTo);
29231 this.resizeRegion = ct.getRegion().adjust(
29232 ct.getFrameWidth('t'),
29233 ct.getFrameWidth('l'),
29234 -ct.getFrameWidth('b'),
29235 -ct.getFrameWidth('r')
29239 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29241 this.proxy.setBox(this.startBox);
29243 this.proxy.setStyle('visibility', 'visible');
29249 onMouseDown : function(handle, e){
29252 this.activeHandle = handle;
29253 this.startSizing(e, handle);
29258 onMouseUp : function(e){
29259 var size = this.resizeElement();
29260 this.resizing = false;
29262 this.overlay.hide();
29264 this.fireEvent("resize", this, size.width, size.height, e);
29268 updateChildSize : function(){
29270 if(this.resizeChild){
29272 var child = this.resizeChild;
29273 var adj = this.adjustments;
29274 if(el.dom.offsetWidth){
29275 var b = el.getSize(true);
29276 child.setSize(b.width+adj[0], b.height+adj[1]);
29278 // Second call here for IE
29279 // The first call enables instant resizing and
29280 // the second call corrects scroll bars if they
29283 setTimeout(function(){
29284 if(el.dom.offsetWidth){
29285 var b = el.getSize(true);
29286 child.setSize(b.width+adj[0], b.height+adj[1]);
29294 snap : function(value, inc, min){
29295 if(!inc || !value) return value;
29296 var newValue = value;
29297 var m = value % inc;
29300 newValue = value + (inc-m);
29302 newValue = value - m;
29305 return Math.max(min, newValue);
29309 resizeElement : function(){
29310 var box = this.proxy.getBox();
29311 if(this.updateBox){
29312 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29314 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29316 this.updateChildSize();
29324 constrain : function(v, diff, m, mx){
29327 }else if(v - diff > mx){
29334 onMouseMove : function(e){
29337 try{// try catch so if something goes wrong the user doesn't get hung
29339 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29343 //var curXY = this.startPoint;
29344 var curSize = this.curSize || this.startBox;
29345 var x = this.startBox.x, y = this.startBox.y;
29346 var ox = x, oy = y;
29347 var w = curSize.width, h = curSize.height;
29348 var ow = w, oh = h;
29349 var mw = this.minWidth, mh = this.minHeight;
29350 var mxw = this.maxWidth, mxh = this.maxHeight;
29351 var wi = this.widthIncrement;
29352 var hi = this.heightIncrement;
29354 var eventXY = e.getXY();
29355 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29356 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29358 var pos = this.activeHandle.position;
29363 w = Math.min(Math.max(mw, w), mxw);
29368 h = Math.min(Math.max(mh, h), mxh);
29373 w = Math.min(Math.max(mw, w), mxw);
29374 h = Math.min(Math.max(mh, h), mxh);
29377 diffY = this.constrain(h, diffY, mh, mxh);
29384 var adiffX = Math.abs(diffX);
29385 var sub = (adiffX % wi); // how much
29386 if (sub > (wi/2)) { // far enough to snap
29387 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29389 // remove difference..
29390 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29394 x = Math.max(this.minX, x);
29397 diffX = this.constrain(w, diffX, mw, mxw);
29403 w = Math.min(Math.max(mw, w), mxw);
29404 diffY = this.constrain(h, diffY, mh, mxh);
29409 diffX = this.constrain(w, diffX, mw, mxw);
29410 diffY = this.constrain(h, diffY, mh, mxh);
29417 diffX = this.constrain(w, diffX, mw, mxw);
29419 h = Math.min(Math.max(mh, h), mxh);
29425 var sw = this.snap(w, wi, mw);
29426 var sh = this.snap(h, hi, mh);
29427 if(sw != w || sh != h){
29450 if(this.preserveRatio){
29455 h = Math.min(Math.max(mh, h), mxh);
29460 w = Math.min(Math.max(mw, w), mxw);
29465 w = Math.min(Math.max(mw, w), mxw);
29471 w = Math.min(Math.max(mw, w), mxw);
29477 h = Math.min(Math.max(mh, h), mxh);
29485 h = Math.min(Math.max(mh, h), mxh);
29495 h = Math.min(Math.max(mh, h), mxh);
29503 if (pos == 'hdrag') {
29506 this.proxy.setBounds(x, y, w, h);
29508 this.resizeElement();
29512 this.fireEvent("resizing", this, x, y, w, h, e);
29516 handleOver : function(){
29518 this.el.addClass("x-resizable-over");
29523 handleOut : function(){
29524 if(!this.resizing){
29525 this.el.removeClass("x-resizable-over");
29530 * Returns the element this component is bound to.
29531 * @return {Roo.Element}
29533 getEl : function(){
29538 * Returns the resizeChild element (or null).
29539 * @return {Roo.Element}
29541 getResizeChild : function(){
29542 return this.resizeChild;
29544 groupHandler : function()
29549 * Destroys this resizable. If the element was wrapped and
29550 * removeEl is not true then the element remains.
29551 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29553 destroy : function(removeEl){
29554 this.proxy.remove();
29556 this.overlay.removeAllListeners();
29557 this.overlay.remove();
29559 var ps = Roo.Resizable.positions;
29561 if(typeof ps[k] != "function" && this[ps[k]]){
29562 var h = this[ps[k]];
29563 h.el.removeAllListeners();
29568 this.el.update("");
29575 // hash to map config positions to true positions
29576 Roo.Resizable.positions = {
29577 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29582 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29584 // only initialize the template if resizable is used
29585 var tpl = Roo.DomHelper.createTemplate(
29586 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29589 Roo.Resizable.Handle.prototype.tpl = tpl;
29591 this.position = pos;
29593 // show north drag fro topdra
29594 var handlepos = pos == 'hdrag' ? 'north' : pos;
29596 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29597 if (pos == 'hdrag') {
29598 this.el.setStyle('cursor', 'pointer');
29600 this.el.unselectable();
29602 this.el.setOpacity(0);
29604 this.el.on("mousedown", this.onMouseDown, this);
29605 if(!disableTrackOver){
29606 this.el.on("mouseover", this.onMouseOver, this);
29607 this.el.on("mouseout", this.onMouseOut, this);
29612 Roo.Resizable.Handle.prototype = {
29613 afterResize : function(rz){
29618 onMouseDown : function(e){
29619 this.rz.onMouseDown(this, e);
29622 onMouseOver : function(e){
29623 this.rz.handleOver(this, e);
29626 onMouseOut : function(e){
29627 this.rz.handleOut(this, e);
29631 * Ext JS Library 1.1.1
29632 * Copyright(c) 2006-2007, Ext JS, LLC.
29634 * Originally Released Under LGPL - original licence link has changed is not relivant.
29637 * <script type="text/javascript">
29641 * @class Roo.Editor
29642 * @extends Roo.Component
29643 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29645 * Create a new Editor
29646 * @param {Roo.form.Field} field The Field object (or descendant)
29647 * @param {Object} config The config object
29649 Roo.Editor = function(field, config){
29650 Roo.Editor.superclass.constructor.call(this, config);
29651 this.field = field;
29654 * @event beforestartedit
29655 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29656 * false from the handler of this event.
29657 * @param {Editor} this
29658 * @param {Roo.Element} boundEl The underlying element bound to this editor
29659 * @param {Mixed} value The field value being set
29661 "beforestartedit" : true,
29664 * Fires when this editor is displayed
29665 * @param {Roo.Element} boundEl The underlying element bound to this editor
29666 * @param {Mixed} value The starting field value
29668 "startedit" : true,
29670 * @event beforecomplete
29671 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29672 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29673 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29674 * event will not fire since no edit actually occurred.
29675 * @param {Editor} this
29676 * @param {Mixed} value The current field value
29677 * @param {Mixed} startValue The original field value
29679 "beforecomplete" : true,
29682 * Fires after editing is complete and any changed value has been written to the underlying field.
29683 * @param {Editor} this
29684 * @param {Mixed} value The current field value
29685 * @param {Mixed} startValue The original field value
29689 * @event specialkey
29690 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29691 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29692 * @param {Roo.form.Field} this
29693 * @param {Roo.EventObject} e The event object
29695 "specialkey" : true
29699 Roo.extend(Roo.Editor, Roo.Component, {
29701 * @cfg {Boolean/String} autosize
29702 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29703 * or "height" to adopt the height only (defaults to false)
29706 * @cfg {Boolean} revertInvalid
29707 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29708 * validation fails (defaults to true)
29711 * @cfg {Boolean} ignoreNoChange
29712 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29713 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29714 * will never be ignored.
29717 * @cfg {Boolean} hideEl
29718 * False to keep the bound element visible while the editor is displayed (defaults to true)
29721 * @cfg {Mixed} value
29722 * The data value of the underlying field (defaults to "")
29726 * @cfg {String} alignment
29727 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29731 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29732 * for bottom-right shadow (defaults to "frame")
29736 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29740 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29742 completeOnEnter : false,
29744 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29746 cancelOnEsc : false,
29748 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29753 onRender : function(ct, position){
29754 this.el = new Roo.Layer({
29755 shadow: this.shadow,
29761 constrain: this.constrain
29763 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29764 if(this.field.msgTarget != 'title'){
29765 this.field.msgTarget = 'qtip';
29767 this.field.render(this.el);
29769 this.field.el.dom.setAttribute('autocomplete', 'off');
29771 this.field.on("specialkey", this.onSpecialKey, this);
29772 if(this.swallowKeys){
29773 this.field.el.swallowEvent(['keydown','keypress']);
29776 this.field.on("blur", this.onBlur, this);
29777 if(this.field.grow){
29778 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29782 onSpecialKey : function(field, e)
29784 //Roo.log('editor onSpecialKey');
29785 if(this.completeOnEnter && e.getKey() == e.ENTER){
29787 this.completeEdit();
29790 // do not fire special key otherwise it might hide close the editor...
29791 if(e.getKey() == e.ENTER){
29794 if(this.cancelOnEsc && e.getKey() == e.ESC){
29798 this.fireEvent('specialkey', field, e);
29803 * Starts the editing process and shows the editor.
29804 * @param {String/HTMLElement/Element} el The element to edit
29805 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29806 * to the innerHTML of el.
29808 startEdit : function(el, value){
29810 this.completeEdit();
29812 this.boundEl = Roo.get(el);
29813 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29814 if(!this.rendered){
29815 this.render(this.parentEl || document.body);
29817 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29820 this.startValue = v;
29821 this.field.setValue(v);
29823 var sz = this.boundEl.getSize();
29824 switch(this.autoSize){
29826 this.setSize(sz.width, "");
29829 this.setSize("", sz.height);
29832 this.setSize(sz.width, sz.height);
29835 this.el.alignTo(this.boundEl, this.alignment);
29836 this.editing = true;
29838 Roo.QuickTips.disable();
29844 * Sets the height and width of this editor.
29845 * @param {Number} width The new width
29846 * @param {Number} height The new height
29848 setSize : function(w, h){
29849 this.field.setSize(w, h);
29856 * Realigns the editor to the bound field based on the current alignment config value.
29858 realign : function(){
29859 this.el.alignTo(this.boundEl, this.alignment);
29863 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29864 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29866 completeEdit : function(remainVisible){
29870 var v = this.getValue();
29871 if(this.revertInvalid !== false && !this.field.isValid()){
29872 v = this.startValue;
29873 this.cancelEdit(true);
29875 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29876 this.editing = false;
29880 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29881 this.editing = false;
29882 if(this.updateEl && this.boundEl){
29883 this.boundEl.update(v);
29885 if(remainVisible !== true){
29888 this.fireEvent("complete", this, v, this.startValue);
29893 onShow : function(){
29895 if(this.hideEl !== false){
29896 this.boundEl.hide();
29899 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29900 this.fixIEFocus = true;
29901 this.deferredFocus.defer(50, this);
29903 this.field.focus();
29905 this.fireEvent("startedit", this.boundEl, this.startValue);
29908 deferredFocus : function(){
29910 this.field.focus();
29915 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29916 * reverted to the original starting value.
29917 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29918 * cancel (defaults to false)
29920 cancelEdit : function(remainVisible){
29922 this.setValue(this.startValue);
29923 if(remainVisible !== true){
29930 onBlur : function(){
29931 if(this.allowBlur !== true && this.editing){
29932 this.completeEdit();
29937 onHide : function(){
29939 this.completeEdit();
29943 if(this.field.collapse){
29944 this.field.collapse();
29947 if(this.hideEl !== false){
29948 this.boundEl.show();
29951 Roo.QuickTips.enable();
29956 * Sets the data value of the editor
29957 * @param {Mixed} value Any valid value supported by the underlying field
29959 setValue : function(v){
29960 this.field.setValue(v);
29964 * Gets the data value of the editor
29965 * @return {Mixed} The data value
29967 getValue : function(){
29968 return this.field.getValue();
29972 * Ext JS Library 1.1.1
29973 * Copyright(c) 2006-2007, Ext JS, LLC.
29975 * Originally Released Under LGPL - original licence link has changed is not relivant.
29978 * <script type="text/javascript">
29982 * @class Roo.BasicDialog
29983 * @extends Roo.util.Observable
29984 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29986 var dlg = new Roo.BasicDialog("my-dlg", {
29995 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
29996 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
29997 dlg.addButton('Cancel', dlg.hide, dlg);
30000 <b>A Dialog should always be a direct child of the body element.</b>
30001 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30002 * @cfg {String} title Default text to display in the title bar (defaults to null)
30003 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30004 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30005 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30006 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30007 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30008 * (defaults to null with no animation)
30009 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30010 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30011 * property for valid values (defaults to 'all')
30012 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30013 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30014 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30015 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30016 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30017 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30018 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30019 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30020 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30021 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30022 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30023 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30024 * draggable = true (defaults to false)
30025 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30026 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30027 * shadow (defaults to false)
30028 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30029 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30030 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30031 * @cfg {Array} buttons Array of buttons
30032 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30034 * Create a new BasicDialog.
30035 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30036 * @param {Object} config Configuration options
30038 Roo.BasicDialog = function(el, config){
30039 this.el = Roo.get(el);
30040 var dh = Roo.DomHelper;
30041 if(!this.el && config && config.autoCreate){
30042 if(typeof config.autoCreate == "object"){
30043 if(!config.autoCreate.id){
30044 config.autoCreate.id = el;
30046 this.el = dh.append(document.body,
30047 config.autoCreate, true);
30049 this.el = dh.append(document.body,
30050 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30054 el.setDisplayed(true);
30055 el.hide = this.hideAction;
30057 el.addClass("x-dlg");
30059 Roo.apply(this, config);
30061 this.proxy = el.createProxy("x-dlg-proxy");
30062 this.proxy.hide = this.hideAction;
30063 this.proxy.setOpacity(.5);
30067 el.setWidth(config.width);
30070 el.setHeight(config.height);
30072 this.size = el.getSize();
30073 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30074 this.xy = [config.x,config.y];
30076 this.xy = el.getCenterXY(true);
30078 /** The header element @type Roo.Element */
30079 this.header = el.child("> .x-dlg-hd");
30080 /** The body element @type Roo.Element */
30081 this.body = el.child("> .x-dlg-bd");
30082 /** The footer element @type Roo.Element */
30083 this.footer = el.child("> .x-dlg-ft");
30086 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30089 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30092 this.header.unselectable();
30094 this.header.update(this.title);
30096 // this element allows the dialog to be focused for keyboard event
30097 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30098 this.focusEl.swallowEvent("click", true);
30100 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30102 // wrap the body and footer for special rendering
30103 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30105 this.bwrap.dom.appendChild(this.footer.dom);
30108 this.bg = this.el.createChild({
30109 tag: "div", cls:"x-dlg-bg",
30110 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30112 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30115 if(this.autoScroll !== false && !this.autoTabs){
30116 this.body.setStyle("overflow", "auto");
30119 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30121 if(this.closable !== false){
30122 this.el.addClass("x-dlg-closable");
30123 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30124 this.close.on("click", this.closeClick, this);
30125 this.close.addClassOnOver("x-dlg-close-over");
30127 if(this.collapsible !== false){
30128 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30129 this.collapseBtn.on("click", this.collapseClick, this);
30130 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30131 this.header.on("dblclick", this.collapseClick, this);
30133 if(this.resizable !== false){
30134 this.el.addClass("x-dlg-resizable");
30135 this.resizer = new Roo.Resizable(el, {
30136 minWidth: this.minWidth || 80,
30137 minHeight:this.minHeight || 80,
30138 handles: this.resizeHandles || "all",
30141 this.resizer.on("beforeresize", this.beforeResize, this);
30142 this.resizer.on("resize", this.onResize, this);
30144 if(this.draggable !== false){
30145 el.addClass("x-dlg-draggable");
30146 if (!this.proxyDrag) {
30147 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30150 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30152 dd.setHandleElId(this.header.id);
30153 dd.endDrag = this.endMove.createDelegate(this);
30154 dd.startDrag = this.startMove.createDelegate(this);
30155 dd.onDrag = this.onDrag.createDelegate(this);
30160 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30161 this.mask.enableDisplayMode("block");
30163 this.el.addClass("x-dlg-modal");
30166 this.shadow = new Roo.Shadow({
30167 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30168 offset : this.shadowOffset
30171 this.shadowOffset = 0;
30173 if(Roo.useShims && this.shim !== false){
30174 this.shim = this.el.createShim();
30175 this.shim.hide = this.hideAction;
30183 if (this.buttons) {
30184 var bts= this.buttons;
30186 Roo.each(bts, function(b) {
30195 * Fires when a key is pressed
30196 * @param {Roo.BasicDialog} this
30197 * @param {Roo.EventObject} e
30202 * Fires when this dialog is moved by the user.
30203 * @param {Roo.BasicDialog} this
30204 * @param {Number} x The new page X
30205 * @param {Number} y The new page Y
30210 * Fires when this dialog is resized by the user.
30211 * @param {Roo.BasicDialog} this
30212 * @param {Number} width The new width
30213 * @param {Number} height The new height
30217 * @event beforehide
30218 * Fires before this dialog is hidden.
30219 * @param {Roo.BasicDialog} this
30221 "beforehide" : true,
30224 * Fires when this dialog is hidden.
30225 * @param {Roo.BasicDialog} this
30229 * @event beforeshow
30230 * Fires before this dialog is shown.
30231 * @param {Roo.BasicDialog} this
30233 "beforeshow" : true,
30236 * Fires when this dialog is shown.
30237 * @param {Roo.BasicDialog} this
30241 el.on("keydown", this.onKeyDown, this);
30242 el.on("mousedown", this.toFront, this);
30243 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30245 Roo.DialogManager.register(this);
30246 Roo.BasicDialog.superclass.constructor.call(this);
30249 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30250 shadowOffset: Roo.isIE ? 6 : 5,
30253 minButtonWidth: 75,
30254 defaultButton: null,
30255 buttonAlign: "right",
30260 * Sets the dialog title text
30261 * @param {String} text The title text to display
30262 * @return {Roo.BasicDialog} this
30264 setTitle : function(text){
30265 this.header.update(text);
30270 closeClick : function(){
30275 collapseClick : function(){
30276 this[this.collapsed ? "expand" : "collapse"]();
30280 * Collapses the dialog to its minimized state (only the title bar is visible).
30281 * Equivalent to the user clicking the collapse dialog button.
30283 collapse : function(){
30284 if(!this.collapsed){
30285 this.collapsed = true;
30286 this.el.addClass("x-dlg-collapsed");
30287 this.restoreHeight = this.el.getHeight();
30288 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30293 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30294 * clicking the expand dialog button.
30296 expand : function(){
30297 if(this.collapsed){
30298 this.collapsed = false;
30299 this.el.removeClass("x-dlg-collapsed");
30300 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30305 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30306 * @return {Roo.TabPanel} The tabs component
30308 initTabs : function(){
30309 var tabs = this.getTabs();
30310 while(tabs.getTab(0)){
30313 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30315 tabs.addTab(Roo.id(dom), dom.title);
30323 beforeResize : function(){
30324 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30328 onResize : function(){
30329 this.refreshSize();
30330 this.syncBodyHeight();
30331 this.adjustAssets();
30333 this.fireEvent("resize", this, this.size.width, this.size.height);
30337 onKeyDown : function(e){
30338 if(this.isVisible()){
30339 this.fireEvent("keydown", this, e);
30344 * Resizes the dialog.
30345 * @param {Number} width
30346 * @param {Number} height
30347 * @return {Roo.BasicDialog} this
30349 resizeTo : function(width, height){
30350 this.el.setSize(width, height);
30351 this.size = {width: width, height: height};
30352 this.syncBodyHeight();
30353 if(this.fixedcenter){
30356 if(this.isVisible()){
30357 this.constrainXY();
30358 this.adjustAssets();
30360 this.fireEvent("resize", this, width, height);
30366 * Resizes the dialog to fit the specified content size.
30367 * @param {Number} width
30368 * @param {Number} height
30369 * @return {Roo.BasicDialog} this
30371 setContentSize : function(w, h){
30372 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30373 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30374 //if(!this.el.isBorderBox()){
30375 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30376 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30379 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30380 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30382 this.resizeTo(w, h);
30387 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30388 * executed in response to a particular key being pressed while the dialog is active.
30389 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30390 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30391 * @param {Function} fn The function to call
30392 * @param {Object} scope (optional) The scope of the function
30393 * @return {Roo.BasicDialog} this
30395 addKeyListener : function(key, fn, scope){
30396 var keyCode, shift, ctrl, alt;
30397 if(typeof key == "object" && !(key instanceof Array)){
30398 keyCode = key["key"];
30399 shift = key["shift"];
30400 ctrl = key["ctrl"];
30405 var handler = function(dlg, e){
30406 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30407 var k = e.getKey();
30408 if(keyCode instanceof Array){
30409 for(var i = 0, len = keyCode.length; i < len; i++){
30410 if(keyCode[i] == k){
30411 fn.call(scope || window, dlg, k, e);
30417 fn.call(scope || window, dlg, k, e);
30422 this.on("keydown", handler);
30427 * Returns the TabPanel component (creates it if it doesn't exist).
30428 * Note: If you wish to simply check for the existence of tabs without creating them,
30429 * check for a null 'tabs' property.
30430 * @return {Roo.TabPanel} The tabs component
30432 getTabs : function(){
30434 this.el.addClass("x-dlg-auto-tabs");
30435 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30436 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30442 * Adds a button to the footer section of the dialog.
30443 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30444 * object or a valid Roo.DomHelper element config
30445 * @param {Function} handler The function called when the button is clicked
30446 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30447 * @return {Roo.Button} The new button
30449 addButton : function(config, handler, scope){
30450 var dh = Roo.DomHelper;
30452 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30454 if(!this.btnContainer){
30455 var tb = this.footer.createChild({
30457 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30458 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30460 this.btnContainer = tb.firstChild.firstChild.firstChild;
30465 minWidth: this.minButtonWidth,
30468 if(typeof config == "string"){
30469 bconfig.text = config;
30472 bconfig.dhconfig = config;
30474 Roo.apply(bconfig, config);
30478 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30479 bconfig.position = Math.max(0, bconfig.position);
30480 fc = this.btnContainer.childNodes[bconfig.position];
30483 var btn = new Roo.Button(
30485 this.btnContainer.insertBefore(document.createElement("td"),fc)
30486 : this.btnContainer.appendChild(document.createElement("td")),
30487 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30490 this.syncBodyHeight();
30493 * Array of all the buttons that have been added to this dialog via addButton
30498 this.buttons.push(btn);
30503 * Sets the default button to be focused when the dialog is displayed.
30504 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30505 * @return {Roo.BasicDialog} this
30507 setDefaultButton : function(btn){
30508 this.defaultButton = btn;
30513 getHeaderFooterHeight : function(safe){
30516 height += this.header.getHeight();
30519 var fm = this.footer.getMargins();
30520 height += (this.footer.getHeight()+fm.top+fm.bottom);
30522 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30523 height += this.centerBg.getPadding("tb");
30528 syncBodyHeight : function()
30530 var bd = this.body, // the text
30531 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30533 var height = this.size.height - this.getHeaderFooterHeight(false);
30534 bd.setHeight(height-bd.getMargins("tb"));
30535 var hh = this.header.getHeight();
30536 var h = this.size.height-hh;
30539 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30540 bw.setHeight(h-cb.getPadding("tb"));
30542 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30543 bd.setWidth(bw.getWidth(true));
30545 this.tabs.syncHeight();
30547 this.tabs.el.repaint();
30553 * Restores the previous state of the dialog if Roo.state is configured.
30554 * @return {Roo.BasicDialog} this
30556 restoreState : function(){
30557 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30558 if(box && box.width){
30559 this.xy = [box.x, box.y];
30560 this.resizeTo(box.width, box.height);
30566 beforeShow : function(){
30568 if(this.fixedcenter){
30569 this.xy = this.el.getCenterXY(true);
30572 Roo.get(document.body).addClass("x-body-masked");
30573 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30576 this.constrainXY();
30580 animShow : function(){
30581 var b = Roo.get(this.animateTarget).getBox();
30582 this.proxy.setSize(b.width, b.height);
30583 this.proxy.setLocation(b.x, b.y);
30585 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30586 true, .35, this.showEl.createDelegate(this));
30590 * Shows the dialog.
30591 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30592 * @return {Roo.BasicDialog} this
30594 show : function(animateTarget){
30595 if (this.fireEvent("beforeshow", this) === false){
30598 if(this.syncHeightBeforeShow){
30599 this.syncBodyHeight();
30600 }else if(this.firstShow){
30601 this.firstShow = false;
30602 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30604 this.animateTarget = animateTarget || this.animateTarget;
30605 if(!this.el.isVisible()){
30607 if(this.animateTarget && Roo.get(this.animateTarget)){
30617 showEl : function(){
30619 this.el.setXY(this.xy);
30621 this.adjustAssets(true);
30624 // IE peekaboo bug - fix found by Dave Fenwick
30628 this.fireEvent("show", this);
30632 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30633 * dialog itself will receive focus.
30635 focus : function(){
30636 if(this.defaultButton){
30637 this.defaultButton.focus();
30639 this.focusEl.focus();
30644 constrainXY : function(){
30645 if(this.constraintoviewport !== false){
30646 if(!this.viewSize){
30647 if(this.container){
30648 var s = this.container.getSize();
30649 this.viewSize = [s.width, s.height];
30651 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30654 var s = Roo.get(this.container||document).getScroll();
30656 var x = this.xy[0], y = this.xy[1];
30657 var w = this.size.width, h = this.size.height;
30658 var vw = this.viewSize[0], vh = this.viewSize[1];
30659 // only move it if it needs it
30661 // first validate right/bottom
30662 if(x + w > vw+s.left){
30666 if(y + h > vh+s.top){
30670 // then make sure top/left isn't negative
30682 if(this.isVisible()){
30683 this.el.setLocation(x, y);
30684 this.adjustAssets();
30691 onDrag : function(){
30692 if(!this.proxyDrag){
30693 this.xy = this.el.getXY();
30694 this.adjustAssets();
30699 adjustAssets : function(doShow){
30700 var x = this.xy[0], y = this.xy[1];
30701 var w = this.size.width, h = this.size.height;
30702 if(doShow === true){
30704 this.shadow.show(this.el);
30710 if(this.shadow && this.shadow.isVisible()){
30711 this.shadow.show(this.el);
30713 if(this.shim && this.shim.isVisible()){
30714 this.shim.setBounds(x, y, w, h);
30719 adjustViewport : function(w, h){
30721 w = Roo.lib.Dom.getViewWidth();
30722 h = Roo.lib.Dom.getViewHeight();
30725 this.viewSize = [w, h];
30726 if(this.modal && this.mask.isVisible()){
30727 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30728 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30730 if(this.isVisible()){
30731 this.constrainXY();
30736 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30737 * shadow, proxy, mask, etc.) Also removes all event listeners.
30738 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30740 destroy : function(removeEl){
30741 if(this.isVisible()){
30742 this.animateTarget = null;
30745 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30747 this.tabs.destroy(removeEl);
30760 for(var i = 0, len = this.buttons.length; i < len; i++){
30761 this.buttons[i].destroy();
30764 this.el.removeAllListeners();
30765 if(removeEl === true){
30766 this.el.update("");
30769 Roo.DialogManager.unregister(this);
30773 startMove : function(){
30774 if(this.proxyDrag){
30777 if(this.constraintoviewport !== false){
30778 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30783 endMove : function(){
30784 if(!this.proxyDrag){
30785 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30787 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30790 this.refreshSize();
30791 this.adjustAssets();
30793 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30797 * Brings this dialog to the front of any other visible dialogs
30798 * @return {Roo.BasicDialog} this
30800 toFront : function(){
30801 Roo.DialogManager.bringToFront(this);
30806 * Sends this dialog to the back (under) of any other visible dialogs
30807 * @return {Roo.BasicDialog} this
30809 toBack : function(){
30810 Roo.DialogManager.sendToBack(this);
30815 * Centers this dialog in the viewport
30816 * @return {Roo.BasicDialog} this
30818 center : function(){
30819 var xy = this.el.getCenterXY(true);
30820 this.moveTo(xy[0], xy[1]);
30825 * Moves the dialog's top-left corner to the specified point
30826 * @param {Number} x
30827 * @param {Number} y
30828 * @return {Roo.BasicDialog} this
30830 moveTo : function(x, y){
30832 if(this.isVisible()){
30833 this.el.setXY(this.xy);
30834 this.adjustAssets();
30840 * Aligns the dialog to the specified element
30841 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30842 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30843 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30844 * @return {Roo.BasicDialog} this
30846 alignTo : function(element, position, offsets){
30847 this.xy = this.el.getAlignToXY(element, position, offsets);
30848 if(this.isVisible()){
30849 this.el.setXY(this.xy);
30850 this.adjustAssets();
30856 * Anchors an element to another element and realigns it when the window is resized.
30857 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30858 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30859 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30860 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30861 * is a number, it is used as the buffer delay (defaults to 50ms).
30862 * @return {Roo.BasicDialog} this
30864 anchorTo : function(el, alignment, offsets, monitorScroll){
30865 var action = function(){
30866 this.alignTo(el, alignment, offsets);
30868 Roo.EventManager.onWindowResize(action, this);
30869 var tm = typeof monitorScroll;
30870 if(tm != 'undefined'){
30871 Roo.EventManager.on(window, 'scroll', action, this,
30872 {buffer: tm == 'number' ? monitorScroll : 50});
30879 * Returns true if the dialog is visible
30880 * @return {Boolean}
30882 isVisible : function(){
30883 return this.el.isVisible();
30887 animHide : function(callback){
30888 var b = Roo.get(this.animateTarget).getBox();
30890 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30892 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30893 this.hideEl.createDelegate(this, [callback]));
30897 * Hides the dialog.
30898 * @param {Function} callback (optional) Function to call when the dialog is hidden
30899 * @return {Roo.BasicDialog} this
30901 hide : function(callback){
30902 if (this.fireEvent("beforehide", this) === false){
30906 this.shadow.hide();
30911 // sometimes animateTarget seems to get set.. causing problems...
30912 // this just double checks..
30913 if(this.animateTarget && Roo.get(this.animateTarget)) {
30914 this.animHide(callback);
30917 this.hideEl(callback);
30923 hideEl : function(callback){
30927 Roo.get(document.body).removeClass("x-body-masked");
30929 this.fireEvent("hide", this);
30930 if(typeof callback == "function"){
30936 hideAction : function(){
30937 this.setLeft("-10000px");
30938 this.setTop("-10000px");
30939 this.setStyle("visibility", "hidden");
30943 refreshSize : function(){
30944 this.size = this.el.getSize();
30945 this.xy = this.el.getXY();
30946 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30950 // z-index is managed by the DialogManager and may be overwritten at any time
30951 setZIndex : function(index){
30953 this.mask.setStyle("z-index", index);
30956 this.shim.setStyle("z-index", ++index);
30959 this.shadow.setZIndex(++index);
30961 this.el.setStyle("z-index", ++index);
30963 this.proxy.setStyle("z-index", ++index);
30966 this.resizer.proxy.setStyle("z-index", ++index);
30969 this.lastZIndex = index;
30973 * Returns the element for this dialog
30974 * @return {Roo.Element} The underlying dialog Element
30976 getEl : function(){
30982 * @class Roo.DialogManager
30983 * Provides global access to BasicDialogs that have been created and
30984 * support for z-indexing (layering) multiple open dialogs.
30986 Roo.DialogManager = function(){
30988 var accessList = [];
30992 var sortDialogs = function(d1, d2){
30993 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
30997 var orderDialogs = function(){
30998 accessList.sort(sortDialogs);
30999 var seed = Roo.DialogManager.zseed;
31000 for(var i = 0, len = accessList.length; i < len; i++){
31001 var dlg = accessList[i];
31003 dlg.setZIndex(seed + (i*10));
31010 * The starting z-index for BasicDialogs (defaults to 9000)
31011 * @type Number The z-index value
31016 register : function(dlg){
31017 list[dlg.id] = dlg;
31018 accessList.push(dlg);
31022 unregister : function(dlg){
31023 delete list[dlg.id];
31026 if(!accessList.indexOf){
31027 for( i = 0, len = accessList.length; i < len; i++){
31028 if(accessList[i] == dlg){
31029 accessList.splice(i, 1);
31034 i = accessList.indexOf(dlg);
31036 accessList.splice(i, 1);
31042 * Gets a registered dialog by id
31043 * @param {String/Object} id The id of the dialog or a dialog
31044 * @return {Roo.BasicDialog} this
31046 get : function(id){
31047 return typeof id == "object" ? id : list[id];
31051 * Brings the specified dialog to the front
31052 * @param {String/Object} dlg The id of the dialog or a dialog
31053 * @return {Roo.BasicDialog} this
31055 bringToFront : function(dlg){
31056 dlg = this.get(dlg);
31059 dlg._lastAccess = new Date().getTime();
31066 * Sends the specified dialog to the back
31067 * @param {String/Object} dlg The id of the dialog or a dialog
31068 * @return {Roo.BasicDialog} this
31070 sendToBack : function(dlg){
31071 dlg = this.get(dlg);
31072 dlg._lastAccess = -(new Date().getTime());
31078 * Hides all dialogs
31080 hideAll : function(){
31081 for(var id in list){
31082 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31091 * @class Roo.LayoutDialog
31092 * @extends Roo.BasicDialog
31093 * Dialog which provides adjustments for working with a layout in a Dialog.
31094 * Add your necessary layout config options to the dialog's config.<br>
31095 * Example usage (including a nested layout):
31098 dialog = new Roo.LayoutDialog("download-dlg", {
31107 // layout config merges with the dialog config
31109 tabPosition: "top",
31110 alwaysShowTabs: true
31113 dialog.addKeyListener(27, dialog.hide, dialog);
31114 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31115 dialog.addButton("Build It!", this.getDownload, this);
31117 // we can even add nested layouts
31118 var innerLayout = new Roo.BorderLayout("dl-inner", {
31128 innerLayout.beginUpdate();
31129 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31130 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31131 innerLayout.endUpdate(true);
31133 var layout = dialog.getLayout();
31134 layout.beginUpdate();
31135 layout.add("center", new Roo.ContentPanel("standard-panel",
31136 {title: "Download the Source", fitToFrame:true}));
31137 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31138 {title: "Build your own roo.js"}));
31139 layout.getRegion("center").showPanel(sp);
31140 layout.endUpdate();
31144 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31145 * @param {Object} config configuration options
31147 Roo.LayoutDialog = function(el, cfg){
31150 if (typeof(cfg) == 'undefined') {
31151 config = Roo.apply({}, el);
31152 // not sure why we use documentElement here.. - it should always be body.
31153 // IE7 borks horribly if we use documentElement.
31154 // webkit also does not like documentElement - it creates a body element...
31155 el = Roo.get( document.body || document.documentElement ).createChild();
31156 //config.autoCreate = true;
31160 config.autoTabs = false;
31161 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31162 this.body.setStyle({overflow:"hidden", position:"relative"});
31163 this.layout = new Roo.BorderLayout(this.body.dom, config);
31164 this.layout.monitorWindowResize = false;
31165 this.el.addClass("x-dlg-auto-layout");
31166 // fix case when center region overwrites center function
31167 this.center = Roo.BasicDialog.prototype.center;
31168 this.on("show", this.layout.layout, this.layout, true);
31169 if (config.items) {
31170 var xitems = config.items;
31171 delete config.items;
31172 Roo.each(xitems, this.addxtype, this);
31177 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31179 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31182 endUpdate : function(){
31183 this.layout.endUpdate();
31187 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31190 beginUpdate : function(){
31191 this.layout.beginUpdate();
31195 * Get the BorderLayout for this dialog
31196 * @return {Roo.BorderLayout}
31198 getLayout : function(){
31199 return this.layout;
31202 showEl : function(){
31203 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31205 this.layout.layout();
31210 // Use the syncHeightBeforeShow config option to control this automatically
31211 syncBodyHeight : function(){
31212 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31213 if(this.layout){this.layout.layout();}
31217 * Add an xtype element (actually adds to the layout.)
31218 * @return {Object} xdata xtype object data.
31221 addxtype : function(c) {
31222 return this.layout.addxtype(c);
31226 * Ext JS Library 1.1.1
31227 * Copyright(c) 2006-2007, Ext JS, LLC.
31229 * Originally Released Under LGPL - original licence link has changed is not relivant.
31232 * <script type="text/javascript">
31236 * @class Roo.MessageBox
31237 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31241 Roo.Msg.alert('Status', 'Changes saved successfully.');
31243 // Prompt for user data:
31244 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31246 // process text value...
31250 // Show a dialog using config options:
31252 title:'Save Changes?',
31253 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31254 buttons: Roo.Msg.YESNOCANCEL,
31261 Roo.MessageBox = function(){
31262 var dlg, opt, mask, waitTimer;
31263 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31264 var buttons, activeTextEl, bwidth;
31267 var handleButton = function(button){
31269 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31273 var handleHide = function(){
31274 if(opt && opt.cls){
31275 dlg.el.removeClass(opt.cls);
31278 Roo.TaskMgr.stop(waitTimer);
31284 var updateButtons = function(b){
31287 buttons["ok"].hide();
31288 buttons["cancel"].hide();
31289 buttons["yes"].hide();
31290 buttons["no"].hide();
31291 dlg.footer.dom.style.display = 'none';
31294 dlg.footer.dom.style.display = '';
31295 for(var k in buttons){
31296 if(typeof buttons[k] != "function"){
31299 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31300 width += buttons[k].el.getWidth()+15;
31310 var handleEsc = function(d, k, e){
31311 if(opt && opt.closable !== false){
31321 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31322 * @return {Roo.BasicDialog} The BasicDialog element
31324 getDialog : function(){
31326 dlg = new Roo.BasicDialog("x-msg-box", {
31331 constraintoviewport:false,
31333 collapsible : false,
31336 width:400, height:100,
31337 buttonAlign:"center",
31338 closeClick : function(){
31339 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31340 handleButton("no");
31342 handleButton("cancel");
31346 dlg.on("hide", handleHide);
31348 dlg.addKeyListener(27, handleEsc);
31350 var bt = this.buttonText;
31351 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31352 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31353 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31354 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31355 bodyEl = dlg.body.createChild({
31357 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>'
31359 msgEl = bodyEl.dom.firstChild;
31360 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31361 textboxEl.enableDisplayMode();
31362 textboxEl.addKeyListener([10,13], function(){
31363 if(dlg.isVisible() && opt && opt.buttons){
31364 if(opt.buttons.ok){
31365 handleButton("ok");
31366 }else if(opt.buttons.yes){
31367 handleButton("yes");
31371 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31372 textareaEl.enableDisplayMode();
31373 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31374 progressEl.enableDisplayMode();
31375 var pf = progressEl.dom.firstChild;
31377 pp = Roo.get(pf.firstChild);
31378 pp.setHeight(pf.offsetHeight);
31386 * Updates the message box body text
31387 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31388 * the XHTML-compliant non-breaking space character '&#160;')
31389 * @return {Roo.MessageBox} This message box
31391 updateText : function(text){
31392 if(!dlg.isVisible() && !opt.width){
31393 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31395 msgEl.innerHTML = text || ' ';
31397 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31398 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31400 Math.min(opt.width || cw , this.maxWidth),
31401 Math.max(opt.minWidth || this.minWidth, bwidth)
31404 activeTextEl.setWidth(w);
31406 if(dlg.isVisible()){
31407 dlg.fixedcenter = false;
31409 // to big, make it scroll. = But as usual stupid IE does not support
31412 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31413 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31414 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31416 bodyEl.dom.style.height = '';
31417 bodyEl.dom.style.overflowY = '';
31420 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31422 bodyEl.dom.style.overflowX = '';
31425 dlg.setContentSize(w, bodyEl.getHeight());
31426 if(dlg.isVisible()){
31427 dlg.fixedcenter = true;
31433 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31434 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31435 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31436 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31437 * @return {Roo.MessageBox} This message box
31439 updateProgress : function(value, text){
31441 this.updateText(text);
31443 if (pp) { // weird bug on my firefox - for some reason this is not defined
31444 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31450 * Returns true if the message box is currently displayed
31451 * @return {Boolean} True if the message box is visible, else false
31453 isVisible : function(){
31454 return dlg && dlg.isVisible();
31458 * Hides the message box if it is displayed
31461 if(this.isVisible()){
31467 * Displays a new message box, or reinitializes an existing message box, based on the config options
31468 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31469 * The following config object properties are supported:
31471 Property Type Description
31472 ---------- --------------- ------------------------------------------------------------------------------------
31473 animEl String/Element An id or Element from which the message box should animate as it opens and
31474 closes (defaults to undefined)
31475 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31476 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31477 closable Boolean False to hide the top-right close button (defaults to true). Note that
31478 progress and wait dialogs will ignore this property and always hide the
31479 close button as they can only be closed programmatically.
31480 cls String A custom CSS class to apply to the message box element
31481 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31482 displayed (defaults to 75)
31483 fn Function A callback function to execute after closing the dialog. The arguments to the
31484 function will be btn (the name of the button that was clicked, if applicable,
31485 e.g. "ok"), and text (the value of the active text field, if applicable).
31486 Progress and wait dialogs will ignore this option since they do not respond to
31487 user actions and can only be closed programmatically, so any required function
31488 should be called by the same code after it closes the dialog.
31489 icon String A CSS class that provides a background image to be used as an icon for
31490 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31491 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31492 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31493 modal Boolean False to allow user interaction with the page while the message box is
31494 displayed (defaults to true)
31495 msg String A string that will replace the existing message box body text (defaults
31496 to the XHTML-compliant non-breaking space character ' ')
31497 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31498 progress Boolean True to display a progress bar (defaults to false)
31499 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31500 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31501 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31502 title String The title text
31503 value String The string value to set into the active textbox element if displayed
31504 wait Boolean True to display a progress bar (defaults to false)
31505 width Number The width of the dialog in pixels
31512 msg: 'Please enter your address:',
31514 buttons: Roo.MessageBox.OKCANCEL,
31517 animEl: 'addAddressBtn'
31520 * @param {Object} config Configuration options
31521 * @return {Roo.MessageBox} This message box
31523 show : function(options)
31526 // this causes nightmares if you show one dialog after another
31527 // especially on callbacks..
31529 if(this.isVisible()){
31532 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31533 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31534 Roo.log("New Dialog Message:" + options.msg )
31535 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31536 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31539 var d = this.getDialog();
31541 d.setTitle(opt.title || " ");
31542 d.close.setDisplayed(opt.closable !== false);
31543 activeTextEl = textboxEl;
31544 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31549 textareaEl.setHeight(typeof opt.multiline == "number" ?
31550 opt.multiline : this.defaultTextHeight);
31551 activeTextEl = textareaEl;
31560 progressEl.setDisplayed(opt.progress === true);
31561 this.updateProgress(0);
31562 activeTextEl.dom.value = opt.value || "";
31564 dlg.setDefaultButton(activeTextEl);
31566 var bs = opt.buttons;
31569 db = buttons["ok"];
31570 }else if(bs && bs.yes){
31571 db = buttons["yes"];
31573 dlg.setDefaultButton(db);
31575 bwidth = updateButtons(opt.buttons);
31576 this.updateText(opt.msg);
31578 d.el.addClass(opt.cls);
31580 d.proxyDrag = opt.proxyDrag === true;
31581 d.modal = opt.modal !== false;
31582 d.mask = opt.modal !== false ? mask : false;
31583 if(!d.isVisible()){
31584 // force it to the end of the z-index stack so it gets a cursor in FF
31585 document.body.appendChild(dlg.el.dom);
31586 d.animateTarget = null;
31587 d.show(options.animEl);
31593 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31594 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31595 * and closing the message box when the process is complete.
31596 * @param {String} title The title bar text
31597 * @param {String} msg The message box body text
31598 * @return {Roo.MessageBox} This message box
31600 progress : function(title, msg){
31607 minWidth: this.minProgressWidth,
31614 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31615 * If a callback function is passed it will be called after the user clicks the button, and the
31616 * id of the button that was clicked will be passed as the only parameter to the callback
31617 * (could also be the top-right close button).
31618 * @param {String} title The title bar text
31619 * @param {String} msg The message box body text
31620 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31621 * @param {Object} scope (optional) The scope of the callback function
31622 * @return {Roo.MessageBox} This message box
31624 alert : function(title, msg, fn, scope){
31637 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31638 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31639 * You are responsible for closing the message box when the process is complete.
31640 * @param {String} msg The message box body text
31641 * @param {String} title (optional) The title bar text
31642 * @return {Roo.MessageBox} This message box
31644 wait : function(msg, title){
31655 waitTimer = Roo.TaskMgr.start({
31657 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31665 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31666 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31667 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31668 * @param {String} title The title bar text
31669 * @param {String} msg The message box body text
31670 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31671 * @param {Object} scope (optional) The scope of the callback function
31672 * @return {Roo.MessageBox} This message box
31674 confirm : function(title, msg, fn, scope){
31678 buttons: this.YESNO,
31687 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31688 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31689 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31690 * (could also be the top-right close button) and the text that was entered will be passed as the two
31691 * parameters to the callback.
31692 * @param {String} title The title bar text
31693 * @param {String} msg The message box body text
31694 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31695 * @param {Object} scope (optional) The scope of the callback function
31696 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31697 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31698 * @return {Roo.MessageBox} This message box
31700 prompt : function(title, msg, fn, scope, multiline){
31704 buttons: this.OKCANCEL,
31709 multiline: multiline,
31716 * Button config that displays a single OK button
31721 * Button config that displays Yes and No buttons
31724 YESNO : {yes:true, no:true},
31726 * Button config that displays OK and Cancel buttons
31729 OKCANCEL : {ok:true, cancel:true},
31731 * Button config that displays Yes, No and Cancel buttons
31734 YESNOCANCEL : {yes:true, no:true, cancel:true},
31737 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31740 defaultTextHeight : 75,
31742 * The maximum width in pixels of the message box (defaults to 600)
31747 * The minimum width in pixels of the message box (defaults to 100)
31752 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31753 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31756 minProgressWidth : 250,
31758 * An object containing the default button text strings that can be overriden for localized language support.
31759 * Supported properties are: ok, cancel, yes and no.
31760 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31773 * Shorthand for {@link Roo.MessageBox}
31775 Roo.Msg = Roo.MessageBox;/*
31777 * Ext JS Library 1.1.1
31778 * Copyright(c) 2006-2007, Ext JS, LLC.
31780 * Originally Released Under LGPL - original licence link has changed is not relivant.
31783 * <script type="text/javascript">
31786 * @class Roo.QuickTips
31787 * Provides attractive and customizable tooltips for any element.
31790 Roo.QuickTips = function(){
31791 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31792 var ce, bd, xy, dd;
31793 var visible = false, disabled = true, inited = false;
31794 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31796 var onOver = function(e){
31800 var t = e.getTarget();
31801 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31804 if(ce && t == ce.el){
31805 clearTimeout(hideProc);
31808 if(t && tagEls[t.id]){
31809 tagEls[t.id].el = t;
31810 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31813 var ttp, et = Roo.fly(t);
31814 var ns = cfg.namespace;
31815 if(tm.interceptTitles && t.title){
31818 t.removeAttribute("title");
31819 e.preventDefault();
31821 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31824 showProc = show.defer(tm.showDelay, tm, [{
31827 width: et.getAttributeNS(ns, cfg.width),
31828 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31829 title: et.getAttributeNS(ns, cfg.title),
31830 cls: et.getAttributeNS(ns, cfg.cls)
31835 var onOut = function(e){
31836 clearTimeout(showProc);
31837 var t = e.getTarget();
31838 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31839 hideProc = setTimeout(hide, tm.hideDelay);
31843 var onMove = function(e){
31849 if(tm.trackMouse && ce){
31854 var onDown = function(e){
31855 clearTimeout(showProc);
31856 clearTimeout(hideProc);
31858 if(tm.hideOnClick){
31861 tm.enable.defer(100, tm);
31866 var getPad = function(){
31867 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31870 var show = function(o){
31874 clearTimeout(dismissProc);
31876 if(removeCls){ // in case manually hidden
31877 el.removeClass(removeCls);
31881 el.addClass(ce.cls);
31882 removeCls = ce.cls;
31885 tipTitle.update(ce.title);
31888 tipTitle.update('');
31891 el.dom.style.width = tm.maxWidth+'px';
31892 //tipBody.dom.style.width = '';
31893 tipBodyText.update(o.text);
31894 var p = getPad(), w = ce.width;
31896 var td = tipBodyText.dom;
31897 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31898 if(aw > tm.maxWidth){
31900 }else if(aw < tm.minWidth){
31906 //tipBody.setWidth(w);
31907 el.setWidth(parseInt(w, 10) + p);
31908 if(ce.autoHide === false){
31909 close.setDisplayed(true);
31914 close.setDisplayed(false);
31920 el.avoidY = xy[1]-18;
31925 el.setStyle("visibility", "visible");
31926 el.fadeIn({callback: afterShow});
31932 var afterShow = function(){
31936 if(tm.autoDismiss && ce.autoHide !== false){
31937 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31942 var hide = function(noanim){
31943 clearTimeout(dismissProc);
31944 clearTimeout(hideProc);
31946 if(el.isVisible()){
31948 if(noanim !== true && tm.animate){
31949 el.fadeOut({callback: afterHide});
31956 var afterHide = function(){
31959 el.removeClass(removeCls);
31966 * @cfg {Number} minWidth
31967 * The minimum width of the quick tip (defaults to 40)
31971 * @cfg {Number} maxWidth
31972 * The maximum width of the quick tip (defaults to 300)
31976 * @cfg {Boolean} interceptTitles
31977 * True to automatically use the element's DOM title value if available (defaults to false)
31979 interceptTitles : false,
31981 * @cfg {Boolean} trackMouse
31982 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31984 trackMouse : false,
31986 * @cfg {Boolean} hideOnClick
31987 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
31989 hideOnClick : true,
31991 * @cfg {Number} showDelay
31992 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
31996 * @cfg {Number} hideDelay
31997 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32001 * @cfg {Boolean} autoHide
32002 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32003 * Used in conjunction with hideDelay.
32008 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32009 * (defaults to true). Used in conjunction with autoDismissDelay.
32011 autoDismiss : true,
32014 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32016 autoDismissDelay : 5000,
32018 * @cfg {Boolean} animate
32019 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32024 * @cfg {String} title
32025 * Title text to display (defaults to ''). This can be any valid HTML markup.
32029 * @cfg {String} text
32030 * Body text to display (defaults to ''). This can be any valid HTML markup.
32034 * @cfg {String} cls
32035 * A CSS class to apply to the base quick tip element (defaults to '').
32039 * @cfg {Number} width
32040 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32041 * minWidth or maxWidth.
32046 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32047 * or display QuickTips in a page.
32050 tm = Roo.QuickTips;
32051 cfg = tm.tagConfig;
32053 if(!Roo.isReady){ // allow calling of init() before onReady
32054 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32057 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32058 el.fxDefaults = {stopFx: true};
32059 // maximum custom styling
32060 //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>');
32061 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>');
32062 tipTitle = el.child('h3');
32063 tipTitle.enableDisplayMode("block");
32064 tipBody = el.child('div.x-tip-bd');
32065 tipBodyText = el.child('div.x-tip-bd-inner');
32066 //bdLeft = el.child('div.x-tip-bd-left');
32067 //bdRight = el.child('div.x-tip-bd-right');
32068 close = el.child('div.x-tip-close');
32069 close.enableDisplayMode("block");
32070 close.on("click", hide);
32071 var d = Roo.get(document);
32072 d.on("mousedown", onDown);
32073 d.on("mouseover", onOver);
32074 d.on("mouseout", onOut);
32075 d.on("mousemove", onMove);
32076 esc = d.addKeyListener(27, hide);
32079 dd = el.initDD("default", null, {
32080 onDrag : function(){
32084 dd.setHandleElId(tipTitle.id);
32093 * Configures a new quick tip instance and assigns it to a target element. The following config options
32096 Property Type Description
32097 ---------- --------------------- ------------------------------------------------------------------------
32098 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32100 * @param {Object} config The config object
32102 register : function(config){
32103 var cs = config instanceof Array ? config : arguments;
32104 for(var i = 0, len = cs.length; i < len; i++) {
32106 var target = c.target;
32108 if(target instanceof Array){
32109 for(var j = 0, jlen = target.length; j < jlen; j++){
32110 tagEls[target[j]] = c;
32113 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32120 * Removes this quick tip from its element and destroys it.
32121 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32123 unregister : function(el){
32124 delete tagEls[Roo.id(el)];
32128 * Enable this quick tip.
32130 enable : function(){
32131 if(inited && disabled){
32133 if(locks.length < 1){
32140 * Disable this quick tip.
32142 disable : function(){
32144 clearTimeout(showProc);
32145 clearTimeout(hideProc);
32146 clearTimeout(dismissProc);
32154 * Returns true if the quick tip is enabled, else false.
32156 isEnabled : function(){
32163 attribute : "qtip",
32173 // backwards compat
32174 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32176 * Ext JS Library 1.1.1
32177 * Copyright(c) 2006-2007, Ext JS, LLC.
32179 * Originally Released Under LGPL - original licence link has changed is not relivant.
32182 * <script type="text/javascript">
32187 * @class Roo.tree.TreePanel
32188 * @extends Roo.data.Tree
32190 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32191 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32192 * @cfg {Boolean} enableDD true to enable drag and drop
32193 * @cfg {Boolean} enableDrag true to enable just drag
32194 * @cfg {Boolean} enableDrop true to enable just drop
32195 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32196 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32197 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32198 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32199 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32200 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32201 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32202 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32203 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32204 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32205 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32206 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32207 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32208 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32209 * @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>
32210 * @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>
32213 * @param {String/HTMLElement/Element} el The container element
32214 * @param {Object} config
32216 Roo.tree.TreePanel = function(el, config){
32218 var loader = false;
32220 root = config.root;
32221 delete config.root;
32223 if (config.loader) {
32224 loader = config.loader;
32225 delete config.loader;
32228 Roo.apply(this, config);
32229 Roo.tree.TreePanel.superclass.constructor.call(this);
32230 this.el = Roo.get(el);
32231 this.el.addClass('x-tree');
32232 //console.log(root);
32234 this.setRootNode( Roo.factory(root, Roo.tree));
32237 this.loader = Roo.factory(loader, Roo.tree);
32240 * Read-only. The id of the container element becomes this TreePanel's id.
32242 this.id = this.el.id;
32245 * @event beforeload
32246 * Fires before a node is loaded, return false to cancel
32247 * @param {Node} node The node being loaded
32249 "beforeload" : true,
32252 * Fires when a node is loaded
32253 * @param {Node} node The node that was loaded
32257 * @event textchange
32258 * Fires when the text for a node is changed
32259 * @param {Node} node The node
32260 * @param {String} text The new text
32261 * @param {String} oldText The old text
32263 "textchange" : true,
32265 * @event beforeexpand
32266 * Fires before a node is expanded, return false to cancel.
32267 * @param {Node} node The node
32268 * @param {Boolean} deep
32269 * @param {Boolean} anim
32271 "beforeexpand" : true,
32273 * @event beforecollapse
32274 * Fires before a node is collapsed, return false to cancel.
32275 * @param {Node} node The node
32276 * @param {Boolean} deep
32277 * @param {Boolean} anim
32279 "beforecollapse" : true,
32282 * Fires when a node is expanded
32283 * @param {Node} node The node
32287 * @event disabledchange
32288 * Fires when the disabled status of a node changes
32289 * @param {Node} node The node
32290 * @param {Boolean} disabled
32292 "disabledchange" : true,
32295 * Fires when a node is collapsed
32296 * @param {Node} node The node
32300 * @event beforeclick
32301 * Fires before click processing on a node. Return false to cancel the default action.
32302 * @param {Node} node The node
32303 * @param {Roo.EventObject} e The event object
32305 "beforeclick":true,
32307 * @event checkchange
32308 * Fires when a node with a checkbox's checked property changes
32309 * @param {Node} this This node
32310 * @param {Boolean} checked
32312 "checkchange":true,
32315 * Fires when a node is clicked
32316 * @param {Node} node The node
32317 * @param {Roo.EventObject} e The event object
32322 * Fires when a node is double clicked
32323 * @param {Node} node The node
32324 * @param {Roo.EventObject} e The event object
32328 * @event contextmenu
32329 * Fires when a node is right clicked
32330 * @param {Node} node The node
32331 * @param {Roo.EventObject} e The event object
32333 "contextmenu":true,
32335 * @event beforechildrenrendered
32336 * Fires right before the child nodes for a node are rendered
32337 * @param {Node} node The node
32339 "beforechildrenrendered":true,
32342 * Fires when a node starts being dragged
32343 * @param {Roo.tree.TreePanel} this
32344 * @param {Roo.tree.TreeNode} node
32345 * @param {event} e The raw browser event
32347 "startdrag" : true,
32350 * Fires when a drag operation is complete
32351 * @param {Roo.tree.TreePanel} this
32352 * @param {Roo.tree.TreeNode} node
32353 * @param {event} e The raw browser event
32358 * Fires when a dragged node is dropped on a valid DD target
32359 * @param {Roo.tree.TreePanel} this
32360 * @param {Roo.tree.TreeNode} node
32361 * @param {DD} dd The dd it was dropped on
32362 * @param {event} e The raw browser event
32366 * @event beforenodedrop
32367 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32368 * passed to handlers has the following properties:<br />
32369 * <ul style="padding:5px;padding-left:16px;">
32370 * <li>tree - The TreePanel</li>
32371 * <li>target - The node being targeted for the drop</li>
32372 * <li>data - The drag data from the drag source</li>
32373 * <li>point - The point of the drop - append, above or below</li>
32374 * <li>source - The drag source</li>
32375 * <li>rawEvent - Raw mouse event</li>
32376 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32377 * to be inserted by setting them on this object.</li>
32378 * <li>cancel - Set this to true to cancel the drop.</li>
32380 * @param {Object} dropEvent
32382 "beforenodedrop" : true,
32385 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32386 * passed to handlers has the following properties:<br />
32387 * <ul style="padding:5px;padding-left:16px;">
32388 * <li>tree - The TreePanel</li>
32389 * <li>target - The node being targeted for the drop</li>
32390 * <li>data - The drag data from the drag source</li>
32391 * <li>point - The point of the drop - append, above or below</li>
32392 * <li>source - The drag source</li>
32393 * <li>rawEvent - Raw mouse event</li>
32394 * <li>dropNode - Dropped node(s).</li>
32396 * @param {Object} dropEvent
32400 * @event nodedragover
32401 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32402 * passed to handlers has the following properties:<br />
32403 * <ul style="padding:5px;padding-left:16px;">
32404 * <li>tree - The TreePanel</li>
32405 * <li>target - The node being targeted for the drop</li>
32406 * <li>data - The drag data from the drag source</li>
32407 * <li>point - The point of the drop - append, above or below</li>
32408 * <li>source - The drag source</li>
32409 * <li>rawEvent - Raw mouse event</li>
32410 * <li>dropNode - Drop node(s) provided by the source.</li>
32411 * <li>cancel - Set this to true to signal drop not allowed.</li>
32413 * @param {Object} dragOverEvent
32415 "nodedragover" : true
32418 if(this.singleExpand){
32419 this.on("beforeexpand", this.restrictExpand, this);
32422 this.editor.tree = this;
32423 this.editor = Roo.factory(this.editor, Roo.tree);
32426 if (this.selModel) {
32427 this.selModel = Roo.factory(this.selModel, Roo.tree);
32431 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32432 rootVisible : true,
32433 animate: Roo.enableFx,
32436 hlDrop : Roo.enableFx,
32440 rendererTip: false,
32442 restrictExpand : function(node){
32443 var p = node.parentNode;
32445 if(p.expandedChild && p.expandedChild.parentNode == p){
32446 p.expandedChild.collapse();
32448 p.expandedChild = node;
32452 // private override
32453 setRootNode : function(node){
32454 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32455 if(!this.rootVisible){
32456 node.ui = new Roo.tree.RootTreeNodeUI(node);
32462 * Returns the container element for this TreePanel
32464 getEl : function(){
32469 * Returns the default TreeLoader for this TreePanel
32471 getLoader : function(){
32472 return this.loader;
32478 expandAll : function(){
32479 this.root.expand(true);
32483 * Collapse all nodes
32485 collapseAll : function(){
32486 this.root.collapse(true);
32490 * Returns the selection model used by this TreePanel
32492 getSelectionModel : function(){
32493 if(!this.selModel){
32494 this.selModel = new Roo.tree.DefaultSelectionModel();
32496 return this.selModel;
32500 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32501 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32502 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32505 getChecked : function(a, startNode){
32506 startNode = startNode || this.root;
32508 var f = function(){
32509 if(this.attributes.checked){
32510 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32513 startNode.cascade(f);
32518 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32519 * @param {String} path
32520 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32521 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32522 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32524 expandPath : function(path, attr, callback){
32525 attr = attr || "id";
32526 var keys = path.split(this.pathSeparator);
32527 var curNode = this.root;
32528 if(curNode.attributes[attr] != keys[1]){ // invalid root
32530 callback(false, null);
32535 var f = function(){
32536 if(++index == keys.length){
32538 callback(true, curNode);
32542 var c = curNode.findChild(attr, keys[index]);
32545 callback(false, curNode);
32550 c.expand(false, false, f);
32552 curNode.expand(false, false, f);
32556 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32557 * @param {String} path
32558 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32559 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32560 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32562 selectPath : function(path, attr, callback){
32563 attr = attr || "id";
32564 var keys = path.split(this.pathSeparator);
32565 var v = keys.pop();
32566 if(keys.length > 0){
32567 var f = function(success, node){
32568 if(success && node){
32569 var n = node.findChild(attr, v);
32575 }else if(callback){
32576 callback(false, n);
32580 callback(false, n);
32584 this.expandPath(keys.join(this.pathSeparator), attr, f);
32586 this.root.select();
32588 callback(true, this.root);
32593 getTreeEl : function(){
32598 * Trigger rendering of this TreePanel
32600 render : function(){
32601 if (this.innerCt) {
32602 return this; // stop it rendering more than once!!
32605 this.innerCt = this.el.createChild({tag:"ul",
32606 cls:"x-tree-root-ct " +
32607 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32609 if(this.containerScroll){
32610 Roo.dd.ScrollManager.register(this.el);
32612 if((this.enableDD || this.enableDrop) && !this.dropZone){
32614 * The dropZone used by this tree if drop is enabled
32615 * @type Roo.tree.TreeDropZone
32617 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32618 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32621 if((this.enableDD || this.enableDrag) && !this.dragZone){
32623 * The dragZone used by this tree if drag is enabled
32624 * @type Roo.tree.TreeDragZone
32626 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32627 ddGroup: this.ddGroup || "TreeDD",
32628 scroll: this.ddScroll
32631 this.getSelectionModel().init(this);
32633 Roo.log("ROOT not set in tree");
32636 this.root.render();
32637 if(!this.rootVisible){
32638 this.root.renderChildren();
32644 * Ext JS Library 1.1.1
32645 * Copyright(c) 2006-2007, Ext JS, LLC.
32647 * Originally Released Under LGPL - original licence link has changed is not relivant.
32650 * <script type="text/javascript">
32655 * @class Roo.tree.DefaultSelectionModel
32656 * @extends Roo.util.Observable
32657 * The default single selection for a TreePanel.
32658 * @param {Object} cfg Configuration
32660 Roo.tree.DefaultSelectionModel = function(cfg){
32661 this.selNode = null;
32667 * @event selectionchange
32668 * Fires when the selected node changes
32669 * @param {DefaultSelectionModel} this
32670 * @param {TreeNode} node the new selection
32672 "selectionchange" : true,
32675 * @event beforeselect
32676 * Fires before the selected node changes, return false to cancel the change
32677 * @param {DefaultSelectionModel} this
32678 * @param {TreeNode} node the new selection
32679 * @param {TreeNode} node the old selection
32681 "beforeselect" : true
32684 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32687 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32688 init : function(tree){
32690 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32691 tree.on("click", this.onNodeClick, this);
32694 onNodeClick : function(node, e){
32695 if (e.ctrlKey && this.selNode == node) {
32696 this.unselect(node);
32704 * @param {TreeNode} node The node to select
32705 * @return {TreeNode} The selected node
32707 select : function(node){
32708 var last = this.selNode;
32709 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32711 last.ui.onSelectedChange(false);
32713 this.selNode = node;
32714 node.ui.onSelectedChange(true);
32715 this.fireEvent("selectionchange", this, node, last);
32722 * @param {TreeNode} node The node to unselect
32724 unselect : function(node){
32725 if(this.selNode == node){
32726 this.clearSelections();
32731 * Clear all selections
32733 clearSelections : function(){
32734 var n = this.selNode;
32736 n.ui.onSelectedChange(false);
32737 this.selNode = null;
32738 this.fireEvent("selectionchange", this, null);
32744 * Get the selected node
32745 * @return {TreeNode} The selected node
32747 getSelectedNode : function(){
32748 return this.selNode;
32752 * Returns true if the node is selected
32753 * @param {TreeNode} node The node to check
32754 * @return {Boolean}
32756 isSelected : function(node){
32757 return this.selNode == node;
32761 * Selects the node above the selected node in the tree, intelligently walking the nodes
32762 * @return TreeNode The new selection
32764 selectPrevious : function(){
32765 var s = this.selNode || this.lastSelNode;
32769 var ps = s.previousSibling;
32771 if(!ps.isExpanded() || ps.childNodes.length < 1){
32772 return this.select(ps);
32774 var lc = ps.lastChild;
32775 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32778 return this.select(lc);
32780 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32781 return this.select(s.parentNode);
32787 * Selects the node above the selected node in the tree, intelligently walking the nodes
32788 * @return TreeNode The new selection
32790 selectNext : function(){
32791 var s = this.selNode || this.lastSelNode;
32795 if(s.firstChild && s.isExpanded()){
32796 return this.select(s.firstChild);
32797 }else if(s.nextSibling){
32798 return this.select(s.nextSibling);
32799 }else if(s.parentNode){
32801 s.parentNode.bubble(function(){
32802 if(this.nextSibling){
32803 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32812 onKeyDown : function(e){
32813 var s = this.selNode || this.lastSelNode;
32814 // undesirable, but required
32819 var k = e.getKey();
32827 this.selectPrevious();
32830 e.preventDefault();
32831 if(s.hasChildNodes()){
32832 if(!s.isExpanded()){
32834 }else if(s.firstChild){
32835 this.select(s.firstChild, e);
32840 e.preventDefault();
32841 if(s.hasChildNodes() && s.isExpanded()){
32843 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32844 this.select(s.parentNode, e);
32852 * @class Roo.tree.MultiSelectionModel
32853 * @extends Roo.util.Observable
32854 * Multi selection for a TreePanel.
32855 * @param {Object} cfg Configuration
32857 Roo.tree.MultiSelectionModel = function(){
32858 this.selNodes = [];
32862 * @event selectionchange
32863 * Fires when the selected nodes change
32864 * @param {MultiSelectionModel} this
32865 * @param {Array} nodes Array of the selected nodes
32867 "selectionchange" : true
32869 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32873 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32874 init : function(tree){
32876 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32877 tree.on("click", this.onNodeClick, this);
32880 onNodeClick : function(node, e){
32881 this.select(node, e, e.ctrlKey);
32886 * @param {TreeNode} node The node to select
32887 * @param {EventObject} e (optional) An event associated with the selection
32888 * @param {Boolean} keepExisting True to retain existing selections
32889 * @return {TreeNode} The selected node
32891 select : function(node, e, keepExisting){
32892 if(keepExisting !== true){
32893 this.clearSelections(true);
32895 if(this.isSelected(node)){
32896 this.lastSelNode = node;
32899 this.selNodes.push(node);
32900 this.selMap[node.id] = node;
32901 this.lastSelNode = node;
32902 node.ui.onSelectedChange(true);
32903 this.fireEvent("selectionchange", this, this.selNodes);
32909 * @param {TreeNode} node The node to unselect
32911 unselect : function(node){
32912 if(this.selMap[node.id]){
32913 node.ui.onSelectedChange(false);
32914 var sn = this.selNodes;
32917 index = sn.indexOf(node);
32919 for(var i = 0, len = sn.length; i < len; i++){
32927 this.selNodes.splice(index, 1);
32929 delete this.selMap[node.id];
32930 this.fireEvent("selectionchange", this, this.selNodes);
32935 * Clear all selections
32937 clearSelections : function(suppressEvent){
32938 var sn = this.selNodes;
32940 for(var i = 0, len = sn.length; i < len; i++){
32941 sn[i].ui.onSelectedChange(false);
32943 this.selNodes = [];
32945 if(suppressEvent !== true){
32946 this.fireEvent("selectionchange", this, this.selNodes);
32952 * Returns true if the node is selected
32953 * @param {TreeNode} node The node to check
32954 * @return {Boolean}
32956 isSelected : function(node){
32957 return this.selMap[node.id] ? true : false;
32961 * Returns an array of the selected nodes
32964 getSelectedNodes : function(){
32965 return this.selNodes;
32968 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32970 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32972 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32975 * Ext JS Library 1.1.1
32976 * Copyright(c) 2006-2007, Ext JS, LLC.
32978 * Originally Released Under LGPL - original licence link has changed is not relivant.
32981 * <script type="text/javascript">
32985 * @class Roo.tree.TreeNode
32986 * @extends Roo.data.Node
32987 * @cfg {String} text The text for this node
32988 * @cfg {Boolean} expanded true to start the node expanded
32989 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
32990 * @cfg {Boolean} allowDrop false if this node cannot be drop on
32991 * @cfg {Boolean} disabled true to start the node disabled
32992 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
32993 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
32994 * @cfg {String} cls A css class to be added to the node
32995 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
32996 * @cfg {String} href URL of the link used for the node (defaults to #)
32997 * @cfg {String} hrefTarget target frame for the link
32998 * @cfg {String} qtip An Ext QuickTip for the node
32999 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33000 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33001 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33002 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33003 * (defaults to undefined with no checkbox rendered)
33005 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33007 Roo.tree.TreeNode = function(attributes){
33008 attributes = attributes || {};
33009 if(typeof attributes == "string"){
33010 attributes = {text: attributes};
33012 this.childrenRendered = false;
33013 this.rendered = false;
33014 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33015 this.expanded = attributes.expanded === true;
33016 this.isTarget = attributes.isTarget !== false;
33017 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33018 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33021 * Read-only. The text for this node. To change it use setText().
33024 this.text = attributes.text;
33026 * True if this node is disabled.
33029 this.disabled = attributes.disabled === true;
33033 * @event textchange
33034 * Fires when the text for this node is changed
33035 * @param {Node} this This node
33036 * @param {String} text The new text
33037 * @param {String} oldText The old text
33039 "textchange" : true,
33041 * @event beforeexpand
33042 * Fires before this node is expanded, return false to cancel.
33043 * @param {Node} this This node
33044 * @param {Boolean} deep
33045 * @param {Boolean} anim
33047 "beforeexpand" : true,
33049 * @event beforecollapse
33050 * Fires before this node is collapsed, return false to cancel.
33051 * @param {Node} this This node
33052 * @param {Boolean} deep
33053 * @param {Boolean} anim
33055 "beforecollapse" : true,
33058 * Fires when this node is expanded
33059 * @param {Node} this This node
33063 * @event disabledchange
33064 * Fires when the disabled status of this node changes
33065 * @param {Node} this This node
33066 * @param {Boolean} disabled
33068 "disabledchange" : true,
33071 * Fires when this node is collapsed
33072 * @param {Node} this This node
33076 * @event beforeclick
33077 * Fires before click processing. Return false to cancel the default action.
33078 * @param {Node} this This node
33079 * @param {Roo.EventObject} e The event object
33081 "beforeclick":true,
33083 * @event checkchange
33084 * Fires when a node with a checkbox's checked property changes
33085 * @param {Node} this This node
33086 * @param {Boolean} checked
33088 "checkchange":true,
33091 * Fires when this node is clicked
33092 * @param {Node} this This node
33093 * @param {Roo.EventObject} e The event object
33098 * Fires when this node is double clicked
33099 * @param {Node} this This node
33100 * @param {Roo.EventObject} e The event object
33104 * @event contextmenu
33105 * Fires when this node is right clicked
33106 * @param {Node} this This node
33107 * @param {Roo.EventObject} e The event object
33109 "contextmenu":true,
33111 * @event beforechildrenrendered
33112 * Fires right before the child nodes for this node are rendered
33113 * @param {Node} this This node
33115 "beforechildrenrendered":true
33118 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33121 * Read-only. The UI for this node
33124 this.ui = new uiClass(this);
33126 // finally support items[]
33127 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33132 Roo.each(this.attributes.items, function(c) {
33133 this.appendChild(Roo.factory(c,Roo.Tree));
33135 delete this.attributes.items;
33140 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33141 preventHScroll: true,
33143 * Returns true if this node is expanded
33144 * @return {Boolean}
33146 isExpanded : function(){
33147 return this.expanded;
33151 * Returns the UI object for this node
33152 * @return {TreeNodeUI}
33154 getUI : function(){
33158 // private override
33159 setFirstChild : function(node){
33160 var of = this.firstChild;
33161 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33162 if(this.childrenRendered && of && node != of){
33163 of.renderIndent(true, true);
33166 this.renderIndent(true, true);
33170 // private override
33171 setLastChild : function(node){
33172 var ol = this.lastChild;
33173 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33174 if(this.childrenRendered && ol && node != ol){
33175 ol.renderIndent(true, true);
33178 this.renderIndent(true, true);
33182 // these methods are overridden to provide lazy rendering support
33183 // private override
33184 appendChild : function()
33186 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33187 if(node && this.childrenRendered){
33190 this.ui.updateExpandIcon();
33194 // private override
33195 removeChild : function(node){
33196 this.ownerTree.getSelectionModel().unselect(node);
33197 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33198 // if it's been rendered remove dom node
33199 if(this.childrenRendered){
33202 if(this.childNodes.length < 1){
33203 this.collapse(false, false);
33205 this.ui.updateExpandIcon();
33207 if(!this.firstChild) {
33208 this.childrenRendered = false;
33213 // private override
33214 insertBefore : function(node, refNode){
33215 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33216 if(newNode && refNode && this.childrenRendered){
33219 this.ui.updateExpandIcon();
33224 * Sets the text for this node
33225 * @param {String} text
33227 setText : function(text){
33228 var oldText = this.text;
33230 this.attributes.text = text;
33231 if(this.rendered){ // event without subscribing
33232 this.ui.onTextChange(this, text, oldText);
33234 this.fireEvent("textchange", this, text, oldText);
33238 * Triggers selection of this node
33240 select : function(){
33241 this.getOwnerTree().getSelectionModel().select(this);
33245 * Triggers deselection of this node
33247 unselect : function(){
33248 this.getOwnerTree().getSelectionModel().unselect(this);
33252 * Returns true if this node is selected
33253 * @return {Boolean}
33255 isSelected : function(){
33256 return this.getOwnerTree().getSelectionModel().isSelected(this);
33260 * Expand this node.
33261 * @param {Boolean} deep (optional) True to expand all children as well
33262 * @param {Boolean} anim (optional) false to cancel the default animation
33263 * @param {Function} callback (optional) A callback to be called when
33264 * expanding this node completes (does not wait for deep expand to complete).
33265 * Called with 1 parameter, this node.
33267 expand : function(deep, anim, callback){
33268 if(!this.expanded){
33269 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33272 if(!this.childrenRendered){
33273 this.renderChildren();
33275 this.expanded = true;
33276 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33277 this.ui.animExpand(function(){
33278 this.fireEvent("expand", this);
33279 if(typeof callback == "function"){
33283 this.expandChildNodes(true);
33285 }.createDelegate(this));
33289 this.fireEvent("expand", this);
33290 if(typeof callback == "function"){
33295 if(typeof callback == "function"){
33300 this.expandChildNodes(true);
33304 isHiddenRoot : function(){
33305 return this.isRoot && !this.getOwnerTree().rootVisible;
33309 * Collapse this node.
33310 * @param {Boolean} deep (optional) True to collapse all children as well
33311 * @param {Boolean} anim (optional) false to cancel the default animation
33313 collapse : function(deep, anim){
33314 if(this.expanded && !this.isHiddenRoot()){
33315 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33318 this.expanded = false;
33319 if((this.getOwnerTree().animate && anim !== false) || anim){
33320 this.ui.animCollapse(function(){
33321 this.fireEvent("collapse", this);
33323 this.collapseChildNodes(true);
33325 }.createDelegate(this));
33328 this.ui.collapse();
33329 this.fireEvent("collapse", this);
33333 var cs = this.childNodes;
33334 for(var i = 0, len = cs.length; i < len; i++) {
33335 cs[i].collapse(true, false);
33341 delayedExpand : function(delay){
33342 if(!this.expandProcId){
33343 this.expandProcId = this.expand.defer(delay, this);
33348 cancelExpand : function(){
33349 if(this.expandProcId){
33350 clearTimeout(this.expandProcId);
33352 this.expandProcId = false;
33356 * Toggles expanded/collapsed state of the node
33358 toggle : function(){
33367 * Ensures all parent nodes are expanded
33369 ensureVisible : function(callback){
33370 var tree = this.getOwnerTree();
33371 tree.expandPath(this.parentNode.getPath(), false, function(){
33372 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33373 Roo.callback(callback);
33374 }.createDelegate(this));
33378 * Expand all child nodes
33379 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33381 expandChildNodes : function(deep){
33382 var cs = this.childNodes;
33383 for(var i = 0, len = cs.length; i < len; i++) {
33384 cs[i].expand(deep);
33389 * Collapse all child nodes
33390 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33392 collapseChildNodes : function(deep){
33393 var cs = this.childNodes;
33394 for(var i = 0, len = cs.length; i < len; i++) {
33395 cs[i].collapse(deep);
33400 * Disables this node
33402 disable : function(){
33403 this.disabled = true;
33405 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33406 this.ui.onDisableChange(this, true);
33408 this.fireEvent("disabledchange", this, true);
33412 * Enables this node
33414 enable : function(){
33415 this.disabled = false;
33416 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33417 this.ui.onDisableChange(this, false);
33419 this.fireEvent("disabledchange", this, false);
33423 renderChildren : function(suppressEvent){
33424 if(suppressEvent !== false){
33425 this.fireEvent("beforechildrenrendered", this);
33427 var cs = this.childNodes;
33428 for(var i = 0, len = cs.length; i < len; i++){
33429 cs[i].render(true);
33431 this.childrenRendered = true;
33435 sort : function(fn, scope){
33436 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33437 if(this.childrenRendered){
33438 var cs = this.childNodes;
33439 for(var i = 0, len = cs.length; i < len; i++){
33440 cs[i].render(true);
33446 render : function(bulkRender){
33447 this.ui.render(bulkRender);
33448 if(!this.rendered){
33449 this.rendered = true;
33451 this.expanded = false;
33452 this.expand(false, false);
33458 renderIndent : function(deep, refresh){
33460 this.ui.childIndent = null;
33462 this.ui.renderIndent();
33463 if(deep === true && this.childrenRendered){
33464 var cs = this.childNodes;
33465 for(var i = 0, len = cs.length; i < len; i++){
33466 cs[i].renderIndent(true, refresh);
33472 * Ext JS Library 1.1.1
33473 * Copyright(c) 2006-2007, Ext JS, LLC.
33475 * Originally Released Under LGPL - original licence link has changed is not relivant.
33478 * <script type="text/javascript">
33482 * @class Roo.tree.AsyncTreeNode
33483 * @extends Roo.tree.TreeNode
33484 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33486 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33488 Roo.tree.AsyncTreeNode = function(config){
33489 this.loaded = false;
33490 this.loading = false;
33491 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33493 * @event beforeload
33494 * Fires before this node is loaded, return false to cancel
33495 * @param {Node} this This node
33497 this.addEvents({'beforeload':true, 'load': true});
33500 * Fires when this node is loaded
33501 * @param {Node} this This node
33504 * The loader used by this node (defaults to using the tree's defined loader)
33509 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33510 expand : function(deep, anim, callback){
33511 if(this.loading){ // if an async load is already running, waiting til it's done
33513 var f = function(){
33514 if(!this.loading){ // done loading
33515 clearInterval(timer);
33516 this.expand(deep, anim, callback);
33518 }.createDelegate(this);
33519 timer = setInterval(f, 200);
33523 if(this.fireEvent("beforeload", this) === false){
33526 this.loading = true;
33527 this.ui.beforeLoad(this);
33528 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33530 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33534 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33538 * Returns true if this node is currently loading
33539 * @return {Boolean}
33541 isLoading : function(){
33542 return this.loading;
33545 loadComplete : function(deep, anim, callback){
33546 this.loading = false;
33547 this.loaded = true;
33548 this.ui.afterLoad(this);
33549 this.fireEvent("load", this);
33550 this.expand(deep, anim, callback);
33554 * Returns true if this node has been loaded
33555 * @return {Boolean}
33557 isLoaded : function(){
33558 return this.loaded;
33561 hasChildNodes : function(){
33562 if(!this.isLeaf() && !this.loaded){
33565 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33570 * Trigger a reload for this node
33571 * @param {Function} callback
33573 reload : function(callback){
33574 this.collapse(false, false);
33575 while(this.firstChild){
33576 this.removeChild(this.firstChild);
33578 this.childrenRendered = false;
33579 this.loaded = false;
33580 if(this.isHiddenRoot()){
33581 this.expanded = false;
33583 this.expand(false, false, callback);
33587 * Ext JS Library 1.1.1
33588 * Copyright(c) 2006-2007, Ext JS, LLC.
33590 * Originally Released Under LGPL - original licence link has changed is not relivant.
33593 * <script type="text/javascript">
33597 * @class Roo.tree.TreeNodeUI
33599 * @param {Object} node The node to render
33600 * The TreeNode UI implementation is separate from the
33601 * tree implementation. Unless you are customizing the tree UI,
33602 * you should never have to use this directly.
33604 Roo.tree.TreeNodeUI = function(node){
33606 this.rendered = false;
33607 this.animating = false;
33608 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33611 Roo.tree.TreeNodeUI.prototype = {
33612 removeChild : function(node){
33614 this.ctNode.removeChild(node.ui.getEl());
33618 beforeLoad : function(){
33619 this.addClass("x-tree-node-loading");
33622 afterLoad : function(){
33623 this.removeClass("x-tree-node-loading");
33626 onTextChange : function(node, text, oldText){
33628 this.textNode.innerHTML = text;
33632 onDisableChange : function(node, state){
33633 this.disabled = state;
33635 this.addClass("x-tree-node-disabled");
33637 this.removeClass("x-tree-node-disabled");
33641 onSelectedChange : function(state){
33644 this.addClass("x-tree-selected");
33647 this.removeClass("x-tree-selected");
33651 onMove : function(tree, node, oldParent, newParent, index, refNode){
33652 this.childIndent = null;
33654 var targetNode = newParent.ui.getContainer();
33655 if(!targetNode){//target not rendered
33656 this.holder = document.createElement("div");
33657 this.holder.appendChild(this.wrap);
33660 var insertBefore = refNode ? refNode.ui.getEl() : null;
33662 targetNode.insertBefore(this.wrap, insertBefore);
33664 targetNode.appendChild(this.wrap);
33666 this.node.renderIndent(true);
33670 addClass : function(cls){
33672 Roo.fly(this.elNode).addClass(cls);
33676 removeClass : function(cls){
33678 Roo.fly(this.elNode).removeClass(cls);
33682 remove : function(){
33684 this.holder = document.createElement("div");
33685 this.holder.appendChild(this.wrap);
33689 fireEvent : function(){
33690 return this.node.fireEvent.apply(this.node, arguments);
33693 initEvents : function(){
33694 this.node.on("move", this.onMove, this);
33695 var E = Roo.EventManager;
33696 var a = this.anchor;
33698 var el = Roo.fly(a, '_treeui');
33700 if(Roo.isOpera){ // opera render bug ignores the CSS
33701 el.setStyle("text-decoration", "none");
33704 el.on("click", this.onClick, this);
33705 el.on("dblclick", this.onDblClick, this);
33708 Roo.EventManager.on(this.checkbox,
33709 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33712 el.on("contextmenu", this.onContextMenu, this);
33714 var icon = Roo.fly(this.iconNode);
33715 icon.on("click", this.onClick, this);
33716 icon.on("dblclick", this.onDblClick, this);
33717 icon.on("contextmenu", this.onContextMenu, this);
33718 E.on(this.ecNode, "click", this.ecClick, this, true);
33720 if(this.node.disabled){
33721 this.addClass("x-tree-node-disabled");
33723 if(this.node.hidden){
33724 this.addClass("x-tree-node-disabled");
33726 var ot = this.node.getOwnerTree();
33727 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33728 if(dd && (!this.node.isRoot || ot.rootVisible)){
33729 Roo.dd.Registry.register(this.elNode, {
33731 handles: this.getDDHandles(),
33737 getDDHandles : function(){
33738 return [this.iconNode, this.textNode];
33743 this.wrap.style.display = "none";
33749 this.wrap.style.display = "";
33753 onContextMenu : function(e){
33754 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33755 e.preventDefault();
33757 this.fireEvent("contextmenu", this.node, e);
33761 onClick : function(e){
33766 if(this.fireEvent("beforeclick", this.node, e) !== false){
33767 if(!this.disabled && this.node.attributes.href){
33768 this.fireEvent("click", this.node, e);
33771 e.preventDefault();
33776 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33777 this.node.toggle();
33780 this.fireEvent("click", this.node, e);
33786 onDblClick : function(e){
33787 e.preventDefault();
33792 this.toggleCheck();
33794 if(!this.animating && this.node.hasChildNodes()){
33795 this.node.toggle();
33797 this.fireEvent("dblclick", this.node, e);
33800 onCheckChange : function(){
33801 var checked = this.checkbox.checked;
33802 this.node.attributes.checked = checked;
33803 this.fireEvent('checkchange', this.node, checked);
33806 ecClick : function(e){
33807 if(!this.animating && this.node.hasChildNodes()){
33808 this.node.toggle();
33812 startDrop : function(){
33813 this.dropping = true;
33816 // delayed drop so the click event doesn't get fired on a drop
33817 endDrop : function(){
33818 setTimeout(function(){
33819 this.dropping = false;
33820 }.createDelegate(this), 50);
33823 expand : function(){
33824 this.updateExpandIcon();
33825 this.ctNode.style.display = "";
33828 focus : function(){
33829 if(!this.node.preventHScroll){
33830 try{this.anchor.focus();
33832 }else if(!Roo.isIE){
33834 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33835 var l = noscroll.scrollLeft;
33836 this.anchor.focus();
33837 noscroll.scrollLeft = l;
33842 toggleCheck : function(value){
33843 var cb = this.checkbox;
33845 cb.checked = (value === undefined ? !cb.checked : value);
33851 this.anchor.blur();
33855 animExpand : function(callback){
33856 var ct = Roo.get(this.ctNode);
33858 if(!this.node.hasChildNodes()){
33859 this.updateExpandIcon();
33860 this.ctNode.style.display = "";
33861 Roo.callback(callback);
33864 this.animating = true;
33865 this.updateExpandIcon();
33868 callback : function(){
33869 this.animating = false;
33870 Roo.callback(callback);
33873 duration: this.node.ownerTree.duration || .25
33877 highlight : function(){
33878 var tree = this.node.getOwnerTree();
33879 Roo.fly(this.wrap).highlight(
33880 tree.hlColor || "C3DAF9",
33881 {endColor: tree.hlBaseColor}
33885 collapse : function(){
33886 this.updateExpandIcon();
33887 this.ctNode.style.display = "none";
33890 animCollapse : function(callback){
33891 var ct = Roo.get(this.ctNode);
33892 ct.enableDisplayMode('block');
33895 this.animating = true;
33896 this.updateExpandIcon();
33899 callback : function(){
33900 this.animating = false;
33901 Roo.callback(callback);
33904 duration: this.node.ownerTree.duration || .25
33908 getContainer : function(){
33909 return this.ctNode;
33912 getEl : function(){
33916 appendDDGhost : function(ghostNode){
33917 ghostNode.appendChild(this.elNode.cloneNode(true));
33920 getDDRepairXY : function(){
33921 return Roo.lib.Dom.getXY(this.iconNode);
33924 onRender : function(){
33928 render : function(bulkRender){
33929 var n = this.node, a = n.attributes;
33930 var targetNode = n.parentNode ?
33931 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33933 if(!this.rendered){
33934 this.rendered = true;
33936 this.renderElements(n, a, targetNode, bulkRender);
33939 if(this.textNode.setAttributeNS){
33940 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33942 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33945 this.textNode.setAttribute("ext:qtip", a.qtip);
33947 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33950 }else if(a.qtipCfg){
33951 a.qtipCfg.target = Roo.id(this.textNode);
33952 Roo.QuickTips.register(a.qtipCfg);
33955 if(!this.node.expanded){
33956 this.updateExpandIcon();
33959 if(bulkRender === true) {
33960 targetNode.appendChild(this.wrap);
33965 renderElements : function(n, a, targetNode, bulkRender)
33967 // add some indent caching, this helps performance when rendering a large tree
33968 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33969 var t = n.getOwnerTree();
33970 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33971 if (typeof(n.attributes.html) != 'undefined') {
33972 txt = n.attributes.html;
33974 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33975 var cb = typeof a.checked == 'boolean';
33976 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33977 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33978 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33979 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33980 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33981 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33982 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33983 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33984 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33985 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33988 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33989 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33990 n.nextSibling.ui.getEl(), buf.join(""));
33992 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33995 this.elNode = this.wrap.childNodes[0];
33996 this.ctNode = this.wrap.childNodes[1];
33997 var cs = this.elNode.childNodes;
33998 this.indentNode = cs[0];
33999 this.ecNode = cs[1];
34000 this.iconNode = cs[2];
34003 this.checkbox = cs[3];
34006 this.anchor = cs[index];
34007 this.textNode = cs[index].firstChild;
34010 getAnchor : function(){
34011 return this.anchor;
34014 getTextEl : function(){
34015 return this.textNode;
34018 getIconEl : function(){
34019 return this.iconNode;
34022 isChecked : function(){
34023 return this.checkbox ? this.checkbox.checked : false;
34026 updateExpandIcon : function(){
34028 var n = this.node, c1, c2;
34029 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34030 var hasChild = n.hasChildNodes();
34034 c1 = "x-tree-node-collapsed";
34035 c2 = "x-tree-node-expanded";
34038 c1 = "x-tree-node-expanded";
34039 c2 = "x-tree-node-collapsed";
34042 this.removeClass("x-tree-node-leaf");
34043 this.wasLeaf = false;
34045 if(this.c1 != c1 || this.c2 != c2){
34046 Roo.fly(this.elNode).replaceClass(c1, c2);
34047 this.c1 = c1; this.c2 = c2;
34050 // this changes non-leafs into leafs if they have no children.
34051 // it's not very rational behaviour..
34053 if(!this.wasLeaf && this.node.leaf){
34054 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34057 this.wasLeaf = true;
34060 var ecc = "x-tree-ec-icon "+cls;
34061 if(this.ecc != ecc){
34062 this.ecNode.className = ecc;
34068 getChildIndent : function(){
34069 if(!this.childIndent){
34073 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34075 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34077 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34082 this.childIndent = buf.join("");
34084 return this.childIndent;
34087 renderIndent : function(){
34090 var p = this.node.parentNode;
34092 indent = p.ui.getChildIndent();
34094 if(this.indentMarkup != indent){ // don't rerender if not required
34095 this.indentNode.innerHTML = indent;
34096 this.indentMarkup = indent;
34098 this.updateExpandIcon();
34103 Roo.tree.RootTreeNodeUI = function(){
34104 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34106 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34107 render : function(){
34108 if(!this.rendered){
34109 var targetNode = this.node.ownerTree.innerCt.dom;
34110 this.node.expanded = true;
34111 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34112 this.wrap = this.ctNode = targetNode.firstChild;
34115 collapse : function(){
34117 expand : function(){
34121 * Ext JS Library 1.1.1
34122 * Copyright(c) 2006-2007, Ext JS, LLC.
34124 * Originally Released Under LGPL - original licence link has changed is not relivant.
34127 * <script type="text/javascript">
34130 * @class Roo.tree.TreeLoader
34131 * @extends Roo.util.Observable
34132 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34133 * nodes from a specified URL. The response must be a javascript Array definition
34134 * who's elements are node definition objects. eg:
34139 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34140 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34147 * The old style respose with just an array is still supported, but not recommended.
34150 * A server request is sent, and child nodes are loaded only when a node is expanded.
34151 * The loading node's id is passed to the server under the parameter name "node" to
34152 * enable the server to produce the correct child nodes.
34154 * To pass extra parameters, an event handler may be attached to the "beforeload"
34155 * event, and the parameters specified in the TreeLoader's baseParams property:
34157 myTreeLoader.on("beforeload", function(treeLoader, node) {
34158 this.baseParams.category = node.attributes.category;
34161 * This would pass an HTTP parameter called "category" to the server containing
34162 * the value of the Node's "category" attribute.
34164 * Creates a new Treeloader.
34165 * @param {Object} config A config object containing config properties.
34167 Roo.tree.TreeLoader = function(config){
34168 this.baseParams = {};
34169 this.requestMethod = "POST";
34170 Roo.apply(this, config);
34175 * @event beforeload
34176 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34177 * @param {Object} This TreeLoader object.
34178 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34179 * @param {Object} callback The callback function specified in the {@link #load} call.
34184 * Fires when the node has been successfuly loaded.
34185 * @param {Object} This TreeLoader object.
34186 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34187 * @param {Object} response The response object containing the data from the server.
34191 * @event loadexception
34192 * Fires if the network request failed.
34193 * @param {Object} This TreeLoader object.
34194 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34195 * @param {Object} response The response object containing the data from the server.
34197 loadexception : true,
34200 * Fires before a node is created, enabling you to return custom Node types
34201 * @param {Object} This TreeLoader object.
34202 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34207 Roo.tree.TreeLoader.superclass.constructor.call(this);
34210 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34212 * @cfg {String} dataUrl The URL from which to request a Json string which
34213 * specifies an array of node definition object representing the child nodes
34217 * @cfg {String} requestMethod either GET or POST
34218 * defaults to POST (due to BC)
34222 * @cfg {Object} baseParams (optional) An object containing properties which
34223 * specify HTTP parameters to be passed to each request for child nodes.
34226 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34227 * created by this loader. If the attributes sent by the server have an attribute in this object,
34228 * they take priority.
34231 * @cfg {Object} uiProviders (optional) An object containing properties which
34233 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34234 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34235 * <i>uiProvider</i> attribute of a returned child node is a string rather
34236 * than a reference to a TreeNodeUI implementation, this that string value
34237 * is used as a property name in the uiProviders object. You can define the provider named
34238 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34243 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34244 * child nodes before loading.
34246 clearOnLoad : true,
34249 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34250 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34251 * Grid query { data : [ .....] }
34256 * @cfg {String} queryParam (optional)
34257 * Name of the query as it will be passed on the querystring (defaults to 'node')
34258 * eg. the request will be ?node=[id]
34265 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34266 * This is called automatically when a node is expanded, but may be used to reload
34267 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34268 * @param {Roo.tree.TreeNode} node
34269 * @param {Function} callback
34271 load : function(node, callback){
34272 if(this.clearOnLoad){
34273 while(node.firstChild){
34274 node.removeChild(node.firstChild);
34277 if(node.attributes.children){ // preloaded json children
34278 var cs = node.attributes.children;
34279 for(var i = 0, len = cs.length; i < len; i++){
34280 node.appendChild(this.createNode(cs[i]));
34282 if(typeof callback == "function"){
34285 }else if(this.dataUrl){
34286 this.requestData(node, callback);
34290 getParams: function(node){
34291 var buf = [], bp = this.baseParams;
34292 for(var key in bp){
34293 if(typeof bp[key] != "function"){
34294 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34297 var n = this.queryParam === false ? 'node' : this.queryParam;
34298 buf.push(n + "=", encodeURIComponent(node.id));
34299 return buf.join("");
34302 requestData : function(node, callback){
34303 if(this.fireEvent("beforeload", this, node, callback) !== false){
34304 this.transId = Roo.Ajax.request({
34305 method:this.requestMethod,
34306 url: this.dataUrl||this.url,
34307 success: this.handleResponse,
34308 failure: this.handleFailure,
34310 argument: {callback: callback, node: node},
34311 params: this.getParams(node)
34314 // if the load is cancelled, make sure we notify
34315 // the node that we are done
34316 if(typeof callback == "function"){
34322 isLoading : function(){
34323 return this.transId ? true : false;
34326 abort : function(){
34327 if(this.isLoading()){
34328 Roo.Ajax.abort(this.transId);
34333 createNode : function(attr)
34335 // apply baseAttrs, nice idea Corey!
34336 if(this.baseAttrs){
34337 Roo.applyIf(attr, this.baseAttrs);
34339 if(this.applyLoader !== false){
34340 attr.loader = this;
34342 // uiProvider = depreciated..
34344 if(typeof(attr.uiProvider) == 'string'){
34345 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34346 /** eval:var:attr */ eval(attr.uiProvider);
34348 if(typeof(this.uiProviders['default']) != 'undefined') {
34349 attr.uiProvider = this.uiProviders['default'];
34352 this.fireEvent('create', this, attr);
34354 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34356 new Roo.tree.TreeNode(attr) :
34357 new Roo.tree.AsyncTreeNode(attr));
34360 processResponse : function(response, node, callback)
34362 var json = response.responseText;
34365 var o = Roo.decode(json);
34367 if (this.root === false && typeof(o.success) != undefined) {
34368 this.root = 'data'; // the default behaviour for list like data..
34371 if (this.root !== false && !o.success) {
34372 // it's a failure condition.
34373 var a = response.argument;
34374 this.fireEvent("loadexception", this, a.node, response);
34375 Roo.log("Load failed - should have a handler really");
34381 if (this.root !== false) {
34385 for(var i = 0, len = o.length; i < len; i++){
34386 var n = this.createNode(o[i]);
34388 node.appendChild(n);
34391 if(typeof callback == "function"){
34392 callback(this, node);
34395 this.handleFailure(response);
34399 handleResponse : function(response){
34400 this.transId = false;
34401 var a = response.argument;
34402 this.processResponse(response, a.node, a.callback);
34403 this.fireEvent("load", this, a.node, response);
34406 handleFailure : function(response)
34408 // should handle failure better..
34409 this.transId = false;
34410 var a = response.argument;
34411 this.fireEvent("loadexception", this, a.node, response);
34412 if(typeof a.callback == "function"){
34413 a.callback(this, a.node);
34418 * Ext JS Library 1.1.1
34419 * Copyright(c) 2006-2007, Ext JS, LLC.
34421 * Originally Released Under LGPL - original licence link has changed is not relivant.
34424 * <script type="text/javascript">
34428 * @class Roo.tree.TreeFilter
34429 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34430 * @param {TreePanel} tree
34431 * @param {Object} config (optional)
34433 Roo.tree.TreeFilter = function(tree, config){
34435 this.filtered = {};
34436 Roo.apply(this, config);
34439 Roo.tree.TreeFilter.prototype = {
34446 * Filter the data by a specific attribute.
34447 * @param {String/RegExp} value Either string that the attribute value
34448 * should start with or a RegExp to test against the attribute
34449 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34450 * @param {TreeNode} startNode (optional) The node to start the filter at.
34452 filter : function(value, attr, startNode){
34453 attr = attr || "text";
34455 if(typeof value == "string"){
34456 var vlen = value.length;
34457 // auto clear empty filter
34458 if(vlen == 0 && this.clearBlank){
34462 value = value.toLowerCase();
34464 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34466 }else if(value.exec){ // regex?
34468 return value.test(n.attributes[attr]);
34471 throw 'Illegal filter type, must be string or regex';
34473 this.filterBy(f, null, startNode);
34477 * Filter by a function. The passed function will be called with each
34478 * node in the tree (or from the startNode). If the function returns true, the node is kept
34479 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34480 * @param {Function} fn The filter function
34481 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34483 filterBy : function(fn, scope, startNode){
34484 startNode = startNode || this.tree.root;
34485 if(this.autoClear){
34488 var af = this.filtered, rv = this.reverse;
34489 var f = function(n){
34490 if(n == startNode){
34496 var m = fn.call(scope || n, n);
34504 startNode.cascade(f);
34507 if(typeof id != "function"){
34509 if(n && n.parentNode){
34510 n.parentNode.removeChild(n);
34518 * Clears the current filter. Note: with the "remove" option
34519 * set a filter cannot be cleared.
34521 clear : function(){
34523 var af = this.filtered;
34525 if(typeof id != "function"){
34532 this.filtered = {};
34537 * Ext JS Library 1.1.1
34538 * Copyright(c) 2006-2007, Ext JS, LLC.
34540 * Originally Released Under LGPL - original licence link has changed is not relivant.
34543 * <script type="text/javascript">
34548 * @class Roo.tree.TreeSorter
34549 * Provides sorting of nodes in a TreePanel
34551 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34552 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34553 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34554 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34555 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34556 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34558 * @param {TreePanel} tree
34559 * @param {Object} config
34561 Roo.tree.TreeSorter = function(tree, config){
34562 Roo.apply(this, config);
34563 tree.on("beforechildrenrendered", this.doSort, this);
34564 tree.on("append", this.updateSort, this);
34565 tree.on("insert", this.updateSort, this);
34567 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34568 var p = this.property || "text";
34569 var sortType = this.sortType;
34570 var fs = this.folderSort;
34571 var cs = this.caseSensitive === true;
34572 var leafAttr = this.leafAttr || 'leaf';
34574 this.sortFn = function(n1, n2){
34576 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34579 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34583 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34584 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34586 return dsc ? +1 : -1;
34588 return dsc ? -1 : +1;
34595 Roo.tree.TreeSorter.prototype = {
34596 doSort : function(node){
34597 node.sort(this.sortFn);
34600 compareNodes : function(n1, n2){
34601 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34604 updateSort : function(tree, node){
34605 if(node.childrenRendered){
34606 this.doSort.defer(1, this, [node]);
34611 * Ext JS Library 1.1.1
34612 * Copyright(c) 2006-2007, Ext JS, LLC.
34614 * Originally Released Under LGPL - original licence link has changed is not relivant.
34617 * <script type="text/javascript">
34620 if(Roo.dd.DropZone){
34622 Roo.tree.TreeDropZone = function(tree, config){
34623 this.allowParentInsert = false;
34624 this.allowContainerDrop = false;
34625 this.appendOnly = false;
34626 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34628 this.lastInsertClass = "x-tree-no-status";
34629 this.dragOverData = {};
34632 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34633 ddGroup : "TreeDD",
34636 expandDelay : 1000,
34638 expandNode : function(node){
34639 if(node.hasChildNodes() && !node.isExpanded()){
34640 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34644 queueExpand : function(node){
34645 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34648 cancelExpand : function(){
34649 if(this.expandProcId){
34650 clearTimeout(this.expandProcId);
34651 this.expandProcId = false;
34655 isValidDropPoint : function(n, pt, dd, e, data){
34656 if(!n || !data){ return false; }
34657 var targetNode = n.node;
34658 var dropNode = data.node;
34659 // default drop rules
34660 if(!(targetNode && targetNode.isTarget && pt)){
34663 if(pt == "append" && targetNode.allowChildren === false){
34666 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34669 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34672 // reuse the object
34673 var overEvent = this.dragOverData;
34674 overEvent.tree = this.tree;
34675 overEvent.target = targetNode;
34676 overEvent.data = data;
34677 overEvent.point = pt;
34678 overEvent.source = dd;
34679 overEvent.rawEvent = e;
34680 overEvent.dropNode = dropNode;
34681 overEvent.cancel = false;
34682 var result = this.tree.fireEvent("nodedragover", overEvent);
34683 return overEvent.cancel === false && result !== false;
34686 getDropPoint : function(e, n, dd)
34690 return tn.allowChildren !== false ? "append" : false; // always append for root
34692 var dragEl = n.ddel;
34693 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34694 var y = Roo.lib.Event.getPageY(e);
34695 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34697 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34698 var noAppend = tn.allowChildren === false;
34699 if(this.appendOnly || tn.parentNode.allowChildren === false){
34700 return noAppend ? false : "append";
34702 var noBelow = false;
34703 if(!this.allowParentInsert){
34704 noBelow = tn.hasChildNodes() && tn.isExpanded();
34706 var q = (b - t) / (noAppend ? 2 : 3);
34707 if(y >= t && y < (t + q)){
34709 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34716 onNodeEnter : function(n, dd, e, data)
34718 this.cancelExpand();
34721 onNodeOver : function(n, dd, e, data)
34724 var pt = this.getDropPoint(e, n, dd);
34727 // auto node expand check
34728 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34729 this.queueExpand(node);
34730 }else if(pt != "append"){
34731 this.cancelExpand();
34734 // set the insert point style on the target node
34735 var returnCls = this.dropNotAllowed;
34736 if(this.isValidDropPoint(n, pt, dd, e, data)){
34741 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34742 cls = "x-tree-drag-insert-above";
34743 }else if(pt == "below"){
34744 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34745 cls = "x-tree-drag-insert-below";
34747 returnCls = "x-tree-drop-ok-append";
34748 cls = "x-tree-drag-append";
34750 if(this.lastInsertClass != cls){
34751 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34752 this.lastInsertClass = cls;
34759 onNodeOut : function(n, dd, e, data){
34761 this.cancelExpand();
34762 this.removeDropIndicators(n);
34765 onNodeDrop : function(n, dd, e, data){
34766 var point = this.getDropPoint(e, n, dd);
34767 var targetNode = n.node;
34768 targetNode.ui.startDrop();
34769 if(!this.isValidDropPoint(n, point, dd, e, data)){
34770 targetNode.ui.endDrop();
34773 // first try to find the drop node
34774 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34777 target: targetNode,
34782 dropNode: dropNode,
34785 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34786 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34787 targetNode.ui.endDrop();
34790 // allow target changing
34791 targetNode = dropEvent.target;
34792 if(point == "append" && !targetNode.isExpanded()){
34793 targetNode.expand(false, null, function(){
34794 this.completeDrop(dropEvent);
34795 }.createDelegate(this));
34797 this.completeDrop(dropEvent);
34802 completeDrop : function(de){
34803 var ns = de.dropNode, p = de.point, t = de.target;
34804 if(!(ns instanceof Array)){
34808 for(var i = 0, len = ns.length; i < len; i++){
34811 t.parentNode.insertBefore(n, t);
34812 }else if(p == "below"){
34813 t.parentNode.insertBefore(n, t.nextSibling);
34819 if(this.tree.hlDrop){
34823 this.tree.fireEvent("nodedrop", de);
34826 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34827 if(this.tree.hlDrop){
34828 dropNode.ui.focus();
34829 dropNode.ui.highlight();
34831 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34834 getTree : function(){
34838 removeDropIndicators : function(n){
34841 Roo.fly(el).removeClass([
34842 "x-tree-drag-insert-above",
34843 "x-tree-drag-insert-below",
34844 "x-tree-drag-append"]);
34845 this.lastInsertClass = "_noclass";
34849 beforeDragDrop : function(target, e, id){
34850 this.cancelExpand();
34854 afterRepair : function(data){
34855 if(data && Roo.enableFx){
34856 data.node.ui.highlight();
34866 * Ext JS Library 1.1.1
34867 * Copyright(c) 2006-2007, Ext JS, LLC.
34869 * Originally Released Under LGPL - original licence link has changed is not relivant.
34872 * <script type="text/javascript">
34876 if(Roo.dd.DragZone){
34877 Roo.tree.TreeDragZone = function(tree, config){
34878 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34882 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34883 ddGroup : "TreeDD",
34885 onBeforeDrag : function(data, e){
34887 return n && n.draggable && !n.disabled;
34891 onInitDrag : function(e){
34892 var data = this.dragData;
34893 this.tree.getSelectionModel().select(data.node);
34894 this.proxy.update("");
34895 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34896 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34899 getRepairXY : function(e, data){
34900 return data.node.ui.getDDRepairXY();
34903 onEndDrag : function(data, e){
34904 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34909 onValidDrop : function(dd, e, id){
34910 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34914 beforeInvalidDrop : function(e, id){
34915 // this scrolls the original position back into view
34916 var sm = this.tree.getSelectionModel();
34917 sm.clearSelections();
34918 sm.select(this.dragData.node);
34923 * Ext JS Library 1.1.1
34924 * Copyright(c) 2006-2007, Ext JS, LLC.
34926 * Originally Released Under LGPL - original licence link has changed is not relivant.
34929 * <script type="text/javascript">
34932 * @class Roo.tree.TreeEditor
34933 * @extends Roo.Editor
34934 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34935 * as the editor field.
34937 * @param {Object} config (used to be the tree panel.)
34938 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34940 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34941 * @cfg {Roo.form.TextField|Object} field The field configuration
34945 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34948 if (oldconfig) { // old style..
34949 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34952 tree = config.tree;
34953 config.field = config.field || {};
34954 config.field.xtype = 'TextField';
34955 field = Roo.factory(config.field, Roo.form);
34957 config = config || {};
34962 * @event beforenodeedit
34963 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34964 * false from the handler of this event.
34965 * @param {Editor} this
34966 * @param {Roo.tree.Node} node
34968 "beforenodeedit" : true
34972 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34976 tree.on('beforeclick', this.beforeNodeClick, this);
34977 tree.getTreeEl().on('mousedown', this.hide, this);
34978 this.on('complete', this.updateNode, this);
34979 this.on('beforestartedit', this.fitToTree, this);
34980 this.on('startedit', this.bindScroll, this, {delay:10});
34981 this.on('specialkey', this.onSpecialKey, this);
34984 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34986 * @cfg {String} alignment
34987 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
34993 * @cfg {Boolean} hideEl
34994 * True to hide the bound element while the editor is displayed (defaults to false)
34998 * @cfg {String} cls
34999 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35001 cls: "x-small-editor x-tree-editor",
35003 * @cfg {Boolean} shim
35004 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35010 * @cfg {Number} maxWidth
35011 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35012 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35013 * scroll and client offsets into account prior to each edit.
35020 fitToTree : function(ed, el){
35021 var td = this.tree.getTreeEl().dom, nd = el.dom;
35022 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35023 td.scrollLeft = nd.offsetLeft;
35027 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35028 this.setSize(w, '');
35030 return this.fireEvent('beforenodeedit', this, this.editNode);
35035 triggerEdit : function(node){
35036 this.completeEdit();
35037 this.editNode = node;
35038 this.startEdit(node.ui.textNode, node.text);
35042 bindScroll : function(){
35043 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35047 beforeNodeClick : function(node, e){
35048 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35049 this.lastClick = new Date();
35050 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35052 this.triggerEdit(node);
35059 updateNode : function(ed, value){
35060 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35061 this.editNode.setText(value);
35065 onHide : function(){
35066 Roo.tree.TreeEditor.superclass.onHide.call(this);
35068 this.editNode.ui.focus();
35073 onSpecialKey : function(field, e){
35074 var k = e.getKey();
35078 }else if(k == e.ENTER && !e.hasModifier()){
35080 this.completeEdit();
35083 });//<Script type="text/javascript">
35086 * Ext JS Library 1.1.1
35087 * Copyright(c) 2006-2007, Ext JS, LLC.
35089 * Originally Released Under LGPL - original licence link has changed is not relivant.
35092 * <script type="text/javascript">
35096 * Not documented??? - probably should be...
35099 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35100 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35102 renderElements : function(n, a, targetNode, bulkRender){
35103 //consel.log("renderElements?");
35104 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35106 var t = n.getOwnerTree();
35107 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35109 var cols = t.columns;
35110 var bw = t.borderWidth;
35112 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35113 var cb = typeof a.checked == "boolean";
35114 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35115 var colcls = 'x-t-' + tid + '-c0';
35117 '<li class="x-tree-node">',
35120 '<div class="x-tree-node-el ', a.cls,'">',
35122 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35125 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35126 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35127 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35128 (a.icon ? ' x-tree-node-inline-icon' : ''),
35129 (a.iconCls ? ' '+a.iconCls : ''),
35130 '" unselectable="on" />',
35131 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35132 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35134 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35135 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35136 '<span unselectable="on" qtip="' + tx + '">',
35140 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35141 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35143 for(var i = 1, len = cols.length; i < len; i++){
35145 colcls = 'x-t-' + tid + '-c' +i;
35146 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35147 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35148 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35154 '<div class="x-clear"></div></div>',
35155 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35158 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35159 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35160 n.nextSibling.ui.getEl(), buf.join(""));
35162 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35164 var el = this.wrap.firstChild;
35166 this.elNode = el.firstChild;
35167 this.ranchor = el.childNodes[1];
35168 this.ctNode = this.wrap.childNodes[1];
35169 var cs = el.firstChild.childNodes;
35170 this.indentNode = cs[0];
35171 this.ecNode = cs[1];
35172 this.iconNode = cs[2];
35175 this.checkbox = cs[3];
35178 this.anchor = cs[index];
35180 this.textNode = cs[index].firstChild;
35182 //el.on("click", this.onClick, this);
35183 //el.on("dblclick", this.onDblClick, this);
35186 // console.log(this);
35188 initEvents : function(){
35189 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35192 var a = this.ranchor;
35194 var el = Roo.get(a);
35196 if(Roo.isOpera){ // opera render bug ignores the CSS
35197 el.setStyle("text-decoration", "none");
35200 el.on("click", this.onClick, this);
35201 el.on("dblclick", this.onDblClick, this);
35202 el.on("contextmenu", this.onContextMenu, this);
35206 /*onSelectedChange : function(state){
35209 this.addClass("x-tree-selected");
35212 this.removeClass("x-tree-selected");
35215 addClass : function(cls){
35217 Roo.fly(this.elRow).addClass(cls);
35223 removeClass : function(cls){
35225 Roo.fly(this.elRow).removeClass(cls);
35231 });//<Script type="text/javascript">
35235 * Ext JS Library 1.1.1
35236 * Copyright(c) 2006-2007, Ext JS, LLC.
35238 * Originally Released Under LGPL - original licence link has changed is not relivant.
35241 * <script type="text/javascript">
35246 * @class Roo.tree.ColumnTree
35247 * @extends Roo.data.TreePanel
35248 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35249 * @cfg {int} borderWidth compined right/left border allowance
35251 * @param {String/HTMLElement/Element} el The container element
35252 * @param {Object} config
35254 Roo.tree.ColumnTree = function(el, config)
35256 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35260 * Fire this event on a container when it resizes
35261 * @param {int} w Width
35262 * @param {int} h Height
35266 this.on('resize', this.onResize, this);
35269 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35273 borderWidth: Roo.isBorderBox ? 0 : 2,
35276 render : function(){
35277 // add the header.....
35279 Roo.tree.ColumnTree.superclass.render.apply(this);
35281 this.el.addClass('x-column-tree');
35283 this.headers = this.el.createChild(
35284 {cls:'x-tree-headers'},this.innerCt.dom);
35286 var cols = this.columns, c;
35287 var totalWidth = 0;
35289 var len = cols.length;
35290 for(var i = 0; i < len; i++){
35292 totalWidth += c.width;
35293 this.headEls.push(this.headers.createChild({
35294 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35296 cls:'x-tree-hd-text',
35299 style:'width:'+(c.width-this.borderWidth)+'px;'
35302 this.headers.createChild({cls:'x-clear'});
35303 // prevent floats from wrapping when clipped
35304 this.headers.setWidth(totalWidth);
35305 //this.innerCt.setWidth(totalWidth);
35306 this.innerCt.setStyle({ overflow: 'auto' });
35307 this.onResize(this.width, this.height);
35311 onResize : function(w,h)
35316 this.innerCt.setWidth(this.width);
35317 this.innerCt.setHeight(this.height-20);
35320 var cols = this.columns, c;
35321 var totalWidth = 0;
35323 var len = cols.length;
35324 for(var i = 0; i < len; i++){
35326 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35327 // it's the expander..
35328 expEl = this.headEls[i];
35331 totalWidth += c.width;
35335 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35337 this.headers.setWidth(w-20);
35346 * Ext JS Library 1.1.1
35347 * Copyright(c) 2006-2007, Ext JS, LLC.
35349 * Originally Released Under LGPL - original licence link has changed is not relivant.
35352 * <script type="text/javascript">
35356 * @class Roo.menu.Menu
35357 * @extends Roo.util.Observable
35358 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35359 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35361 * Creates a new Menu
35362 * @param {Object} config Configuration options
35364 Roo.menu.Menu = function(config){
35365 Roo.apply(this, config);
35366 this.id = this.id || Roo.id();
35369 * @event beforeshow
35370 * Fires before this menu is displayed
35371 * @param {Roo.menu.Menu} this
35375 * @event beforehide
35376 * Fires before this menu is hidden
35377 * @param {Roo.menu.Menu} this
35382 * Fires after this menu is displayed
35383 * @param {Roo.menu.Menu} this
35388 * Fires after this menu is hidden
35389 * @param {Roo.menu.Menu} this
35394 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35395 * @param {Roo.menu.Menu} this
35396 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35397 * @param {Roo.EventObject} e
35402 * Fires when the mouse is hovering over this menu
35403 * @param {Roo.menu.Menu} this
35404 * @param {Roo.EventObject} e
35405 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35410 * Fires when the mouse exits this menu
35411 * @param {Roo.menu.Menu} this
35412 * @param {Roo.EventObject} e
35413 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35418 * Fires when a menu item contained in this menu is clicked
35419 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35420 * @param {Roo.EventObject} e
35424 if (this.registerMenu) {
35425 Roo.menu.MenuMgr.register(this);
35428 var mis = this.items;
35429 this.items = new Roo.util.MixedCollection();
35431 this.add.apply(this, mis);
35435 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35437 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35441 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35442 * for bottom-right shadow (defaults to "sides")
35446 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35447 * this menu (defaults to "tl-tr?")
35449 subMenuAlign : "tl-tr?",
35451 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35452 * relative to its element of origin (defaults to "tl-bl?")
35454 defaultAlign : "tl-bl?",
35456 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35458 allowOtherMenus : false,
35460 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35462 registerMenu : true,
35467 render : function(){
35471 var el = this.el = new Roo.Layer({
35473 shadow:this.shadow,
35475 parentEl: this.parentEl || document.body,
35479 this.keyNav = new Roo.menu.MenuNav(this);
35482 el.addClass("x-menu-plain");
35485 el.addClass(this.cls);
35487 // generic focus element
35488 this.focusEl = el.createChild({
35489 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35491 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35492 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35494 ul.on("mouseover", this.onMouseOver, this);
35495 ul.on("mouseout", this.onMouseOut, this);
35496 this.items.each(function(item){
35501 var li = document.createElement("li");
35502 li.className = "x-menu-list-item";
35503 ul.dom.appendChild(li);
35504 item.render(li, this);
35511 autoWidth : function(){
35512 var el = this.el, ul = this.ul;
35516 var w = this.width;
35519 }else if(Roo.isIE){
35520 el.setWidth(this.minWidth);
35521 var t = el.dom.offsetWidth; // force recalc
35522 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35527 delayAutoWidth : function(){
35530 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35532 this.awTask.delay(20);
35537 findTargetItem : function(e){
35538 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35539 if(t && t.menuItemId){
35540 return this.items.get(t.menuItemId);
35545 onClick : function(e){
35546 Roo.log("menu.onClick");
35547 var t = this.findTargetItem(e);
35552 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35553 if(t == this.activeItem && t.shouldDeactivate(e)){
35554 this.activeItem.deactivate();
35555 delete this.activeItem;
35559 this.setActiveItem(t, true);
35567 this.fireEvent("click", this, t, e);
35571 setActiveItem : function(item, autoExpand){
35572 if(item != this.activeItem){
35573 if(this.activeItem){
35574 this.activeItem.deactivate();
35576 this.activeItem = item;
35577 item.activate(autoExpand);
35578 }else if(autoExpand){
35584 tryActivate : function(start, step){
35585 var items = this.items;
35586 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35587 var item = items.get(i);
35588 if(!item.disabled && item.canActivate){
35589 this.setActiveItem(item, false);
35597 onMouseOver : function(e){
35599 if(t = this.findTargetItem(e)){
35600 if(t.canActivate && !t.disabled){
35601 this.setActiveItem(t, true);
35604 this.fireEvent("mouseover", this, e, t);
35608 onMouseOut : function(e){
35610 if(t = this.findTargetItem(e)){
35611 if(t == this.activeItem && t.shouldDeactivate(e)){
35612 this.activeItem.deactivate();
35613 delete this.activeItem;
35616 this.fireEvent("mouseout", this, e, t);
35620 * Read-only. Returns true if the menu is currently displayed, else false.
35623 isVisible : function(){
35624 return this.el && !this.hidden;
35628 * Displays this menu relative to another element
35629 * @param {String/HTMLElement/Roo.Element} element The element to align to
35630 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35631 * the element (defaults to this.defaultAlign)
35632 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35634 show : function(el, pos, parentMenu){
35635 this.parentMenu = parentMenu;
35639 this.fireEvent("beforeshow", this);
35640 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35644 * Displays this menu at a specific xy position
35645 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35646 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35648 showAt : function(xy, parentMenu, /* private: */_e){
35649 this.parentMenu = parentMenu;
35654 this.fireEvent("beforeshow", this);
35655 xy = this.el.adjustForConstraints(xy);
35659 this.hidden = false;
35661 this.fireEvent("show", this);
35664 focus : function(){
35666 this.doFocus.defer(50, this);
35670 doFocus : function(){
35672 this.focusEl.focus();
35677 * Hides this menu and optionally all parent menus
35678 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35680 hide : function(deep){
35681 if(this.el && this.isVisible()){
35682 this.fireEvent("beforehide", this);
35683 if(this.activeItem){
35684 this.activeItem.deactivate();
35685 this.activeItem = null;
35688 this.hidden = true;
35689 this.fireEvent("hide", this);
35691 if(deep === true && this.parentMenu){
35692 this.parentMenu.hide(true);
35697 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35698 * Any of the following are valid:
35700 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35701 * <li>An HTMLElement object which will be converted to a menu item</li>
35702 * <li>A menu item config object that will be created as a new menu item</li>
35703 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35704 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35709 var menu = new Roo.menu.Menu();
35711 // Create a menu item to add by reference
35712 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35714 // Add a bunch of items at once using different methods.
35715 // Only the last item added will be returned.
35716 var item = menu.add(
35717 menuItem, // add existing item by ref
35718 'Dynamic Item', // new TextItem
35719 '-', // new separator
35720 { text: 'Config Item' } // new item by config
35723 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35724 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35727 var a = arguments, l = a.length, item;
35728 for(var i = 0; i < l; i++){
35730 if ((typeof(el) == "object") && el.xtype && el.xns) {
35731 el = Roo.factory(el, Roo.menu);
35734 if(el.render){ // some kind of Item
35735 item = this.addItem(el);
35736 }else if(typeof el == "string"){ // string
35737 if(el == "separator" || el == "-"){
35738 item = this.addSeparator();
35740 item = this.addText(el);
35742 }else if(el.tagName || el.el){ // element
35743 item = this.addElement(el);
35744 }else if(typeof el == "object"){ // must be menu item config?
35745 item = this.addMenuItem(el);
35752 * Returns this menu's underlying {@link Roo.Element} object
35753 * @return {Roo.Element} The element
35755 getEl : function(){
35763 * Adds a separator bar to the menu
35764 * @return {Roo.menu.Item} The menu item that was added
35766 addSeparator : function(){
35767 return this.addItem(new Roo.menu.Separator());
35771 * Adds an {@link Roo.Element} object to the menu
35772 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35773 * @return {Roo.menu.Item} The menu item that was added
35775 addElement : function(el){
35776 return this.addItem(new Roo.menu.BaseItem(el));
35780 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35781 * @param {Roo.menu.Item} item The menu item to add
35782 * @return {Roo.menu.Item} The menu item that was added
35784 addItem : function(item){
35785 this.items.add(item);
35787 var li = document.createElement("li");
35788 li.className = "x-menu-list-item";
35789 this.ul.dom.appendChild(li);
35790 item.render(li, this);
35791 this.delayAutoWidth();
35797 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35798 * @param {Object} config A MenuItem config object
35799 * @return {Roo.menu.Item} The menu item that was added
35801 addMenuItem : function(config){
35802 if(!(config instanceof Roo.menu.Item)){
35803 if(typeof config.checked == "boolean"){ // must be check menu item config?
35804 config = new Roo.menu.CheckItem(config);
35806 config = new Roo.menu.Item(config);
35809 return this.addItem(config);
35813 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35814 * @param {String} text The text to display in the menu item
35815 * @return {Roo.menu.Item} The menu item that was added
35817 addText : function(text){
35818 return this.addItem(new Roo.menu.TextItem({ text : text }));
35822 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35823 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35824 * @param {Roo.menu.Item} item The menu item to add
35825 * @return {Roo.menu.Item} The menu item that was added
35827 insert : function(index, item){
35828 this.items.insert(index, item);
35830 var li = document.createElement("li");
35831 li.className = "x-menu-list-item";
35832 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35833 item.render(li, this);
35834 this.delayAutoWidth();
35840 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35841 * @param {Roo.menu.Item} item The menu item to remove
35843 remove : function(item){
35844 this.items.removeKey(item.id);
35849 * Removes and destroys all items in the menu
35851 removeAll : function(){
35853 while(f = this.items.first()){
35859 // MenuNav is a private utility class used internally by the Menu
35860 Roo.menu.MenuNav = function(menu){
35861 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35862 this.scope = this.menu = menu;
35865 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35866 doRelay : function(e, h){
35867 var k = e.getKey();
35868 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35869 this.menu.tryActivate(0, 1);
35872 return h.call(this.scope || this, e, this.menu);
35875 up : function(e, m){
35876 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35877 m.tryActivate(m.items.length-1, -1);
35881 down : function(e, m){
35882 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35883 m.tryActivate(0, 1);
35887 right : function(e, m){
35889 m.activeItem.expandMenu(true);
35893 left : function(e, m){
35895 if(m.parentMenu && m.parentMenu.activeItem){
35896 m.parentMenu.activeItem.activate();
35900 enter : function(e, m){
35902 e.stopPropagation();
35903 m.activeItem.onClick(e);
35904 m.fireEvent("click", this, m.activeItem);
35910 * Ext JS Library 1.1.1
35911 * Copyright(c) 2006-2007, Ext JS, LLC.
35913 * Originally Released Under LGPL - original licence link has changed is not relivant.
35916 * <script type="text/javascript">
35920 * @class Roo.menu.MenuMgr
35921 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35924 Roo.menu.MenuMgr = function(){
35925 var menus, active, groups = {}, attached = false, lastShow = new Date();
35927 // private - called when first menu is created
35930 active = new Roo.util.MixedCollection();
35931 Roo.get(document).addKeyListener(27, function(){
35932 if(active.length > 0){
35939 function hideAll(){
35940 if(active && active.length > 0){
35941 var c = active.clone();
35942 c.each(function(m){
35949 function onHide(m){
35951 if(active.length < 1){
35952 Roo.get(document).un("mousedown", onMouseDown);
35958 function onShow(m){
35959 var last = active.last();
35960 lastShow = new Date();
35963 Roo.get(document).on("mousedown", onMouseDown);
35967 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35968 m.parentMenu.activeChild = m;
35969 }else if(last && last.isVisible()){
35970 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35975 function onBeforeHide(m){
35977 m.activeChild.hide();
35979 if(m.autoHideTimer){
35980 clearTimeout(m.autoHideTimer);
35981 delete m.autoHideTimer;
35986 function onBeforeShow(m){
35987 var pm = m.parentMenu;
35988 if(!pm && !m.allowOtherMenus){
35990 }else if(pm && pm.activeChild && active != m){
35991 pm.activeChild.hide();
35996 function onMouseDown(e){
35997 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36003 function onBeforeCheck(mi, state){
36005 var g = groups[mi.group];
36006 for(var i = 0, l = g.length; i < l; i++){
36008 g[i].setChecked(false);
36017 * Hides all menus that are currently visible
36019 hideAll : function(){
36024 register : function(menu){
36028 menus[menu.id] = menu;
36029 menu.on("beforehide", onBeforeHide);
36030 menu.on("hide", onHide);
36031 menu.on("beforeshow", onBeforeShow);
36032 menu.on("show", onShow);
36033 var g = menu.group;
36034 if(g && menu.events["checkchange"]){
36038 groups[g].push(menu);
36039 menu.on("checkchange", onCheck);
36044 * Returns a {@link Roo.menu.Menu} object
36045 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36046 * be used to generate and return a new Menu instance.
36048 get : function(menu){
36049 if(typeof menu == "string"){ // menu id
36050 return menus[menu];
36051 }else if(menu.events){ // menu instance
36053 }else if(typeof menu.length == 'number'){ // array of menu items?
36054 return new Roo.menu.Menu({items:menu});
36055 }else{ // otherwise, must be a config
36056 return new Roo.menu.Menu(menu);
36061 unregister : function(menu){
36062 delete menus[menu.id];
36063 menu.un("beforehide", onBeforeHide);
36064 menu.un("hide", onHide);
36065 menu.un("beforeshow", onBeforeShow);
36066 menu.un("show", onShow);
36067 var g = menu.group;
36068 if(g && menu.events["checkchange"]){
36069 groups[g].remove(menu);
36070 menu.un("checkchange", onCheck);
36075 registerCheckable : function(menuItem){
36076 var g = menuItem.group;
36081 groups[g].push(menuItem);
36082 menuItem.on("beforecheckchange", onBeforeCheck);
36087 unregisterCheckable : function(menuItem){
36088 var g = menuItem.group;
36090 groups[g].remove(menuItem);
36091 menuItem.un("beforecheckchange", onBeforeCheck);
36097 * Ext JS Library 1.1.1
36098 * Copyright(c) 2006-2007, Ext JS, LLC.
36100 * Originally Released Under LGPL - original licence link has changed is not relivant.
36103 * <script type="text/javascript">
36108 * @class Roo.menu.BaseItem
36109 * @extends Roo.Component
36110 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36111 * management and base configuration options shared by all menu components.
36113 * Creates a new BaseItem
36114 * @param {Object} config Configuration options
36116 Roo.menu.BaseItem = function(config){
36117 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36122 * Fires when this item is clicked
36123 * @param {Roo.menu.BaseItem} this
36124 * @param {Roo.EventObject} e
36129 * Fires when this item is activated
36130 * @param {Roo.menu.BaseItem} this
36134 * @event deactivate
36135 * Fires when this item is deactivated
36136 * @param {Roo.menu.BaseItem} this
36142 this.on("click", this.handler, this.scope, true);
36146 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36148 * @cfg {Function} handler
36149 * A function that will handle the click event of this menu item (defaults to undefined)
36152 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36154 canActivate : false,
36157 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36162 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36164 activeClass : "x-menu-item-active",
36166 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36168 hideOnClick : true,
36170 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36175 ctype: "Roo.menu.BaseItem",
36178 actionMode : "container",
36181 render : function(container, parentMenu){
36182 this.parentMenu = parentMenu;
36183 Roo.menu.BaseItem.superclass.render.call(this, container);
36184 this.container.menuItemId = this.id;
36188 onRender : function(container, position){
36189 this.el = Roo.get(this.el);
36190 container.dom.appendChild(this.el.dom);
36194 onClick : function(e){
36195 if(!this.disabled && this.fireEvent("click", this, e) !== false
36196 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36197 this.handleClick(e);
36204 activate : function(){
36208 var li = this.container;
36209 li.addClass(this.activeClass);
36210 this.region = li.getRegion().adjust(2, 2, -2, -2);
36211 this.fireEvent("activate", this);
36216 deactivate : function(){
36217 this.container.removeClass(this.activeClass);
36218 this.fireEvent("deactivate", this);
36222 shouldDeactivate : function(e){
36223 return !this.region || !this.region.contains(e.getPoint());
36227 handleClick : function(e){
36228 if(this.hideOnClick){
36229 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36234 expandMenu : function(autoActivate){
36239 hideMenu : function(){
36244 * Ext JS Library 1.1.1
36245 * Copyright(c) 2006-2007, Ext JS, LLC.
36247 * Originally Released Under LGPL - original licence link has changed is not relivant.
36250 * <script type="text/javascript">
36254 * @class Roo.menu.Adapter
36255 * @extends Roo.menu.BaseItem
36256 * 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.
36257 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36259 * Creates a new Adapter
36260 * @param {Object} config Configuration options
36262 Roo.menu.Adapter = function(component, config){
36263 Roo.menu.Adapter.superclass.constructor.call(this, config);
36264 this.component = component;
36266 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36268 canActivate : true,
36271 onRender : function(container, position){
36272 this.component.render(container);
36273 this.el = this.component.getEl();
36277 activate : function(){
36281 this.component.focus();
36282 this.fireEvent("activate", this);
36287 deactivate : function(){
36288 this.fireEvent("deactivate", this);
36292 disable : function(){
36293 this.component.disable();
36294 Roo.menu.Adapter.superclass.disable.call(this);
36298 enable : function(){
36299 this.component.enable();
36300 Roo.menu.Adapter.superclass.enable.call(this);
36304 * Ext JS Library 1.1.1
36305 * Copyright(c) 2006-2007, Ext JS, LLC.
36307 * Originally Released Under LGPL - original licence link has changed is not relivant.
36310 * <script type="text/javascript">
36314 * @class Roo.menu.TextItem
36315 * @extends Roo.menu.BaseItem
36316 * Adds a static text string to a menu, usually used as either a heading or group separator.
36317 * Note: old style constructor with text is still supported.
36320 * Creates a new TextItem
36321 * @param {Object} cfg Configuration
36323 Roo.menu.TextItem = function(cfg){
36324 if (typeof(cfg) == 'string') {
36327 Roo.apply(this,cfg);
36330 Roo.menu.TextItem.superclass.constructor.call(this);
36333 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36335 * @cfg {Boolean} text Text to show on item.
36340 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36342 hideOnClick : false,
36344 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36346 itemCls : "x-menu-text",
36349 onRender : function(){
36350 var s = document.createElement("span");
36351 s.className = this.itemCls;
36352 s.innerHTML = this.text;
36354 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36358 * Ext JS Library 1.1.1
36359 * Copyright(c) 2006-2007, Ext JS, LLC.
36361 * Originally Released Under LGPL - original licence link has changed is not relivant.
36364 * <script type="text/javascript">
36368 * @class Roo.menu.Separator
36369 * @extends Roo.menu.BaseItem
36370 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36371 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36373 * @param {Object} config Configuration options
36375 Roo.menu.Separator = function(config){
36376 Roo.menu.Separator.superclass.constructor.call(this, config);
36379 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36381 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36383 itemCls : "x-menu-sep",
36385 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36387 hideOnClick : false,
36390 onRender : function(li){
36391 var s = document.createElement("span");
36392 s.className = this.itemCls;
36393 s.innerHTML = " ";
36395 li.addClass("x-menu-sep-li");
36396 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36400 * Ext JS Library 1.1.1
36401 * Copyright(c) 2006-2007, Ext JS, LLC.
36403 * Originally Released Under LGPL - original licence link has changed is not relivant.
36406 * <script type="text/javascript">
36409 * @class Roo.menu.Item
36410 * @extends Roo.menu.BaseItem
36411 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36412 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36413 * activation and click handling.
36415 * Creates a new Item
36416 * @param {Object} config Configuration options
36418 Roo.menu.Item = function(config){
36419 Roo.menu.Item.superclass.constructor.call(this, config);
36421 this.menu = Roo.menu.MenuMgr.get(this.menu);
36424 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36427 * @cfg {String} text
36428 * The text to show on the menu item.
36432 * @cfg {String} HTML to render in menu
36433 * The text to show on the menu item (HTML version).
36437 * @cfg {String} icon
36438 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36442 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36444 itemCls : "x-menu-item",
36446 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36448 canActivate : true,
36450 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36453 // doc'd in BaseItem
36457 ctype: "Roo.menu.Item",
36460 onRender : function(container, position){
36461 var el = document.createElement("a");
36462 el.hideFocus = true;
36463 el.unselectable = "on";
36464 el.href = this.href || "#";
36465 if(this.hrefTarget){
36466 el.target = this.hrefTarget;
36468 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36470 var html = this.html.length ? this.html : String.format('{0}',this.text);
36472 el.innerHTML = String.format(
36473 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36474 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36476 Roo.menu.Item.superclass.onRender.call(this, container, position);
36480 * Sets the text to display in this menu item
36481 * @param {String} text The text to display
36482 * @param {Boolean} isHTML true to indicate text is pure html.
36484 setText : function(text, isHTML){
36492 var html = this.html.length ? this.html : String.format('{0}',this.text);
36494 this.el.update(String.format(
36495 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36496 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36497 this.parentMenu.autoWidth();
36502 handleClick : function(e){
36503 if(!this.href){ // if no link defined, stop the event automatically
36506 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36510 activate : function(autoExpand){
36511 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36521 shouldDeactivate : function(e){
36522 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36523 if(this.menu && this.menu.isVisible()){
36524 return !this.menu.getEl().getRegion().contains(e.getPoint());
36532 deactivate : function(){
36533 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36538 expandMenu : function(autoActivate){
36539 if(!this.disabled && this.menu){
36540 clearTimeout(this.hideTimer);
36541 delete this.hideTimer;
36542 if(!this.menu.isVisible() && !this.showTimer){
36543 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36544 }else if (this.menu.isVisible() && autoActivate){
36545 this.menu.tryActivate(0, 1);
36551 deferExpand : function(autoActivate){
36552 delete this.showTimer;
36553 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36555 this.menu.tryActivate(0, 1);
36560 hideMenu : function(){
36561 clearTimeout(this.showTimer);
36562 delete this.showTimer;
36563 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36564 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36569 deferHide : function(){
36570 delete this.hideTimer;
36575 * Ext JS Library 1.1.1
36576 * Copyright(c) 2006-2007, Ext JS, LLC.
36578 * Originally Released Under LGPL - original licence link has changed is not relivant.
36581 * <script type="text/javascript">
36585 * @class Roo.menu.CheckItem
36586 * @extends Roo.menu.Item
36587 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36589 * Creates a new CheckItem
36590 * @param {Object} config Configuration options
36592 Roo.menu.CheckItem = function(config){
36593 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36596 * @event beforecheckchange
36597 * Fires before the checked value is set, providing an opportunity to cancel if needed
36598 * @param {Roo.menu.CheckItem} this
36599 * @param {Boolean} checked The new checked value that will be set
36601 "beforecheckchange" : true,
36603 * @event checkchange
36604 * Fires after the checked value has been set
36605 * @param {Roo.menu.CheckItem} this
36606 * @param {Boolean} checked The checked value that was set
36608 "checkchange" : true
36610 if(this.checkHandler){
36611 this.on('checkchange', this.checkHandler, this.scope);
36614 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36616 * @cfg {String} group
36617 * All check items with the same group name will automatically be grouped into a single-select
36618 * radio button group (defaults to '')
36621 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36623 itemCls : "x-menu-item x-menu-check-item",
36625 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36627 groupClass : "x-menu-group-item",
36630 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36631 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36632 * initialized with checked = true will be rendered as checked.
36637 ctype: "Roo.menu.CheckItem",
36640 onRender : function(c){
36641 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36643 this.el.addClass(this.groupClass);
36645 Roo.menu.MenuMgr.registerCheckable(this);
36647 this.checked = false;
36648 this.setChecked(true, true);
36653 destroy : function(){
36655 Roo.menu.MenuMgr.unregisterCheckable(this);
36657 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36661 * Set the checked state of this item
36662 * @param {Boolean} checked The new checked value
36663 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36665 setChecked : function(state, suppressEvent){
36666 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36667 if(this.container){
36668 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36670 this.checked = state;
36671 if(suppressEvent !== true){
36672 this.fireEvent("checkchange", this, state);
36678 handleClick : function(e){
36679 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36680 this.setChecked(!this.checked);
36682 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36686 * Ext JS Library 1.1.1
36687 * Copyright(c) 2006-2007, Ext JS, LLC.
36689 * Originally Released Under LGPL - original licence link has changed is not relivant.
36692 * <script type="text/javascript">
36696 * @class Roo.menu.DateItem
36697 * @extends Roo.menu.Adapter
36698 * A menu item that wraps the {@link Roo.DatPicker} component.
36700 * Creates a new DateItem
36701 * @param {Object} config Configuration options
36703 Roo.menu.DateItem = function(config){
36704 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36705 /** The Roo.DatePicker object @type Roo.DatePicker */
36706 this.picker = this.component;
36707 this.addEvents({select: true});
36709 this.picker.on("render", function(picker){
36710 picker.getEl().swallowEvent("click");
36711 picker.container.addClass("x-menu-date-item");
36714 this.picker.on("select", this.onSelect, this);
36717 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36719 onSelect : function(picker, date){
36720 this.fireEvent("select", this, date, picker);
36721 Roo.menu.DateItem.superclass.handleClick.call(this);
36725 * Ext JS Library 1.1.1
36726 * Copyright(c) 2006-2007, Ext JS, LLC.
36728 * Originally Released Under LGPL - original licence link has changed is not relivant.
36731 * <script type="text/javascript">
36735 * @class Roo.menu.ColorItem
36736 * @extends Roo.menu.Adapter
36737 * A menu item that wraps the {@link Roo.ColorPalette} component.
36739 * Creates a new ColorItem
36740 * @param {Object} config Configuration options
36742 Roo.menu.ColorItem = function(config){
36743 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36744 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36745 this.palette = this.component;
36746 this.relayEvents(this.palette, ["select"]);
36747 if(this.selectHandler){
36748 this.on('select', this.selectHandler, this.scope);
36751 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36753 * Ext JS Library 1.1.1
36754 * Copyright(c) 2006-2007, Ext JS, LLC.
36756 * Originally Released Under LGPL - original licence link has changed is not relivant.
36759 * <script type="text/javascript">
36764 * @class Roo.menu.DateMenu
36765 * @extends Roo.menu.Menu
36766 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36768 * Creates a new DateMenu
36769 * @param {Object} config Configuration options
36771 Roo.menu.DateMenu = function(config){
36772 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36774 var di = new Roo.menu.DateItem(config);
36777 * The {@link Roo.DatePicker} instance for this DateMenu
36780 this.picker = di.picker;
36783 * @param {DatePicker} picker
36784 * @param {Date} date
36786 this.relayEvents(di, ["select"]);
36787 this.on('beforeshow', function(){
36789 this.picker.hideMonthPicker(false);
36793 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36797 * Ext JS Library 1.1.1
36798 * Copyright(c) 2006-2007, Ext JS, LLC.
36800 * Originally Released Under LGPL - original licence link has changed is not relivant.
36803 * <script type="text/javascript">
36808 * @class Roo.menu.ColorMenu
36809 * @extends Roo.menu.Menu
36810 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36812 * Creates a new ColorMenu
36813 * @param {Object} config Configuration options
36815 Roo.menu.ColorMenu = function(config){
36816 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36818 var ci = new Roo.menu.ColorItem(config);
36821 * The {@link Roo.ColorPalette} instance for this ColorMenu
36822 * @type ColorPalette
36824 this.palette = ci.palette;
36827 * @param {ColorPalette} palette
36828 * @param {String} color
36830 this.relayEvents(ci, ["select"]);
36832 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36834 * Ext JS Library 1.1.1
36835 * Copyright(c) 2006-2007, Ext JS, LLC.
36837 * Originally Released Under LGPL - original licence link has changed is not relivant.
36840 * <script type="text/javascript">
36844 * @class Roo.form.Field
36845 * @extends Roo.BoxComponent
36846 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36848 * Creates a new Field
36849 * @param {Object} config Configuration options
36851 Roo.form.Field = function(config){
36852 Roo.form.Field.superclass.constructor.call(this, config);
36855 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36857 * @cfg {String} fieldLabel Label to use when rendering a form.
36860 * @cfg {String} qtip Mouse over tip
36864 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36866 invalidClass : "x-form-invalid",
36868 * @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")
36870 invalidText : "The value in this field is invalid",
36872 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36874 focusClass : "x-form-focus",
36876 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36877 automatic validation (defaults to "keyup").
36879 validationEvent : "keyup",
36881 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36883 validateOnBlur : true,
36885 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36887 validationDelay : 250,
36889 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36890 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36892 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36894 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36896 fieldClass : "x-form-field",
36898 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36901 ----------- ----------------------------------------------------------------------
36902 qtip Display a quick tip when the user hovers over the field
36903 title Display a default browser title attribute popup
36904 under Add a block div beneath the field containing the error text
36905 side Add an error icon to the right of the field with a popup on hover
36906 [element id] Add the error text directly to the innerHTML of the specified element
36909 msgTarget : 'qtip',
36911 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36916 * @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.
36921 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36926 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36928 inputType : undefined,
36931 * @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).
36933 tabIndex : undefined,
36936 isFormField : true,
36941 * @property {Roo.Element} fieldEl
36942 * Element Containing the rendered Field (with label etc.)
36945 * @cfg {Mixed} value A value to initialize this field with.
36950 * @cfg {String} name The field's HTML name attribute.
36953 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36957 initComponent : function(){
36958 Roo.form.Field.superclass.initComponent.call(this);
36962 * Fires when this field receives input focus.
36963 * @param {Roo.form.Field} this
36968 * Fires when this field loses input focus.
36969 * @param {Roo.form.Field} this
36973 * @event specialkey
36974 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36975 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36976 * @param {Roo.form.Field} this
36977 * @param {Roo.EventObject} e The event object
36982 * Fires just before the field blurs if the field value has changed.
36983 * @param {Roo.form.Field} this
36984 * @param {Mixed} newValue The new value
36985 * @param {Mixed} oldValue The original value
36990 * Fires after the field has been marked as invalid.
36991 * @param {Roo.form.Field} this
36992 * @param {String} msg The validation message
36997 * Fires after the field has been validated with no errors.
36998 * @param {Roo.form.Field} this
37003 * Fires after the key up
37004 * @param {Roo.form.Field} this
37005 * @param {Roo.EventObject} e The event Object
37012 * Returns the name attribute of the field if available
37013 * @return {String} name The field name
37015 getName: function(){
37016 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37020 onRender : function(ct, position){
37021 Roo.form.Field.superclass.onRender.call(this, ct, position);
37023 var cfg = this.getAutoCreate();
37025 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37027 if (!cfg.name.length) {
37030 if(this.inputType){
37031 cfg.type = this.inputType;
37033 this.el = ct.createChild(cfg, position);
37035 var type = this.el.dom.type;
37037 if(type == 'password'){
37040 this.el.addClass('x-form-'+type);
37043 this.el.dom.readOnly = true;
37045 if(this.tabIndex !== undefined){
37046 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37049 this.el.addClass([this.fieldClass, this.cls]);
37054 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37055 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37056 * @return {Roo.form.Field} this
37058 applyTo : function(target){
37059 this.allowDomMove = false;
37060 this.el = Roo.get(target);
37061 this.render(this.el.dom.parentNode);
37066 initValue : function(){
37067 if(this.value !== undefined){
37068 this.setValue(this.value);
37069 }else if(this.el.dom.value.length > 0){
37070 this.setValue(this.el.dom.value);
37075 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37077 isDirty : function() {
37078 if(this.disabled) {
37081 return String(this.getValue()) !== String(this.originalValue);
37085 afterRender : function(){
37086 Roo.form.Field.superclass.afterRender.call(this);
37091 fireKey : function(e){
37092 //Roo.log('field ' + e.getKey());
37093 if(e.isNavKeyPress()){
37094 this.fireEvent("specialkey", this, e);
37099 * Resets the current field value to the originally loaded value and clears any validation messages
37101 reset : function(){
37102 this.setValue(this.resetValue);
37103 this.clearInvalid();
37107 initEvents : function(){
37108 // safari killled keypress - so keydown is now used..
37109 this.el.on("keydown" , this.fireKey, this);
37110 this.el.on("focus", this.onFocus, this);
37111 this.el.on("blur", this.onBlur, this);
37112 this.el.relayEvent('keyup', this);
37114 // reference to original value for reset
37115 this.originalValue = this.getValue();
37116 this.resetValue = this.getValue();
37120 onFocus : function(){
37121 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37122 this.el.addClass(this.focusClass);
37124 if(!this.hasFocus){
37125 this.hasFocus = true;
37126 this.startValue = this.getValue();
37127 this.fireEvent("focus", this);
37131 beforeBlur : Roo.emptyFn,
37134 onBlur : function(){
37136 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37137 this.el.removeClass(this.focusClass);
37139 this.hasFocus = false;
37140 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37143 var v = this.getValue();
37144 if(String(v) !== String(this.startValue)){
37145 this.fireEvent('change', this, v, this.startValue);
37147 this.fireEvent("blur", this);
37151 * Returns whether or not the field value is currently valid
37152 * @param {Boolean} preventMark True to disable marking the field invalid
37153 * @return {Boolean} True if the value is valid, else false
37155 isValid : function(preventMark){
37159 var restore = this.preventMark;
37160 this.preventMark = preventMark === true;
37161 var v = this.validateValue(this.processValue(this.getRawValue()));
37162 this.preventMark = restore;
37167 * Validates the field value
37168 * @return {Boolean} True if the value is valid, else false
37170 validate : function(){
37171 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37172 this.clearInvalid();
37178 processValue : function(value){
37183 // Subclasses should provide the validation implementation by overriding this
37184 validateValue : function(value){
37189 * Mark this field as invalid
37190 * @param {String} msg The validation message
37192 markInvalid : function(msg){
37193 if(!this.rendered || this.preventMark){ // not rendered
37197 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37199 obj.el.addClass(this.invalidClass);
37200 msg = msg || this.invalidText;
37201 switch(this.msgTarget){
37203 obj.el.dom.qtip = msg;
37204 obj.el.dom.qclass = 'x-form-invalid-tip';
37205 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37206 Roo.QuickTips.enable();
37210 this.el.dom.title = msg;
37214 var elp = this.el.findParent('.x-form-element', 5, true);
37215 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37216 this.errorEl.setWidth(elp.getWidth(true)-20);
37218 this.errorEl.update(msg);
37219 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37222 if(!this.errorIcon){
37223 var elp = this.el.findParent('.x-form-element', 5, true);
37224 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37226 this.alignErrorIcon();
37227 this.errorIcon.dom.qtip = msg;
37228 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37229 this.errorIcon.show();
37230 this.on('resize', this.alignErrorIcon, this);
37233 var t = Roo.getDom(this.msgTarget);
37235 t.style.display = this.msgDisplay;
37238 this.fireEvent('invalid', this, msg);
37242 alignErrorIcon : function(){
37243 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37247 * Clear any invalid styles/messages for this field
37249 clearInvalid : function(){
37250 if(!this.rendered || this.preventMark){ // not rendered
37253 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37255 obj.el.removeClass(this.invalidClass);
37256 switch(this.msgTarget){
37258 obj.el.dom.qtip = '';
37261 this.el.dom.title = '';
37265 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37269 if(this.errorIcon){
37270 this.errorIcon.dom.qtip = '';
37271 this.errorIcon.hide();
37272 this.un('resize', this.alignErrorIcon, this);
37276 var t = Roo.getDom(this.msgTarget);
37278 t.style.display = 'none';
37281 this.fireEvent('valid', this);
37285 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37286 * @return {Mixed} value The field value
37288 getRawValue : function(){
37289 var v = this.el.getValue();
37295 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37296 * @return {Mixed} value The field value
37298 getValue : function(){
37299 var v = this.el.getValue();
37305 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37306 * @param {Mixed} value The value to set
37308 setRawValue : function(v){
37309 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37313 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37314 * @param {Mixed} value The value to set
37316 setValue : function(v){
37319 this.el.dom.value = (v === null || v === undefined ? '' : v);
37324 adjustSize : function(w, h){
37325 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37326 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37330 adjustWidth : function(tag, w){
37331 tag = tag.toLowerCase();
37332 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37333 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37334 if(tag == 'input'){
37337 if(tag == 'textarea'){
37340 }else if(Roo.isOpera){
37341 if(tag == 'input'){
37344 if(tag == 'textarea'){
37354 // anything other than normal should be considered experimental
37355 Roo.form.Field.msgFx = {
37357 show: function(msgEl, f){
37358 msgEl.setDisplayed('block');
37361 hide : function(msgEl, f){
37362 msgEl.setDisplayed(false).update('');
37367 show: function(msgEl, f){
37368 msgEl.slideIn('t', {stopFx:true});
37371 hide : function(msgEl, f){
37372 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37377 show: function(msgEl, f){
37378 msgEl.fixDisplay();
37379 msgEl.alignTo(f.el, 'tl-tr');
37380 msgEl.slideIn('l', {stopFx:true});
37383 hide : function(msgEl, f){
37384 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37389 * Ext JS Library 1.1.1
37390 * Copyright(c) 2006-2007, Ext JS, LLC.
37392 * Originally Released Under LGPL - original licence link has changed is not relivant.
37395 * <script type="text/javascript">
37400 * @class Roo.form.TextField
37401 * @extends Roo.form.Field
37402 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37403 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37405 * Creates a new TextField
37406 * @param {Object} config Configuration options
37408 Roo.form.TextField = function(config){
37409 Roo.form.TextField.superclass.constructor.call(this, config);
37413 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37414 * according to the default logic, but this event provides a hook for the developer to apply additional
37415 * logic at runtime to resize the field if needed.
37416 * @param {Roo.form.Field} this This text field
37417 * @param {Number} width The new field width
37423 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37425 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37429 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37433 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37437 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37441 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37445 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37447 disableKeyFilter : false,
37449 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37453 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37457 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37459 maxLength : Number.MAX_VALUE,
37461 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37463 minLengthText : "The minimum length for this field is {0}",
37465 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37467 maxLengthText : "The maximum length for this field is {0}",
37469 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37471 selectOnFocus : false,
37473 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37475 blankText : "This field is required",
37477 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37478 * If available, this function will be called only after the basic validators all return true, and will be passed the
37479 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37483 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37484 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37485 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37489 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37493 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37499 initEvents : function()
37501 if (this.emptyText) {
37502 this.el.attr('placeholder', this.emptyText);
37505 Roo.form.TextField.superclass.initEvents.call(this);
37506 if(this.validationEvent == 'keyup'){
37507 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37508 this.el.on('keyup', this.filterValidation, this);
37510 else if(this.validationEvent !== false){
37511 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37514 if(this.selectOnFocus){
37515 this.on("focus", this.preFocus, this);
37518 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37519 this.el.on("keypress", this.filterKeys, this);
37522 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37523 this.el.on("click", this.autoSize, this);
37525 if(this.el.is('input[type=password]') && Roo.isSafari){
37526 this.el.on('keydown', this.SafariOnKeyDown, this);
37530 processValue : function(value){
37531 if(this.stripCharsRe){
37532 var newValue = value.replace(this.stripCharsRe, '');
37533 if(newValue !== value){
37534 this.setRawValue(newValue);
37541 filterValidation : function(e){
37542 if(!e.isNavKeyPress()){
37543 this.validationTask.delay(this.validationDelay);
37548 onKeyUp : function(e){
37549 if(!e.isNavKeyPress()){
37555 * Resets the current field value to the originally-loaded value and clears any validation messages.
37558 reset : function(){
37559 Roo.form.TextField.superclass.reset.call(this);
37565 preFocus : function(){
37567 if(this.selectOnFocus){
37568 this.el.dom.select();
37574 filterKeys : function(e){
37575 var k = e.getKey();
37576 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37579 var c = e.getCharCode(), cc = String.fromCharCode(c);
37580 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37583 if(!this.maskRe.test(cc)){
37588 setValue : function(v){
37590 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37596 * Validates a value according to the field's validation rules and marks the field as invalid
37597 * if the validation fails
37598 * @param {Mixed} value The value to validate
37599 * @return {Boolean} True if the value is valid, else false
37601 validateValue : function(value){
37602 if(value.length < 1) { // if it's blank
37603 if(this.allowBlank){
37604 this.clearInvalid();
37607 this.markInvalid(this.blankText);
37611 if(value.length < this.minLength){
37612 this.markInvalid(String.format(this.minLengthText, this.minLength));
37615 if(value.length > this.maxLength){
37616 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37620 var vt = Roo.form.VTypes;
37621 if(!vt[this.vtype](value, this)){
37622 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37626 if(typeof this.validator == "function"){
37627 var msg = this.validator(value);
37629 this.markInvalid(msg);
37633 if(this.regex && !this.regex.test(value)){
37634 this.markInvalid(this.regexText);
37641 * Selects text in this field
37642 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37643 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37645 selectText : function(start, end){
37646 var v = this.getRawValue();
37648 start = start === undefined ? 0 : start;
37649 end = end === undefined ? v.length : end;
37650 var d = this.el.dom;
37651 if(d.setSelectionRange){
37652 d.setSelectionRange(start, end);
37653 }else if(d.createTextRange){
37654 var range = d.createTextRange();
37655 range.moveStart("character", start);
37656 range.moveEnd("character", v.length-end);
37663 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37664 * This only takes effect if grow = true, and fires the autosize event.
37666 autoSize : function(){
37667 if(!this.grow || !this.rendered){
37671 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37674 var v = el.dom.value;
37675 var d = document.createElement('div');
37676 d.appendChild(document.createTextNode(v));
37680 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37681 this.el.setWidth(w);
37682 this.fireEvent("autosize", this, w);
37686 SafariOnKeyDown : function(event)
37688 // this is a workaround for a password hang bug on chrome/ webkit.
37690 var isSelectAll = false;
37692 if(this.el.dom.selectionEnd > 0){
37693 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37695 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37696 event.preventDefault();
37701 if(isSelectAll){ // backspace and delete key
37703 event.preventDefault();
37704 // this is very hacky as keydown always get's upper case.
37706 var cc = String.fromCharCode(event.getCharCode());
37707 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37715 * Ext JS Library 1.1.1
37716 * Copyright(c) 2006-2007, Ext JS, LLC.
37718 * Originally Released Under LGPL - original licence link has changed is not relivant.
37721 * <script type="text/javascript">
37725 * @class Roo.form.Hidden
37726 * @extends Roo.form.TextField
37727 * Simple Hidden element used on forms
37729 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37732 * Creates a new Hidden form element.
37733 * @param {Object} config Configuration options
37738 // easy hidden field...
37739 Roo.form.Hidden = function(config){
37740 Roo.form.Hidden.superclass.constructor.call(this, config);
37743 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37745 inputType: 'hidden',
37748 labelSeparator: '',
37750 itemCls : 'x-form-item-display-none'
37758 * Ext JS Library 1.1.1
37759 * Copyright(c) 2006-2007, Ext JS, LLC.
37761 * Originally Released Under LGPL - original licence link has changed is not relivant.
37764 * <script type="text/javascript">
37768 * @class Roo.form.TriggerField
37769 * @extends Roo.form.TextField
37770 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37771 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37772 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37773 * for which you can provide a custom implementation. For example:
37775 var trigger = new Roo.form.TriggerField();
37776 trigger.onTriggerClick = myTriggerFn;
37777 trigger.applyTo('my-field');
37780 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37781 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37782 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37783 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37785 * Create a new TriggerField.
37786 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37787 * to the base TextField)
37789 Roo.form.TriggerField = function(config){
37790 this.mimicing = false;
37791 Roo.form.TriggerField.superclass.constructor.call(this, config);
37794 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37796 * @cfg {String} triggerClass A CSS class to apply to the trigger
37799 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37800 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37802 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37804 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37808 /** @cfg {Boolean} grow @hide */
37809 /** @cfg {Number} growMin @hide */
37810 /** @cfg {Number} growMax @hide */
37816 autoSize: Roo.emptyFn,
37820 deferHeight : true,
37823 actionMode : 'wrap',
37825 onResize : function(w, h){
37826 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37827 if(typeof w == 'number'){
37828 var x = w - this.trigger.getWidth();
37829 this.el.setWidth(this.adjustWidth('input', x));
37830 this.trigger.setStyle('left', x+'px');
37835 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37838 getResizeEl : function(){
37843 getPositionEl : function(){
37848 alignErrorIcon : function(){
37849 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37853 onRender : function(ct, position){
37854 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37855 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37856 this.trigger = this.wrap.createChild(this.triggerConfig ||
37857 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37858 if(this.hideTrigger){
37859 this.trigger.setDisplayed(false);
37861 this.initTrigger();
37863 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37868 initTrigger : function(){
37869 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37870 this.trigger.addClassOnOver('x-form-trigger-over');
37871 this.trigger.addClassOnClick('x-form-trigger-click');
37875 onDestroy : function(){
37877 this.trigger.removeAllListeners();
37878 this.trigger.remove();
37881 this.wrap.remove();
37883 Roo.form.TriggerField.superclass.onDestroy.call(this);
37887 onFocus : function(){
37888 Roo.form.TriggerField.superclass.onFocus.call(this);
37889 if(!this.mimicing){
37890 this.wrap.addClass('x-trigger-wrap-focus');
37891 this.mimicing = true;
37892 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37893 if(this.monitorTab){
37894 this.el.on("keydown", this.checkTab, this);
37900 checkTab : function(e){
37901 if(e.getKey() == e.TAB){
37902 this.triggerBlur();
37907 onBlur : function(){
37912 mimicBlur : function(e, t){
37913 if(!this.wrap.contains(t) && this.validateBlur()){
37914 this.triggerBlur();
37919 triggerBlur : function(){
37920 this.mimicing = false;
37921 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37922 if(this.monitorTab){
37923 this.el.un("keydown", this.checkTab, this);
37925 this.wrap.removeClass('x-trigger-wrap-focus');
37926 Roo.form.TriggerField.superclass.onBlur.call(this);
37930 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37931 validateBlur : function(e, t){
37936 onDisable : function(){
37937 Roo.form.TriggerField.superclass.onDisable.call(this);
37939 this.wrap.addClass('x-item-disabled');
37944 onEnable : function(){
37945 Roo.form.TriggerField.superclass.onEnable.call(this);
37947 this.wrap.removeClass('x-item-disabled');
37952 onShow : function(){
37953 var ae = this.getActionEl();
37956 ae.dom.style.display = '';
37957 ae.dom.style.visibility = 'visible';
37963 onHide : function(){
37964 var ae = this.getActionEl();
37965 ae.dom.style.display = 'none';
37969 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37970 * by an implementing function.
37972 * @param {EventObject} e
37974 onTriggerClick : Roo.emptyFn
37977 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37978 // to be extended by an implementing class. For an example of implementing this class, see the custom
37979 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37980 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37981 initComponent : function(){
37982 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37984 this.triggerConfig = {
37985 tag:'span', cls:'x-form-twin-triggers', cn:[
37986 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37987 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
37991 getTrigger : function(index){
37992 return this.triggers[index];
37995 initTrigger : function(){
37996 var ts = this.trigger.select('.x-form-trigger', true);
37997 this.wrap.setStyle('overflow', 'hidden');
37998 var triggerField = this;
37999 ts.each(function(t, all, index){
38000 t.hide = function(){
38001 var w = triggerField.wrap.getWidth();
38002 this.dom.style.display = 'none';
38003 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38005 t.show = function(){
38006 var w = triggerField.wrap.getWidth();
38007 this.dom.style.display = '';
38008 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38010 var triggerIndex = 'Trigger'+(index+1);
38012 if(this['hide'+triggerIndex]){
38013 t.dom.style.display = 'none';
38015 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38016 t.addClassOnOver('x-form-trigger-over');
38017 t.addClassOnClick('x-form-trigger-click');
38019 this.triggers = ts.elements;
38022 onTrigger1Click : Roo.emptyFn,
38023 onTrigger2Click : Roo.emptyFn
38026 * Ext JS Library 1.1.1
38027 * Copyright(c) 2006-2007, Ext JS, LLC.
38029 * Originally Released Under LGPL - original licence link has changed is not relivant.
38032 * <script type="text/javascript">
38036 * @class Roo.form.TextArea
38037 * @extends Roo.form.TextField
38038 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38039 * support for auto-sizing.
38041 * Creates a new TextArea
38042 * @param {Object} config Configuration options
38044 Roo.form.TextArea = function(config){
38045 Roo.form.TextArea.superclass.constructor.call(this, config);
38046 // these are provided exchanges for backwards compat
38047 // minHeight/maxHeight were replaced by growMin/growMax to be
38048 // compatible with TextField growing config values
38049 if(this.minHeight !== undefined){
38050 this.growMin = this.minHeight;
38052 if(this.maxHeight !== undefined){
38053 this.growMax = this.maxHeight;
38057 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38059 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38063 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38067 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38068 * in the field (equivalent to setting overflow: hidden, defaults to false)
38070 preventScrollbars: false,
38072 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38073 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38077 onRender : function(ct, position){
38079 this.defaultAutoCreate = {
38081 style:"width:300px;height:60px;",
38082 autocomplete: "off"
38085 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38087 this.textSizeEl = Roo.DomHelper.append(document.body, {
38088 tag: "pre", cls: "x-form-grow-sizer"
38090 if(this.preventScrollbars){
38091 this.el.setStyle("overflow", "hidden");
38093 this.el.setHeight(this.growMin);
38097 onDestroy : function(){
38098 if(this.textSizeEl){
38099 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38101 Roo.form.TextArea.superclass.onDestroy.call(this);
38105 onKeyUp : function(e){
38106 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38112 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38113 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38115 autoSize : function(){
38116 if(!this.grow || !this.textSizeEl){
38120 var v = el.dom.value;
38121 var ts = this.textSizeEl;
38124 ts.appendChild(document.createTextNode(v));
38127 Roo.fly(ts).setWidth(this.el.getWidth());
38129 v = "  ";
38132 v = v.replace(/\n/g, '<p> </p>');
38134 v += " \n ";
38137 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38138 if(h != this.lastHeight){
38139 this.lastHeight = h;
38140 this.el.setHeight(h);
38141 this.fireEvent("autosize", this, h);
38146 * Ext JS Library 1.1.1
38147 * Copyright(c) 2006-2007, Ext JS, LLC.
38149 * Originally Released Under LGPL - original licence link has changed is not relivant.
38152 * <script type="text/javascript">
38157 * @class Roo.form.NumberField
38158 * @extends Roo.form.TextField
38159 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38161 * Creates a new NumberField
38162 * @param {Object} config Configuration options
38164 Roo.form.NumberField = function(config){
38165 Roo.form.NumberField.superclass.constructor.call(this, config);
38168 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38170 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38172 fieldClass: "x-form-field x-form-num-field",
38174 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38176 allowDecimals : true,
38178 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38180 decimalSeparator : ".",
38182 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38184 decimalPrecision : 2,
38186 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38188 allowNegative : true,
38190 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38192 minValue : Number.NEGATIVE_INFINITY,
38194 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38196 maxValue : Number.MAX_VALUE,
38198 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38200 minText : "The minimum value for this field is {0}",
38202 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38204 maxText : "The maximum value for this field is {0}",
38206 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38207 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38209 nanText : "{0} is not a valid number",
38212 initEvents : function(){
38213 Roo.form.NumberField.superclass.initEvents.call(this);
38214 var allowed = "0123456789";
38215 if(this.allowDecimals){
38216 allowed += this.decimalSeparator;
38218 if(this.allowNegative){
38221 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38222 var keyPress = function(e){
38223 var k = e.getKey();
38224 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38227 var c = e.getCharCode();
38228 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38232 this.el.on("keypress", keyPress, this);
38236 validateValue : function(value){
38237 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38240 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38243 var num = this.parseValue(value);
38245 this.markInvalid(String.format(this.nanText, value));
38248 if(num < this.minValue){
38249 this.markInvalid(String.format(this.minText, this.minValue));
38252 if(num > this.maxValue){
38253 this.markInvalid(String.format(this.maxText, this.maxValue));
38259 getValue : function(){
38260 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38264 parseValue : function(value){
38265 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38266 return isNaN(value) ? '' : value;
38270 fixPrecision : function(value){
38271 var nan = isNaN(value);
38272 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38273 return nan ? '' : value;
38275 return parseFloat(value).toFixed(this.decimalPrecision);
38278 setValue : function(v){
38279 v = this.fixPrecision(v);
38280 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38284 decimalPrecisionFcn : function(v){
38285 return Math.floor(v);
38288 beforeBlur : function(){
38289 var v = this.parseValue(this.getRawValue());
38296 * Ext JS Library 1.1.1
38297 * Copyright(c) 2006-2007, Ext JS, LLC.
38299 * Originally Released Under LGPL - original licence link has changed is not relivant.
38302 * <script type="text/javascript">
38306 * @class Roo.form.DateField
38307 * @extends Roo.form.TriggerField
38308 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38310 * Create a new DateField
38311 * @param {Object} config
38313 Roo.form.DateField = function(config){
38314 Roo.form.DateField.superclass.constructor.call(this, config);
38320 * Fires when a date is selected
38321 * @param {Roo.form.DateField} combo This combo box
38322 * @param {Date} date The date selected
38329 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38330 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38331 this.ddMatch = null;
38332 if(this.disabledDates){
38333 var dd = this.disabledDates;
38335 for(var i = 0; i < dd.length; i++){
38337 if(i != dd.length-1) re += "|";
38339 this.ddMatch = new RegExp(re + ")");
38343 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38345 * @cfg {String} format
38346 * The default date format string which can be overriden for localization support. The format must be
38347 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38351 * @cfg {String} altFormats
38352 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38353 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38355 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38357 * @cfg {Array} disabledDays
38358 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38360 disabledDays : null,
38362 * @cfg {String} disabledDaysText
38363 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38365 disabledDaysText : "Disabled",
38367 * @cfg {Array} disabledDates
38368 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38369 * expression so they are very powerful. Some examples:
38371 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38372 * <li>["03/08", "09/16"] would disable those days for every year</li>
38373 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38374 * <li>["03/../2006"] would disable every day in March 2006</li>
38375 * <li>["^03"] would disable every day in every March</li>
38377 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38378 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38380 disabledDates : null,
38382 * @cfg {String} disabledDatesText
38383 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38385 disabledDatesText : "Disabled",
38387 * @cfg {Date/String} minValue
38388 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38389 * valid format (defaults to null).
38393 * @cfg {Date/String} maxValue
38394 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38395 * valid format (defaults to null).
38399 * @cfg {String} minText
38400 * The error text to display when the date in the cell is before minValue (defaults to
38401 * 'The date in this field must be after {minValue}').
38403 minText : "The date in this field must be equal to or after {0}",
38405 * @cfg {String} maxText
38406 * The error text to display when the date in the cell is after maxValue (defaults to
38407 * 'The date in this field must be before {maxValue}').
38409 maxText : "The date in this field must be equal to or before {0}",
38411 * @cfg {String} invalidText
38412 * The error text to display when the date in the field is invalid (defaults to
38413 * '{value} is not a valid date - it must be in the format {format}').
38415 invalidText : "{0} is not a valid date - it must be in the format {1}",
38417 * @cfg {String} triggerClass
38418 * An additional CSS class used to style the trigger button. The trigger will always get the
38419 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38420 * which displays a calendar icon).
38422 triggerClass : 'x-form-date-trigger',
38426 * @cfg {Boolean} useIso
38427 * if enabled, then the date field will use a hidden field to store the
38428 * real value as iso formated date. default (false)
38432 * @cfg {String/Object} autoCreate
38433 * A DomHelper element spec, or true for a default element spec (defaults to
38434 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38437 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38440 hiddenField: false,
38442 onRender : function(ct, position)
38444 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38446 //this.el.dom.removeAttribute('name');
38447 Roo.log("Changing name?");
38448 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38449 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38451 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38452 // prevent input submission
38453 this.hiddenName = this.name;
38460 validateValue : function(value)
38462 value = this.formatDate(value);
38463 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38464 Roo.log('super failed');
38467 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38470 var svalue = value;
38471 value = this.parseDate(value);
38473 Roo.log('parse date failed' + svalue);
38474 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38477 var time = value.getTime();
38478 if(this.minValue && time < this.minValue.getTime()){
38479 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38482 if(this.maxValue && time > this.maxValue.getTime()){
38483 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38486 if(this.disabledDays){
38487 var day = value.getDay();
38488 for(var i = 0; i < this.disabledDays.length; i++) {
38489 if(day === this.disabledDays[i]){
38490 this.markInvalid(this.disabledDaysText);
38495 var fvalue = this.formatDate(value);
38496 if(this.ddMatch && this.ddMatch.test(fvalue)){
38497 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38504 // Provides logic to override the default TriggerField.validateBlur which just returns true
38505 validateBlur : function(){
38506 return !this.menu || !this.menu.isVisible();
38509 getName: function()
38511 // returns hidden if it's set..
38512 if (!this.rendered) {return ''};
38513 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38518 * Returns the current date value of the date field.
38519 * @return {Date} The date value
38521 getValue : function(){
38523 return this.hiddenField ?
38524 this.hiddenField.value :
38525 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38529 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38530 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38531 * (the default format used is "m/d/y").
38534 //All of these calls set the same date value (May 4, 2006)
38536 //Pass a date object:
38537 var dt = new Date('5/4/06');
38538 dateField.setValue(dt);
38540 //Pass a date string (default format):
38541 dateField.setValue('5/4/06');
38543 //Pass a date string (custom format):
38544 dateField.format = 'Y-m-d';
38545 dateField.setValue('2006-5-4');
38547 * @param {String/Date} date The date or valid date string
38549 setValue : function(date){
38550 if (this.hiddenField) {
38551 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38553 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38554 // make sure the value field is always stored as a date..
38555 this.value = this.parseDate(date);
38561 parseDate : function(value){
38562 if(!value || value instanceof Date){
38565 var v = Date.parseDate(value, this.format);
38566 if (!v && this.useIso) {
38567 v = Date.parseDate(value, 'Y-m-d');
38569 if(!v && this.altFormats){
38570 if(!this.altFormatsArray){
38571 this.altFormatsArray = this.altFormats.split("|");
38573 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38574 v = Date.parseDate(value, this.altFormatsArray[i]);
38581 formatDate : function(date, fmt){
38582 return (!date || !(date instanceof Date)) ?
38583 date : date.dateFormat(fmt || this.format);
38588 select: function(m, d){
38591 this.fireEvent('select', this, d);
38593 show : function(){ // retain focus styling
38597 this.focus.defer(10, this);
38598 var ml = this.menuListeners;
38599 this.menu.un("select", ml.select, this);
38600 this.menu.un("show", ml.show, this);
38601 this.menu.un("hide", ml.hide, this);
38606 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38607 onTriggerClick : function(){
38611 if(this.menu == null){
38612 this.menu = new Roo.menu.DateMenu();
38614 Roo.apply(this.menu.picker, {
38615 showClear: this.allowBlank,
38616 minDate : this.minValue,
38617 maxDate : this.maxValue,
38618 disabledDatesRE : this.ddMatch,
38619 disabledDatesText : this.disabledDatesText,
38620 disabledDays : this.disabledDays,
38621 disabledDaysText : this.disabledDaysText,
38622 format : this.useIso ? 'Y-m-d' : this.format,
38623 minText : String.format(this.minText, this.formatDate(this.minValue)),
38624 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38626 this.menu.on(Roo.apply({}, this.menuListeners, {
38629 this.menu.picker.setValue(this.getValue() || new Date());
38630 this.menu.show(this.el, "tl-bl?");
38633 beforeBlur : function(){
38634 var v = this.parseDate(this.getRawValue());
38644 isDirty : function() {
38645 if(this.disabled) {
38649 if(typeof(this.startValue) === 'undefined'){
38653 return String(this.getValue()) !== String(this.startValue);
38658 * Ext JS Library 1.1.1
38659 * Copyright(c) 2006-2007, Ext JS, LLC.
38661 * Originally Released Under LGPL - original licence link has changed is not relivant.
38664 * <script type="text/javascript">
38668 * @class Roo.form.MonthField
38669 * @extends Roo.form.TriggerField
38670 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38672 * Create a new MonthField
38673 * @param {Object} config
38675 Roo.form.MonthField = function(config){
38677 Roo.form.MonthField.superclass.constructor.call(this, config);
38683 * Fires when a date is selected
38684 * @param {Roo.form.MonthFieeld} combo This combo box
38685 * @param {Date} date The date selected
38692 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38693 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38694 this.ddMatch = null;
38695 if(this.disabledDates){
38696 var dd = this.disabledDates;
38698 for(var i = 0; i < dd.length; i++){
38700 if(i != dd.length-1) re += "|";
38702 this.ddMatch = new RegExp(re + ")");
38706 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38708 * @cfg {String} format
38709 * The default date format string which can be overriden for localization support. The format must be
38710 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38714 * @cfg {String} altFormats
38715 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38716 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38718 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38720 * @cfg {Array} disabledDays
38721 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38723 disabledDays : [0,1,2,3,4,5,6],
38725 * @cfg {String} disabledDaysText
38726 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38728 disabledDaysText : "Disabled",
38730 * @cfg {Array} disabledDates
38731 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38732 * expression so they are very powerful. Some examples:
38734 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38735 * <li>["03/08", "09/16"] would disable those days for every year</li>
38736 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38737 * <li>["03/../2006"] would disable every day in March 2006</li>
38738 * <li>["^03"] would disable every day in every March</li>
38740 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38741 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38743 disabledDates : null,
38745 * @cfg {String} disabledDatesText
38746 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38748 disabledDatesText : "Disabled",
38750 * @cfg {Date/String} minValue
38751 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38752 * valid format (defaults to null).
38756 * @cfg {Date/String} maxValue
38757 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38758 * valid format (defaults to null).
38762 * @cfg {String} minText
38763 * The error text to display when the date in the cell is before minValue (defaults to
38764 * 'The date in this field must be after {minValue}').
38766 minText : "The date in this field must be equal to or after {0}",
38768 * @cfg {String} maxTextf
38769 * The error text to display when the date in the cell is after maxValue (defaults to
38770 * 'The date in this field must be before {maxValue}').
38772 maxText : "The date in this field must be equal to or before {0}",
38774 * @cfg {String} invalidText
38775 * The error text to display when the date in the field is invalid (defaults to
38776 * '{value} is not a valid date - it must be in the format {format}').
38778 invalidText : "{0} is not a valid date - it must be in the format {1}",
38780 * @cfg {String} triggerClass
38781 * An additional CSS class used to style the trigger button. The trigger will always get the
38782 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38783 * which displays a calendar icon).
38785 triggerClass : 'x-form-date-trigger',
38789 * @cfg {Boolean} useIso
38790 * if enabled, then the date field will use a hidden field to store the
38791 * real value as iso formated date. default (true)
38795 * @cfg {String/Object} autoCreate
38796 * A DomHelper element spec, or true for a default element spec (defaults to
38797 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38800 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38803 hiddenField: false,
38805 hideMonthPicker : false,
38807 onRender : function(ct, position)
38809 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38811 this.el.dom.removeAttribute('name');
38812 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38814 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38815 // prevent input submission
38816 this.hiddenName = this.name;
38823 validateValue : function(value)
38825 value = this.formatDate(value);
38826 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38829 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38832 var svalue = value;
38833 value = this.parseDate(value);
38835 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38838 var time = value.getTime();
38839 if(this.minValue && time < this.minValue.getTime()){
38840 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38843 if(this.maxValue && time > this.maxValue.getTime()){
38844 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38847 /*if(this.disabledDays){
38848 var day = value.getDay();
38849 for(var i = 0; i < this.disabledDays.length; i++) {
38850 if(day === this.disabledDays[i]){
38851 this.markInvalid(this.disabledDaysText);
38857 var fvalue = this.formatDate(value);
38858 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38859 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38867 // Provides logic to override the default TriggerField.validateBlur which just returns true
38868 validateBlur : function(){
38869 return !this.menu || !this.menu.isVisible();
38873 * Returns the current date value of the date field.
38874 * @return {Date} The date value
38876 getValue : function(){
38880 return this.hiddenField ?
38881 this.hiddenField.value :
38882 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38886 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38887 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38888 * (the default format used is "m/d/y").
38891 //All of these calls set the same date value (May 4, 2006)
38893 //Pass a date object:
38894 var dt = new Date('5/4/06');
38895 monthField.setValue(dt);
38897 //Pass a date string (default format):
38898 monthField.setValue('5/4/06');
38900 //Pass a date string (custom format):
38901 monthField.format = 'Y-m-d';
38902 monthField.setValue('2006-5-4');
38904 * @param {String/Date} date The date or valid date string
38906 setValue : function(date){
38907 Roo.log('month setValue' + date);
38908 // can only be first of month..
38910 var val = this.parseDate(date);
38912 if (this.hiddenField) {
38913 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38915 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38916 this.value = this.parseDate(date);
38920 parseDate : function(value){
38921 if(!value || value instanceof Date){
38922 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38925 var v = Date.parseDate(value, this.format);
38926 if (!v && this.useIso) {
38927 v = Date.parseDate(value, 'Y-m-d');
38931 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38935 if(!v && this.altFormats){
38936 if(!this.altFormatsArray){
38937 this.altFormatsArray = this.altFormats.split("|");
38939 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38940 v = Date.parseDate(value, this.altFormatsArray[i]);
38947 formatDate : function(date, fmt){
38948 return (!date || !(date instanceof Date)) ?
38949 date : date.dateFormat(fmt || this.format);
38954 select: function(m, d){
38956 this.fireEvent('select', this, d);
38958 show : function(){ // retain focus styling
38962 this.focus.defer(10, this);
38963 var ml = this.menuListeners;
38964 this.menu.un("select", ml.select, this);
38965 this.menu.un("show", ml.show, this);
38966 this.menu.un("hide", ml.hide, this);
38970 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38971 onTriggerClick : function(){
38975 if(this.menu == null){
38976 this.menu = new Roo.menu.DateMenu();
38980 Roo.apply(this.menu.picker, {
38982 showClear: this.allowBlank,
38983 minDate : this.minValue,
38984 maxDate : this.maxValue,
38985 disabledDatesRE : this.ddMatch,
38986 disabledDatesText : this.disabledDatesText,
38988 format : this.useIso ? 'Y-m-d' : this.format,
38989 minText : String.format(this.minText, this.formatDate(this.minValue)),
38990 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38993 this.menu.on(Roo.apply({}, this.menuListeners, {
39001 // hide month picker get's called when we called by 'before hide';
39003 var ignorehide = true;
39004 p.hideMonthPicker = function(disableAnim){
39008 if(this.monthPicker){
39009 Roo.log("hideMonthPicker called");
39010 if(disableAnim === true){
39011 this.monthPicker.hide();
39013 this.monthPicker.slideOut('t', {duration:.2});
39014 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39015 p.fireEvent("select", this, this.value);
39021 Roo.log('picker set value');
39022 Roo.log(this.getValue());
39023 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39024 m.show(this.el, 'tl-bl?');
39025 ignorehide = false;
39026 // this will trigger hideMonthPicker..
39029 // hidden the day picker
39030 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39036 p.showMonthPicker.defer(100, p);
39042 beforeBlur : function(){
39043 var v = this.parseDate(this.getRawValue());
39049 /** @cfg {Boolean} grow @hide */
39050 /** @cfg {Number} growMin @hide */
39051 /** @cfg {Number} growMax @hide */
39058 * Ext JS Library 1.1.1
39059 * Copyright(c) 2006-2007, Ext JS, LLC.
39061 * Originally Released Under LGPL - original licence link has changed is not relivant.
39064 * <script type="text/javascript">
39069 * @class Roo.form.ComboBox
39070 * @extends Roo.form.TriggerField
39071 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39073 * Create a new ComboBox.
39074 * @param {Object} config Configuration options
39076 Roo.form.ComboBox = function(config){
39077 Roo.form.ComboBox.superclass.constructor.call(this, config);
39081 * Fires when the dropdown list is expanded
39082 * @param {Roo.form.ComboBox} combo This combo box
39087 * Fires when the dropdown list is collapsed
39088 * @param {Roo.form.ComboBox} combo This combo box
39092 * @event beforeselect
39093 * Fires before a list item is selected. Return false to cancel the selection.
39094 * @param {Roo.form.ComboBox} combo This combo box
39095 * @param {Roo.data.Record} record The data record returned from the underlying store
39096 * @param {Number} index The index of the selected item in the dropdown list
39098 'beforeselect' : true,
39101 * Fires when a list item is selected
39102 * @param {Roo.form.ComboBox} combo This combo box
39103 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39104 * @param {Number} index The index of the selected item in the dropdown list
39108 * @event beforequery
39109 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39110 * The event object passed has these properties:
39111 * @param {Roo.form.ComboBox} combo This combo box
39112 * @param {String} query The query
39113 * @param {Boolean} forceAll true to force "all" query
39114 * @param {Boolean} cancel true to cancel the query
39115 * @param {Object} e The query event object
39117 'beforequery': true,
39120 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39121 * @param {Roo.form.ComboBox} combo This combo box
39126 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39127 * @param {Roo.form.ComboBox} combo This combo box
39128 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39134 if(this.transform){
39135 this.allowDomMove = false;
39136 var s = Roo.getDom(this.transform);
39137 if(!this.hiddenName){
39138 this.hiddenName = s.name;
39141 this.mode = 'local';
39142 var d = [], opts = s.options;
39143 for(var i = 0, len = opts.length;i < len; i++){
39145 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39147 this.value = value;
39149 d.push([value, o.text]);
39151 this.store = new Roo.data.SimpleStore({
39153 fields: ['value', 'text'],
39156 this.valueField = 'value';
39157 this.displayField = 'text';
39159 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39160 if(!this.lazyRender){
39161 this.target = true;
39162 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39163 s.parentNode.removeChild(s); // remove it
39164 this.render(this.el.parentNode);
39166 s.parentNode.removeChild(s); // remove it
39171 this.store = Roo.factory(this.store, Roo.data);
39174 this.selectedIndex = -1;
39175 if(this.mode == 'local'){
39176 if(config.queryDelay === undefined){
39177 this.queryDelay = 10;
39179 if(config.minChars === undefined){
39185 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39187 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39190 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39191 * rendering into an Roo.Editor, defaults to false)
39194 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39195 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39198 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39201 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39202 * the dropdown list (defaults to undefined, with no header element)
39206 * @cfg {String/Roo.Template} tpl The template to use to render the output
39210 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39212 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39214 listWidth: undefined,
39216 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39217 * mode = 'remote' or 'text' if mode = 'local')
39219 displayField: undefined,
39221 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39222 * mode = 'remote' or 'value' if mode = 'local').
39223 * Note: use of a valueField requires the user make a selection
39224 * in order for a value to be mapped.
39226 valueField: undefined,
39230 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39231 * field's data value (defaults to the underlying DOM element's name)
39233 hiddenName: undefined,
39235 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39239 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39241 selectedClass: 'x-combo-selected',
39243 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39244 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39245 * which displays a downward arrow icon).
39247 triggerClass : 'x-form-arrow-trigger',
39249 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39253 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39254 * anchor positions (defaults to 'tl-bl')
39256 listAlign: 'tl-bl?',
39258 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39262 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39263 * query specified by the allQuery config option (defaults to 'query')
39265 triggerAction: 'query',
39267 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39268 * (defaults to 4, does not apply if editable = false)
39272 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39273 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39277 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39278 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39282 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39283 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39287 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39288 * when editable = true (defaults to false)
39290 selectOnFocus:false,
39292 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39294 queryParam: 'query',
39296 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39297 * when mode = 'remote' (defaults to 'Loading...')
39299 loadingText: 'Loading...',
39301 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39305 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39309 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39310 * traditional select (defaults to true)
39314 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39318 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39322 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39323 * listWidth has a higher value)
39327 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39328 * allow the user to set arbitrary text into the field (defaults to false)
39330 forceSelection:false,
39332 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39333 * if typeAhead = true (defaults to 250)
39335 typeAheadDelay : 250,
39337 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39338 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39340 valueNotFoundText : undefined,
39342 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39344 blockFocus : false,
39347 * @cfg {Boolean} disableClear Disable showing of clear button.
39349 disableClear : false,
39351 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39353 alwaysQuery : false,
39359 // element that contains real text value.. (when hidden is used..)
39362 onRender : function(ct, position){
39363 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39364 if(this.hiddenName){
39365 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39367 this.hiddenField.value =
39368 this.hiddenValue !== undefined ? this.hiddenValue :
39369 this.value !== undefined ? this.value : '';
39371 // prevent input submission
39372 this.el.dom.removeAttribute('name');
39377 this.el.dom.setAttribute('autocomplete', 'off');
39380 var cls = 'x-combo-list';
39382 this.list = new Roo.Layer({
39383 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39386 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39387 this.list.setWidth(lw);
39388 this.list.swallowEvent('mousewheel');
39389 this.assetHeight = 0;
39392 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39393 this.assetHeight += this.header.getHeight();
39396 this.innerList = this.list.createChild({cls:cls+'-inner'});
39397 this.innerList.on('mouseover', this.onViewOver, this);
39398 this.innerList.on('mousemove', this.onViewMove, this);
39399 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39401 if(this.allowBlank && !this.pageSize && !this.disableClear){
39402 this.footer = this.list.createChild({cls:cls+'-ft'});
39403 this.pageTb = new Roo.Toolbar(this.footer);
39407 this.footer = this.list.createChild({cls:cls+'-ft'});
39408 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39409 {pageSize: this.pageSize});
39413 if (this.pageTb && this.allowBlank && !this.disableClear) {
39415 this.pageTb.add(new Roo.Toolbar.Fill(), {
39416 cls: 'x-btn-icon x-btn-clear',
39418 handler: function()
39421 _this.clearValue();
39422 _this.onSelect(false, -1);
39427 this.assetHeight += this.footer.getHeight();
39432 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39435 this.view = new Roo.View(this.innerList, this.tpl, {
39436 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39439 this.view.on('click', this.onViewClick, this);
39441 this.store.on('beforeload', this.onBeforeLoad, this);
39442 this.store.on('load', this.onLoad, this);
39443 this.store.on('loadexception', this.onLoadException, this);
39445 if(this.resizable){
39446 this.resizer = new Roo.Resizable(this.list, {
39447 pinned:true, handles:'se'
39449 this.resizer.on('resize', function(r, w, h){
39450 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39451 this.listWidth = w;
39452 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39453 this.restrictHeight();
39455 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39457 if(!this.editable){
39458 this.editable = true;
39459 this.setEditable(false);
39463 if (typeof(this.events.add.listeners) != 'undefined') {
39465 this.addicon = this.wrap.createChild(
39466 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39468 this.addicon.on('click', function(e) {
39469 this.fireEvent('add', this);
39472 if (typeof(this.events.edit.listeners) != 'undefined') {
39474 this.editicon = this.wrap.createChild(
39475 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39476 if (this.addicon) {
39477 this.editicon.setStyle('margin-left', '40px');
39479 this.editicon.on('click', function(e) {
39481 // we fire even if inothing is selected..
39482 this.fireEvent('edit', this, this.lastData );
39492 initEvents : function(){
39493 Roo.form.ComboBox.superclass.initEvents.call(this);
39495 this.keyNav = new Roo.KeyNav(this.el, {
39496 "up" : function(e){
39497 this.inKeyMode = true;
39501 "down" : function(e){
39502 if(!this.isExpanded()){
39503 this.onTriggerClick();
39505 this.inKeyMode = true;
39510 "enter" : function(e){
39511 this.onViewClick();
39515 "esc" : function(e){
39519 "tab" : function(e){
39520 this.onViewClick(false);
39521 this.fireEvent("specialkey", this, e);
39527 doRelay : function(foo, bar, hname){
39528 if(hname == 'down' || this.scope.isExpanded()){
39529 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39536 this.queryDelay = Math.max(this.queryDelay || 10,
39537 this.mode == 'local' ? 10 : 250);
39538 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39539 if(this.typeAhead){
39540 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39542 if(this.editable !== false){
39543 this.el.on("keyup", this.onKeyUp, this);
39545 if(this.forceSelection){
39546 this.on('blur', this.doForce, this);
39550 onDestroy : function(){
39552 this.view.setStore(null);
39553 this.view.el.removeAllListeners();
39554 this.view.el.remove();
39555 this.view.purgeListeners();
39558 this.list.destroy();
39561 this.store.un('beforeload', this.onBeforeLoad, this);
39562 this.store.un('load', this.onLoad, this);
39563 this.store.un('loadexception', this.onLoadException, this);
39565 Roo.form.ComboBox.superclass.onDestroy.call(this);
39569 fireKey : function(e){
39570 if(e.isNavKeyPress() && !this.list.isVisible()){
39571 this.fireEvent("specialkey", this, e);
39576 onResize: function(w, h){
39577 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39579 if(typeof w != 'number'){
39580 // we do not handle it!?!?
39583 var tw = this.trigger.getWidth();
39584 tw += this.addicon ? this.addicon.getWidth() : 0;
39585 tw += this.editicon ? this.editicon.getWidth() : 0;
39587 this.el.setWidth( this.adjustWidth('input', x));
39589 this.trigger.setStyle('left', x+'px');
39591 if(this.list && this.listWidth === undefined){
39592 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39593 this.list.setWidth(lw);
39594 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39602 * Allow or prevent the user from directly editing the field text. If false is passed,
39603 * the user will only be able to select from the items defined in the dropdown list. This method
39604 * is the runtime equivalent of setting the 'editable' config option at config time.
39605 * @param {Boolean} value True to allow the user to directly edit the field text
39607 setEditable : function(value){
39608 if(value == this.editable){
39611 this.editable = value;
39613 this.el.dom.setAttribute('readOnly', true);
39614 this.el.on('mousedown', this.onTriggerClick, this);
39615 this.el.addClass('x-combo-noedit');
39617 this.el.dom.setAttribute('readOnly', false);
39618 this.el.un('mousedown', this.onTriggerClick, this);
39619 this.el.removeClass('x-combo-noedit');
39624 onBeforeLoad : function(){
39625 if(!this.hasFocus){
39628 this.innerList.update(this.loadingText ?
39629 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39630 this.restrictHeight();
39631 this.selectedIndex = -1;
39635 onLoad : function(){
39636 if(!this.hasFocus){
39639 if(this.store.getCount() > 0){
39641 this.restrictHeight();
39642 if(this.lastQuery == this.allQuery){
39644 this.el.dom.select();
39646 if(!this.selectByValue(this.value, true)){
39647 this.select(0, true);
39651 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39652 this.taTask.delay(this.typeAheadDelay);
39656 this.onEmptyResults();
39661 onLoadException : function()
39664 Roo.log(this.store.reader.jsonData);
39665 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39666 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39672 onTypeAhead : function(){
39673 if(this.store.getCount() > 0){
39674 var r = this.store.getAt(0);
39675 var newValue = r.data[this.displayField];
39676 var len = newValue.length;
39677 var selStart = this.getRawValue().length;
39678 if(selStart != len){
39679 this.setRawValue(newValue);
39680 this.selectText(selStart, newValue.length);
39686 onSelect : function(record, index){
39687 if(this.fireEvent('beforeselect', this, record, index) !== false){
39688 this.setFromData(index > -1 ? record.data : false);
39690 this.fireEvent('select', this, record, index);
39695 * Returns the currently selected field value or empty string if no value is set.
39696 * @return {String} value The selected value
39698 getValue : function(){
39699 if(this.valueField){
39700 return typeof this.value != 'undefined' ? this.value : '';
39702 return Roo.form.ComboBox.superclass.getValue.call(this);
39707 * Clears any text/value currently set in the field
39709 clearValue : function(){
39710 if(this.hiddenField){
39711 this.hiddenField.value = '';
39714 this.setRawValue('');
39715 this.lastSelectionText = '';
39720 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39721 * will be displayed in the field. If the value does not match the data value of an existing item,
39722 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39723 * Otherwise the field will be blank (although the value will still be set).
39724 * @param {String} value The value to match
39726 setValue : function(v){
39728 if(this.valueField){
39729 var r = this.findRecord(this.valueField, v);
39731 text = r.data[this.displayField];
39732 }else if(this.valueNotFoundText !== undefined){
39733 text = this.valueNotFoundText;
39736 this.lastSelectionText = text;
39737 if(this.hiddenField){
39738 this.hiddenField.value = v;
39740 Roo.form.ComboBox.superclass.setValue.call(this, text);
39744 * @property {Object} the last set data for the element
39749 * Sets the value of the field based on a object which is related to the record format for the store.
39750 * @param {Object} value the value to set as. or false on reset?
39752 setFromData : function(o){
39753 var dv = ''; // display value
39754 var vv = ''; // value value..
39756 if (this.displayField) {
39757 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39759 // this is an error condition!!!
39760 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39763 if(this.valueField){
39764 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39766 if(this.hiddenField){
39767 this.hiddenField.value = vv;
39769 this.lastSelectionText = dv;
39770 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39774 // no hidden field.. - we store the value in 'value', but still display
39775 // display field!!!!
39776 this.lastSelectionText = dv;
39777 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39783 reset : function(){
39784 // overridden so that last data is reset..
39785 this.setValue(this.resetValue);
39786 this.clearInvalid();
39787 this.lastData = false;
39789 this.view.clearSelections();
39793 findRecord : function(prop, value){
39795 if(this.store.getCount() > 0){
39796 this.store.each(function(r){
39797 if(r.data[prop] == value){
39807 getName: function()
39809 // returns hidden if it's set..
39810 if (!this.rendered) {return ''};
39811 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39815 onViewMove : function(e, t){
39816 this.inKeyMode = false;
39820 onViewOver : function(e, t){
39821 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39824 var item = this.view.findItemFromChild(t);
39826 var index = this.view.indexOf(item);
39827 this.select(index, false);
39832 onViewClick : function(doFocus)
39834 var index = this.view.getSelectedIndexes()[0];
39835 var r = this.store.getAt(index);
39837 this.onSelect(r, index);
39839 if(doFocus !== false && !this.blockFocus){
39845 restrictHeight : function(){
39846 this.innerList.dom.style.height = '';
39847 var inner = this.innerList.dom;
39848 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39849 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39850 this.list.beginUpdate();
39851 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39852 this.list.alignTo(this.el, this.listAlign);
39853 this.list.endUpdate();
39857 onEmptyResults : function(){
39862 * Returns true if the dropdown list is expanded, else false.
39864 isExpanded : function(){
39865 return this.list.isVisible();
39869 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39870 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39871 * @param {String} value The data value of the item to select
39872 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39873 * selected item if it is not currently in view (defaults to true)
39874 * @return {Boolean} True if the value matched an item in the list, else false
39876 selectByValue : function(v, scrollIntoView){
39877 if(v !== undefined && v !== null){
39878 var r = this.findRecord(this.valueField || this.displayField, v);
39880 this.select(this.store.indexOf(r), scrollIntoView);
39888 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39889 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39890 * @param {Number} index The zero-based index of the list item to select
39891 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39892 * selected item if it is not currently in view (defaults to true)
39894 select : function(index, scrollIntoView){
39895 this.selectedIndex = index;
39896 this.view.select(index);
39897 if(scrollIntoView !== false){
39898 var el = this.view.getNode(index);
39900 this.innerList.scrollChildIntoView(el, false);
39906 selectNext : function(){
39907 var ct = this.store.getCount();
39909 if(this.selectedIndex == -1){
39911 }else if(this.selectedIndex < ct-1){
39912 this.select(this.selectedIndex+1);
39918 selectPrev : function(){
39919 var ct = this.store.getCount();
39921 if(this.selectedIndex == -1){
39923 }else if(this.selectedIndex != 0){
39924 this.select(this.selectedIndex-1);
39930 onKeyUp : function(e){
39931 if(this.editable !== false && !e.isSpecialKey()){
39932 this.lastKey = e.getKey();
39933 this.dqTask.delay(this.queryDelay);
39938 validateBlur : function(){
39939 return !this.list || !this.list.isVisible();
39943 initQuery : function(){
39944 this.doQuery(this.getRawValue());
39948 doForce : function(){
39949 if(this.el.dom.value.length > 0){
39950 this.el.dom.value =
39951 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39957 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39958 * query allowing the query action to be canceled if needed.
39959 * @param {String} query The SQL query to execute
39960 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39961 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39962 * saved in the current store (defaults to false)
39964 doQuery : function(q, forceAll){
39965 if(q === undefined || q === null){
39970 forceAll: forceAll,
39974 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39978 forceAll = qe.forceAll;
39979 if(forceAll === true || (q.length >= this.minChars)){
39980 if(this.lastQuery != q || this.alwaysQuery){
39981 this.lastQuery = q;
39982 if(this.mode == 'local'){
39983 this.selectedIndex = -1;
39985 this.store.clearFilter();
39987 this.store.filter(this.displayField, q);
39991 this.store.baseParams[this.queryParam] = q;
39993 params: this.getParams(q)
39998 this.selectedIndex = -1;
40005 getParams : function(q){
40007 //p[this.queryParam] = q;
40010 p.limit = this.pageSize;
40016 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40018 collapse : function(){
40019 if(!this.isExpanded()){
40023 Roo.get(document).un('mousedown', this.collapseIf, this);
40024 Roo.get(document).un('mousewheel', this.collapseIf, this);
40025 if (!this.editable) {
40026 Roo.get(document).un('keydown', this.listKeyPress, this);
40028 this.fireEvent('collapse', this);
40032 collapseIf : function(e){
40033 if(!e.within(this.wrap) && !e.within(this.list)){
40039 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40041 expand : function(){
40042 if(this.isExpanded() || !this.hasFocus){
40045 this.list.alignTo(this.el, this.listAlign);
40047 Roo.get(document).on('mousedown', this.collapseIf, this);
40048 Roo.get(document).on('mousewheel', this.collapseIf, this);
40049 if (!this.editable) {
40050 Roo.get(document).on('keydown', this.listKeyPress, this);
40053 this.fireEvent('expand', this);
40057 // Implements the default empty TriggerField.onTriggerClick function
40058 onTriggerClick : function(){
40062 if(this.isExpanded()){
40064 if (!this.blockFocus) {
40069 this.hasFocus = true;
40070 if(this.triggerAction == 'all') {
40071 this.doQuery(this.allQuery, true);
40073 this.doQuery(this.getRawValue());
40075 if (!this.blockFocus) {
40080 listKeyPress : function(e)
40082 //Roo.log('listkeypress');
40083 // scroll to first matching element based on key pres..
40084 if (e.isSpecialKey()) {
40087 var k = String.fromCharCode(e.getKey()).toUpperCase();
40090 var csel = this.view.getSelectedNodes();
40091 var cselitem = false;
40093 var ix = this.view.indexOf(csel[0]);
40094 cselitem = this.store.getAt(ix);
40095 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40101 this.store.each(function(v) {
40103 // start at existing selection.
40104 if (cselitem.id == v.id) {
40110 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40111 match = this.store.indexOf(v);
40116 if (match === false) {
40117 return true; // no more action?
40120 this.view.select(match);
40121 var sn = Roo.get(this.view.getSelectedNodes()[0])
40122 sn.scrollIntoView(sn.dom.parentNode, false);
40126 * @cfg {Boolean} grow
40130 * @cfg {Number} growMin
40134 * @cfg {Number} growMax
40142 * Copyright(c) 2010-2012, Roo J Solutions Limited
40149 * @class Roo.form.ComboBoxArray
40150 * @extends Roo.form.TextField
40151 * A facebook style adder... for lists of email / people / countries etc...
40152 * pick multiple items from a combo box, and shows each one.
40154 * Fred [x] Brian [x] [Pick another |v]
40157 * For this to work: it needs various extra information
40158 * - normal combo problay has
40160 * + displayField, valueField
40162 * For our purpose...
40165 * If we change from 'extends' to wrapping...
40172 * Create a new ComboBoxArray.
40173 * @param {Object} config Configuration options
40177 Roo.form.ComboBoxArray = function(config)
40182 * Fires when remove the value from the list
40183 * @param {Roo.form.ComboBoxArray} _self This combo box array
40184 * @param {Roo.form.ComboBoxArray.Item} item removed item
40191 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40193 this.items = new Roo.util.MixedCollection(false);
40195 // construct the child combo...
40205 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40208 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40213 // behavies liek a hiddne field
40214 inputType: 'hidden',
40216 * @cfg {Number} width The width of the box that displays the selected element
40223 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40227 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40229 hiddenName : false,
40232 // private the array of items that are displayed..
40234 // private - the hidden field el.
40236 // private - the filed el..
40239 //validateValue : function() { return true; }, // all values are ok!
40240 //onAddClick: function() { },
40242 onRender : function(ct, position)
40245 // create the standard hidden element
40246 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40249 // give fake names to child combo;
40250 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40251 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40253 this.combo = Roo.factory(this.combo, Roo.form);
40254 this.combo.onRender(ct, position);
40255 if (typeof(this.combo.width) != 'undefined') {
40256 this.combo.onResize(this.combo.width,0);
40259 this.combo.initEvents();
40261 // assigned so form know we need to do this..
40262 this.store = this.combo.store;
40263 this.valueField = this.combo.valueField;
40264 this.displayField = this.combo.displayField ;
40267 this.combo.wrap.addClass('x-cbarray-grp');
40269 var cbwrap = this.combo.wrap.createChild(
40270 {tag: 'div', cls: 'x-cbarray-cb'},
40275 this.hiddenEl = this.combo.wrap.createChild({
40276 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40278 this.el = this.combo.wrap.createChild({
40279 tag: 'input', type:'hidden' , name: this.name, value : ''
40281 // this.el.dom.removeAttribute("name");
40284 this.outerWrap = this.combo.wrap;
40285 this.wrap = cbwrap;
40287 this.outerWrap.setWidth(this.width);
40288 this.outerWrap.dom.removeChild(this.el.dom);
40290 this.wrap.dom.appendChild(this.el.dom);
40291 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40292 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40294 this.combo.trigger.setStyle('position','relative');
40295 this.combo.trigger.setStyle('left', '0px');
40296 this.combo.trigger.setStyle('top', '2px');
40298 this.combo.el.setStyle('vertical-align', 'text-bottom');
40300 //this.trigger.setStyle('vertical-align', 'top');
40302 // this should use the code from combo really... on('add' ....)
40306 this.adder = this.outerWrap.createChild(
40307 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40309 this.adder.on('click', function(e) {
40310 _t.fireEvent('adderclick', this, e);
40314 //this.adder.on('click', this.onAddClick, _t);
40317 this.combo.on('select', function(cb, rec, ix) {
40318 this.addItem(rec.data);
40321 cb.el.dom.value = '';
40322 //cb.lastData = rec.data;
40331 getName: function()
40333 // returns hidden if it's set..
40334 if (!this.rendered) {return ''};
40335 return this.hiddenName ? this.hiddenName : this.name;
40340 onResize: function(w, h){
40343 // not sure if this is needed..
40344 //this.combo.onResize(w,h);
40346 if(typeof w != 'number'){
40347 // we do not handle it!?!?
40350 var tw = this.combo.trigger.getWidth();
40351 tw += this.addicon ? this.addicon.getWidth() : 0;
40352 tw += this.editicon ? this.editicon.getWidth() : 0;
40354 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40356 this.combo.trigger.setStyle('left', '0px');
40358 if(this.list && this.listWidth === undefined){
40359 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40360 this.list.setWidth(lw);
40361 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40368 addItem: function(rec)
40370 var valueField = this.combo.valueField;
40371 var displayField = this.combo.displayField;
40372 if (this.items.indexOfKey(rec[valueField]) > -1) {
40373 //console.log("GOT " + rec.data.id);
40377 var x = new Roo.form.ComboBoxArray.Item({
40378 //id : rec[this.idField],
40380 displayField : displayField ,
40381 tipField : displayField ,
40385 this.items.add(rec[valueField],x);
40386 // add it before the element..
40387 this.updateHiddenEl();
40388 x.render(this.outerWrap, this.wrap.dom);
40389 // add the image handler..
40392 updateHiddenEl : function()
40395 if (!this.hiddenEl) {
40399 var idField = this.combo.valueField;
40401 this.items.each(function(f) {
40402 ar.push(f.data[idField]);
40405 this.hiddenEl.dom.value = ar.join(',');
40411 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40412 this.items.each(function(f) {
40415 this.el.dom.value = '';
40416 if (this.hiddenEl) {
40417 this.hiddenEl.dom.value = '';
40421 getValue: function()
40423 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40425 setValue: function(v) // not a valid action - must use addItems..
40432 if (this.store.isLocal && (typeof(v) == 'string')) {
40433 // then we can use the store to find the values..
40434 // comma seperated at present.. this needs to allow JSON based encoding..
40435 this.hiddenEl.value = v;
40437 Roo.each(v.split(','), function(k) {
40438 Roo.log("CHECK " + this.valueField + ',' + k);
40439 var li = this.store.query(this.valueField, k);
40444 add[this.valueField] = k;
40445 add[this.displayField] = li.item(0).data[this.displayField];
40451 if (typeof(v) == 'object') {
40452 // then let's assume it's an array of objects..
40453 Roo.each(v, function(l) {
40461 setFromData: function(v)
40463 // this recieves an object, if setValues is called.
40465 this.el.dom.value = v[this.displayField];
40466 this.hiddenEl.dom.value = v[this.valueField];
40467 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40470 var kv = v[this.valueField];
40471 var dv = v[this.displayField];
40472 kv = typeof(kv) != 'string' ? '' : kv;
40473 dv = typeof(dv) != 'string' ? '' : dv;
40476 var keys = kv.split(',');
40477 var display = dv.split(',');
40478 for (var i = 0 ; i < keys.length; i++) {
40481 add[this.valueField] = keys[i];
40482 add[this.displayField] = display[i];
40490 * Validates the combox array value
40491 * @return {Boolean} True if the value is valid, else false
40493 validate : function(){
40494 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40495 this.clearInvalid();
40501 validateValue : function(value){
40502 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40510 isDirty : function() {
40511 if(this.disabled) {
40516 var d = Roo.decode(String(this.originalValue));
40518 return String(this.getValue()) !== String(this.originalValue);
40521 var originalValue = [];
40523 for (var i = 0; i < d.length; i++){
40524 originalValue.push(d[i][this.valueField]);
40527 return String(this.getValue()) !== String(originalValue.join(','));
40536 * @class Roo.form.ComboBoxArray.Item
40537 * @extends Roo.BoxComponent
40538 * A selected item in the list
40539 * Fred [x] Brian [x] [Pick another |v]
40542 * Create a new item.
40543 * @param {Object} config Configuration options
40546 Roo.form.ComboBoxArray.Item = function(config) {
40547 config.id = Roo.id();
40548 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40551 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40554 displayField : false,
40558 defaultAutoCreate : {
40560 cls: 'x-cbarray-item',
40567 src : Roo.BLANK_IMAGE_URL ,
40575 onRender : function(ct, position)
40577 Roo.form.Field.superclass.onRender.call(this, ct, position);
40580 var cfg = this.getAutoCreate();
40581 this.el = ct.createChild(cfg, position);
40584 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40586 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40587 this.cb.renderer(this.data) :
40588 String.format('{0}',this.data[this.displayField]);
40591 this.el.child('div').dom.setAttribute('qtip',
40592 String.format('{0}',this.data[this.tipField])
40595 this.el.child('img').on('click', this.remove, this);
40599 remove : function()
40601 this.cb.items.remove(this);
40602 this.el.child('img').un('click', this.remove, this);
40604 this.cb.updateHiddenEl();
40606 this.cb.fireEvent('remove', this.cb, this);
40610 * Ext JS Library 1.1.1
40611 * Copyright(c) 2006-2007, Ext JS, LLC.
40613 * Originally Released Under LGPL - original licence link has changed is not relivant.
40616 * <script type="text/javascript">
40619 * @class Roo.form.Checkbox
40620 * @extends Roo.form.Field
40621 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40623 * Creates a new Checkbox
40624 * @param {Object} config Configuration options
40626 Roo.form.Checkbox = function(config){
40627 Roo.form.Checkbox.superclass.constructor.call(this, config);
40631 * Fires when the checkbox is checked or unchecked.
40632 * @param {Roo.form.Checkbox} this This checkbox
40633 * @param {Boolean} checked The new checked value
40639 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40641 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40643 focusClass : undefined,
40645 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40647 fieldClass: "x-form-field",
40649 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40653 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40654 * {tag: "input", type: "checkbox", autocomplete: "off"})
40656 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40658 * @cfg {String} boxLabel The text that appears beside the checkbox
40662 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40666 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40668 valueOff: '0', // value when not checked..
40670 actionMode : 'viewEl',
40673 itemCls : 'x-menu-check-item x-form-item',
40674 groupClass : 'x-menu-group-item',
40675 inputType : 'hidden',
40678 inSetChecked: false, // check that we are not calling self...
40680 inputElement: false, // real input element?
40681 basedOn: false, // ????
40683 isFormField: true, // not sure where this is needed!!!!
40685 onResize : function(){
40686 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40687 if(!this.boxLabel){
40688 this.el.alignTo(this.wrap, 'c-c');
40692 initEvents : function(){
40693 Roo.form.Checkbox.superclass.initEvents.call(this);
40694 this.el.on("click", this.onClick, this);
40695 this.el.on("change", this.onClick, this);
40699 getResizeEl : function(){
40703 getPositionEl : function(){
40708 onRender : function(ct, position){
40709 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40711 if(this.inputValue !== undefined){
40712 this.el.dom.value = this.inputValue;
40715 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40716 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40717 var viewEl = this.wrap.createChild({
40718 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40719 this.viewEl = viewEl;
40720 this.wrap.on('click', this.onClick, this);
40722 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40723 this.el.on('propertychange', this.setFromHidden, this); //ie
40728 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40729 // viewEl.on('click', this.onClick, this);
40731 //if(this.checked){
40732 this.setChecked(this.checked);
40734 //this.checked = this.el.dom;
40740 initValue : Roo.emptyFn,
40743 * Returns the checked state of the checkbox.
40744 * @return {Boolean} True if checked, else false
40746 getValue : function(){
40748 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40750 return this.valueOff;
40755 onClick : function(){
40756 this.setChecked(!this.checked);
40758 //if(this.el.dom.checked != this.checked){
40759 // this.setValue(this.el.dom.checked);
40764 * Sets the checked state of the checkbox.
40765 * On is always based on a string comparison between inputValue and the param.
40766 * @param {Boolean/String} value - the value to set
40767 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40769 setValue : function(v,suppressEvent){
40772 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40773 //if(this.el && this.el.dom){
40774 // this.el.dom.checked = this.checked;
40775 // this.el.dom.defaultChecked = this.checked;
40777 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40778 //this.fireEvent("check", this, this.checked);
40781 setChecked : function(state,suppressEvent)
40783 if (this.inSetChecked) {
40784 this.checked = state;
40790 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40792 this.checked = state;
40793 if(suppressEvent !== true){
40794 this.fireEvent('check', this, state);
40796 this.inSetChecked = true;
40797 this.el.dom.value = state ? this.inputValue : this.valueOff;
40798 this.inSetChecked = false;
40801 // handle setting of hidden value by some other method!!?!?
40802 setFromHidden: function()
40807 //console.log("SET FROM HIDDEN");
40808 //alert('setFrom hidden');
40809 this.setValue(this.el.dom.value);
40812 onDestroy : function()
40815 Roo.get(this.viewEl).remove();
40818 Roo.form.Checkbox.superclass.onDestroy.call(this);
40823 * Ext JS Library 1.1.1
40824 * Copyright(c) 2006-2007, Ext JS, LLC.
40826 * Originally Released Under LGPL - original licence link has changed is not relivant.
40829 * <script type="text/javascript">
40833 * @class Roo.form.Radio
40834 * @extends Roo.form.Checkbox
40835 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40836 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40838 * Creates a new Radio
40839 * @param {Object} config Configuration options
40841 Roo.form.Radio = function(){
40842 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40844 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40845 inputType: 'radio',
40848 * If this radio is part of a group, it will return the selected value
40851 getGroupValue : function(){
40852 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40856 onRender : function(ct, position){
40857 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40859 if(this.inputValue !== undefined){
40860 this.el.dom.value = this.inputValue;
40863 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40864 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40865 //var viewEl = this.wrap.createChild({
40866 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40867 //this.viewEl = viewEl;
40868 //this.wrap.on('click', this.onClick, this);
40870 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40871 //this.el.on('propertychange', this.setFromHidden, this); //ie
40876 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40877 // viewEl.on('click', this.onClick, this);
40880 this.el.dom.checked = 'checked' ;
40886 });//<script type="text/javascript">
40889 * Based Ext JS Library 1.1.1
40890 * Copyright(c) 2006-2007, Ext JS, LLC.
40896 * @class Roo.HtmlEditorCore
40897 * @extends Roo.Component
40898 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
40900 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40903 Roo.HtmlEditorCore = function(config){
40906 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
40909 * @event initialize
40910 * Fires when the editor is fully initialized (including the iframe)
40911 * @param {Roo.HtmlEditorCore} this
40916 * Fires when the editor is first receives the focus. Any insertion must wait
40917 * until after this event.
40918 * @param {Roo.HtmlEditorCore} this
40922 * @event beforesync
40923 * Fires before the textarea is updated with content from the editor iframe. Return false
40924 * to cancel the sync.
40925 * @param {Roo.HtmlEditorCore} this
40926 * @param {String} html
40930 * @event beforepush
40931 * Fires before the iframe editor is updated with content from the textarea. Return false
40932 * to cancel the push.
40933 * @param {Roo.HtmlEditorCore} this
40934 * @param {String} html
40939 * Fires when the textarea is updated with content from the editor iframe.
40940 * @param {Roo.HtmlEditorCore} this
40941 * @param {String} html
40946 * Fires when the iframe editor is updated with content from the textarea.
40947 * @param {Roo.HtmlEditorCore} this
40948 * @param {String} html
40953 * @event editorevent
40954 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40955 * @param {Roo.HtmlEditorCore} this
40963 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
40967 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
40973 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40978 * @cfg {Number} height (in pixels)
40982 * @cfg {Number} width (in pixels)
40987 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
40990 stylesheets: false,
40995 // private properties
40996 validationEvent : false,
40998 initialized : false,
41000 sourceEditMode : false,
41001 onFocus : Roo.emptyFn,
41003 hideMode:'offsets',
41011 * Protected method that will not generally be called directly. It
41012 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41013 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41015 getDocMarkup : function(){
41018 Roo.log(this.stylesheets);
41020 // inherit styels from page...??
41021 if (this.stylesheets === false) {
41023 Roo.get(document.head).select('style').each(function(node) {
41024 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41027 Roo.get(document.head).select('link').each(function(node) {
41028 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41031 } else if (!this.stylesheets.length) {
41033 st = '<style type="text/css">' +
41034 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41037 Roo.each(this.stylesheets, function(s) {
41038 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
41043 st += '<style type="text/css">' +
41044 'IMG { cursor: pointer } ' +
41048 return '<html><head>' + st +
41049 //<style type="text/css">' +
41050 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41052 ' </head><body class="roo-htmleditor-body"></body></html>';
41056 onRender : function(ct, position)
41059 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41060 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41063 this.el.dom.style.border = '0 none';
41064 this.el.dom.setAttribute('tabIndex', -1);
41065 this.el.addClass('x-hidden hide');
41069 if(Roo.isIE){ // fix IE 1px bogus margin
41070 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41074 this.frameId = Roo.id();
41078 var iframe = this.owner.wrap.createChild({
41080 cls: 'form-control', // bootstrap..
41082 name: this.frameId,
41083 frameBorder : 'no',
41084 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41089 this.iframe = iframe.dom;
41091 this.assignDocWin();
41093 this.doc.designMode = 'on';
41096 this.doc.write(this.getDocMarkup());
41100 var task = { // must defer to wait for browser to be ready
41102 //console.log("run task?" + this.doc.readyState);
41103 this.assignDocWin();
41104 if(this.doc.body || this.doc.readyState == 'complete'){
41106 this.doc.designMode="on";
41110 Roo.TaskMgr.stop(task);
41111 this.initEditor.defer(10, this);
41118 Roo.TaskMgr.start(task);
41125 onResize : function(w, h)
41127 Roo.log('resize: ' +w + ',' + h );
41128 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41132 if(typeof w == 'number'){
41134 this.iframe.style.width = w + 'px';
41136 if(typeof h == 'number'){
41138 this.iframe.style.height = h + 'px';
41140 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41147 * Toggles the editor between standard and source edit mode.
41148 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41150 toggleSourceEdit : function(sourceEditMode){
41152 this.sourceEditMode = sourceEditMode === true;
41154 if(this.sourceEditMode){
41156 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41159 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41160 //this.iframe.className = '';
41163 //this.setSize(this.owner.wrap.getSize());
41164 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41171 * Protected method that will not generally be called directly. If you need/want
41172 * custom HTML cleanup, this is the method you should override.
41173 * @param {String} html The HTML to be cleaned
41174 * return {String} The cleaned HTML
41176 cleanHtml : function(html){
41177 html = String(html);
41178 if(html.length > 5){
41179 if(Roo.isSafari){ // strip safari nonsense
41180 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41183 if(html == ' '){
41190 * HTML Editor -> Textarea
41191 * Protected method that will not generally be called directly. Syncs the contents
41192 * of the editor iframe with the textarea.
41194 syncValue : function(){
41195 if(this.initialized){
41196 var bd = (this.doc.body || this.doc.documentElement);
41197 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41198 var html = bd.innerHTML;
41200 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41201 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41203 html = '<div style="'+m[0]+'">' + html + '</div>';
41206 html = this.cleanHtml(html);
41207 // fix up the special chars.. normaly like back quotes in word...
41208 // however we do not want to do this with chinese..
41209 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41210 var cc = b.charCodeAt();
41212 (cc >= 0x4E00 && cc < 0xA000 ) ||
41213 (cc >= 0x3400 && cc < 0x4E00 ) ||
41214 (cc >= 0xf900 && cc < 0xfb00 )
41220 if(this.owner.fireEvent('beforesync', this, html) !== false){
41221 this.el.dom.value = html;
41222 this.owner.fireEvent('sync', this, html);
41228 * Protected method that will not generally be called directly. Pushes the value of the textarea
41229 * into the iframe editor.
41231 pushValue : function(){
41232 if(this.initialized){
41233 var v = this.el.dom.value.trim();
41235 // if(v.length < 1){
41239 if(this.owner.fireEvent('beforepush', this, v) !== false){
41240 var d = (this.doc.body || this.doc.documentElement);
41242 this.cleanUpPaste();
41243 this.el.dom.value = d.innerHTML;
41244 this.owner.fireEvent('push', this, v);
41250 deferFocus : function(){
41251 this.focus.defer(10, this);
41255 focus : function(){
41256 if(this.win && !this.sourceEditMode){
41263 assignDocWin: function()
41265 var iframe = this.iframe;
41268 this.doc = iframe.contentWindow.document;
41269 this.win = iframe.contentWindow;
41271 if (!Roo.get(this.frameId)) {
41274 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41275 this.win = Roo.get(this.frameId).dom.contentWindow;
41280 initEditor : function(){
41281 //console.log("INIT EDITOR");
41282 this.assignDocWin();
41286 this.doc.designMode="on";
41288 this.doc.write(this.getDocMarkup());
41291 var dbody = (this.doc.body || this.doc.documentElement);
41292 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41293 // this copies styles from the containing element into thsi one..
41294 // not sure why we need all of this..
41295 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41296 ss['background-attachment'] = 'fixed'; // w3c
41297 dbody.bgProperties = 'fixed'; // ie
41298 Roo.DomHelper.applyStyles(dbody, ss);
41299 Roo.EventManager.on(this.doc, {
41300 //'mousedown': this.onEditorEvent,
41301 'mouseup': this.onEditorEvent,
41302 'dblclick': this.onEditorEvent,
41303 'click': this.onEditorEvent,
41304 'keyup': this.onEditorEvent,
41309 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41311 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41312 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41314 this.initialized = true;
41316 this.owner.fireEvent('initialize', this);
41321 onDestroy : function(){
41327 //for (var i =0; i < this.toolbars.length;i++) {
41328 // // fixme - ask toolbars for heights?
41329 // this.toolbars[i].onDestroy();
41332 //this.wrap.dom.innerHTML = '';
41333 //this.wrap.remove();
41338 onFirstFocus : function(){
41340 this.assignDocWin();
41343 this.activated = true;
41346 if(Roo.isGecko){ // prevent silly gecko errors
41348 var s = this.win.getSelection();
41349 if(!s.focusNode || s.focusNode.nodeType != 3){
41350 var r = s.getRangeAt(0);
41351 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41356 this.execCmd('useCSS', true);
41357 this.execCmd('styleWithCSS', false);
41360 this.owner.fireEvent('activate', this);
41364 adjustFont: function(btn){
41365 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41366 //if(Roo.isSafari){ // safari
41369 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41370 if(Roo.isSafari){ // safari
41371 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41372 v = (v < 10) ? 10 : v;
41373 v = (v > 48) ? 48 : v;
41374 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41379 v = Math.max(1, v+adjust);
41381 this.execCmd('FontSize', v );
41384 onEditorEvent : function(e){
41385 this.owner.fireEvent('editorevent', this, e);
41386 // this.updateToolbar();
41387 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41390 insertTag : function(tg)
41392 // could be a bit smarter... -> wrap the current selected tRoo..
41393 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41395 range = this.createRange(this.getSelection());
41396 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41397 wrappingNode.appendChild(range.extractContents());
41398 range.insertNode(wrappingNode);
41405 this.execCmd("formatblock", tg);
41409 insertText : function(txt)
41413 var range = this.createRange();
41414 range.deleteContents();
41415 //alert(Sender.getAttribute('label'));
41417 range.insertNode(this.doc.createTextNode(txt));
41423 * Executes a Midas editor command on the editor document and performs necessary focus and
41424 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41425 * @param {String} cmd The Midas command
41426 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41428 relayCmd : function(cmd, value){
41430 this.execCmd(cmd, value);
41431 this.owner.fireEvent('editorevent', this);
41432 //this.updateToolbar();
41433 this.owner.deferFocus();
41437 * Executes a Midas editor command directly on the editor document.
41438 * For visual commands, you should use {@link #relayCmd} instead.
41439 * <b>This should only be called after the editor is initialized.</b>
41440 * @param {String} cmd The Midas command
41441 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41443 execCmd : function(cmd, value){
41444 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41451 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41453 * @param {String} text | dom node..
41455 insertAtCursor : function(text)
41460 if(!this.activated){
41466 var r = this.doc.selection.createRange();
41477 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41481 // from jquery ui (MIT licenced)
41483 var win = this.win;
41485 if (win.getSelection && win.getSelection().getRangeAt) {
41486 range = win.getSelection().getRangeAt(0);
41487 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41488 range.insertNode(node);
41489 } else if (win.document.selection && win.document.selection.createRange) {
41490 // no firefox support
41491 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41492 win.document.selection.createRange().pasteHTML(txt);
41494 // no firefox support
41495 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41496 this.execCmd('InsertHTML', txt);
41505 mozKeyPress : function(e){
41507 var c = e.getCharCode(), cmd;
41510 c = String.fromCharCode(c).toLowerCase();
41524 this.cleanUpPaste.defer(100, this);
41532 e.preventDefault();
41540 fixKeys : function(){ // load time branching for fastest keydown performance
41542 return function(e){
41543 var k = e.getKey(), r;
41546 r = this.doc.selection.createRange();
41549 r.pasteHTML('    ');
41556 r = this.doc.selection.createRange();
41558 var target = r.parentElement();
41559 if(!target || target.tagName.toLowerCase() != 'li'){
41561 r.pasteHTML('<br />');
41567 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41568 this.cleanUpPaste.defer(100, this);
41574 }else if(Roo.isOpera){
41575 return function(e){
41576 var k = e.getKey();
41580 this.execCmd('InsertHTML','    ');
41583 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41584 this.cleanUpPaste.defer(100, this);
41589 }else if(Roo.isSafari){
41590 return function(e){
41591 var k = e.getKey();
41595 this.execCmd('InsertText','\t');
41599 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41600 this.cleanUpPaste.defer(100, this);
41608 getAllAncestors: function()
41610 var p = this.getSelectedNode();
41613 a.push(p); // push blank onto stack..
41614 p = this.getParentElement();
41618 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41622 a.push(this.doc.body);
41626 lastSelNode : false,
41629 getSelection : function()
41631 this.assignDocWin();
41632 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41635 getSelectedNode: function()
41637 // this may only work on Gecko!!!
41639 // should we cache this!!!!
41644 var range = this.createRange(this.getSelection()).cloneRange();
41647 var parent = range.parentElement();
41649 var testRange = range.duplicate();
41650 testRange.moveToElementText(parent);
41651 if (testRange.inRange(range)) {
41654 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41657 parent = parent.parentElement;
41662 // is ancestor a text element.
41663 var ac = range.commonAncestorContainer;
41664 if (ac.nodeType == 3) {
41665 ac = ac.parentNode;
41668 var ar = ac.childNodes;
41671 var other_nodes = [];
41672 var has_other_nodes = false;
41673 for (var i=0;i<ar.length;i++) {
41674 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41677 // fullly contained node.
41679 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41684 // probably selected..
41685 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41686 other_nodes.push(ar[i]);
41690 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41695 has_other_nodes = true;
41697 if (!nodes.length && other_nodes.length) {
41698 nodes= other_nodes;
41700 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41706 createRange: function(sel)
41708 // this has strange effects when using with
41709 // top toolbar - not sure if it's a great idea.
41710 //this.editor.contentWindow.focus();
41711 if (typeof sel != "undefined") {
41713 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41715 return this.doc.createRange();
41718 return this.doc.createRange();
41721 getParentElement: function()
41724 this.assignDocWin();
41725 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41727 var range = this.createRange(sel);
41730 var p = range.commonAncestorContainer;
41731 while (p.nodeType == 3) { // text node
41742 * Range intersection.. the hard stuff...
41746 * [ -- selected range --- ]
41750 * if end is before start or hits it. fail.
41751 * if start is after end or hits it fail.
41753 * if either hits (but other is outside. - then it's not
41759 // @see http://www.thismuchiknow.co.uk/?p=64.
41760 rangeIntersectsNode : function(range, node)
41762 var nodeRange = node.ownerDocument.createRange();
41764 nodeRange.selectNode(node);
41766 nodeRange.selectNodeContents(node);
41769 var rangeStartRange = range.cloneRange();
41770 rangeStartRange.collapse(true);
41772 var rangeEndRange = range.cloneRange();
41773 rangeEndRange.collapse(false);
41775 var nodeStartRange = nodeRange.cloneRange();
41776 nodeStartRange.collapse(true);
41778 var nodeEndRange = nodeRange.cloneRange();
41779 nodeEndRange.collapse(false);
41781 return rangeStartRange.compareBoundaryPoints(
41782 Range.START_TO_START, nodeEndRange) == -1 &&
41783 rangeEndRange.compareBoundaryPoints(
41784 Range.START_TO_START, nodeStartRange) == 1;
41788 rangeCompareNode : function(range, node)
41790 var nodeRange = node.ownerDocument.createRange();
41792 nodeRange.selectNode(node);
41794 nodeRange.selectNodeContents(node);
41798 range.collapse(true);
41800 nodeRange.collapse(true);
41802 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41803 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41805 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41807 var nodeIsBefore = ss == 1;
41808 var nodeIsAfter = ee == -1;
41810 if (nodeIsBefore && nodeIsAfter)
41812 if (!nodeIsBefore && nodeIsAfter)
41813 return 1; //right trailed.
41815 if (nodeIsBefore && !nodeIsAfter)
41816 return 2; // left trailed.
41821 // private? - in a new class?
41822 cleanUpPaste : function()
41824 // cleans up the whole document..
41825 Roo.log('cleanuppaste');
41827 this.cleanUpChildren(this.doc.body);
41828 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41829 if (clean != this.doc.body.innerHTML) {
41830 this.doc.body.innerHTML = clean;
41835 cleanWordChars : function(input) {// change the chars to hex code
41836 var he = Roo.HtmlEditorCore;
41838 var output = input;
41839 Roo.each(he.swapCodes, function(sw) {
41840 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41842 output = output.replace(swapper, sw[1]);
41849 cleanUpChildren : function (n)
41851 if (!n.childNodes.length) {
41854 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41855 this.cleanUpChild(n.childNodes[i]);
41862 cleanUpChild : function (node)
41865 //console.log(node);
41866 if (node.nodeName == "#text") {
41867 // clean up silly Windows -- stuff?
41870 if (node.nodeName == "#comment") {
41871 node.parentNode.removeChild(node);
41872 // clean up silly Windows -- stuff?
41876 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
41878 node.parentNode.removeChild(node);
41883 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
41885 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41886 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41888 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41889 // remove_keep_children = true;
41892 if (remove_keep_children) {
41893 this.cleanUpChildren(node);
41894 // inserts everything just before this node...
41895 while (node.childNodes.length) {
41896 var cn = node.childNodes[0];
41897 node.removeChild(cn);
41898 node.parentNode.insertBefore(cn, node);
41900 node.parentNode.removeChild(node);
41904 if (!node.attributes || !node.attributes.length) {
41905 this.cleanUpChildren(node);
41909 function cleanAttr(n,v)
41912 if (v.match(/^\./) || v.match(/^\//)) {
41915 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41918 if (v.match(/^#/)) {
41921 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41922 node.removeAttribute(n);
41926 function cleanStyle(n,v)
41928 if (v.match(/expression/)) { //XSS?? should we even bother..
41929 node.removeAttribute(n);
41932 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
41933 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
41936 var parts = v.split(/;/);
41939 Roo.each(parts, function(p) {
41940 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
41944 var l = p.split(':').shift().replace(/\s+/g,'');
41945 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
41947 if ( cblack.indexOf(l) > -1) {
41948 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41949 //node.removeAttribute(n);
41953 // only allow 'c whitelisted system attributes'
41954 if ( cwhite.length && cwhite.indexOf(l) < 0) {
41955 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41956 //node.removeAttribute(n);
41966 if (clean.length) {
41967 node.setAttribute(n, clean.join(';'));
41969 node.removeAttribute(n);
41975 for (var i = node.attributes.length-1; i > -1 ; i--) {
41976 var a = node.attributes[i];
41979 if (a.name.toLowerCase().substr(0,2)=='on') {
41980 node.removeAttribute(a.name);
41983 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
41984 node.removeAttribute(a.name);
41987 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
41988 cleanAttr(a.name,a.value); // fixme..
41991 if (a.name == 'style') {
41992 cleanStyle(a.name,a.value);
41995 /// clean up MS crap..
41996 // tecnically this should be a list of valid class'es..
41999 if (a.name == 'class') {
42000 if (a.value.match(/^Mso/)) {
42001 node.className = '';
42004 if (a.value.match(/body/)) {
42005 node.className = '';
42016 this.cleanUpChildren(node);
42022 // hide stuff that is not compatible
42036 * @event specialkey
42040 * @cfg {String} fieldClass @hide
42043 * @cfg {String} focusClass @hide
42046 * @cfg {String} autoCreate @hide
42049 * @cfg {String} inputType @hide
42052 * @cfg {String} invalidClass @hide
42055 * @cfg {String} invalidText @hide
42058 * @cfg {String} msgFx @hide
42061 * @cfg {String} validateOnBlur @hide
42065 Roo.HtmlEditorCore.white = [
42066 'area', 'br', 'img', 'input', 'hr', 'wbr',
42068 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42069 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42070 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42071 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42072 'table', 'ul', 'xmp',
42074 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42077 'dir', 'menu', 'ol', 'ul', 'dl',
42083 Roo.HtmlEditorCore.black = [
42084 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42086 'base', 'basefont', 'bgsound', 'blink', 'body',
42087 'frame', 'frameset', 'head', 'html', 'ilayer',
42088 'iframe', 'layer', 'link', 'meta', 'object',
42089 'script', 'style' ,'title', 'xml' // clean later..
42091 Roo.HtmlEditorCore.clean = [
42092 'script', 'style', 'title', 'xml'
42094 Roo.HtmlEditorCore.remove = [
42099 Roo.HtmlEditorCore.ablack = [
42103 Roo.HtmlEditorCore.aclean = [
42104 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42108 Roo.HtmlEditorCore.pwhite= [
42109 'http', 'https', 'mailto'
42112 // white listed style attributes.
42113 Roo.HtmlEditorCore.cwhite= [
42114 // 'text-align', /// default is to allow most things..
42120 // black listed style attributes.
42121 Roo.HtmlEditorCore.cblack= [
42122 // 'font-size' -- this can be set by the project
42126 Roo.HtmlEditorCore.swapCodes =[
42137 //<script type="text/javascript">
42140 * Ext JS Library 1.1.1
42141 * Copyright(c) 2006-2007, Ext JS, LLC.
42147 Roo.form.HtmlEditor = function(config){
42151 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42153 if (!this.toolbars) {
42154 this.toolbars = [];
42156 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42162 * @class Roo.form.HtmlEditor
42163 * @extends Roo.form.Field
42164 * Provides a lightweight HTML Editor component.
42166 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42168 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42169 * supported by this editor.</b><br/><br/>
42170 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42171 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42173 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42175 * @cfg {Boolean} clearUp
42179 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42184 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42189 * @cfg {Number} height (in pixels)
42193 * @cfg {Number} width (in pixels)
42198 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42201 stylesheets: false,
42206 // private properties
42207 validationEvent : false,
42209 initialized : false,
42212 onFocus : Roo.emptyFn,
42214 hideMode:'offsets',
42216 defaultAutoCreate : { // modified by initCompnoent..
42218 style:"width:500px;height:300px;",
42219 autocomplete: "off"
42223 initComponent : function(){
42226 * @event initialize
42227 * Fires when the editor is fully initialized (including the iframe)
42228 * @param {HtmlEditor} this
42233 * Fires when the editor is first receives the focus. Any insertion must wait
42234 * until after this event.
42235 * @param {HtmlEditor} this
42239 * @event beforesync
42240 * Fires before the textarea is updated with content from the editor iframe. Return false
42241 * to cancel the sync.
42242 * @param {HtmlEditor} this
42243 * @param {String} html
42247 * @event beforepush
42248 * Fires before the iframe editor is updated with content from the textarea. Return false
42249 * to cancel the push.
42250 * @param {HtmlEditor} this
42251 * @param {String} html
42256 * Fires when the textarea is updated with content from the editor iframe.
42257 * @param {HtmlEditor} this
42258 * @param {String} html
42263 * Fires when the iframe editor is updated with content from the textarea.
42264 * @param {HtmlEditor} this
42265 * @param {String} html
42269 * @event editmodechange
42270 * Fires when the editor switches edit modes
42271 * @param {HtmlEditor} this
42272 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42274 editmodechange: true,
42276 * @event editorevent
42277 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42278 * @param {HtmlEditor} this
42282 * @event firstfocus
42283 * Fires when on first focus - needed by toolbars..
42284 * @param {HtmlEditor} this
42289 * Auto save the htmlEditor value as a file into Events
42290 * @param {HtmlEditor} this
42294 * @event savedpreview
42295 * preview the saved version of htmlEditor
42296 * @param {HtmlEditor} this
42300 this.defaultAutoCreate = {
42302 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42303 autocomplete: "off"
42308 * Protected method that will not generally be called directly. It
42309 * is called when the editor creates its toolbar. Override this method if you need to
42310 * add custom toolbar buttons.
42311 * @param {HtmlEditor} editor
42313 createToolbar : function(editor){
42314 Roo.log("create toolbars");
42315 if (!editor.toolbars || !editor.toolbars.length) {
42316 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42319 for (var i =0 ; i < editor.toolbars.length;i++) {
42320 editor.toolbars[i] = Roo.factory(
42321 typeof(editor.toolbars[i]) == 'string' ?
42322 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42323 Roo.form.HtmlEditor);
42324 editor.toolbars[i].init(editor);
42332 onRender : function(ct, position)
42335 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
42337 this.wrap = this.el.wrap({
42338 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
42341 this.editorcore.onRender(ct, position);
42343 if (this.resizable) {
42344 this.resizeEl = new Roo.Resizable(this.wrap, {
42348 minHeight : this.height,
42349 height: this.height,
42350 handles : this.resizable,
42353 resize : function(r, w, h) {
42354 _t.onResize(w,h); // -something
42360 this.createToolbar(this);
42364 this.setSize(this.wrap.getSize());
42366 if (this.resizeEl) {
42367 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
42368 // should trigger onReize..
42371 // if(this.autosave && this.w){
42372 // this.autoSaveFn = setInterval(this.autosave, 1000);
42377 onResize : function(w, h)
42379 //Roo.log('resize: ' +w + ',' + h );
42380 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
42385 if(typeof w == 'number'){
42386 var aw = w - this.wrap.getFrameWidth('lr');
42387 this.el.setWidth(this.adjustWidth('textarea', aw));
42390 if(typeof h == 'number'){
42392 for (var i =0; i < this.toolbars.length;i++) {
42393 // fixme - ask toolbars for heights?
42394 tbh += this.toolbars[i].tb.el.getHeight();
42395 if (this.toolbars[i].footer) {
42396 tbh += this.toolbars[i].footer.el.getHeight();
42403 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
42404 ah -= 5; // knock a few pixes off for look..
42405 this.el.setHeight(this.adjustWidth('textarea', ah));
42409 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
42410 this.editorcore.onResize(ew,eh);
42415 * Toggles the editor between standard and source edit mode.
42416 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42418 toggleSourceEdit : function(sourceEditMode)
42420 this.editorcore.toggleSourceEdit(sourceEditMode);
42422 if(this.editorcore.sourceEditMode){
42423 Roo.log('editor - showing textarea');
42426 // Roo.log(this.syncValue());
42427 this.editorcore.syncValue();
42428 this.el.removeClass('x-hidden');
42429 this.el.dom.removeAttribute('tabIndex');
42432 Roo.log('editor - hiding textarea');
42434 // Roo.log(this.pushValue());
42435 this.editorcore.pushValue();
42437 this.el.addClass('x-hidden');
42438 this.el.dom.setAttribute('tabIndex', -1);
42439 //this.deferFocus();
42442 this.setSize(this.wrap.getSize());
42443 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
42446 // private (for BoxComponent)
42447 adjustSize : Roo.BoxComponent.prototype.adjustSize,
42449 // private (for BoxComponent)
42450 getResizeEl : function(){
42454 // private (for BoxComponent)
42455 getPositionEl : function(){
42460 initEvents : function(){
42461 this.originalValue = this.getValue();
42465 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42468 markInvalid : Roo.emptyFn,
42470 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42473 clearInvalid : Roo.emptyFn,
42475 setValue : function(v){
42476 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
42477 this.editorcore.pushValue();
42482 deferFocus : function(){
42483 this.focus.defer(10, this);
42487 focus : function(){
42488 this.editorcore.focus();
42494 onDestroy : function(){
42500 for (var i =0; i < this.toolbars.length;i++) {
42501 // fixme - ask toolbars for heights?
42502 this.toolbars[i].onDestroy();
42505 this.wrap.dom.innerHTML = '';
42506 this.wrap.remove();
42511 onFirstFocus : function(){
42512 //Roo.log("onFirstFocus");
42513 this.editorcore.onFirstFocus();
42514 for (var i =0; i < this.toolbars.length;i++) {
42515 this.toolbars[i].onFirstFocus();
42521 syncValue : function()
42523 this.editorcore.syncValue();
42526 pushValue : function()
42528 this.editorcore.pushValue();
42532 // hide stuff that is not compatible
42546 * @event specialkey
42550 * @cfg {String} fieldClass @hide
42553 * @cfg {String} focusClass @hide
42556 * @cfg {String} autoCreate @hide
42559 * @cfg {String} inputType @hide
42562 * @cfg {String} invalidClass @hide
42565 * @cfg {String} invalidText @hide
42568 * @cfg {String} msgFx @hide
42571 * @cfg {String} validateOnBlur @hide
42575 // <script type="text/javascript">
42578 * Ext JS Library 1.1.1
42579 * Copyright(c) 2006-2007, Ext JS, LLC.
42585 * @class Roo.form.HtmlEditorToolbar1
42590 new Roo.form.HtmlEditor({
42593 new Roo.form.HtmlEditorToolbar1({
42594 disable : { fonts: 1 , format: 1, ..., ... , ...],
42600 * @cfg {Object} disable List of elements to disable..
42601 * @cfg {Array} btns List of additional buttons.
42605 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
42608 Roo.form.HtmlEditor.ToolbarStandard = function(config)
42611 Roo.apply(this, config);
42613 // default disabled, based on 'good practice'..
42614 this.disable = this.disable || {};
42615 Roo.applyIf(this.disable, {
42618 specialElements : true
42622 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42623 // dont call parent... till later.
42626 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
42633 editorcore : false,
42635 * @cfg {Object} disable List of toolbar elements to disable
42642 * @cfg {String} createLinkText The default text for the create link prompt
42644 createLinkText : 'Please enter the URL for the link:',
42646 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
42648 defaultLinkValue : 'http:/'+'/',
42652 * @cfg {Array} fontFamilies An array of available font families
42670 // "á" , ?? a acute?
42675 "°" // , // degrees
42677 // "é" , // e ecute
42678 // "ú" , // u ecute?
42681 specialElements : [
42683 text: "Insert Table",
42686 ihtml : '<table><tr><td>Cell</td></tr></table>'
42690 text: "Insert Image",
42693 ihtml : '<img src="about:blank"/>'
42702 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
42703 "input:submit", "input:button", "select", "textarea", "label" ],
42706 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
42708 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
42716 * @cfg {String} defaultFont default font to use.
42718 defaultFont: 'tahoma',
42720 fontSelect : false,
42723 formatCombo : false,
42725 init : function(editor)
42727 this.editor = editor;
42728 this.editorcore = editor.editorcore ? editor.editorcore : editor;
42729 var editorcore = this.editorcore;
42733 var fid = editorcore.frameId;
42735 function btn(id, toggle, handler){
42736 var xid = fid + '-'+ id ;
42740 cls : 'x-btn-icon x-edit-'+id,
42741 enableToggle:toggle !== false,
42742 scope: _t, // was editor...
42743 handler:handler||_t.relayBtnCmd,
42744 clickEvent:'mousedown',
42745 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42752 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
42754 // stop form submits
42755 tb.el.on('click', function(e){
42756 e.preventDefault(); // what does this do?
42759 if(!this.disable.font) { // && !Roo.isSafari){
42760 /* why no safari for fonts
42761 editor.fontSelect = tb.el.createChild({
42764 cls:'x-font-select',
42765 html: this.createFontOptions()
42768 editor.fontSelect.on('change', function(){
42769 var font = editor.fontSelect.dom.value;
42770 editor.relayCmd('fontname', font);
42771 editor.deferFocus();
42775 editor.fontSelect.dom,
42781 if(!this.disable.formats){
42782 this.formatCombo = new Roo.form.ComboBox({
42783 store: new Roo.data.SimpleStore({
42786 data : this.formats // from states.js
42790 //autoCreate : {tag: "div", size: "20"},
42791 displayField:'tag',
42795 triggerAction: 'all',
42796 emptyText:'Add tag',
42797 selectOnFocus:true,
42800 'select': function(c, r, i) {
42801 editorcore.insertTag(r.get('tag'));
42807 tb.addField(this.formatCombo);
42811 if(!this.disable.format){
42818 if(!this.disable.fontSize){
42823 btn('increasefontsize', false, editorcore.adjustFont),
42824 btn('decreasefontsize', false, editorcore.adjustFont)
42829 if(!this.disable.colors){
42832 id:editorcore.frameId +'-forecolor',
42833 cls:'x-btn-icon x-edit-forecolor',
42834 clickEvent:'mousedown',
42835 tooltip: this.buttonTips['forecolor'] || undefined,
42837 menu : new Roo.menu.ColorMenu({
42838 allowReselect: true,
42839 focus: Roo.emptyFn,
42842 selectHandler: function(cp, color){
42843 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
42844 editor.deferFocus();
42847 clickEvent:'mousedown'
42850 id:editorcore.frameId +'backcolor',
42851 cls:'x-btn-icon x-edit-backcolor',
42852 clickEvent:'mousedown',
42853 tooltip: this.buttonTips['backcolor'] || undefined,
42855 menu : new Roo.menu.ColorMenu({
42856 focus: Roo.emptyFn,
42859 allowReselect: true,
42860 selectHandler: function(cp, color){
42862 editorcore.execCmd('useCSS', false);
42863 editorcore.execCmd('hilitecolor', color);
42864 editorcore.execCmd('useCSS', true);
42865 editor.deferFocus();
42867 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
42868 Roo.isSafari || Roo.isIE ? '#'+color : color);
42869 editor.deferFocus();
42873 clickEvent:'mousedown'
42878 // now add all the items...
42881 if(!this.disable.alignments){
42884 btn('justifyleft'),
42885 btn('justifycenter'),
42886 btn('justifyright')
42890 //if(!Roo.isSafari){
42891 if(!this.disable.links){
42894 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
42898 if(!this.disable.lists){
42901 btn('insertorderedlist'),
42902 btn('insertunorderedlist')
42905 if(!this.disable.sourceEdit){
42908 btn('sourceedit', true, function(btn){
42910 this.toggleSourceEdit(btn.pressed);
42917 // special menu.. - needs to be tidied up..
42918 if (!this.disable.special) {
42921 cls: 'x-edit-none',
42927 for (var i =0; i < this.specialChars.length; i++) {
42928 smenu.menu.items.push({
42930 html: this.specialChars[i],
42931 handler: function(a,b) {
42932 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
42933 //editor.insertAtCursor(a.html);
42947 if (!this.disable.cleanStyles) {
42949 cls: 'x-btn-icon x-btn-clear',
42955 for (var i =0; i < this.cleanStyles.length; i++) {
42956 cmenu.menu.items.push({
42957 actiontype : this.cleanStyles[i],
42958 html: 'Remove ' + this.cleanStyles[i],
42959 handler: function(a,b) {
42962 var c = Roo.get(editorcore.doc.body);
42963 c.select('[style]').each(function(s) {
42964 s.dom.style.removeProperty(a.actiontype);
42971 cmenu.menu.items.push({
42972 actiontype : 'all',
42973 html: 'Remove All Styles',
42974 handler: function(a,b) {
42976 var c = Roo.get(editorcore.doc.body);
42977 c.select('[style]').each(function(s) {
42978 s.dom.removeAttribute('style');
42987 if (!this.disable.specialElements) {
42990 cls: 'x-edit-none',
42995 for (var i =0; i < this.specialElements.length; i++) {
42996 semenu.menu.items.push(
42998 handler: function(a,b) {
42999 editor.insertAtCursor(this.ihtml);
43001 }, this.specialElements[i])
43013 for(var i =0; i< this.btns.length;i++) {
43014 var b = Roo.factory(this.btns[i],Roo.form);
43015 b.cls = 'x-edit-none';
43016 b.scope = editorcore;
43024 // disable everything...
43026 this.tb.items.each(function(item){
43027 if(item.id != editorcore.frameId+ '-sourceedit'){
43031 this.rendered = true;
43033 // the all the btns;
43034 editor.on('editorevent', this.updateToolbar, this);
43035 // other toolbars need to implement this..
43036 //editor.on('editmodechange', this.updateToolbar, this);
43040 relayBtnCmd : function(btn) {
43041 this.editorcore.relayCmd(btn.cmd);
43043 // private used internally
43044 createLink : function(){
43045 Roo.log("create link?");
43046 var url = prompt(this.createLinkText, this.defaultLinkValue);
43047 if(url && url != 'http:/'+'/'){
43048 this.editorcore.relayCmd('createlink', url);
43054 * Protected method that will not generally be called directly. It triggers
43055 * a toolbar update by reading the markup state of the current selection in the editor.
43057 updateToolbar: function(){
43059 if(!this.editorcore.activated){
43060 this.editor.onFirstFocus();
43064 var btns = this.tb.items.map,
43065 doc = this.editorcore.doc,
43066 frameId = this.editorcore.frameId;
43068 if(!this.disable.font && !Roo.isSafari){
43070 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43071 if(name != this.fontSelect.dom.value){
43072 this.fontSelect.dom.value = name;
43076 if(!this.disable.format){
43077 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43078 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43079 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43081 if(!this.disable.alignments){
43082 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43083 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43084 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43086 if(!Roo.isSafari && !this.disable.lists){
43087 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43088 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43091 var ans = this.editorcore.getAllAncestors();
43092 if (this.formatCombo) {
43095 var store = this.formatCombo.store;
43096 this.formatCombo.setValue("");
43097 for (var i =0; i < ans.length;i++) {
43098 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43100 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43108 // hides menus... - so this cant be on a menu...
43109 Roo.menu.MenuMgr.hideAll();
43111 //this.editorsyncValue();
43115 createFontOptions : function(){
43116 var buf = [], fs = this.fontFamilies, ff, lc;
43120 for(var i = 0, len = fs.length; i< len; i++){
43122 lc = ff.toLowerCase();
43124 '<option value="',lc,'" style="font-family:',ff,';"',
43125 (this.defaultFont == lc ? ' selected="true">' : '>'),
43130 return buf.join('');
43133 toggleSourceEdit : function(sourceEditMode){
43135 Roo.log("toolbar toogle");
43136 if(sourceEditMode === undefined){
43137 sourceEditMode = !this.sourceEditMode;
43139 this.sourceEditMode = sourceEditMode === true;
43140 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43141 // just toggle the button?
43142 if(btn.pressed !== this.sourceEditMode){
43143 btn.toggle(this.sourceEditMode);
43147 if(sourceEditMode){
43148 Roo.log("disabling buttons");
43149 this.tb.items.each(function(item){
43150 if(item.cmd != 'sourceedit'){
43156 Roo.log("enabling buttons");
43157 if(this.editorcore.initialized){
43158 this.tb.items.each(function(item){
43164 Roo.log("calling toggole on editor");
43165 // tell the editor that it's been pressed..
43166 this.editor.toggleSourceEdit(sourceEditMode);
43170 * Object collection of toolbar tooltips for the buttons in the editor. The key
43171 * is the command id associated with that button and the value is a valid QuickTips object.
43176 title: 'Bold (Ctrl+B)',
43177 text: 'Make the selected text bold.',
43178 cls: 'x-html-editor-tip'
43181 title: 'Italic (Ctrl+I)',
43182 text: 'Make the selected text italic.',
43183 cls: 'x-html-editor-tip'
43191 title: 'Bold (Ctrl+B)',
43192 text: 'Make the selected text bold.',
43193 cls: 'x-html-editor-tip'
43196 title: 'Italic (Ctrl+I)',
43197 text: 'Make the selected text italic.',
43198 cls: 'x-html-editor-tip'
43201 title: 'Underline (Ctrl+U)',
43202 text: 'Underline the selected text.',
43203 cls: 'x-html-editor-tip'
43205 increasefontsize : {
43206 title: 'Grow Text',
43207 text: 'Increase the font size.',
43208 cls: 'x-html-editor-tip'
43210 decreasefontsize : {
43211 title: 'Shrink Text',
43212 text: 'Decrease the font size.',
43213 cls: 'x-html-editor-tip'
43216 title: 'Text Highlight Color',
43217 text: 'Change the background color of the selected text.',
43218 cls: 'x-html-editor-tip'
43221 title: 'Font Color',
43222 text: 'Change the color of the selected text.',
43223 cls: 'x-html-editor-tip'
43226 title: 'Align Text Left',
43227 text: 'Align text to the left.',
43228 cls: 'x-html-editor-tip'
43231 title: 'Center Text',
43232 text: 'Center text in the editor.',
43233 cls: 'x-html-editor-tip'
43236 title: 'Align Text Right',
43237 text: 'Align text to the right.',
43238 cls: 'x-html-editor-tip'
43240 insertunorderedlist : {
43241 title: 'Bullet List',
43242 text: 'Start a bulleted list.',
43243 cls: 'x-html-editor-tip'
43245 insertorderedlist : {
43246 title: 'Numbered List',
43247 text: 'Start a numbered list.',
43248 cls: 'x-html-editor-tip'
43251 title: 'Hyperlink',
43252 text: 'Make the selected text a hyperlink.',
43253 cls: 'x-html-editor-tip'
43256 title: 'Source Edit',
43257 text: 'Switch to source editing mode.',
43258 cls: 'x-html-editor-tip'
43262 onDestroy : function(){
43265 this.tb.items.each(function(item){
43267 item.menu.removeAll();
43269 item.menu.el.destroy();
43277 onFirstFocus: function() {
43278 this.tb.items.each(function(item){
43287 // <script type="text/javascript">
43290 * Ext JS Library 1.1.1
43291 * Copyright(c) 2006-2007, Ext JS, LLC.
43298 * @class Roo.form.HtmlEditor.ToolbarContext
43303 new Roo.form.HtmlEditor({
43306 { xtype: 'ToolbarStandard', styles : {} }
43307 { xtype: 'ToolbarContext', disable : {} }
43313 * @config : {Object} disable List of elements to disable.. (not done yet.)
43314 * @config : {Object} styles Map of styles available.
43318 Roo.form.HtmlEditor.ToolbarContext = function(config)
43321 Roo.apply(this, config);
43322 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43323 // dont call parent... till later.
43324 this.styles = this.styles || {};
43329 Roo.form.HtmlEditor.ToolbarContext.types = {
43341 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
43407 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
43412 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
43422 style : 'fontFamily',
43423 displayField: 'display',
43424 optname : 'font-family',
43473 // should we really allow this??
43474 // should this just be
43485 style : 'fontFamily',
43486 displayField: 'display',
43487 optname : 'font-family',
43494 style : 'fontFamily',
43495 displayField: 'display',
43496 optname : 'font-family',
43503 style : 'fontFamily',
43504 displayField: 'display',
43505 optname : 'font-family',
43516 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
43517 Roo.form.HtmlEditor.ToolbarContext.stores = false;
43519 Roo.form.HtmlEditor.ToolbarContext.options = {
43521 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
43522 [ 'Courier New', 'Courier New'],
43523 [ 'Tahoma', 'Tahoma'],
43524 [ 'Times New Roman,serif', 'Times'],
43525 [ 'Verdana','Verdana' ]
43529 // fixme - these need to be configurable..
43532 Roo.form.HtmlEditor.ToolbarContext.types
43535 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
43542 editorcore : false,
43544 * @cfg {Object} disable List of toolbar elements to disable
43549 * @cfg {Object} styles List of styles
43550 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
43552 * These must be defined in the page, so they get rendered correctly..
43563 init : function(editor)
43565 this.editor = editor;
43566 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43567 var editorcore = this.editorcore;
43569 var fid = editorcore.frameId;
43571 function btn(id, toggle, handler){
43572 var xid = fid + '-'+ id ;
43576 cls : 'x-btn-icon x-edit-'+id,
43577 enableToggle:toggle !== false,
43578 scope: editorcore, // was editor...
43579 handler:handler||editorcore.relayBtnCmd,
43580 clickEvent:'mousedown',
43581 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43585 // create a new element.
43586 var wdiv = editor.wrap.createChild({
43588 }, editor.wrap.dom.firstChild.nextSibling, true);
43590 // can we do this more than once??
43592 // stop form submits
43595 // disable everything...
43596 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43597 this.toolbars = {};
43599 for (var i in ty) {
43601 this.toolbars[i] = this.buildToolbar(ty[i],i);
43603 this.tb = this.toolbars.BODY;
43605 this.buildFooter();
43606 this.footer.show();
43607 editor.on('hide', function( ) { this.footer.hide() }, this);
43608 editor.on('show', function( ) { this.footer.show() }, this);
43611 this.rendered = true;
43613 // the all the btns;
43614 editor.on('editorevent', this.updateToolbar, this);
43615 // other toolbars need to implement this..
43616 //editor.on('editmodechange', this.updateToolbar, this);
43622 * Protected method that will not generally be called directly. It triggers
43623 * a toolbar update by reading the markup state of the current selection in the editor.
43625 updateToolbar: function(editor,ev,sel){
43628 // capture mouse up - this is handy for selecting images..
43629 // perhaps should go somewhere else...
43630 if(!this.editorcore.activated){
43631 this.editor.onFirstFocus();
43635 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
43636 // selectNode - might want to handle IE?
43638 (ev.type == 'mouseup' || ev.type == 'click' ) &&
43639 ev.target && ev.target.tagName == 'IMG') {
43640 // they have click on an image...
43641 // let's see if we can change the selection...
43644 var nodeRange = sel.ownerDocument.createRange();
43646 nodeRange.selectNode(sel);
43648 nodeRange.selectNodeContents(sel);
43650 //nodeRange.collapse(true);
43651 var s = this.editorcore.win.getSelection();
43652 s.removeAllRanges();
43653 s.addRange(nodeRange);
43657 var updateFooter = sel ? false : true;
43660 var ans = this.editorcore.getAllAncestors();
43663 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43666 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
43667 sel = sel ? sel : this.editorcore.doc.body;
43668 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
43671 // pick a menu that exists..
43672 var tn = sel.tagName.toUpperCase();
43673 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
43675 tn = sel.tagName.toUpperCase();
43677 var lastSel = this.tb.selectedNode
43679 this.tb.selectedNode = sel;
43681 // if current menu does not match..
43682 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
43685 ///console.log("show: " + tn);
43686 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
43689 this.tb.items.first().el.innerHTML = tn + ': ';
43692 // update attributes
43693 if (this.tb.fields) {
43694 this.tb.fields.each(function(e) {
43696 e.setValue(sel.style[e.stylename]);
43699 e.setValue(sel.getAttribute(e.attrname));
43703 var hasStyles = false;
43704 for(var i in this.styles) {
43711 var st = this.tb.fields.item(0);
43713 st.store.removeAll();
43716 var cn = sel.className.split(/\s+/);
43719 if (this.styles['*']) {
43721 Roo.each(this.styles['*'], function(v) {
43722 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43725 if (this.styles[tn]) {
43726 Roo.each(this.styles[tn], function(v) {
43727 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43731 st.store.loadData(avs);
43735 // flag our selected Node.
43736 this.tb.selectedNode = sel;
43739 Roo.menu.MenuMgr.hideAll();
43743 if (!updateFooter) {
43744 //this.footDisp.dom.innerHTML = '';
43747 // update the footer
43751 this.footerEls = ans.reverse();
43752 Roo.each(this.footerEls, function(a,i) {
43753 if (!a) { return; }
43754 html += html.length ? ' > ' : '';
43756 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
43761 var sz = this.footDisp.up('td').getSize();
43762 this.footDisp.dom.style.width = (sz.width -10) + 'px';
43763 this.footDisp.dom.style.marginLeft = '5px';
43765 this.footDisp.dom.style.overflow = 'hidden';
43767 this.footDisp.dom.innerHTML = html;
43769 //this.editorsyncValue();
43776 onDestroy : function(){
43779 this.tb.items.each(function(item){
43781 item.menu.removeAll();
43783 item.menu.el.destroy();
43791 onFirstFocus: function() {
43792 // need to do this for all the toolbars..
43793 this.tb.items.each(function(item){
43797 buildToolbar: function(tlist, nm)
43799 var editor = this.editor;
43800 var editorcore = this.editorcore;
43801 // create a new element.
43802 var wdiv = editor.wrap.createChild({
43804 }, editor.wrap.dom.firstChild.nextSibling, true);
43807 var tb = new Roo.Toolbar(wdiv);
43810 tb.add(nm+ ": ");
43813 for(var i in this.styles) {
43818 if (styles && styles.length) {
43820 // this needs a multi-select checkbox...
43821 tb.addField( new Roo.form.ComboBox({
43822 store: new Roo.data.SimpleStore({
43824 fields: ['val', 'selected'],
43827 name : '-roo-edit-className',
43828 attrname : 'className',
43829 displayField: 'val',
43833 triggerAction: 'all',
43834 emptyText:'Select Style',
43835 selectOnFocus:true,
43838 'select': function(c, r, i) {
43839 // initial support only for on class per el..
43840 tb.selectedNode.className = r ? r.get('val') : '';
43841 editorcore.syncValue();
43848 var tbc = Roo.form.HtmlEditor.ToolbarContext;
43849 var tbops = tbc.options;
43851 for (var i in tlist) {
43853 var item = tlist[i];
43854 tb.add(item.title + ": ");
43857 //optname == used so you can configure the options available..
43858 var opts = item.opts ? item.opts : false;
43859 if (item.optname) {
43860 opts = tbops[item.optname];
43865 // opts == pulldown..
43866 tb.addField( new Roo.form.ComboBox({
43867 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
43869 fields: ['val', 'display'],
43872 name : '-roo-edit-' + i,
43874 stylename : item.style ? item.style : false,
43875 displayField: item.displayField ? item.displayField : 'val',
43876 valueField : 'val',
43878 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
43880 triggerAction: 'all',
43881 emptyText:'Select',
43882 selectOnFocus:true,
43883 width: item.width ? item.width : 130,
43885 'select': function(c, r, i) {
43887 tb.selectedNode.style[c.stylename] = r.get('val');
43890 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
43899 tb.addField( new Roo.form.TextField({
43902 //allowBlank:false,
43907 tb.addField( new Roo.form.TextField({
43908 name: '-roo-edit-' + i,
43915 'change' : function(f, nv, ov) {
43916 tb.selectedNode.setAttribute(f.attrname, nv);
43925 text: 'Remove Tag',
43928 click : function ()
43931 // undo does not work.
43933 var sn = tb.selectedNode;
43935 var pn = sn.parentNode;
43937 var stn = sn.childNodes[0];
43938 var en = sn.childNodes[sn.childNodes.length - 1 ];
43939 while (sn.childNodes.length) {
43940 var node = sn.childNodes[0];
43941 sn.removeChild(node);
43943 pn.insertBefore(node, sn);
43946 pn.removeChild(sn);
43947 var range = editorcore.createRange();
43949 range.setStart(stn,0);
43950 range.setEnd(en,0); //????
43951 //range.selectNode(sel);
43954 var selection = editorcore.getSelection();
43955 selection.removeAllRanges();
43956 selection.addRange(range);
43960 //_this.updateToolbar(null, null, pn);
43961 _this.updateToolbar(null, null, null);
43962 _this.footDisp.dom.innerHTML = '';
43972 tb.el.on('click', function(e){
43973 e.preventDefault(); // what does this do?
43975 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
43978 // dont need to disable them... as they will get hidden
43983 buildFooter : function()
43986 var fel = this.editor.wrap.createChild();
43987 this.footer = new Roo.Toolbar(fel);
43988 // toolbar has scrolly on left / right?
43989 var footDisp= new Roo.Toolbar.Fill();
43995 handler : function() {
43996 _t.footDisp.scrollTo('left',0,true)
44000 this.footer.add( footDisp );
44005 handler : function() {
44007 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44011 var fel = Roo.get(footDisp.el);
44012 fel.addClass('x-editor-context');
44013 this.footDispWrap = fel;
44014 this.footDispWrap.overflow = 'hidden';
44016 this.footDisp = fel.createChild();
44017 this.footDispWrap.on('click', this.onContextClick, this)
44021 onContextClick : function (ev,dom)
44023 ev.preventDefault();
44024 var cn = dom.className;
44026 if (!cn.match(/x-ed-loc-/)) {
44029 var n = cn.split('-').pop();
44030 var ans = this.footerEls;
44034 var range = this.editorcore.createRange();
44036 range.selectNodeContents(sel);
44037 //range.selectNode(sel);
44040 var selection = this.editorcore.getSelection();
44041 selection.removeAllRanges();
44042 selection.addRange(range);
44046 this.updateToolbar(null, null, sel);
44063 * Ext JS Library 1.1.1
44064 * Copyright(c) 2006-2007, Ext JS, LLC.
44066 * Originally Released Under LGPL - original licence link has changed is not relivant.
44069 * <script type="text/javascript">
44073 * @class Roo.form.BasicForm
44074 * @extends Roo.util.Observable
44075 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44077 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44078 * @param {Object} config Configuration options
44080 Roo.form.BasicForm = function(el, config){
44081 this.allItems = [];
44082 this.childForms = [];
44083 Roo.apply(this, config);
44085 * The Roo.form.Field items in this form.
44086 * @type MixedCollection
44090 this.items = new Roo.util.MixedCollection(false, function(o){
44091 return o.id || (o.id = Roo.id());
44095 * @event beforeaction
44096 * Fires before any action is performed. Return false to cancel the action.
44097 * @param {Form} this
44098 * @param {Action} action The action to be performed
44100 beforeaction: true,
44102 * @event actionfailed
44103 * Fires when an action fails.
44104 * @param {Form} this
44105 * @param {Action} action The action that failed
44107 actionfailed : true,
44109 * @event actioncomplete
44110 * Fires when an action is completed.
44111 * @param {Form} this
44112 * @param {Action} action The action that completed
44114 actioncomplete : true
44119 Roo.form.BasicForm.superclass.constructor.call(this);
44122 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44124 * @cfg {String} method
44125 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
44128 * @cfg {DataReader} reader
44129 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
44130 * This is optional as there is built-in support for processing JSON.
44133 * @cfg {DataReader} errorReader
44134 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
44135 * This is completely optional as there is built-in support for processing JSON.
44138 * @cfg {String} url
44139 * The URL to use for form actions if one isn't supplied in the action options.
44142 * @cfg {Boolean} fileUpload
44143 * Set to true if this form is a file upload.
44147 * @cfg {Object} baseParams
44148 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
44153 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
44158 activeAction : null,
44161 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
44162 * or setValues() data instead of when the form was first created.
44164 trackResetOnLoad : false,
44168 * childForms - used for multi-tab forms
44171 childForms : false,
44174 * allItems - full list of fields.
44180 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
44181 * element by passing it or its id or mask the form itself by passing in true.
44184 waitMsgTarget : false,
44187 initEl : function(el){
44188 this.el = Roo.get(el);
44189 this.id = this.el.id || Roo.id();
44190 this.el.on('submit', this.onSubmit, this);
44191 this.el.addClass('x-form');
44195 onSubmit : function(e){
44200 * Returns true if client-side validation on the form is successful.
44203 isValid : function(){
44205 this.items.each(function(f){
44214 * Returns true if any fields in this form have changed since their original load.
44217 isDirty : function(){
44219 this.items.each(function(f){
44229 * Performs a predefined action (submit or load) or custom actions you define on this form.
44230 * @param {String} actionName The name of the action type
44231 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
44232 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
44233 * accept other config options):
44235 Property Type Description
44236 ---------------- --------------- ----------------------------------------------------------------------------------
44237 url String The url for the action (defaults to the form's url)
44238 method String The form method to use (defaults to the form's method, or POST if not defined)
44239 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
44240 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
44241 validate the form on the client (defaults to false)
44243 * @return {BasicForm} this
44245 doAction : function(action, options){
44246 if(typeof action == 'string'){
44247 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
44249 if(this.fireEvent('beforeaction', this, action) !== false){
44250 this.beforeAction(action);
44251 action.run.defer(100, action);
44257 * Shortcut to do a submit action.
44258 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44259 * @return {BasicForm} this
44261 submit : function(options){
44262 this.doAction('submit', options);
44267 * Shortcut to do a load action.
44268 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44269 * @return {BasicForm} this
44271 load : function(options){
44272 this.doAction('load', options);
44277 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
44278 * @param {Record} record The record to edit
44279 * @return {BasicForm} this
44281 updateRecord : function(record){
44282 record.beginEdit();
44283 var fs = record.fields;
44284 fs.each(function(f){
44285 var field = this.findField(f.name);
44287 record.set(f.name, field.getValue());
44295 * Loads an Roo.data.Record into this form.
44296 * @param {Record} record The record to load
44297 * @return {BasicForm} this
44299 loadRecord : function(record){
44300 this.setValues(record.data);
44305 beforeAction : function(action){
44306 var o = action.options;
44309 if(this.waitMsgTarget === true){
44310 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
44311 }else if(this.waitMsgTarget){
44312 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
44313 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
44315 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
44321 afterAction : function(action, success){
44322 this.activeAction = null;
44323 var o = action.options;
44325 if(this.waitMsgTarget === true){
44327 }else if(this.waitMsgTarget){
44328 this.waitMsgTarget.unmask();
44330 Roo.MessageBox.updateProgress(1);
44331 Roo.MessageBox.hide();
44338 Roo.callback(o.success, o.scope, [this, action]);
44339 this.fireEvent('actioncomplete', this, action);
44343 // failure condition..
44344 // we have a scenario where updates need confirming.
44345 // eg. if a locking scenario exists..
44346 // we look for { errors : { needs_confirm : true }} in the response.
44348 (typeof(action.result) != 'undefined') &&
44349 (typeof(action.result.errors) != 'undefined') &&
44350 (typeof(action.result.errors.needs_confirm) != 'undefined')
44353 Roo.MessageBox.confirm(
44354 "Change requires confirmation",
44355 action.result.errorMsg,
44360 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
44370 Roo.callback(o.failure, o.scope, [this, action]);
44371 // show an error message if no failed handler is set..
44372 if (!this.hasListener('actionfailed')) {
44373 Roo.MessageBox.alert("Error",
44374 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
44375 action.result.errorMsg :
44376 "Saving Failed, please check your entries or try again"
44380 this.fireEvent('actionfailed', this, action);
44386 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
44387 * @param {String} id The value to search for
44390 findField : function(id){
44391 var field = this.items.get(id);
44393 this.items.each(function(f){
44394 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
44400 return field || null;
44404 * Add a secondary form to this one,
44405 * Used to provide tabbed forms. One form is primary, with hidden values
44406 * which mirror the elements from the other forms.
44408 * @param {Roo.form.Form} form to add.
44411 addForm : function(form)
44414 if (this.childForms.indexOf(form) > -1) {
44418 this.childForms.push(form);
44420 Roo.each(form.allItems, function (fe) {
44422 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
44423 if (this.findField(n)) { // already added..
44426 var add = new Roo.form.Hidden({
44429 add.render(this.el);
44436 * Mark fields in this form invalid in bulk.
44437 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
44438 * @return {BasicForm} this
44440 markInvalid : function(errors){
44441 if(errors instanceof Array){
44442 for(var i = 0, len = errors.length; i < len; i++){
44443 var fieldError = errors[i];
44444 var f = this.findField(fieldError.id);
44446 f.markInvalid(fieldError.msg);
44452 if(typeof errors[id] != 'function' && (field = this.findField(id))){
44453 field.markInvalid(errors[id]);
44457 Roo.each(this.childForms || [], function (f) {
44458 f.markInvalid(errors);
44465 * Set values for fields in this form in bulk.
44466 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
44467 * @return {BasicForm} this
44469 setValues : function(values){
44470 if(values instanceof Array){ // array of objects
44471 for(var i = 0, len = values.length; i < len; i++){
44473 var f = this.findField(v.id);
44475 f.setValue(v.value);
44476 if(this.trackResetOnLoad){
44477 f.originalValue = f.getValue();
44481 }else{ // object hash
44484 if(typeof values[id] != 'function' && (field = this.findField(id))){
44486 if (field.setFromData &&
44487 field.valueField &&
44488 field.displayField &&
44489 // combos' with local stores can
44490 // be queried via setValue()
44491 // to set their value..
44492 (field.store && !field.store.isLocal)
44496 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44497 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44498 field.setFromData(sd);
44501 field.setValue(values[id]);
44505 if(this.trackResetOnLoad){
44506 field.originalValue = field.getValue();
44512 Roo.each(this.childForms || [], function (f) {
44513 f.setValues(values);
44520 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
44521 * they are returned as an array.
44522 * @param {Boolean} asString
44525 getValues : function(asString){
44526 if (this.childForms) {
44527 // copy values from the child forms
44528 Roo.each(this.childForms, function (f) {
44529 this.setValues(f.getValues());
44535 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
44536 if(asString === true){
44539 return Roo.urlDecode(fs);
44543 * Returns the fields in this form as an object with key/value pairs.
44544 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
44547 getFieldValues : function(with_hidden)
44549 if (this.childForms) {
44550 // copy values from the child forms
44551 // should this call getFieldValues - probably not as we do not currently copy
44552 // hidden fields when we generate..
44553 Roo.each(this.childForms, function (f) {
44554 this.setValues(f.getValues());
44559 this.items.each(function(f){
44560 if (!f.getName()) {
44563 var v = f.getValue();
44564 if (f.inputType =='radio') {
44565 if (typeof(ret[f.getName()]) == 'undefined') {
44566 ret[f.getName()] = ''; // empty..
44569 if (!f.el.dom.checked) {
44573 v = f.el.dom.value;
44577 // not sure if this supported any more..
44578 if ((typeof(v) == 'object') && f.getRawValue) {
44579 v = f.getRawValue() ; // dates..
44581 // combo boxes where name != hiddenName...
44582 if (f.name != f.getName()) {
44583 ret[f.name] = f.getRawValue();
44585 ret[f.getName()] = v;
44592 * Clears all invalid messages in this form.
44593 * @return {BasicForm} this
44595 clearInvalid : function(){
44596 this.items.each(function(f){
44600 Roo.each(this.childForms || [], function (f) {
44609 * Resets this form.
44610 * @return {BasicForm} this
44612 reset : function(){
44613 this.items.each(function(f){
44617 Roo.each(this.childForms || [], function (f) {
44626 * Add Roo.form components to this form.
44627 * @param {Field} field1
44628 * @param {Field} field2 (optional)
44629 * @param {Field} etc (optional)
44630 * @return {BasicForm} this
44633 this.items.addAll(Array.prototype.slice.call(arguments, 0));
44639 * Removes a field from the items collection (does NOT remove its markup).
44640 * @param {Field} field
44641 * @return {BasicForm} this
44643 remove : function(field){
44644 this.items.remove(field);
44649 * Looks at the fields in this form, checks them for an id attribute,
44650 * and calls applyTo on the existing dom element with that id.
44651 * @return {BasicForm} this
44653 render : function(){
44654 this.items.each(function(f){
44655 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
44663 * Calls {@link Ext#apply} for all fields in this form with the passed object.
44664 * @param {Object} values
44665 * @return {BasicForm} this
44667 applyToFields : function(o){
44668 this.items.each(function(f){
44675 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
44676 * @param {Object} values
44677 * @return {BasicForm} this
44679 applyIfToFields : function(o){
44680 this.items.each(function(f){
44688 Roo.BasicForm = Roo.form.BasicForm;/*
44690 * Ext JS Library 1.1.1
44691 * Copyright(c) 2006-2007, Ext JS, LLC.
44693 * Originally Released Under LGPL - original licence link has changed is not relivant.
44696 * <script type="text/javascript">
44700 * @class Roo.form.Form
44701 * @extends Roo.form.BasicForm
44702 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
44704 * @param {Object} config Configuration options
44706 Roo.form.Form = function(config){
44708 if (config.items) {
44709 xitems = config.items;
44710 delete config.items;
44714 Roo.form.Form.superclass.constructor.call(this, null, config);
44715 this.url = this.url || this.action;
44717 this.root = new Roo.form.Layout(Roo.applyIf({
44721 this.active = this.root;
44723 * Array of all the buttons that have been added to this form via {@link addButton}
44727 this.allItems = [];
44730 * @event clientvalidation
44731 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
44732 * @param {Form} this
44733 * @param {Boolean} valid true if the form has passed client-side validation
44735 clientvalidation: true,
44738 * Fires when the form is rendered
44739 * @param {Roo.form.Form} form
44744 if (this.progressUrl) {
44745 // push a hidden field onto the list of fields..
44749 name : 'UPLOAD_IDENTIFIER'
44754 Roo.each(xitems, this.addxtype, this);
44760 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
44762 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
44765 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
44768 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
44770 buttonAlign:'center',
44773 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
44778 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
44779 * This property cascades to child containers if not set.
44784 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
44785 * fires a looping event with that state. This is required to bind buttons to the valid
44786 * state using the config value formBind:true on the button.
44788 monitorValid : false,
44791 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
44796 * @cfg {String} progressUrl - Url to return progress data
44799 progressUrl : false,
44802 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
44803 * fields are added and the column is closed. If no fields are passed the column remains open
44804 * until end() is called.
44805 * @param {Object} config The config to pass to the column
44806 * @param {Field} field1 (optional)
44807 * @param {Field} field2 (optional)
44808 * @param {Field} etc (optional)
44809 * @return Column The column container object
44811 column : function(c){
44812 var col = new Roo.form.Column(c);
44814 if(arguments.length > 1){ // duplicate code required because of Opera
44815 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44822 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
44823 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
44824 * until end() is called.
44825 * @param {Object} config The config to pass to the fieldset
44826 * @param {Field} field1 (optional)
44827 * @param {Field} field2 (optional)
44828 * @param {Field} etc (optional)
44829 * @return FieldSet The fieldset container object
44831 fieldset : function(c){
44832 var fs = new Roo.form.FieldSet(c);
44834 if(arguments.length > 1){ // duplicate code required because of Opera
44835 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44842 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
44843 * fields are added and the container is closed. If no fields are passed the container remains open
44844 * until end() is called.
44845 * @param {Object} config The config to pass to the Layout
44846 * @param {Field} field1 (optional)
44847 * @param {Field} field2 (optional)
44848 * @param {Field} etc (optional)
44849 * @return Layout The container object
44851 container : function(c){
44852 var l = new Roo.form.Layout(c);
44854 if(arguments.length > 1){ // duplicate code required because of Opera
44855 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44862 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
44863 * @param {Object} container A Roo.form.Layout or subclass of Layout
44864 * @return {Form} this
44866 start : function(c){
44867 // cascade label info
44868 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
44869 this.active.stack.push(c);
44870 c.ownerCt = this.active;
44876 * Closes the current open container
44877 * @return {Form} this
44880 if(this.active == this.root){
44883 this.active = this.active.ownerCt;
44888 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
44889 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
44890 * as the label of the field.
44891 * @param {Field} field1
44892 * @param {Field} field2 (optional)
44893 * @param {Field} etc. (optional)
44894 * @return {Form} this
44897 this.active.stack.push.apply(this.active.stack, arguments);
44898 this.allItems.push.apply(this.allItems,arguments);
44900 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
44901 if(a[i].isFormField){
44906 Roo.form.Form.superclass.add.apply(this, r);
44916 * Find any element that has been added to a form, using it's ID or name
44917 * This can include framesets, columns etc. along with regular fields..
44918 * @param {String} id - id or name to find.
44920 * @return {Element} e - or false if nothing found.
44922 findbyId : function(id)
44928 Roo.each(this.allItems, function(f){
44929 if (f.id == id || f.name == id ){
44940 * Render this form into the passed container. This should only be called once!
44941 * @param {String/HTMLElement/Element} container The element this component should be rendered into
44942 * @return {Form} this
44944 render : function(ct)
44950 var o = this.autoCreate || {
44952 method : this.method || 'POST',
44953 id : this.id || Roo.id()
44955 this.initEl(ct.createChild(o));
44957 this.root.render(this.el);
44961 this.items.each(function(f){
44962 f.render('x-form-el-'+f.id);
44965 if(this.buttons.length > 0){
44966 // tables are required to maintain order and for correct IE layout
44967 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
44968 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
44969 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
44971 var tr = tb.getElementsByTagName('tr')[0];
44972 for(var i = 0, len = this.buttons.length; i < len; i++) {
44973 var b = this.buttons[i];
44974 var td = document.createElement('td');
44975 td.className = 'x-form-btn-td';
44976 b.render(tr.appendChild(td));
44979 if(this.monitorValid){ // initialize after render
44980 this.startMonitoring();
44982 this.fireEvent('rendered', this);
44987 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
44988 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
44989 * object or a valid Roo.DomHelper element config
44990 * @param {Function} handler The function called when the button is clicked
44991 * @param {Object} scope (optional) The scope of the handler function
44992 * @return {Roo.Button}
44994 addButton : function(config, handler, scope){
44998 minWidth: this.minButtonWidth,
45001 if(typeof config == "string"){
45004 Roo.apply(bc, config);
45006 var btn = new Roo.Button(null, bc);
45007 this.buttons.push(btn);
45012 * Adds a series of form elements (using the xtype property as the factory method.
45013 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45014 * @param {Object} config
45017 addxtype : function()
45019 var ar = Array.prototype.slice.call(arguments, 0);
45021 for(var i = 0; i < ar.length; i++) {
45023 continue; // skip -- if this happends something invalid got sent, we
45024 // should ignore it, as basically that interface element will not show up
45025 // and that should be pretty obvious!!
45028 if (Roo.form[ar[i].xtype]) {
45030 var fe = Roo.factory(ar[i], Roo.form);
45036 fe.store.form = this;
45041 this.allItems.push(fe);
45042 if (fe.items && fe.addxtype) {
45043 fe.addxtype.apply(fe, fe.items);
45053 // console.log('adding ' + ar[i].xtype);
45055 if (ar[i].xtype == 'Button') {
45056 //console.log('adding button');
45057 //console.log(ar[i]);
45058 this.addButton(ar[i]);
45059 this.allItems.push(fe);
45063 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45064 alert('end is not supported on xtype any more, use items');
45066 // //console.log('adding end');
45074 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45075 * option "monitorValid"
45077 startMonitoring : function(){
45080 Roo.TaskMgr.start({
45081 run : this.bindHandler,
45082 interval : this.monitorPoll || 200,
45089 * Stops monitoring of the valid state of this form
45091 stopMonitoring : function(){
45092 this.bound = false;
45096 bindHandler : function(){
45098 return false; // stops binding
45101 this.items.each(function(f){
45102 if(!f.isValid(true)){
45107 for(var i = 0, len = this.buttons.length; i < len; i++){
45108 var btn = this.buttons[i];
45109 if(btn.formBind === true && btn.disabled === valid){
45110 btn.setDisabled(!valid);
45113 this.fireEvent('clientvalidation', this, valid);
45127 Roo.Form = Roo.form.Form;
45130 * Ext JS Library 1.1.1
45131 * Copyright(c) 2006-2007, Ext JS, LLC.
45133 * Originally Released Under LGPL - original licence link has changed is not relivant.
45136 * <script type="text/javascript">
45139 // as we use this in bootstrap.
45140 Roo.namespace('Roo.form');
45142 * @class Roo.form.Action
45143 * Internal Class used to handle form actions
45145 * @param {Roo.form.BasicForm} el The form element or its id
45146 * @param {Object} config Configuration options
45151 // define the action interface
45152 Roo.form.Action = function(form, options){
45154 this.options = options || {};
45157 * Client Validation Failed
45160 Roo.form.Action.CLIENT_INVALID = 'client';
45162 * Server Validation Failed
45165 Roo.form.Action.SERVER_INVALID = 'server';
45167 * Connect to Server Failed
45170 Roo.form.Action.CONNECT_FAILURE = 'connect';
45172 * Reading Data from Server Failed
45175 Roo.form.Action.LOAD_FAILURE = 'load';
45177 Roo.form.Action.prototype = {
45179 failureType : undefined,
45180 response : undefined,
45181 result : undefined,
45183 // interface method
45184 run : function(options){
45188 // interface method
45189 success : function(response){
45193 // interface method
45194 handleResponse : function(response){
45198 // default connection failure
45199 failure : function(response){
45201 this.response = response;
45202 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45203 this.form.afterAction(this, false);
45206 processResponse : function(response){
45207 this.response = response;
45208 if(!response.responseText){
45211 this.result = this.handleResponse(response);
45212 return this.result;
45215 // utility functions used internally
45216 getUrl : function(appendParams){
45217 var url = this.options.url || this.form.url || this.form.el.dom.action;
45219 var p = this.getParams();
45221 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
45227 getMethod : function(){
45228 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
45231 getParams : function(){
45232 var bp = this.form.baseParams;
45233 var p = this.options.params;
45235 if(typeof p == "object"){
45236 p = Roo.urlEncode(Roo.applyIf(p, bp));
45237 }else if(typeof p == 'string' && bp){
45238 p += '&' + Roo.urlEncode(bp);
45241 p = Roo.urlEncode(bp);
45246 createCallback : function(){
45248 success: this.success,
45249 failure: this.failure,
45251 timeout: (this.form.timeout*1000),
45252 upload: this.form.fileUpload ? this.success : undefined
45257 Roo.form.Action.Submit = function(form, options){
45258 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
45261 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
45264 haveProgress : false,
45265 uploadComplete : false,
45267 // uploadProgress indicator.
45268 uploadProgress : function()
45270 if (!this.form.progressUrl) {
45274 if (!this.haveProgress) {
45275 Roo.MessageBox.progress("Uploading", "Uploading");
45277 if (this.uploadComplete) {
45278 Roo.MessageBox.hide();
45282 this.haveProgress = true;
45284 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
45286 var c = new Roo.data.Connection();
45288 url : this.form.progressUrl,
45293 success : function(req){
45294 //console.log(data);
45298 rdata = Roo.decode(req.responseText)
45300 Roo.log("Invalid data from server..");
45304 if (!rdata || !rdata.success) {
45306 Roo.MessageBox.alert(Roo.encode(rdata));
45309 var data = rdata.data;
45311 if (this.uploadComplete) {
45312 Roo.MessageBox.hide();
45317 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
45318 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
45321 this.uploadProgress.defer(2000,this);
45324 failure: function(data) {
45325 Roo.log('progress url failed ');
45336 // run get Values on the form, so it syncs any secondary forms.
45337 this.form.getValues();
45339 var o = this.options;
45340 var method = this.getMethod();
45341 var isPost = method == 'POST';
45342 if(o.clientValidation === false || this.form.isValid()){
45344 if (this.form.progressUrl) {
45345 this.form.findField('UPLOAD_IDENTIFIER').setValue(
45346 (new Date() * 1) + '' + Math.random());
45351 Roo.Ajax.request(Roo.apply(this.createCallback(), {
45352 form:this.form.el.dom,
45353 url:this.getUrl(!isPost),
45355 params:isPost ? this.getParams() : null,
45356 isUpload: this.form.fileUpload
45359 this.uploadProgress();
45361 }else if (o.clientValidation !== false){ // client validation failed
45362 this.failureType = Roo.form.Action.CLIENT_INVALID;
45363 this.form.afterAction(this, false);
45367 success : function(response)
45369 this.uploadComplete= true;
45370 if (this.haveProgress) {
45371 Roo.MessageBox.hide();
45375 var result = this.processResponse(response);
45376 if(result === true || result.success){
45377 this.form.afterAction(this, true);
45381 this.form.markInvalid(result.errors);
45382 this.failureType = Roo.form.Action.SERVER_INVALID;
45384 this.form.afterAction(this, false);
45386 failure : function(response)
45388 this.uploadComplete= true;
45389 if (this.haveProgress) {
45390 Roo.MessageBox.hide();
45393 this.response = response;
45394 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45395 this.form.afterAction(this, false);
45398 handleResponse : function(response){
45399 if(this.form.errorReader){
45400 var rs = this.form.errorReader.read(response);
45403 for(var i = 0, len = rs.records.length; i < len; i++) {
45404 var r = rs.records[i];
45405 errors[i] = r.data;
45408 if(errors.length < 1){
45412 success : rs.success,
45418 ret = Roo.decode(response.responseText);
45422 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
45432 Roo.form.Action.Load = function(form, options){
45433 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
45434 this.reader = this.form.reader;
45437 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
45442 Roo.Ajax.request(Roo.apply(
45443 this.createCallback(), {
45444 method:this.getMethod(),
45445 url:this.getUrl(false),
45446 params:this.getParams()
45450 success : function(response){
45452 var result = this.processResponse(response);
45453 if(result === true || !result.success || !result.data){
45454 this.failureType = Roo.form.Action.LOAD_FAILURE;
45455 this.form.afterAction(this, false);
45458 this.form.clearInvalid();
45459 this.form.setValues(result.data);
45460 this.form.afterAction(this, true);
45463 handleResponse : function(response){
45464 if(this.form.reader){
45465 var rs = this.form.reader.read(response);
45466 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
45468 success : rs.success,
45472 return Roo.decode(response.responseText);
45476 Roo.form.Action.ACTION_TYPES = {
45477 'load' : Roo.form.Action.Load,
45478 'submit' : Roo.form.Action.Submit
45481 * Ext JS Library 1.1.1
45482 * Copyright(c) 2006-2007, Ext JS, LLC.
45484 * Originally Released Under LGPL - original licence link has changed is not relivant.
45487 * <script type="text/javascript">
45491 * @class Roo.form.Layout
45492 * @extends Roo.Component
45493 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45495 * @param {Object} config Configuration options
45497 Roo.form.Layout = function(config){
45499 if (config.items) {
45500 xitems = config.items;
45501 delete config.items;
45503 Roo.form.Layout.superclass.constructor.call(this, config);
45505 Roo.each(xitems, this.addxtype, this);
45509 Roo.extend(Roo.form.Layout, Roo.Component, {
45511 * @cfg {String/Object} autoCreate
45512 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
45515 * @cfg {String/Object/Function} style
45516 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
45517 * a function which returns such a specification.
45520 * @cfg {String} labelAlign
45521 * Valid values are "left," "top" and "right" (defaults to "left")
45524 * @cfg {Number} labelWidth
45525 * Fixed width in pixels of all field labels (defaults to undefined)
45528 * @cfg {Boolean} clear
45529 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
45533 * @cfg {String} labelSeparator
45534 * The separator to use after field labels (defaults to ':')
45536 labelSeparator : ':',
45538 * @cfg {Boolean} hideLabels
45539 * True to suppress the display of field labels in this layout (defaults to false)
45541 hideLabels : false,
45544 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
45549 onRender : function(ct, position){
45550 if(this.el){ // from markup
45551 this.el = Roo.get(this.el);
45552 }else { // generate
45553 var cfg = this.getAutoCreate();
45554 this.el = ct.createChild(cfg, position);
45557 this.el.applyStyles(this.style);
45559 if(this.labelAlign){
45560 this.el.addClass('x-form-label-'+this.labelAlign);
45562 if(this.hideLabels){
45563 this.labelStyle = "display:none";
45564 this.elementStyle = "padding-left:0;";
45566 if(typeof this.labelWidth == 'number'){
45567 this.labelStyle = "width:"+this.labelWidth+"px;";
45568 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
45570 if(this.labelAlign == 'top'){
45571 this.labelStyle = "width:auto;";
45572 this.elementStyle = "padding-left:0;";
45575 var stack = this.stack;
45576 var slen = stack.length;
45578 if(!this.fieldTpl){
45579 var t = new Roo.Template(
45580 '<div class="x-form-item {5}">',
45581 '<label for="{0}" style="{2}">{1}{4}</label>',
45582 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45584 '</div><div class="x-form-clear-left"></div>'
45586 t.disableFormats = true;
45588 Roo.form.Layout.prototype.fieldTpl = t;
45590 for(var i = 0; i < slen; i++) {
45591 if(stack[i].isFormField){
45592 this.renderField(stack[i]);
45594 this.renderComponent(stack[i]);
45599 this.el.createChild({cls:'x-form-clear'});
45604 renderField : function(f){
45605 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
45608 f.labelStyle||this.labelStyle||'', //2
45609 this.elementStyle||'', //3
45610 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
45611 f.itemCls||this.itemCls||'' //5
45612 ], true).getPrevSibling());
45616 renderComponent : function(c){
45617 c.render(c.isLayout ? this.el : this.el.createChild());
45620 * Adds a object form elements (using the xtype property as the factory method.)
45621 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
45622 * @param {Object} config
45624 addxtype : function(o)
45626 // create the lement.
45627 o.form = this.form;
45628 var fe = Roo.factory(o, Roo.form);
45629 this.form.allItems.push(fe);
45630 this.stack.push(fe);
45632 if (fe.isFormField) {
45633 this.form.items.add(fe);
45641 * @class Roo.form.Column
45642 * @extends Roo.form.Layout
45643 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
45645 * @param {Object} config Configuration options
45647 Roo.form.Column = function(config){
45648 Roo.form.Column.superclass.constructor.call(this, config);
45651 Roo.extend(Roo.form.Column, Roo.form.Layout, {
45653 * @cfg {Number/String} width
45654 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45657 * @cfg {String/Object} autoCreate
45658 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
45662 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
45665 onRender : function(ct, position){
45666 Roo.form.Column.superclass.onRender.call(this, ct, position);
45668 this.el.setWidth(this.width);
45675 * @class Roo.form.Row
45676 * @extends Roo.form.Layout
45677 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
45679 * @param {Object} config Configuration options
45683 Roo.form.Row = function(config){
45684 Roo.form.Row.superclass.constructor.call(this, config);
45687 Roo.extend(Roo.form.Row, Roo.form.Layout, {
45689 * @cfg {Number/String} width
45690 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45693 * @cfg {Number/String} height
45694 * The fixed height of the column in pixels or CSS value (defaults to "auto")
45696 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
45700 onRender : function(ct, position){
45701 //console.log('row render');
45703 var t = new Roo.Template(
45704 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
45705 '<label for="{0}" style="{2}">{1}{4}</label>',
45706 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45710 t.disableFormats = true;
45712 Roo.form.Layout.prototype.rowTpl = t;
45714 this.fieldTpl = this.rowTpl;
45716 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
45717 var labelWidth = 100;
45719 if ((this.labelAlign != 'top')) {
45720 if (typeof this.labelWidth == 'number') {
45721 labelWidth = this.labelWidth
45723 this.padWidth = 20 + labelWidth;
45727 Roo.form.Column.superclass.onRender.call(this, ct, position);
45729 this.el.setWidth(this.width);
45732 this.el.setHeight(this.height);
45737 renderField : function(f){
45738 f.fieldEl = this.fieldTpl.append(this.el, [
45739 f.id, f.fieldLabel,
45740 f.labelStyle||this.labelStyle||'',
45741 this.elementStyle||'',
45742 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
45743 f.itemCls||this.itemCls||'',
45744 f.width ? f.width + this.padWidth : 160 + this.padWidth
45751 * @class Roo.form.FieldSet
45752 * @extends Roo.form.Layout
45753 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
45755 * @param {Object} config Configuration options
45757 Roo.form.FieldSet = function(config){
45758 Roo.form.FieldSet.superclass.constructor.call(this, config);
45761 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
45763 * @cfg {String} legend
45764 * The text to display as the legend for the FieldSet (defaults to '')
45767 * @cfg {String/Object} autoCreate
45768 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
45772 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
45775 onRender : function(ct, position){
45776 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
45778 this.setLegend(this.legend);
45783 setLegend : function(text){
45785 this.el.child('legend').update(text);
45790 * Ext JS Library 1.1.1
45791 * Copyright(c) 2006-2007, Ext JS, LLC.
45793 * Originally Released Under LGPL - original licence link has changed is not relivant.
45796 * <script type="text/javascript">
45799 * @class Roo.form.VTypes
45800 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
45803 Roo.form.VTypes = function(){
45804 // closure these in so they are only created once.
45805 var alpha = /^[a-zA-Z_]+$/;
45806 var alphanum = /^[a-zA-Z0-9_]+$/;
45807 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
45808 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
45810 // All these messages and functions are configurable
45813 * The function used to validate email addresses
45814 * @param {String} value The email address
45816 'email' : function(v){
45817 return email.test(v);
45820 * The error text to display when the email validation function returns false
45823 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
45825 * The keystroke filter mask to be applied on email input
45828 'emailMask' : /[a-z0-9_\.\-@]/i,
45831 * The function used to validate URLs
45832 * @param {String} value The URL
45834 'url' : function(v){
45835 return url.test(v);
45838 * The error text to display when the url validation function returns false
45841 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
45844 * The function used to validate alpha values
45845 * @param {String} value The value
45847 'alpha' : function(v){
45848 return alpha.test(v);
45851 * The error text to display when the alpha validation function returns false
45854 'alphaText' : 'This field should only contain letters and _',
45856 * The keystroke filter mask to be applied on alpha input
45859 'alphaMask' : /[a-z_]/i,
45862 * The function used to validate alphanumeric values
45863 * @param {String} value The value
45865 'alphanum' : function(v){
45866 return alphanum.test(v);
45869 * The error text to display when the alphanumeric validation function returns false
45872 'alphanumText' : 'This field should only contain letters, numbers and _',
45874 * The keystroke filter mask to be applied on alphanumeric input
45877 'alphanumMask' : /[a-z0-9_]/i
45879 }();//<script type="text/javascript">
45882 * @class Roo.form.FCKeditor
45883 * @extends Roo.form.TextArea
45884 * Wrapper around the FCKEditor http://www.fckeditor.net
45886 * Creates a new FCKeditor
45887 * @param {Object} config Configuration options
45889 Roo.form.FCKeditor = function(config){
45890 Roo.form.FCKeditor.superclass.constructor.call(this, config);
45893 * @event editorinit
45894 * Fired when the editor is initialized - you can add extra handlers here..
45895 * @param {FCKeditor} this
45896 * @param {Object} the FCK object.
45903 Roo.form.FCKeditor.editors = { };
45904 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
45906 //defaultAutoCreate : {
45907 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
45911 * @cfg {Object} fck options - see fck manual for details.
45916 * @cfg {Object} fck toolbar set (Basic or Default)
45918 toolbarSet : 'Basic',
45920 * @cfg {Object} fck BasePath
45922 basePath : '/fckeditor/',
45930 onRender : function(ct, position)
45933 this.defaultAutoCreate = {
45935 style:"width:300px;height:60px;",
45936 autocomplete: "off"
45939 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
45942 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
45943 if(this.preventScrollbars){
45944 this.el.setStyle("overflow", "hidden");
45946 this.el.setHeight(this.growMin);
45949 //console.log('onrender' + this.getId() );
45950 Roo.form.FCKeditor.editors[this.getId()] = this;
45953 this.replaceTextarea() ;
45957 getEditor : function() {
45958 return this.fckEditor;
45961 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
45962 * @param {Mixed} value The value to set
45966 setValue : function(value)
45968 //console.log('setValue: ' + value);
45970 if(typeof(value) == 'undefined') { // not sure why this is happending...
45973 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
45975 //if(!this.el || !this.getEditor()) {
45976 // this.value = value;
45977 //this.setValue.defer(100,this,[value]);
45981 if(!this.getEditor()) {
45985 this.getEditor().SetData(value);
45992 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
45993 * @return {Mixed} value The field value
45995 getValue : function()
45998 if (this.frame && this.frame.dom.style.display == 'none') {
45999 return Roo.form.FCKeditor.superclass.getValue.call(this);
46002 if(!this.el || !this.getEditor()) {
46004 // this.getValue.defer(100,this);
46009 var value=this.getEditor().GetData();
46010 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46011 return Roo.form.FCKeditor.superclass.getValue.call(this);
46017 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46018 * @return {Mixed} value The field value
46020 getRawValue : function()
46022 if (this.frame && this.frame.dom.style.display == 'none') {
46023 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46026 if(!this.el || !this.getEditor()) {
46027 //this.getRawValue.defer(100,this);
46034 var value=this.getEditor().GetData();
46035 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46036 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46040 setSize : function(w,h) {
46044 //if (this.frame && this.frame.dom.style.display == 'none') {
46045 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46048 //if(!this.el || !this.getEditor()) {
46049 // this.setSize.defer(100,this, [w,h]);
46055 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46057 this.frame.dom.setAttribute('width', w);
46058 this.frame.dom.setAttribute('height', h);
46059 this.frame.setSize(w,h);
46063 toggleSourceEdit : function(value) {
46067 this.el.dom.style.display = value ? '' : 'none';
46068 this.frame.dom.style.display = value ? 'none' : '';
46073 focus: function(tag)
46075 if (this.frame.dom.style.display == 'none') {
46076 return Roo.form.FCKeditor.superclass.focus.call(this);
46078 if(!this.el || !this.getEditor()) {
46079 this.focus.defer(100,this, [tag]);
46086 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46087 this.getEditor().Focus();
46089 if (!this.getEditor().Selection.GetSelection()) {
46090 this.focus.defer(100,this, [tag]);
46095 var r = this.getEditor().EditorDocument.createRange();
46096 r.setStart(tgs[0],0);
46097 r.setEnd(tgs[0],0);
46098 this.getEditor().Selection.GetSelection().removeAllRanges();
46099 this.getEditor().Selection.GetSelection().addRange(r);
46100 this.getEditor().Focus();
46107 replaceTextarea : function()
46109 if ( document.getElementById( this.getId() + '___Frame' ) )
46111 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46113 // We must check the elements firstly using the Id and then the name.
46114 var oTextarea = document.getElementById( this.getId() );
46116 var colElementsByName = document.getElementsByName( this.getId() ) ;
46118 oTextarea.style.display = 'none' ;
46120 if ( oTextarea.tabIndex ) {
46121 this.TabIndex = oTextarea.tabIndex ;
46124 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46125 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46126 this.frame = Roo.get(this.getId() + '___Frame')
46129 _getConfigHtml : function()
46133 for ( var o in this.fckconfig ) {
46134 sConfig += sConfig.length > 0 ? '&' : '';
46135 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
46138 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
46142 _getIFrameHtml : function()
46144 var sFile = 'fckeditor.html' ;
46145 /* no idea what this is about..
46148 if ( (/fcksource=true/i).test( window.top.location.search ) )
46149 sFile = 'fckeditor.original.html' ;
46154 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
46155 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
46158 var html = '<iframe id="' + this.getId() +
46159 '___Frame" src="' + sLink +
46160 '" width="' + this.width +
46161 '" height="' + this.height + '"' +
46162 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
46163 ' frameborder="0" scrolling="no"></iframe>' ;
46168 _insertHtmlBefore : function( html, element )
46170 if ( element.insertAdjacentHTML ) {
46172 element.insertAdjacentHTML( 'beforeBegin', html ) ;
46174 var oRange = document.createRange() ;
46175 oRange.setStartBefore( element ) ;
46176 var oFragment = oRange.createContextualFragment( html );
46177 element.parentNode.insertBefore( oFragment, element ) ;
46190 //Roo.reg('fckeditor', Roo.form.FCKeditor);
46192 function FCKeditor_OnComplete(editorInstance){
46193 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
46194 f.fckEditor = editorInstance;
46195 //console.log("loaded");
46196 f.fireEvent('editorinit', f, editorInstance);
46216 //<script type="text/javascript">
46218 * @class Roo.form.GridField
46219 * @extends Roo.form.Field
46220 * Embed a grid (or editable grid into a form)
46223 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
46225 * xgrid.store = Roo.data.Store
46226 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
46227 * xgrid.store.reader = Roo.data.JsonReader
46231 * Creates a new GridField
46232 * @param {Object} config Configuration options
46234 Roo.form.GridField = function(config){
46235 Roo.form.GridField.superclass.constructor.call(this, config);
46239 Roo.extend(Roo.form.GridField, Roo.form.Field, {
46241 * @cfg {Number} width - used to restrict width of grid..
46245 * @cfg {Number} height - used to restrict height of grid..
46249 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
46255 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46256 * {tag: "input", type: "checkbox", autocomplete: "off"})
46258 // defaultAutoCreate : { tag: 'div' },
46259 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46261 * @cfg {String} addTitle Text to include for adding a title.
46265 onResize : function(){
46266 Roo.form.Field.superclass.onResize.apply(this, arguments);
46269 initEvents : function(){
46270 // Roo.form.Checkbox.superclass.initEvents.call(this);
46271 // has no events...
46276 getResizeEl : function(){
46280 getPositionEl : function(){
46285 onRender : function(ct, position){
46287 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
46288 var style = this.style;
46291 Roo.form.GridField.superclass.onRender.call(this, ct, position);
46292 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
46293 this.viewEl = this.wrap.createChild({ tag: 'div' });
46295 this.viewEl.applyStyles(style);
46298 this.viewEl.setWidth(this.width);
46301 this.viewEl.setHeight(this.height);
46303 //if(this.inputValue !== undefined){
46304 //this.setValue(this.value);
46307 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
46310 this.grid.render();
46311 this.grid.getDataSource().on('remove', this.refreshValue, this);
46312 this.grid.getDataSource().on('update', this.refreshValue, this);
46313 this.grid.on('afteredit', this.refreshValue, this);
46319 * Sets the value of the item.
46320 * @param {String} either an object or a string..
46322 setValue : function(v){
46324 v = v || []; // empty set..
46325 // this does not seem smart - it really only affects memoryproxy grids..
46326 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
46327 var ds = this.grid.getDataSource();
46328 // assumes a json reader..
46330 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
46331 ds.loadData( data);
46333 // clear selection so it does not get stale.
46334 if (this.grid.sm) {
46335 this.grid.sm.clearSelections();
46338 Roo.form.GridField.superclass.setValue.call(this, v);
46339 this.refreshValue();
46340 // should load data in the grid really....
46344 refreshValue: function() {
46346 this.grid.getDataSource().each(function(r) {
46349 this.el.dom.value = Roo.encode(val);
46357 * Ext JS Library 1.1.1
46358 * Copyright(c) 2006-2007, Ext JS, LLC.
46360 * Originally Released Under LGPL - original licence link has changed is not relivant.
46363 * <script type="text/javascript">
46366 * @class Roo.form.DisplayField
46367 * @extends Roo.form.Field
46368 * A generic Field to display non-editable data.
46370 * Creates a new Display Field item.
46371 * @param {Object} config Configuration options
46373 Roo.form.DisplayField = function(config){
46374 Roo.form.DisplayField.superclass.constructor.call(this, config);
46378 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
46379 inputType: 'hidden',
46385 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46387 focusClass : undefined,
46389 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46391 fieldClass: 'x-form-field',
46394 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
46396 valueRenderer: undefined,
46400 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46401 * {tag: "input", type: "checkbox", autocomplete: "off"})
46404 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46406 onResize : function(){
46407 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
46411 initEvents : function(){
46412 // Roo.form.Checkbox.superclass.initEvents.call(this);
46413 // has no events...
46418 getResizeEl : function(){
46422 getPositionEl : function(){
46427 onRender : function(ct, position){
46429 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
46430 //if(this.inputValue !== undefined){
46431 this.wrap = this.el.wrap();
46433 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
46435 if (this.bodyStyle) {
46436 this.viewEl.applyStyles(this.bodyStyle);
46438 //this.viewEl.setStyle('padding', '2px');
46440 this.setValue(this.value);
46445 initValue : Roo.emptyFn,
46450 onClick : function(){
46455 * Sets the checked state of the checkbox.
46456 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
46458 setValue : function(v){
46460 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
46461 // this might be called before we have a dom element..
46462 if (!this.viewEl) {
46465 this.viewEl.dom.innerHTML = html;
46466 Roo.form.DisplayField.superclass.setValue.call(this, v);
46476 * @class Roo.form.DayPicker
46477 * @extends Roo.form.Field
46478 * A Day picker show [M] [T] [W] ....
46480 * Creates a new Day Picker
46481 * @param {Object} config Configuration options
46483 Roo.form.DayPicker= function(config){
46484 Roo.form.DayPicker.superclass.constructor.call(this, config);
46488 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
46490 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46492 focusClass : undefined,
46494 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46496 fieldClass: "x-form-field",
46499 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46500 * {tag: "input", type: "checkbox", autocomplete: "off"})
46502 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
46505 actionMode : 'viewEl',
46509 inputType : 'hidden',
46512 inputElement: false, // real input element?
46513 basedOn: false, // ????
46515 isFormField: true, // not sure where this is needed!!!!
46517 onResize : function(){
46518 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
46519 if(!this.boxLabel){
46520 this.el.alignTo(this.wrap, 'c-c');
46524 initEvents : function(){
46525 Roo.form.Checkbox.superclass.initEvents.call(this);
46526 this.el.on("click", this.onClick, this);
46527 this.el.on("change", this.onClick, this);
46531 getResizeEl : function(){
46535 getPositionEl : function(){
46541 onRender : function(ct, position){
46542 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
46544 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
46546 var r1 = '<table><tr>';
46547 var r2 = '<tr class="x-form-daypick-icons">';
46548 for (var i=0; i < 7; i++) {
46549 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
46550 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
46553 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
46554 viewEl.select('img').on('click', this.onClick, this);
46555 this.viewEl = viewEl;
46558 // this will not work on Chrome!!!
46559 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
46560 this.el.on('propertychange', this.setFromHidden, this); //ie
46568 initValue : Roo.emptyFn,
46571 * Returns the checked state of the checkbox.
46572 * @return {Boolean} True if checked, else false
46574 getValue : function(){
46575 return this.el.dom.value;
46580 onClick : function(e){
46581 //this.setChecked(!this.checked);
46582 Roo.get(e.target).toggleClass('x-menu-item-checked');
46583 this.refreshValue();
46584 //if(this.el.dom.checked != this.checked){
46585 // this.setValue(this.el.dom.checked);
46590 refreshValue : function()
46593 this.viewEl.select('img',true).each(function(e,i,n) {
46594 val += e.is(".x-menu-item-checked") ? String(n) : '';
46596 this.setValue(val, true);
46600 * Sets the checked state of the checkbox.
46601 * On is always based on a string comparison between inputValue and the param.
46602 * @param {Boolean/String} value - the value to set
46603 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
46605 setValue : function(v,suppressEvent){
46606 if (!this.el.dom) {
46609 var old = this.el.dom.value ;
46610 this.el.dom.value = v;
46611 if (suppressEvent) {
46615 // update display..
46616 this.viewEl.select('img',true).each(function(e,i,n) {
46618 var on = e.is(".x-menu-item-checked");
46619 var newv = v.indexOf(String(n)) > -1;
46621 e.toggleClass('x-menu-item-checked');
46627 this.fireEvent('change', this, v, old);
46632 // handle setting of hidden value by some other method!!?!?
46633 setFromHidden: function()
46638 //console.log("SET FROM HIDDEN");
46639 //alert('setFrom hidden');
46640 this.setValue(this.el.dom.value);
46643 onDestroy : function()
46646 Roo.get(this.viewEl).remove();
46649 Roo.form.DayPicker.superclass.onDestroy.call(this);
46653 * RooJS Library 1.1.1
46654 * Copyright(c) 2008-2011 Alan Knowles
46661 * @class Roo.form.ComboCheck
46662 * @extends Roo.form.ComboBox
46663 * A combobox for multiple select items.
46665 * FIXME - could do with a reset button..
46668 * Create a new ComboCheck
46669 * @param {Object} config Configuration options
46671 Roo.form.ComboCheck = function(config){
46672 Roo.form.ComboCheck.superclass.constructor.call(this, config);
46673 // should verify some data...
46675 // hiddenName = required..
46676 // displayField = required
46677 // valudField == required
46678 var req= [ 'hiddenName', 'displayField', 'valueField' ];
46680 Roo.each(req, function(e) {
46681 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
46682 throw "Roo.form.ComboCheck : missing value for: " + e;
46689 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
46694 selectedClass: 'x-menu-item-checked',
46697 onRender : function(ct, position){
46703 var cls = 'x-combo-list';
46706 this.tpl = new Roo.Template({
46707 html : '<div class="'+cls+'-item x-menu-check-item">' +
46708 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
46709 '<span>{' + this.displayField + '}</span>' +
46716 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
46717 this.view.singleSelect = false;
46718 this.view.multiSelect = true;
46719 this.view.toggleSelect = true;
46720 this.pageTb.add(new Roo.Toolbar.Fill(), {
46723 handler: function()
46730 onViewOver : function(e, t){
46736 onViewClick : function(doFocus,index){
46740 select: function () {
46741 //Roo.log("SELECT CALLED");
46744 selectByValue : function(xv, scrollIntoView){
46745 var ar = this.getValueArray();
46748 Roo.each(ar, function(v) {
46749 if(v === undefined || v === null){
46752 var r = this.findRecord(this.valueField, v);
46754 sels.push(this.store.indexOf(r))
46758 this.view.select(sels);
46764 onSelect : function(record, index){
46765 // Roo.log("onselect Called");
46766 // this is only called by the clear button now..
46767 this.view.clearSelections();
46768 this.setValue('[]');
46769 if (this.value != this.valueBefore) {
46770 this.fireEvent('change', this, this.value, this.valueBefore);
46771 this.valueBefore = this.value;
46774 getValueArray : function()
46779 //Roo.log(this.value);
46780 if (typeof(this.value) == 'undefined') {
46783 var ar = Roo.decode(this.value);
46784 return ar instanceof Array ? ar : []; //?? valid?
46787 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
46792 expand : function ()
46795 Roo.form.ComboCheck.superclass.expand.call(this);
46796 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
46797 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
46802 collapse : function(){
46803 Roo.form.ComboCheck.superclass.collapse.call(this);
46804 var sl = this.view.getSelectedIndexes();
46805 var st = this.store;
46809 Roo.each(sl, function(i) {
46811 nv.push(r.get(this.valueField));
46813 this.setValue(Roo.encode(nv));
46814 if (this.value != this.valueBefore) {
46816 this.fireEvent('change', this, this.value, this.valueBefore);
46817 this.valueBefore = this.value;
46822 setValue : function(v){
46826 var vals = this.getValueArray();
46828 Roo.each(vals, function(k) {
46829 var r = this.findRecord(this.valueField, k);
46831 tv.push(r.data[this.displayField]);
46832 }else if(this.valueNotFoundText !== undefined){
46833 tv.push( this.valueNotFoundText );
46838 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
46839 this.hiddenField.value = v;
46845 * Ext JS Library 1.1.1
46846 * Copyright(c) 2006-2007, Ext JS, LLC.
46848 * Originally Released Under LGPL - original licence link has changed is not relivant.
46851 * <script type="text/javascript">
46855 * @class Roo.form.Signature
46856 * @extends Roo.form.Field
46860 * @param {Object} config Configuration options
46863 Roo.form.Signature = function(config){
46864 Roo.form.Signature.superclass.constructor.call(this, config);
46866 this.addEvents({// not in used??
46869 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
46870 * @param {Roo.form.Signature} combo This combo box
46875 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
46876 * @param {Roo.form.ComboBox} combo This combo box
46877 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
46883 Roo.extend(Roo.form.Signature, Roo.form.Field, {
46885 * @cfg {Object} labels Label to use when rendering a form.
46889 * confirm : "Confirm"
46894 confirm : "Confirm"
46897 * @cfg {Number} width The signature panel width (defaults to 300)
46901 * @cfg {Number} height The signature panel height (defaults to 100)
46905 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
46907 allowBlank : false,
46910 // {Object} signPanel The signature SVG panel element (defaults to {})
46912 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
46913 isMouseDown : false,
46914 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
46915 isConfirmed : false,
46916 // {String} signatureTmp SVG mapping string (defaults to empty string)
46920 defaultAutoCreate : { // modified by initCompnoent..
46926 onRender : function(ct, position){
46928 Roo.form.Signature.superclass.onRender.call(this, ct, position);
46930 this.wrap = this.el.wrap({
46931 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
46934 this.createToolbar(this);
46935 this.signPanel = this.wrap.createChild({
46937 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
46941 this.svgID = Roo.id();
46942 this.svgEl = this.signPanel.createChild({
46943 xmlns : 'http://www.w3.org/2000/svg',
46945 id : this.svgID + "-svg",
46947 height: this.height,
46948 viewBox: '0 0 '+this.width+' '+this.height,
46952 id: this.svgID + "-svg-r",
46954 height: this.height,
46959 id: this.svgID + "-svg-l",
46961 y1: (this.height*0.8), // start set the line in 80% of height
46962 x2: this.width, // end
46963 y2: (this.height*0.8), // end set the line in 80% of height
46965 'stroke-width': "1",
46966 'stroke-dasharray': "3",
46967 'shape-rendering': "crispEdges",
46968 'pointer-events': "none"
46972 id: this.svgID + "-svg-p",
46974 'stroke-width': "3",
46976 'pointer-events': 'none'
46981 this.svgBox = this.svgEl.dom.getScreenCTM();
46983 createSVG : function(){
46984 var svg = this.signPanel;
46985 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
46988 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
46989 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
46990 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
46991 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
46992 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
46993 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
46994 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
46997 isTouchEvent : function(e){
46998 return e.type.match(/^touch/);
47000 getCoords : function (e) {
47001 var pt = this.svgEl.dom.createSVGPoint();
47004 if (this.isTouchEvent(e)) {
47005 pt.x = e.targetTouches[0].clientX
47006 pt.y = e.targetTouches[0].clientY;
47008 var a = this.svgEl.dom.getScreenCTM();
47009 var b = a.inverse();
47010 var mx = pt.matrixTransform(b);
47011 return mx.x + ',' + mx.y;
47013 //mouse event headler
47014 down : function (e) {
47015 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47016 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47018 this.isMouseDown = true;
47020 e.preventDefault();
47022 move : function (e) {
47023 if (this.isMouseDown) {
47024 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47025 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47028 e.preventDefault();
47030 up : function (e) {
47031 this.isMouseDown = false;
47032 var sp = this.signatureTmp.split(' ');
47035 if(!sp[sp.length-2].match(/^L/)){
47039 this.signatureTmp = sp.join(" ");
47042 if(this.getValue() != this.signatureTmp){
47043 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47044 this.isConfirmed = false;
47046 e.preventDefault();
47050 * Protected method that will not generally be called directly. It
47051 * is called when the editor creates its toolbar. Override this method if you need to
47052 * add custom toolbar buttons.
47053 * @param {HtmlEditor} editor
47055 createToolbar : function(editor){
47056 function btn(id, toggle, handler){
47057 var xid = fid + '-'+ id ;
47061 cls : 'x-btn-icon x-edit-'+id,
47062 enableToggle:toggle !== false,
47063 scope: editor, // was editor...
47064 handler:handler||editor.relayBtnCmd,
47065 clickEvent:'mousedown',
47066 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47072 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47076 cls : ' x-signature-btn x-signature-'+id,
47077 scope: editor, // was editor...
47078 handler: this.reset,
47079 clickEvent:'mousedown',
47080 text: this.labels.clear
47087 cls : ' x-signature-btn x-signature-'+id,
47088 scope: editor, // was editor...
47089 handler: this.confirmHandler,
47090 clickEvent:'mousedown',
47091 text: this.labels.confirm
47098 * when user is clicked confirm then show this image.....
47100 * @return {String} Image Data URI
47102 getImageDataURI : function(){
47103 var svg = this.svgEl.dom.parentNode.innerHTML;
47104 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47109 * @return {Boolean} this.isConfirmed
47111 getConfirmed : function(){
47112 return this.isConfirmed;
47116 * @return {Number} this.width
47118 getWidth : function(){
47123 * @return {Number} this.height
47125 getHeight : function(){
47126 return this.height;
47129 getSignature : function(){
47130 return this.signatureTmp;
47133 reset : function(){
47134 this.signatureTmp = '';
47135 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47136 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
47137 this.isConfirmed = false;
47138 Roo.form.Signature.superclass.reset.call(this);
47140 setSignature : function(s){
47141 this.signatureTmp = s;
47142 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47143 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
47145 this.isConfirmed = false;
47146 Roo.form.Signature.superclass.reset.call(this);
47149 // Roo.log(this.signPanel.dom.contentWindow.up())
47152 setConfirmed : function(){
47156 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
47159 confirmHandler : function(){
47160 if(!this.getSignature()){
47164 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
47165 this.setValue(this.getSignature());
47166 this.isConfirmed = true;
47168 this.fireEvent('confirm', this);
47171 // Subclasses should provide the validation implementation by overriding this
47172 validateValue : function(value){
47173 if(this.allowBlank){
47177 if(this.isConfirmed){
47184 * Ext JS Library 1.1.1
47185 * Copyright(c) 2006-2007, Ext JS, LLC.
47187 * Originally Released Under LGPL - original licence link has changed is not relivant.
47190 * <script type="text/javascript">
47195 * @class Roo.form.ComboBox
47196 * @extends Roo.form.TriggerField
47197 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
47199 * Create a new ComboBox.
47200 * @param {Object} config Configuration options
47202 Roo.form.Select = function(config){
47203 Roo.form.Select.superclass.constructor.call(this, config);
47207 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
47209 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
47212 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
47213 * rendering into an Roo.Editor, defaults to false)
47216 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
47217 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
47220 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
47223 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
47224 * the dropdown list (defaults to undefined, with no header element)
47228 * @cfg {String/Roo.Template} tpl The template to use to render the output
47232 defaultAutoCreate : {tag: "select" },
47234 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
47236 listWidth: undefined,
47238 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
47239 * mode = 'remote' or 'text' if mode = 'local')
47241 displayField: undefined,
47243 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
47244 * mode = 'remote' or 'value' if mode = 'local').
47245 * Note: use of a valueField requires the user make a selection
47246 * in order for a value to be mapped.
47248 valueField: undefined,
47252 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
47253 * field's data value (defaults to the underlying DOM element's name)
47255 hiddenName: undefined,
47257 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
47261 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
47263 selectedClass: 'x-combo-selected',
47265 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
47266 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
47267 * which displays a downward arrow icon).
47269 triggerClass : 'x-form-arrow-trigger',
47271 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
47275 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
47276 * anchor positions (defaults to 'tl-bl')
47278 listAlign: 'tl-bl?',
47280 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
47284 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
47285 * query specified by the allQuery config option (defaults to 'query')
47287 triggerAction: 'query',
47289 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
47290 * (defaults to 4, does not apply if editable = false)
47294 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
47295 * delay (typeAheadDelay) if it matches a known value (defaults to false)
47299 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
47300 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
47304 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
47305 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
47309 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
47310 * when editable = true (defaults to false)
47312 selectOnFocus:false,
47314 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
47316 queryParam: 'query',
47318 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
47319 * when mode = 'remote' (defaults to 'Loading...')
47321 loadingText: 'Loading...',
47323 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
47327 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
47331 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
47332 * traditional select (defaults to true)
47336 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
47340 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
47344 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
47345 * listWidth has a higher value)
47349 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
47350 * allow the user to set arbitrary text into the field (defaults to false)
47352 forceSelection:false,
47354 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
47355 * if typeAhead = true (defaults to 250)
47357 typeAheadDelay : 250,
47359 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
47360 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
47362 valueNotFoundText : undefined,
47365 * @cfg {String} defaultValue The value displayed after loading the store.
47370 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
47372 blockFocus : false,
47375 * @cfg {Boolean} disableClear Disable showing of clear button.
47377 disableClear : false,
47379 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
47381 alwaysQuery : false,
47387 // element that contains real text value.. (when hidden is used..)
47390 onRender : function(ct, position){
47391 Roo.form.Field.prototype.onRender.call(this, ct, position);
47394 this.store.on('beforeload', this.onBeforeLoad, this);
47395 this.store.on('load', this.onLoad, this);
47396 this.store.on('loadexception', this.onLoadException, this);
47397 this.store.load({});
47405 initEvents : function(){
47406 //Roo.form.ComboBox.superclass.initEvents.call(this);
47410 onDestroy : function(){
47413 this.store.un('beforeload', this.onBeforeLoad, this);
47414 this.store.un('load', this.onLoad, this);
47415 this.store.un('loadexception', this.onLoadException, this);
47417 //Roo.form.ComboBox.superclass.onDestroy.call(this);
47421 fireKey : function(e){
47422 if(e.isNavKeyPress() && !this.list.isVisible()){
47423 this.fireEvent("specialkey", this, e);
47428 onResize: function(w, h){
47436 * Allow or prevent the user from directly editing the field text. If false is passed,
47437 * the user will only be able to select from the items defined in the dropdown list. This method
47438 * is the runtime equivalent of setting the 'editable' config option at config time.
47439 * @param {Boolean} value True to allow the user to directly edit the field text
47441 setEditable : function(value){
47446 onBeforeLoad : function(){
47448 Roo.log("Select before load");
47451 this.innerList.update(this.loadingText ?
47452 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
47453 //this.restrictHeight();
47454 this.selectedIndex = -1;
47458 onLoad : function(){
47461 var dom = this.el.dom;
47462 dom.innerHTML = '';
47463 var od = dom.ownerDocument;
47465 if (this.emptyText) {
47466 var op = od.createElement('option');
47467 op.setAttribute('value', '');
47468 op.innerHTML = String.format('{0}', this.emptyText);
47469 dom.appendChild(op);
47471 if(this.store.getCount() > 0){
47473 var vf = this.valueField;
47474 var df = this.displayField;
47475 this.store.data.each(function(r) {
47476 // which colmsn to use... testing - cdoe / title..
47477 var op = od.createElement('option');
47478 op.setAttribute('value', r.data[vf]);
47479 op.innerHTML = String.format('{0}', r.data[df]);
47480 dom.appendChild(op);
47482 if (typeof(this.defaultValue != 'undefined')) {
47483 this.setValue(this.defaultValue);
47488 //this.onEmptyResults();
47493 onLoadException : function()
47495 dom.innerHTML = '';
47497 Roo.log("Select on load exception");
47501 Roo.log(this.store.reader.jsonData);
47502 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
47503 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
47509 onTypeAhead : function(){
47514 onSelect : function(record, index){
47515 Roo.log('on select?');
47517 if(this.fireEvent('beforeselect', this, record, index) !== false){
47518 this.setFromData(index > -1 ? record.data : false);
47520 this.fireEvent('select', this, record, index);
47525 * Returns the currently selected field value or empty string if no value is set.
47526 * @return {String} value The selected value
47528 getValue : function(){
47529 var dom = this.el.dom;
47530 this.value = dom.options[dom.selectedIndex].value;
47536 * Clears any text/value currently set in the field
47538 clearValue : function(){
47540 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
47545 * Sets the specified value into the field. If the value finds a match, the corresponding record text
47546 * will be displayed in the field. If the value does not match the data value of an existing item,
47547 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
47548 * Otherwise the field will be blank (although the value will still be set).
47549 * @param {String} value The value to match
47551 setValue : function(v){
47552 var d = this.el.dom;
47553 for (var i =0; i < d.options.length;i++) {
47554 if (v == d.options[i].value) {
47555 d.selectedIndex = i;
47563 * @property {Object} the last set data for the element
47568 * Sets the value of the field based on a object which is related to the record format for the store.
47569 * @param {Object} value the value to set as. or false on reset?
47571 setFromData : function(o){
47572 Roo.log('setfrom data?');
47578 reset : function(){
47582 findRecord : function(prop, value){
47587 if(this.store.getCount() > 0){
47588 this.store.each(function(r){
47589 if(r.data[prop] == value){
47599 getName: function()
47601 // returns hidden if it's set..
47602 if (!this.rendered) {return ''};
47603 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
47611 onEmptyResults : function(){
47612 Roo.log('empty results');
47617 * Returns true if the dropdown list is expanded, else false.
47619 isExpanded : function(){
47624 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
47625 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47626 * @param {String} value The data value of the item to select
47627 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47628 * selected item if it is not currently in view (defaults to true)
47629 * @return {Boolean} True if the value matched an item in the list, else false
47631 selectByValue : function(v, scrollIntoView){
47632 Roo.log('select By Value');
47635 if(v !== undefined && v !== null){
47636 var r = this.findRecord(this.valueField || this.displayField, v);
47638 this.select(this.store.indexOf(r), scrollIntoView);
47646 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
47647 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47648 * @param {Number} index The zero-based index of the list item to select
47649 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47650 * selected item if it is not currently in view (defaults to true)
47652 select : function(index, scrollIntoView){
47653 Roo.log('select ');
47656 this.selectedIndex = index;
47657 this.view.select(index);
47658 if(scrollIntoView !== false){
47659 var el = this.view.getNode(index);
47661 this.innerList.scrollChildIntoView(el, false);
47669 validateBlur : function(){
47676 initQuery : function(){
47677 this.doQuery(this.getRawValue());
47681 doForce : function(){
47682 if(this.el.dom.value.length > 0){
47683 this.el.dom.value =
47684 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
47690 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
47691 * query allowing the query action to be canceled if needed.
47692 * @param {String} query The SQL query to execute
47693 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
47694 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
47695 * saved in the current store (defaults to false)
47697 doQuery : function(q, forceAll){
47699 Roo.log('doQuery?');
47700 if(q === undefined || q === null){
47705 forceAll: forceAll,
47709 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
47713 forceAll = qe.forceAll;
47714 if(forceAll === true || (q.length >= this.minChars)){
47715 if(this.lastQuery != q || this.alwaysQuery){
47716 this.lastQuery = q;
47717 if(this.mode == 'local'){
47718 this.selectedIndex = -1;
47720 this.store.clearFilter();
47722 this.store.filter(this.displayField, q);
47726 this.store.baseParams[this.queryParam] = q;
47728 params: this.getParams(q)
47733 this.selectedIndex = -1;
47740 getParams : function(q){
47742 //p[this.queryParam] = q;
47745 p.limit = this.pageSize;
47751 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
47753 collapse : function(){
47758 collapseIf : function(e){
47763 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
47765 expand : function(){
47773 * @cfg {Boolean} grow
47777 * @cfg {Number} growMin
47781 * @cfg {Number} growMax
47789 setWidth : function()
47793 getResizeEl : function(){
47796 });//<script type="text/javasscript">
47800 * @class Roo.DDView
47801 * A DnD enabled version of Roo.View.
47802 * @param {Element/String} container The Element in which to create the View.
47803 * @param {String} tpl The template string used to create the markup for each element of the View
47804 * @param {Object} config The configuration properties. These include all the config options of
47805 * {@link Roo.View} plus some specific to this class.<br>
47807 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
47808 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
47810 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
47811 .x-view-drag-insert-above {
47812 border-top:1px dotted #3366cc;
47814 .x-view-drag-insert-below {
47815 border-bottom:1px dotted #3366cc;
47821 Roo.DDView = function(container, tpl, config) {
47822 Roo.DDView.superclass.constructor.apply(this, arguments);
47823 this.getEl().setStyle("outline", "0px none");
47824 this.getEl().unselectable();
47825 if (this.dragGroup) {
47826 this.setDraggable(this.dragGroup.split(","));
47828 if (this.dropGroup) {
47829 this.setDroppable(this.dropGroup.split(","));
47831 if (this.deletable) {
47832 this.setDeletable();
47834 this.isDirtyFlag = false;
47840 Roo.extend(Roo.DDView, Roo.View, {
47841 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
47842 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
47843 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
47844 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
47848 reset: Roo.emptyFn,
47850 clearInvalid: Roo.form.Field.prototype.clearInvalid,
47852 validate: function() {
47856 destroy: function() {
47857 this.purgeListeners();
47858 this.getEl.removeAllListeners();
47859 this.getEl().remove();
47860 if (this.dragZone) {
47861 if (this.dragZone.destroy) {
47862 this.dragZone.destroy();
47865 if (this.dropZone) {
47866 if (this.dropZone.destroy) {
47867 this.dropZone.destroy();
47872 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
47873 getName: function() {
47877 /** Loads the View from a JSON string representing the Records to put into the Store. */
47878 setValue: function(v) {
47880 throw "DDView.setValue(). DDView must be constructed with a valid Store";
47883 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
47884 this.store.proxy = new Roo.data.MemoryProxy(data);
47888 /** @return {String} a parenthesised list of the ids of the Records in the View. */
47889 getValue: function() {
47891 this.store.each(function(rec) {
47892 result += rec.id + ',';
47894 return result.substr(0, result.length - 1) + ')';
47897 getIds: function() {
47898 var i = 0, result = new Array(this.store.getCount());
47899 this.store.each(function(rec) {
47900 result[i++] = rec.id;
47905 isDirty: function() {
47906 return this.isDirtyFlag;
47910 * Part of the Roo.dd.DropZone interface. If no target node is found, the
47911 * whole Element becomes the target, and this causes the drop gesture to append.
47913 getTargetFromEvent : function(e) {
47914 var target = e.getTarget();
47915 while ((target !== null) && (target.parentNode != this.el.dom)) {
47916 target = target.parentNode;
47919 target = this.el.dom.lastChild || this.el.dom;
47925 * Create the drag data which consists of an object which has the property "ddel" as
47926 * the drag proxy element.
47928 getDragData : function(e) {
47929 var target = this.findItemFromChild(e.getTarget());
47931 this.handleSelection(e);
47932 var selNodes = this.getSelectedNodes();
47935 copy: this.copy || (this.allowCopy && e.ctrlKey),
47939 var selectedIndices = this.getSelectedIndexes();
47940 for (var i = 0; i < selectedIndices.length; i++) {
47941 dragData.records.push(this.store.getAt(selectedIndices[i]));
47943 if (selNodes.length == 1) {
47944 dragData.ddel = target.cloneNode(true); // the div element
47946 var div = document.createElement('div'); // create the multi element drag "ghost"
47947 div.className = 'multi-proxy';
47948 for (var i = 0, len = selNodes.length; i < len; i++) {
47949 div.appendChild(selNodes[i].cloneNode(true));
47951 dragData.ddel = div;
47953 //console.log(dragData)
47954 //console.log(dragData.ddel.innerHTML)
47957 //console.log('nodragData')
47961 /** Specify to which ddGroup items in this DDView may be dragged. */
47962 setDraggable: function(ddGroup) {
47963 if (ddGroup instanceof Array) {
47964 Roo.each(ddGroup, this.setDraggable, this);
47967 if (this.dragZone) {
47968 this.dragZone.addToGroup(ddGroup);
47970 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
47971 containerScroll: true,
47975 // Draggability implies selection. DragZone's mousedown selects the element.
47976 if (!this.multiSelect) { this.singleSelect = true; }
47978 // Wire the DragZone's handlers up to methods in *this*
47979 this.dragZone.getDragData = this.getDragData.createDelegate(this);
47983 /** Specify from which ddGroup this DDView accepts drops. */
47984 setDroppable: function(ddGroup) {
47985 if (ddGroup instanceof Array) {
47986 Roo.each(ddGroup, this.setDroppable, this);
47989 if (this.dropZone) {
47990 this.dropZone.addToGroup(ddGroup);
47992 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
47993 containerScroll: true,
47997 // Wire the DropZone's handlers up to methods in *this*
47998 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
47999 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48000 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48001 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48002 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48006 /** Decide whether to drop above or below a View node. */
48007 getDropPoint : function(e, n, dd){
48008 if (n == this.el.dom) { return "above"; }
48009 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48010 var c = t + (b - t) / 2;
48011 var y = Roo.lib.Event.getPageY(e);
48019 onNodeEnter : function(n, dd, e, data){
48023 onNodeOver : function(n, dd, e, data){
48024 var pt = this.getDropPoint(e, n, dd);
48025 // set the insert point style on the target node
48026 var dragElClass = this.dropNotAllowed;
48029 if (pt == "above"){
48030 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48031 targetElClass = "x-view-drag-insert-above";
48033 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48034 targetElClass = "x-view-drag-insert-below";
48036 if (this.lastInsertClass != targetElClass){
48037 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48038 this.lastInsertClass = targetElClass;
48041 return dragElClass;
48044 onNodeOut : function(n, dd, e, data){
48045 this.removeDropIndicators(n);
48048 onNodeDrop : function(n, dd, e, data){
48049 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48052 var pt = this.getDropPoint(e, n, dd);
48053 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48054 if (pt == "below") { insertAt++; }
48055 for (var i = 0; i < data.records.length; i++) {
48056 var r = data.records[i];
48057 var dup = this.store.getById(r.id);
48058 if (dup && (dd != this.dragZone)) {
48059 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48062 this.store.insert(insertAt++, r.copy());
48064 data.source.isDirtyFlag = true;
48066 this.store.insert(insertAt++, r);
48068 this.isDirtyFlag = true;
48071 this.dragZone.cachedTarget = null;
48075 removeDropIndicators : function(n){
48077 Roo.fly(n).removeClass([
48078 "x-view-drag-insert-above",
48079 "x-view-drag-insert-below"]);
48080 this.lastInsertClass = "_noclass";
48085 * Utility method. Add a delete option to the DDView's context menu.
48086 * @param {String} imageUrl The URL of the "delete" icon image.
48088 setDeletable: function(imageUrl) {
48089 if (!this.singleSelect && !this.multiSelect) {
48090 this.singleSelect = true;
48092 var c = this.getContextMenu();
48093 this.contextMenu.on("itemclick", function(item) {
48096 this.remove(this.getSelectedIndexes());
48100 this.contextMenu.add({
48107 /** Return the context menu for this DDView. */
48108 getContextMenu: function() {
48109 if (!this.contextMenu) {
48110 // Create the View's context menu
48111 this.contextMenu = new Roo.menu.Menu({
48112 id: this.id + "-contextmenu"
48114 this.el.on("contextmenu", this.showContextMenu, this);
48116 return this.contextMenu;
48119 disableContextMenu: function() {
48120 if (this.contextMenu) {
48121 this.el.un("contextmenu", this.showContextMenu, this);
48125 showContextMenu: function(e, item) {
48126 item = this.findItemFromChild(e.getTarget());
48129 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
48130 this.contextMenu.showAt(e.getXY());
48135 * Remove {@link Roo.data.Record}s at the specified indices.
48136 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
48138 remove: function(selectedIndices) {
48139 selectedIndices = [].concat(selectedIndices);
48140 for (var i = 0; i < selectedIndices.length; i++) {
48141 var rec = this.store.getAt(selectedIndices[i]);
48142 this.store.remove(rec);
48147 * Double click fires the event, but also, if this is draggable, and there is only one other
48148 * related DropZone, it transfers the selected node.
48150 onDblClick : function(e){
48151 var item = this.findItemFromChild(e.getTarget());
48153 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
48156 if (this.dragGroup) {
48157 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
48158 while (targets.indexOf(this.dropZone) > -1) {
48159 targets.remove(this.dropZone);
48161 if (targets.length == 1) {
48162 this.dragZone.cachedTarget = null;
48163 var el = Roo.get(targets[0].getEl());
48164 var box = el.getBox(true);
48165 targets[0].onNodeDrop(el.dom, {
48167 xy: [box.x, box.y + box.height - 1]
48168 }, null, this.getDragData(e));
48174 handleSelection: function(e) {
48175 this.dragZone.cachedTarget = null;
48176 var item = this.findItemFromChild(e.getTarget());
48178 this.clearSelections(true);
48181 if (item && (this.multiSelect || this.singleSelect)){
48182 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
48183 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
48184 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
48185 this.unselect(item);
48187 this.select(item, this.multiSelect && e.ctrlKey);
48188 this.lastSelection = item;
48193 onItemClick : function(item, index, e){
48194 if(this.fireEvent("beforeclick", this, index, item, e) === false){
48200 unselect : function(nodeInfo, suppressEvent){
48201 var node = this.getNode(nodeInfo);
48202 if(node && this.isSelected(node)){
48203 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
48204 Roo.fly(node).removeClass(this.selectedClass);
48205 this.selections.remove(node);
48206 if(!suppressEvent){
48207 this.fireEvent("selectionchange", this, this.selections);
48215 * Ext JS Library 1.1.1
48216 * Copyright(c) 2006-2007, Ext JS, LLC.
48218 * Originally Released Under LGPL - original licence link has changed is not relivant.
48221 * <script type="text/javascript">
48225 * @class Roo.LayoutManager
48226 * @extends Roo.util.Observable
48227 * Base class for layout managers.
48229 Roo.LayoutManager = function(container, config){
48230 Roo.LayoutManager.superclass.constructor.call(this);
48231 this.el = Roo.get(container);
48232 // ie scrollbar fix
48233 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
48234 document.body.scroll = "no";
48235 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
48236 this.el.position('relative');
48238 this.id = this.el.id;
48239 this.el.addClass("x-layout-container");
48240 /** false to disable window resize monitoring @type Boolean */
48241 this.monitorWindowResize = true;
48246 * Fires when a layout is performed.
48247 * @param {Roo.LayoutManager} this
48251 * @event regionresized
48252 * Fires when the user resizes a region.
48253 * @param {Roo.LayoutRegion} region The resized region
48254 * @param {Number} newSize The new size (width for east/west, height for north/south)
48256 "regionresized" : true,
48258 * @event regioncollapsed
48259 * Fires when a region is collapsed.
48260 * @param {Roo.LayoutRegion} region The collapsed region
48262 "regioncollapsed" : true,
48264 * @event regionexpanded
48265 * Fires when a region is expanded.
48266 * @param {Roo.LayoutRegion} region The expanded region
48268 "regionexpanded" : true
48270 this.updating = false;
48271 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48274 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
48276 * Returns true if this layout is currently being updated
48277 * @return {Boolean}
48279 isUpdating : function(){
48280 return this.updating;
48284 * Suspend the LayoutManager from doing auto-layouts while
48285 * making multiple add or remove calls
48287 beginUpdate : function(){
48288 this.updating = true;
48292 * Restore auto-layouts and optionally disable the manager from performing a layout
48293 * @param {Boolean} noLayout true to disable a layout update
48295 endUpdate : function(noLayout){
48296 this.updating = false;
48302 layout: function(){
48306 onRegionResized : function(region, newSize){
48307 this.fireEvent("regionresized", region, newSize);
48311 onRegionCollapsed : function(region){
48312 this.fireEvent("regioncollapsed", region);
48315 onRegionExpanded : function(region){
48316 this.fireEvent("regionexpanded", region);
48320 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
48321 * performs box-model adjustments.
48322 * @return {Object} The size as an object {width: (the width), height: (the height)}
48324 getViewSize : function(){
48326 if(this.el.dom != document.body){
48327 size = this.el.getSize();
48329 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
48331 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
48332 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
48337 * Returns the Element this layout is bound to.
48338 * @return {Roo.Element}
48340 getEl : function(){
48345 * Returns the specified region.
48346 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
48347 * @return {Roo.LayoutRegion}
48349 getRegion : function(target){
48350 return this.regions[target.toLowerCase()];
48353 onWindowResize : function(){
48354 if(this.monitorWindowResize){
48360 * Ext JS Library 1.1.1
48361 * Copyright(c) 2006-2007, Ext JS, LLC.
48363 * Originally Released Under LGPL - original licence link has changed is not relivant.
48366 * <script type="text/javascript">
48369 * @class Roo.BorderLayout
48370 * @extends Roo.LayoutManager
48371 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
48372 * please see: <br><br>
48373 * <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>
48374 * <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>
48377 var layout = new Roo.BorderLayout(document.body, {
48411 preferredTabWidth: 150
48416 var CP = Roo.ContentPanel;
48418 layout.beginUpdate();
48419 layout.add("north", new CP("north", "North"));
48420 layout.add("south", new CP("south", {title: "South", closable: true}));
48421 layout.add("west", new CP("west", {title: "West"}));
48422 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
48423 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
48424 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
48425 layout.getRegion("center").showPanel("center1");
48426 layout.endUpdate();
48429 <b>The container the layout is rendered into can be either the body element or any other element.
48430 If it is not the body element, the container needs to either be an absolute positioned element,
48431 or you will need to add "position:relative" to the css of the container. You will also need to specify
48432 the container size if it is not the body element.</b>
48435 * Create a new BorderLayout
48436 * @param {String/HTMLElement/Element} container The container this layout is bound to
48437 * @param {Object} config Configuration options
48439 Roo.BorderLayout = function(container, config){
48440 config = config || {};
48441 Roo.BorderLayout.superclass.constructor.call(this, container, config);
48442 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
48443 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
48444 var target = this.factory.validRegions[i];
48445 if(config[target]){
48446 this.addRegion(target, config[target]);
48451 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
48453 * Creates and adds a new region if it doesn't already exist.
48454 * @param {String} target The target region key (north, south, east, west or center).
48455 * @param {Object} config The regions config object
48456 * @return {BorderLayoutRegion} The new region
48458 addRegion : function(target, config){
48459 if(!this.regions[target]){
48460 var r = this.factory.create(target, this, config);
48461 this.bindRegion(target, r);
48463 return this.regions[target];
48467 bindRegion : function(name, r){
48468 this.regions[name] = r;
48469 r.on("visibilitychange", this.layout, this);
48470 r.on("paneladded", this.layout, this);
48471 r.on("panelremoved", this.layout, this);
48472 r.on("invalidated", this.layout, this);
48473 r.on("resized", this.onRegionResized, this);
48474 r.on("collapsed", this.onRegionCollapsed, this);
48475 r.on("expanded", this.onRegionExpanded, this);
48479 * Performs a layout update.
48481 layout : function(){
48482 if(this.updating) return;
48483 var size = this.getViewSize();
48484 var w = size.width;
48485 var h = size.height;
48490 //var x = 0, y = 0;
48492 var rs = this.regions;
48493 var north = rs["north"];
48494 var south = rs["south"];
48495 var west = rs["west"];
48496 var east = rs["east"];
48497 var center = rs["center"];
48498 //if(this.hideOnLayout){ // not supported anymore
48499 //c.el.setStyle("display", "none");
48501 if(north && north.isVisible()){
48502 var b = north.getBox();
48503 var m = north.getMargins();
48504 b.width = w - (m.left+m.right);
48507 centerY = b.height + b.y + m.bottom;
48508 centerH -= centerY;
48509 north.updateBox(this.safeBox(b));
48511 if(south && south.isVisible()){
48512 var b = south.getBox();
48513 var m = south.getMargins();
48514 b.width = w - (m.left+m.right);
48516 var totalHeight = (b.height + m.top + m.bottom);
48517 b.y = h - totalHeight + m.top;
48518 centerH -= totalHeight;
48519 south.updateBox(this.safeBox(b));
48521 if(west && west.isVisible()){
48522 var b = west.getBox();
48523 var m = west.getMargins();
48524 b.height = centerH - (m.top+m.bottom);
48526 b.y = centerY + m.top;
48527 var totalWidth = (b.width + m.left + m.right);
48528 centerX += totalWidth;
48529 centerW -= totalWidth;
48530 west.updateBox(this.safeBox(b));
48532 if(east && east.isVisible()){
48533 var b = east.getBox();
48534 var m = east.getMargins();
48535 b.height = centerH - (m.top+m.bottom);
48536 var totalWidth = (b.width + m.left + m.right);
48537 b.x = w - totalWidth + m.left;
48538 b.y = centerY + m.top;
48539 centerW -= totalWidth;
48540 east.updateBox(this.safeBox(b));
48543 var m = center.getMargins();
48545 x: centerX + m.left,
48546 y: centerY + m.top,
48547 width: centerW - (m.left+m.right),
48548 height: centerH - (m.top+m.bottom)
48550 //if(this.hideOnLayout){
48551 //center.el.setStyle("display", "block");
48553 center.updateBox(this.safeBox(centerBox));
48556 this.fireEvent("layout", this);
48560 safeBox : function(box){
48561 box.width = Math.max(0, box.width);
48562 box.height = Math.max(0, box.height);
48567 * Adds a ContentPanel (or subclass) to this layout.
48568 * @param {String} target The target region key (north, south, east, west or center).
48569 * @param {Roo.ContentPanel} panel The panel to add
48570 * @return {Roo.ContentPanel} The added panel
48572 add : function(target, panel){
48574 target = target.toLowerCase();
48575 return this.regions[target].add(panel);
48579 * Remove a ContentPanel (or subclass) to this layout.
48580 * @param {String} target The target region key (north, south, east, west or center).
48581 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
48582 * @return {Roo.ContentPanel} The removed panel
48584 remove : function(target, panel){
48585 target = target.toLowerCase();
48586 return this.regions[target].remove(panel);
48590 * Searches all regions for a panel with the specified id
48591 * @param {String} panelId
48592 * @return {Roo.ContentPanel} The panel or null if it wasn't found
48594 findPanel : function(panelId){
48595 var rs = this.regions;
48596 for(var target in rs){
48597 if(typeof rs[target] != "function"){
48598 var p = rs[target].getPanel(panelId);
48608 * Searches all regions for a panel with the specified id and activates (shows) it.
48609 * @param {String/ContentPanel} panelId The panels id or the panel itself
48610 * @return {Roo.ContentPanel} The shown panel or null
48612 showPanel : function(panelId) {
48613 var rs = this.regions;
48614 for(var target in rs){
48615 var r = rs[target];
48616 if(typeof r != "function"){
48617 if(r.hasPanel(panelId)){
48618 return r.showPanel(panelId);
48626 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
48627 * @param {Roo.state.Provider} provider (optional) An alternate state provider
48629 restoreState : function(provider){
48631 provider = Roo.state.Manager;
48633 var sm = new Roo.LayoutStateManager();
48634 sm.init(this, provider);
48638 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
48639 * object should contain properties for each region to add ContentPanels to, and each property's value should be
48640 * a valid ContentPanel config object. Example:
48642 // Create the main layout
48643 var layout = new Roo.BorderLayout('main-ct', {
48654 // Create and add multiple ContentPanels at once via configs
48657 id: 'source-files',
48659 title:'Ext Source Files',
48672 * @param {Object} regions An object containing ContentPanel configs by region name
48674 batchAdd : function(regions){
48675 this.beginUpdate();
48676 for(var rname in regions){
48677 var lr = this.regions[rname];
48679 this.addTypedPanels(lr, regions[rname]);
48686 addTypedPanels : function(lr, ps){
48687 if(typeof ps == 'string'){
48688 lr.add(new Roo.ContentPanel(ps));
48690 else if(ps instanceof Array){
48691 for(var i =0, len = ps.length; i < len; i++){
48692 this.addTypedPanels(lr, ps[i]);
48695 else if(!ps.events){ // raw config?
48697 delete ps.el; // prevent conflict
48698 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
48700 else { // panel object assumed!
48705 * Adds a xtype elements to the layout.
48709 xtype : 'ContentPanel',
48716 xtype : 'NestedLayoutPanel',
48722 items : [ ... list of content panels or nested layout panels.. ]
48726 * @param {Object} cfg Xtype definition of item to add.
48728 addxtype : function(cfg)
48730 // basically accepts a pannel...
48731 // can accept a layout region..!?!?
48732 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
48734 if (!cfg.xtype.match(/Panel$/)) {
48739 if (typeof(cfg.region) == 'undefined') {
48740 Roo.log("Failed to add Panel, region was not set");
48744 var region = cfg.region;
48750 xitems = cfg.items;
48757 case 'ContentPanel': // ContentPanel (el, cfg)
48758 case 'ScrollPanel': // ContentPanel (el, cfg)
48760 if(cfg.autoCreate) {
48761 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48763 var el = this.el.createChild();
48764 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
48767 this.add(region, ret);
48771 case 'TreePanel': // our new panel!
48772 cfg.el = this.el.createChild();
48773 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48774 this.add(region, ret);
48777 case 'NestedLayoutPanel':
48778 // create a new Layout (which is a Border Layout...
48779 var el = this.el.createChild();
48780 var clayout = cfg.layout;
48782 clayout.items = clayout.items || [];
48783 // replace this exitems with the clayout ones..
48784 xitems = clayout.items;
48787 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
48788 cfg.background = false;
48790 var layout = new Roo.BorderLayout(el, clayout);
48792 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
48793 //console.log('adding nested layout panel ' + cfg.toSource());
48794 this.add(region, ret);
48795 nb = {}; /// find first...
48800 // needs grid and region
48802 //var el = this.getRegion(region).el.createChild();
48803 var el = this.el.createChild();
48804 // create the grid first...
48806 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
48808 if (region == 'center' && this.active ) {
48809 cfg.background = false;
48811 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
48813 this.add(region, ret);
48814 if (cfg.background) {
48815 ret.on('activate', function(gp) {
48816 if (!gp.grid.rendered) {
48831 if (typeof(Roo[cfg.xtype]) != 'undefined') {
48833 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48834 this.add(region, ret);
48837 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
48841 // GridPanel (grid, cfg)
48844 this.beginUpdate();
48848 Roo.each(xitems, function(i) {
48849 region = nb && i.region ? i.region : false;
48851 var add = ret.addxtype(i);
48854 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
48855 if (!i.background) {
48856 abn[region] = nb[region] ;
48863 // make the last non-background panel active..
48864 //if (nb) { Roo.log(abn); }
48867 for(var r in abn) {
48868 region = this.getRegion(r);
48870 // tried using nb[r], but it does not work..
48872 region.showPanel(abn[r]);
48883 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
48884 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
48885 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
48886 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
48889 var CP = Roo.ContentPanel;
48891 var layout = Roo.BorderLayout.create({
48895 panels: [new CP("north", "North")]
48904 panels: [new CP("west", {title: "West"})]
48913 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
48922 panels: [new CP("south", {title: "South", closable: true})]
48929 preferredTabWidth: 150,
48931 new CP("center1", {title: "Close Me", closable: true}),
48932 new CP("center2", {title: "Center Panel", closable: false})
48937 layout.getRegion("center").showPanel("center1");
48942 Roo.BorderLayout.create = function(config, targetEl){
48943 var layout = new Roo.BorderLayout(targetEl || document.body, config);
48944 layout.beginUpdate();
48945 var regions = Roo.BorderLayout.RegionFactory.validRegions;
48946 for(var j = 0, jlen = regions.length; j < jlen; j++){
48947 var lr = regions[j];
48948 if(layout.regions[lr] && config[lr].panels){
48949 var r = layout.regions[lr];
48950 var ps = config[lr].panels;
48951 layout.addTypedPanels(r, ps);
48954 layout.endUpdate();
48959 Roo.BorderLayout.RegionFactory = {
48961 validRegions : ["north","south","east","west","center"],
48964 create : function(target, mgr, config){
48965 target = target.toLowerCase();
48966 if(config.lightweight || config.basic){
48967 return new Roo.BasicLayoutRegion(mgr, config, target);
48971 return new Roo.NorthLayoutRegion(mgr, config);
48973 return new Roo.SouthLayoutRegion(mgr, config);
48975 return new Roo.EastLayoutRegion(mgr, config);
48977 return new Roo.WestLayoutRegion(mgr, config);
48979 return new Roo.CenterLayoutRegion(mgr, config);
48981 throw 'Layout region "'+target+'" not supported.';
48985 * Ext JS Library 1.1.1
48986 * Copyright(c) 2006-2007, Ext JS, LLC.
48988 * Originally Released Under LGPL - original licence link has changed is not relivant.
48991 * <script type="text/javascript">
48995 * @class Roo.BasicLayoutRegion
48996 * @extends Roo.util.Observable
48997 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
48998 * and does not have a titlebar, tabs or any other features. All it does is size and position
48999 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49001 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49003 this.position = pos;
49006 * @scope Roo.BasicLayoutRegion
49010 * @event beforeremove
49011 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49012 * @param {Roo.LayoutRegion} this
49013 * @param {Roo.ContentPanel} panel The panel
49014 * @param {Object} e The cancel event object
49016 "beforeremove" : true,
49018 * @event invalidated
49019 * Fires when the layout for this region is changed.
49020 * @param {Roo.LayoutRegion} this
49022 "invalidated" : true,
49024 * @event visibilitychange
49025 * Fires when this region is shown or hidden
49026 * @param {Roo.LayoutRegion} this
49027 * @param {Boolean} visibility true or false
49029 "visibilitychange" : true,
49031 * @event paneladded
49032 * Fires when a panel is added.
49033 * @param {Roo.LayoutRegion} this
49034 * @param {Roo.ContentPanel} panel The panel
49036 "paneladded" : true,
49038 * @event panelremoved
49039 * Fires when a panel is removed.
49040 * @param {Roo.LayoutRegion} this
49041 * @param {Roo.ContentPanel} panel The panel
49043 "panelremoved" : true,
49046 * Fires when this region is collapsed.
49047 * @param {Roo.LayoutRegion} this
49049 "collapsed" : true,
49052 * Fires when this region is expanded.
49053 * @param {Roo.LayoutRegion} this
49058 * Fires when this region is slid into view.
49059 * @param {Roo.LayoutRegion} this
49061 "slideshow" : true,
49064 * Fires when this region slides out of view.
49065 * @param {Roo.LayoutRegion} this
49067 "slidehide" : true,
49069 * @event panelactivated
49070 * Fires when a panel is activated.
49071 * @param {Roo.LayoutRegion} this
49072 * @param {Roo.ContentPanel} panel The activated panel
49074 "panelactivated" : true,
49077 * Fires when the user resizes this region.
49078 * @param {Roo.LayoutRegion} this
49079 * @param {Number} newSize The new size (width for east/west, height for north/south)
49083 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49084 this.panels = new Roo.util.MixedCollection();
49085 this.panels.getKey = this.getPanelId.createDelegate(this);
49087 this.activePanel = null;
49088 // ensure listeners are added...
49090 if (config.listeners || config.events) {
49091 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49092 listeners : config.listeners || {},
49093 events : config.events || {}
49097 if(skipConfig !== true){
49098 this.applyConfig(config);
49102 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49103 getPanelId : function(p){
49107 applyConfig : function(config){
49108 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49109 this.config = config;
49114 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49115 * the width, for horizontal (north, south) the height.
49116 * @param {Number} newSize The new width or height
49118 resizeTo : function(newSize){
49119 var el = this.el ? this.el :
49120 (this.activePanel ? this.activePanel.getEl() : null);
49122 switch(this.position){
49125 el.setWidth(newSize);
49126 this.fireEvent("resized", this, newSize);
49130 el.setHeight(newSize);
49131 this.fireEvent("resized", this, newSize);
49137 getBox : function(){
49138 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
49141 getMargins : function(){
49142 return this.margins;
49145 updateBox : function(box){
49147 var el = this.activePanel.getEl();
49148 el.dom.style.left = box.x + "px";
49149 el.dom.style.top = box.y + "px";
49150 this.activePanel.setSize(box.width, box.height);
49154 * Returns the container element for this region.
49155 * @return {Roo.Element}
49157 getEl : function(){
49158 return this.activePanel;
49162 * Returns true if this region is currently visible.
49163 * @return {Boolean}
49165 isVisible : function(){
49166 return this.activePanel ? true : false;
49169 setActivePanel : function(panel){
49170 panel = this.getPanel(panel);
49171 if(this.activePanel && this.activePanel != panel){
49172 this.activePanel.setActiveState(false);
49173 this.activePanel.getEl().setLeftTop(-10000,-10000);
49175 this.activePanel = panel;
49176 panel.setActiveState(true);
49178 panel.setSize(this.box.width, this.box.height);
49180 this.fireEvent("panelactivated", this, panel);
49181 this.fireEvent("invalidated");
49185 * Show the specified panel.
49186 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
49187 * @return {Roo.ContentPanel} The shown panel or null
49189 showPanel : function(panel){
49190 if(panel = this.getPanel(panel)){
49191 this.setActivePanel(panel);
49197 * Get the active panel for this region.
49198 * @return {Roo.ContentPanel} The active panel or null
49200 getActivePanel : function(){
49201 return this.activePanel;
49205 * Add the passed ContentPanel(s)
49206 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49207 * @return {Roo.ContentPanel} The panel added (if only one was added)
49209 add : function(panel){
49210 if(arguments.length > 1){
49211 for(var i = 0, len = arguments.length; i < len; i++) {
49212 this.add(arguments[i]);
49216 if(this.hasPanel(panel)){
49217 this.showPanel(panel);
49220 var el = panel.getEl();
49221 if(el.dom.parentNode != this.mgr.el.dom){
49222 this.mgr.el.dom.appendChild(el.dom);
49224 if(panel.setRegion){
49225 panel.setRegion(this);
49227 this.panels.add(panel);
49228 el.setStyle("position", "absolute");
49229 if(!panel.background){
49230 this.setActivePanel(panel);
49231 if(this.config.initialSize && this.panels.getCount()==1){
49232 this.resizeTo(this.config.initialSize);
49235 this.fireEvent("paneladded", this, panel);
49240 * Returns true if the panel is in this region.
49241 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49242 * @return {Boolean}
49244 hasPanel : function(panel){
49245 if(typeof panel == "object"){ // must be panel obj
49246 panel = panel.getId();
49248 return this.getPanel(panel) ? true : false;
49252 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49253 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49254 * @param {Boolean} preservePanel Overrides the config preservePanel option
49255 * @return {Roo.ContentPanel} The panel that was removed
49257 remove : function(panel, preservePanel){
49258 panel = this.getPanel(panel);
49263 this.fireEvent("beforeremove", this, panel, e);
49264 if(e.cancel === true){
49267 var panelId = panel.getId();
49268 this.panels.removeKey(panelId);
49273 * Returns the panel specified or null if it's not in this region.
49274 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49275 * @return {Roo.ContentPanel}
49277 getPanel : function(id){
49278 if(typeof id == "object"){ // must be panel obj
49281 return this.panels.get(id);
49285 * Returns this regions position (north/south/east/west/center).
49288 getPosition: function(){
49289 return this.position;
49293 * Ext JS Library 1.1.1
49294 * Copyright(c) 2006-2007, Ext JS, LLC.
49296 * Originally Released Under LGPL - original licence link has changed is not relivant.
49299 * <script type="text/javascript">
49303 * @class Roo.LayoutRegion
49304 * @extends Roo.BasicLayoutRegion
49305 * This class represents a region in a layout manager.
49306 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
49307 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
49308 * @cfg {Boolean} floatable False to disable floating (defaults to true)
49309 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
49310 * @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})
49311 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
49312 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
49313 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
49314 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
49315 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
49316 * @cfg {String} title The title for the region (overrides panel titles)
49317 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
49318 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
49319 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
49320 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
49321 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
49322 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
49323 * the space available, similar to FireFox 1.5 tabs (defaults to false)
49324 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
49325 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
49326 * @cfg {Boolean} showPin True to show a pin button
49327 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
49328 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
49329 * @cfg {Boolean} disableTabTips True to disable tab tooltips
49330 * @cfg {Number} width For East/West panels
49331 * @cfg {Number} height For North/South panels
49332 * @cfg {Boolean} split To show the splitter
49333 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
49335 Roo.LayoutRegion = function(mgr, config, pos){
49336 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
49337 var dh = Roo.DomHelper;
49338 /** This region's container element
49339 * @type Roo.Element */
49340 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
49341 /** This region's title element
49342 * @type Roo.Element */
49344 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
49345 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
49346 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
49348 this.titleEl.enableDisplayMode();
49349 /** This region's title text element
49350 * @type HTMLElement */
49351 this.titleTextEl = this.titleEl.dom.firstChild;
49352 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
49353 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
49354 this.closeBtn.enableDisplayMode();
49355 this.closeBtn.on("click", this.closeClicked, this);
49356 this.closeBtn.hide();
49358 this.createBody(config);
49359 this.visible = true;
49360 this.collapsed = false;
49362 if(config.hideWhenEmpty){
49364 this.on("paneladded", this.validateVisibility, this);
49365 this.on("panelremoved", this.validateVisibility, this);
49367 this.applyConfig(config);
49370 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
49372 createBody : function(){
49373 /** This region's body element
49374 * @type Roo.Element */
49375 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
49378 applyConfig : function(c){
49379 if(c.collapsible && this.position != "center" && !this.collapsedEl){
49380 var dh = Roo.DomHelper;
49381 if(c.titlebar !== false){
49382 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
49383 this.collapseBtn.on("click", this.collapse, this);
49384 this.collapseBtn.enableDisplayMode();
49386 if(c.showPin === true || this.showPin){
49387 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
49388 this.stickBtn.enableDisplayMode();
49389 this.stickBtn.on("click", this.expand, this);
49390 this.stickBtn.hide();
49393 /** This region's collapsed element
49394 * @type Roo.Element */
49395 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
49396 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
49398 if(c.floatable !== false){
49399 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
49400 this.collapsedEl.on("click", this.collapseClick, this);
49403 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
49404 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
49405 id: "message", unselectable: "on", style:{"float":"left"}});
49406 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
49408 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
49409 this.expandBtn.on("click", this.expand, this);
49411 if(this.collapseBtn){
49412 this.collapseBtn.setVisible(c.collapsible == true);
49414 this.cmargins = c.cmargins || this.cmargins ||
49415 (this.position == "west" || this.position == "east" ?
49416 {top: 0, left: 2, right:2, bottom: 0} :
49417 {top: 2, left: 0, right:0, bottom: 2});
49418 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49419 this.bottomTabs = c.tabPosition != "top";
49420 this.autoScroll = c.autoScroll || false;
49421 if(this.autoScroll){
49422 this.bodyEl.setStyle("overflow", "auto");
49424 this.bodyEl.setStyle("overflow", "hidden");
49426 //if(c.titlebar !== false){
49427 if((!c.titlebar && !c.title) || c.titlebar === false){
49428 this.titleEl.hide();
49430 this.titleEl.show();
49432 this.titleTextEl.innerHTML = c.title;
49436 this.duration = c.duration || .30;
49437 this.slideDuration = c.slideDuration || .45;
49440 this.collapse(true);
49447 * Returns true if this region is currently visible.
49448 * @return {Boolean}
49450 isVisible : function(){
49451 return this.visible;
49455 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
49456 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
49458 setCollapsedTitle : function(title){
49459 title = title || " ";
49460 if(this.collapsedTitleTextEl){
49461 this.collapsedTitleTextEl.innerHTML = title;
49465 getBox : function(){
49467 if(!this.collapsed){
49468 b = this.el.getBox(false, true);
49470 b = this.collapsedEl.getBox(false, true);
49475 getMargins : function(){
49476 return this.collapsed ? this.cmargins : this.margins;
49479 highlight : function(){
49480 this.el.addClass("x-layout-panel-dragover");
49483 unhighlight : function(){
49484 this.el.removeClass("x-layout-panel-dragover");
49487 updateBox : function(box){
49489 if(!this.collapsed){
49490 this.el.dom.style.left = box.x + "px";
49491 this.el.dom.style.top = box.y + "px";
49492 this.updateBody(box.width, box.height);
49494 this.collapsedEl.dom.style.left = box.x + "px";
49495 this.collapsedEl.dom.style.top = box.y + "px";
49496 this.collapsedEl.setSize(box.width, box.height);
49499 this.tabs.autoSizeTabs();
49503 updateBody : function(w, h){
49505 this.el.setWidth(w);
49506 w -= this.el.getBorderWidth("rl");
49507 if(this.config.adjustments){
49508 w += this.config.adjustments[0];
49512 this.el.setHeight(h);
49513 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
49514 h -= this.el.getBorderWidth("tb");
49515 if(this.config.adjustments){
49516 h += this.config.adjustments[1];
49518 this.bodyEl.setHeight(h);
49520 h = this.tabs.syncHeight(h);
49523 if(this.panelSize){
49524 w = w !== null ? w : this.panelSize.width;
49525 h = h !== null ? h : this.panelSize.height;
49527 if(this.activePanel){
49528 var el = this.activePanel.getEl();
49529 w = w !== null ? w : el.getWidth();
49530 h = h !== null ? h : el.getHeight();
49531 this.panelSize = {width: w, height: h};
49532 this.activePanel.setSize(w, h);
49534 if(Roo.isIE && this.tabs){
49535 this.tabs.el.repaint();
49540 * Returns the container element for this region.
49541 * @return {Roo.Element}
49543 getEl : function(){
49548 * Hides this region.
49551 if(!this.collapsed){
49552 this.el.dom.style.left = "-2000px";
49555 this.collapsedEl.dom.style.left = "-2000px";
49556 this.collapsedEl.hide();
49558 this.visible = false;
49559 this.fireEvent("visibilitychange", this, false);
49563 * Shows this region if it was previously hidden.
49566 if(!this.collapsed){
49569 this.collapsedEl.show();
49571 this.visible = true;
49572 this.fireEvent("visibilitychange", this, true);
49575 closeClicked : function(){
49576 if(this.activePanel){
49577 this.remove(this.activePanel);
49581 collapseClick : function(e){
49583 e.stopPropagation();
49586 e.stopPropagation();
49592 * Collapses this region.
49593 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
49595 collapse : function(skipAnim){
49596 if(this.collapsed) return;
49597 this.collapsed = true;
49599 this.split.el.hide();
49601 if(this.config.animate && skipAnim !== true){
49602 this.fireEvent("invalidated", this);
49603 this.animateCollapse();
49605 this.el.setLocation(-20000,-20000);
49607 this.collapsedEl.show();
49608 this.fireEvent("collapsed", this);
49609 this.fireEvent("invalidated", this);
49613 animateCollapse : function(){
49618 * Expands this region if it was previously collapsed.
49619 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
49620 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
49622 expand : function(e, skipAnim){
49623 if(e) e.stopPropagation();
49624 if(!this.collapsed || this.el.hasActiveFx()) return;
49626 this.afterSlideIn();
49629 this.collapsed = false;
49630 if(this.config.animate && skipAnim !== true){
49631 this.animateExpand();
49635 this.split.el.show();
49637 this.collapsedEl.setLocation(-2000,-2000);
49638 this.collapsedEl.hide();
49639 this.fireEvent("invalidated", this);
49640 this.fireEvent("expanded", this);
49644 animateExpand : function(){
49648 initTabs : function()
49650 this.bodyEl.setStyle("overflow", "hidden");
49651 var ts = new Roo.TabPanel(
49654 tabPosition: this.bottomTabs ? 'bottom' : 'top',
49655 disableTooltips: this.config.disableTabTips,
49656 toolbar : this.config.toolbar
49659 if(this.config.hideTabs){
49660 ts.stripWrap.setDisplayed(false);
49663 ts.resizeTabs = this.config.resizeTabs === true;
49664 ts.minTabWidth = this.config.minTabWidth || 40;
49665 ts.maxTabWidth = this.config.maxTabWidth || 250;
49666 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
49667 ts.monitorResize = false;
49668 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49669 ts.bodyEl.addClass('x-layout-tabs-body');
49670 this.panels.each(this.initPanelAsTab, this);
49673 initPanelAsTab : function(panel){
49674 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
49675 this.config.closeOnTab && panel.isClosable());
49676 if(panel.tabTip !== undefined){
49677 ti.setTooltip(panel.tabTip);
49679 ti.on("activate", function(){
49680 this.setActivePanel(panel);
49682 if(this.config.closeOnTab){
49683 ti.on("beforeclose", function(t, e){
49685 this.remove(panel);
49691 updatePanelTitle : function(panel, title){
49692 if(this.activePanel == panel){
49693 this.updateTitle(title);
49696 var ti = this.tabs.getTab(panel.getEl().id);
49698 if(panel.tabTip !== undefined){
49699 ti.setTooltip(panel.tabTip);
49704 updateTitle : function(title){
49705 if(this.titleTextEl && !this.config.title){
49706 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
49710 setActivePanel : function(panel){
49711 panel = this.getPanel(panel);
49712 if(this.activePanel && this.activePanel != panel){
49713 this.activePanel.setActiveState(false);
49715 this.activePanel = panel;
49716 panel.setActiveState(true);
49717 if(this.panelSize){
49718 panel.setSize(this.panelSize.width, this.panelSize.height);
49721 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
49723 this.updateTitle(panel.getTitle());
49725 this.fireEvent("invalidated", this);
49727 this.fireEvent("panelactivated", this, panel);
49731 * Shows the specified panel.
49732 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
49733 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
49735 showPanel : function(panel){
49736 if(panel = this.getPanel(panel)){
49738 var tab = this.tabs.getTab(panel.getEl().id);
49739 if(tab.isHidden()){
49740 this.tabs.unhideTab(tab.id);
49744 this.setActivePanel(panel);
49751 * Get the active panel for this region.
49752 * @return {Roo.ContentPanel} The active panel or null
49754 getActivePanel : function(){
49755 return this.activePanel;
49758 validateVisibility : function(){
49759 if(this.panels.getCount() < 1){
49760 this.updateTitle(" ");
49761 this.closeBtn.hide();
49764 if(!this.isVisible()){
49771 * Adds the passed ContentPanel(s) to this region.
49772 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49773 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
49775 add : function(panel){
49776 if(arguments.length > 1){
49777 for(var i = 0, len = arguments.length; i < len; i++) {
49778 this.add(arguments[i]);
49782 if(this.hasPanel(panel)){
49783 this.showPanel(panel);
49786 panel.setRegion(this);
49787 this.panels.add(panel);
49788 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
49789 this.bodyEl.dom.appendChild(panel.getEl().dom);
49790 if(panel.background !== true){
49791 this.setActivePanel(panel);
49793 this.fireEvent("paneladded", this, panel);
49799 this.initPanelAsTab(panel);
49801 if(panel.background !== true){
49802 this.tabs.activate(panel.getEl().id);
49804 this.fireEvent("paneladded", this, panel);
49809 * Hides the tab for the specified panel.
49810 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49812 hidePanel : function(panel){
49813 if(this.tabs && (panel = this.getPanel(panel))){
49814 this.tabs.hideTab(panel.getEl().id);
49819 * Unhides the tab for a previously hidden panel.
49820 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49822 unhidePanel : function(panel){
49823 if(this.tabs && (panel = this.getPanel(panel))){
49824 this.tabs.unhideTab(panel.getEl().id);
49828 clearPanels : function(){
49829 while(this.panels.getCount() > 0){
49830 this.remove(this.panels.first());
49835 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49836 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49837 * @param {Boolean} preservePanel Overrides the config preservePanel option
49838 * @return {Roo.ContentPanel} The panel that was removed
49840 remove : function(panel, preservePanel){
49841 panel = this.getPanel(panel);
49846 this.fireEvent("beforeremove", this, panel, e);
49847 if(e.cancel === true){
49850 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
49851 var panelId = panel.getId();
49852 this.panels.removeKey(panelId);
49854 document.body.appendChild(panel.getEl().dom);
49857 this.tabs.removeTab(panel.getEl().id);
49858 }else if (!preservePanel){
49859 this.bodyEl.dom.removeChild(panel.getEl().dom);
49861 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
49862 var p = this.panels.first();
49863 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
49864 tempEl.appendChild(p.getEl().dom);
49865 this.bodyEl.update("");
49866 this.bodyEl.dom.appendChild(p.getEl().dom);
49868 this.updateTitle(p.getTitle());
49870 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49871 this.setActivePanel(p);
49873 panel.setRegion(null);
49874 if(this.activePanel == panel){
49875 this.activePanel = null;
49877 if(this.config.autoDestroy !== false && preservePanel !== true){
49878 try{panel.destroy();}catch(e){}
49880 this.fireEvent("panelremoved", this, panel);
49885 * Returns the TabPanel component used by this region
49886 * @return {Roo.TabPanel}
49888 getTabs : function(){
49892 createTool : function(parentEl, className){
49893 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
49894 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
49895 btn.addClassOnOver("x-layout-tools-button-over");
49900 * Ext JS Library 1.1.1
49901 * Copyright(c) 2006-2007, Ext JS, LLC.
49903 * Originally Released Under LGPL - original licence link has changed is not relivant.
49906 * <script type="text/javascript">
49912 * @class Roo.SplitLayoutRegion
49913 * @extends Roo.LayoutRegion
49914 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
49916 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
49917 this.cursor = cursor;
49918 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
49921 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
49922 splitTip : "Drag to resize.",
49923 collapsibleSplitTip : "Drag to resize. Double click to hide.",
49924 useSplitTips : false,
49926 applyConfig : function(config){
49927 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
49930 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
49931 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
49932 /** The SplitBar for this region
49933 * @type Roo.SplitBar */
49934 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
49935 this.split.on("moved", this.onSplitMove, this);
49936 this.split.useShim = config.useShim === true;
49937 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
49938 if(this.useSplitTips){
49939 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
49941 if(config.collapsible){
49942 this.split.el.on("dblclick", this.collapse, this);
49945 if(typeof config.minSize != "undefined"){
49946 this.split.minSize = config.minSize;
49948 if(typeof config.maxSize != "undefined"){
49949 this.split.maxSize = config.maxSize;
49951 if(config.hideWhenEmpty || config.hidden || config.collapsed){
49952 this.hideSplitter();
49957 getHMaxSize : function(){
49958 var cmax = this.config.maxSize || 10000;
49959 var center = this.mgr.getRegion("center");
49960 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
49963 getVMaxSize : function(){
49964 var cmax = this.config.maxSize || 10000;
49965 var center = this.mgr.getRegion("center");
49966 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
49969 onSplitMove : function(split, newSize){
49970 this.fireEvent("resized", this, newSize);
49974 * Returns the {@link Roo.SplitBar} for this region.
49975 * @return {Roo.SplitBar}
49977 getSplitBar : function(){
49982 this.hideSplitter();
49983 Roo.SplitLayoutRegion.superclass.hide.call(this);
49986 hideSplitter : function(){
49988 this.split.el.setLocation(-2000,-2000);
49989 this.split.el.hide();
49995 this.split.el.show();
49997 Roo.SplitLayoutRegion.superclass.show.call(this);
50000 beforeSlide: function(){
50001 if(Roo.isGecko){// firefox overflow auto bug workaround
50002 this.bodyEl.clip();
50003 if(this.tabs) this.tabs.bodyEl.clip();
50004 if(this.activePanel){
50005 this.activePanel.getEl().clip();
50007 if(this.activePanel.beforeSlide){
50008 this.activePanel.beforeSlide();
50014 afterSlide : function(){
50015 if(Roo.isGecko){// firefox overflow auto bug workaround
50016 this.bodyEl.unclip();
50017 if(this.tabs) this.tabs.bodyEl.unclip();
50018 if(this.activePanel){
50019 this.activePanel.getEl().unclip();
50020 if(this.activePanel.afterSlide){
50021 this.activePanel.afterSlide();
50027 initAutoHide : function(){
50028 if(this.autoHide !== false){
50029 if(!this.autoHideHd){
50030 var st = new Roo.util.DelayedTask(this.slideIn, this);
50031 this.autoHideHd = {
50032 "mouseout": function(e){
50033 if(!e.within(this.el, true)){
50037 "mouseover" : function(e){
50043 this.el.on(this.autoHideHd);
50047 clearAutoHide : function(){
50048 if(this.autoHide !== false){
50049 this.el.un("mouseout", this.autoHideHd.mouseout);
50050 this.el.un("mouseover", this.autoHideHd.mouseover);
50054 clearMonitor : function(){
50055 Roo.get(document).un("click", this.slideInIf, this);
50058 // these names are backwards but not changed for compat
50059 slideOut : function(){
50060 if(this.isSlid || this.el.hasActiveFx()){
50063 this.isSlid = true;
50064 if(this.collapseBtn){
50065 this.collapseBtn.hide();
50067 this.closeBtnState = this.closeBtn.getStyle('display');
50068 this.closeBtn.hide();
50070 this.stickBtn.show();
50073 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50074 this.beforeSlide();
50075 this.el.setStyle("z-index", 10001);
50076 this.el.slideIn(this.getSlideAnchor(), {
50077 callback: function(){
50079 this.initAutoHide();
50080 Roo.get(document).on("click", this.slideInIf, this);
50081 this.fireEvent("slideshow", this);
50088 afterSlideIn : function(){
50089 this.clearAutoHide();
50090 this.isSlid = false;
50091 this.clearMonitor();
50092 this.el.setStyle("z-index", "");
50093 if(this.collapseBtn){
50094 this.collapseBtn.show();
50096 this.closeBtn.setStyle('display', this.closeBtnState);
50098 this.stickBtn.hide();
50100 this.fireEvent("slidehide", this);
50103 slideIn : function(cb){
50104 if(!this.isSlid || this.el.hasActiveFx()){
50108 this.isSlid = false;
50109 this.beforeSlide();
50110 this.el.slideOut(this.getSlideAnchor(), {
50111 callback: function(){
50112 this.el.setLeftTop(-10000, -10000);
50114 this.afterSlideIn();
50122 slideInIf : function(e){
50123 if(!e.within(this.el)){
50128 animateCollapse : function(){
50129 this.beforeSlide();
50130 this.el.setStyle("z-index", 20000);
50131 var anchor = this.getSlideAnchor();
50132 this.el.slideOut(anchor, {
50133 callback : function(){
50134 this.el.setStyle("z-index", "");
50135 this.collapsedEl.slideIn(anchor, {duration:.3});
50137 this.el.setLocation(-10000,-10000);
50139 this.fireEvent("collapsed", this);
50146 animateExpand : function(){
50147 this.beforeSlide();
50148 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
50149 this.el.setStyle("z-index", 20000);
50150 this.collapsedEl.hide({
50153 this.el.slideIn(this.getSlideAnchor(), {
50154 callback : function(){
50155 this.el.setStyle("z-index", "");
50158 this.split.el.show();
50160 this.fireEvent("invalidated", this);
50161 this.fireEvent("expanded", this);
50189 getAnchor : function(){
50190 return this.anchors[this.position];
50193 getCollapseAnchor : function(){
50194 return this.canchors[this.position];
50197 getSlideAnchor : function(){
50198 return this.sanchors[this.position];
50201 getAlignAdj : function(){
50202 var cm = this.cmargins;
50203 switch(this.position){
50219 getExpandAdj : function(){
50220 var c = this.collapsedEl, cm = this.cmargins;
50221 switch(this.position){
50223 return [-(cm.right+c.getWidth()+cm.left), 0];
50226 return [cm.right+c.getWidth()+cm.left, 0];
50229 return [0, -(cm.top+cm.bottom+c.getHeight())];
50232 return [0, cm.top+cm.bottom+c.getHeight()];
50238 * Ext JS Library 1.1.1
50239 * Copyright(c) 2006-2007, Ext JS, LLC.
50241 * Originally Released Under LGPL - original licence link has changed is not relivant.
50244 * <script type="text/javascript">
50247 * These classes are private internal classes
50249 Roo.CenterLayoutRegion = function(mgr, config){
50250 Roo.LayoutRegion.call(this, mgr, config, "center");
50251 this.visible = true;
50252 this.minWidth = config.minWidth || 20;
50253 this.minHeight = config.minHeight || 20;
50256 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
50258 // center panel can't be hidden
50262 // center panel can't be hidden
50265 getMinWidth: function(){
50266 return this.minWidth;
50269 getMinHeight: function(){
50270 return this.minHeight;
50275 Roo.NorthLayoutRegion = function(mgr, config){
50276 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
50278 this.split.placement = Roo.SplitBar.TOP;
50279 this.split.orientation = Roo.SplitBar.VERTICAL;
50280 this.split.el.addClass("x-layout-split-v");
50282 var size = config.initialSize || config.height;
50283 if(typeof size != "undefined"){
50284 this.el.setHeight(size);
50287 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
50288 orientation: Roo.SplitBar.VERTICAL,
50289 getBox : function(){
50290 if(this.collapsed){
50291 return this.collapsedEl.getBox();
50293 var box = this.el.getBox();
50295 box.height += this.split.el.getHeight();
50300 updateBox : function(box){
50301 if(this.split && !this.collapsed){
50302 box.height -= this.split.el.getHeight();
50303 this.split.el.setLeft(box.x);
50304 this.split.el.setTop(box.y+box.height);
50305 this.split.el.setWidth(box.width);
50307 if(this.collapsed){
50308 this.updateBody(box.width, null);
50310 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50314 Roo.SouthLayoutRegion = function(mgr, config){
50315 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
50317 this.split.placement = Roo.SplitBar.BOTTOM;
50318 this.split.orientation = Roo.SplitBar.VERTICAL;
50319 this.split.el.addClass("x-layout-split-v");
50321 var size = config.initialSize || config.height;
50322 if(typeof size != "undefined"){
50323 this.el.setHeight(size);
50326 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
50327 orientation: Roo.SplitBar.VERTICAL,
50328 getBox : function(){
50329 if(this.collapsed){
50330 return this.collapsedEl.getBox();
50332 var box = this.el.getBox();
50334 var sh = this.split.el.getHeight();
50341 updateBox : function(box){
50342 if(this.split && !this.collapsed){
50343 var sh = this.split.el.getHeight();
50346 this.split.el.setLeft(box.x);
50347 this.split.el.setTop(box.y-sh);
50348 this.split.el.setWidth(box.width);
50350 if(this.collapsed){
50351 this.updateBody(box.width, null);
50353 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50357 Roo.EastLayoutRegion = function(mgr, config){
50358 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
50360 this.split.placement = Roo.SplitBar.RIGHT;
50361 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50362 this.split.el.addClass("x-layout-split-h");
50364 var size = config.initialSize || config.width;
50365 if(typeof size != "undefined"){
50366 this.el.setWidth(size);
50369 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
50370 orientation: Roo.SplitBar.HORIZONTAL,
50371 getBox : function(){
50372 if(this.collapsed){
50373 return this.collapsedEl.getBox();
50375 var box = this.el.getBox();
50377 var sw = this.split.el.getWidth();
50384 updateBox : function(box){
50385 if(this.split && !this.collapsed){
50386 var sw = this.split.el.getWidth();
50388 this.split.el.setLeft(box.x);
50389 this.split.el.setTop(box.y);
50390 this.split.el.setHeight(box.height);
50393 if(this.collapsed){
50394 this.updateBody(null, box.height);
50396 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50400 Roo.WestLayoutRegion = function(mgr, config){
50401 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
50403 this.split.placement = Roo.SplitBar.LEFT;
50404 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50405 this.split.el.addClass("x-layout-split-h");
50407 var size = config.initialSize || config.width;
50408 if(typeof size != "undefined"){
50409 this.el.setWidth(size);
50412 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
50413 orientation: Roo.SplitBar.HORIZONTAL,
50414 getBox : function(){
50415 if(this.collapsed){
50416 return this.collapsedEl.getBox();
50418 var box = this.el.getBox();
50420 box.width += this.split.el.getWidth();
50425 updateBox : function(box){
50426 if(this.split && !this.collapsed){
50427 var sw = this.split.el.getWidth();
50429 this.split.el.setLeft(box.x+box.width);
50430 this.split.el.setTop(box.y);
50431 this.split.el.setHeight(box.height);
50433 if(this.collapsed){
50434 this.updateBody(null, box.height);
50436 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50441 * Ext JS Library 1.1.1
50442 * Copyright(c) 2006-2007, Ext JS, LLC.
50444 * Originally Released Under LGPL - original licence link has changed is not relivant.
50447 * <script type="text/javascript">
50452 * Private internal class for reading and applying state
50454 Roo.LayoutStateManager = function(layout){
50455 // default empty state
50464 Roo.LayoutStateManager.prototype = {
50465 init : function(layout, provider){
50466 this.provider = provider;
50467 var state = provider.get(layout.id+"-layout-state");
50469 var wasUpdating = layout.isUpdating();
50471 layout.beginUpdate();
50473 for(var key in state){
50474 if(typeof state[key] != "function"){
50475 var rstate = state[key];
50476 var r = layout.getRegion(key);
50479 r.resizeTo(rstate.size);
50481 if(rstate.collapsed == true){
50484 r.expand(null, true);
50490 layout.endUpdate();
50492 this.state = state;
50494 this.layout = layout;
50495 layout.on("regionresized", this.onRegionResized, this);
50496 layout.on("regioncollapsed", this.onRegionCollapsed, this);
50497 layout.on("regionexpanded", this.onRegionExpanded, this);
50500 storeState : function(){
50501 this.provider.set(this.layout.id+"-layout-state", this.state);
50504 onRegionResized : function(region, newSize){
50505 this.state[region.getPosition()].size = newSize;
50509 onRegionCollapsed : function(region){
50510 this.state[region.getPosition()].collapsed = true;
50514 onRegionExpanded : function(region){
50515 this.state[region.getPosition()].collapsed = false;
50520 * Ext JS Library 1.1.1
50521 * Copyright(c) 2006-2007, Ext JS, LLC.
50523 * Originally Released Under LGPL - original licence link has changed is not relivant.
50526 * <script type="text/javascript">
50529 * @class Roo.ContentPanel
50530 * @extends Roo.util.Observable
50531 * A basic ContentPanel element.
50532 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
50533 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
50534 * @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
50535 * @cfg {Boolean} closable True if the panel can be closed/removed
50536 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
50537 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
50538 * @cfg {Toolbar} toolbar A toolbar for this panel
50539 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
50540 * @cfg {String} title The title for this panel
50541 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
50542 * @cfg {String} url Calls {@link #setUrl} with this value
50543 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
50544 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
50545 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
50546 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
50549 * Create a new ContentPanel.
50550 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
50551 * @param {String/Object} config A string to set only the title or a config object
50552 * @param {String} content (optional) Set the HTML content for this panel
50553 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
50555 Roo.ContentPanel = function(el, config, content){
50559 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
50563 if (config && config.parentLayout) {
50564 el = config.parentLayout.el.createChild();
50567 if(el.autoCreate){ // xtype is available if this is called from factory
50571 this.el = Roo.get(el);
50572 if(!this.el && config && config.autoCreate){
50573 if(typeof config.autoCreate == "object"){
50574 if(!config.autoCreate.id){
50575 config.autoCreate.id = config.id||el;
50577 this.el = Roo.DomHelper.append(document.body,
50578 config.autoCreate, true);
50580 this.el = Roo.DomHelper.append(document.body,
50581 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
50584 this.closable = false;
50585 this.loaded = false;
50586 this.active = false;
50587 if(typeof config == "string"){
50588 this.title = config;
50590 Roo.apply(this, config);
50593 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
50594 this.wrapEl = this.el.wrap();
50595 this.toolbar.container = this.el.insertSibling(false, 'before');
50596 this.toolbar = new Roo.Toolbar(this.toolbar);
50599 // xtype created footer. - not sure if will work as we normally have to render first..
50600 if (this.footer && !this.footer.el && this.footer.xtype) {
50601 if (!this.wrapEl) {
50602 this.wrapEl = this.el.wrap();
50605 this.footer.container = this.wrapEl.createChild();
50607 this.footer = Roo.factory(this.footer, Roo);
50612 this.resizeEl = Roo.get(this.resizeEl, true);
50614 this.resizeEl = this.el;
50616 // handle view.xtype
50624 * Fires when this panel is activated.
50625 * @param {Roo.ContentPanel} this
50629 * @event deactivate
50630 * Fires when this panel is activated.
50631 * @param {Roo.ContentPanel} this
50633 "deactivate" : true,
50637 * Fires when this panel is resized if fitToFrame is true.
50638 * @param {Roo.ContentPanel} this
50639 * @param {Number} width The width after any component adjustments
50640 * @param {Number} height The height after any component adjustments
50646 * Fires when this tab is created
50647 * @param {Roo.ContentPanel} this
50658 if(this.autoScroll){
50659 this.resizeEl.setStyle("overflow", "auto");
50661 // fix randome scrolling
50662 this.el.on('scroll', function() {
50663 Roo.log('fix random scolling');
50664 this.scrollTo('top',0);
50667 content = content || this.content;
50669 this.setContent(content);
50671 if(config && config.url){
50672 this.setUrl(this.url, this.params, this.loadOnce);
50677 Roo.ContentPanel.superclass.constructor.call(this);
50679 if (this.view && typeof(this.view.xtype) != 'undefined') {
50680 this.view.el = this.el.appendChild(document.createElement("div"));
50681 this.view = Roo.factory(this.view);
50682 this.view.render && this.view.render(false, '');
50686 this.fireEvent('render', this);
50689 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
50691 setRegion : function(region){
50692 this.region = region;
50694 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
50696 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
50701 * Returns the toolbar for this Panel if one was configured.
50702 * @return {Roo.Toolbar}
50704 getToolbar : function(){
50705 return this.toolbar;
50708 setActiveState : function(active){
50709 this.active = active;
50711 this.fireEvent("deactivate", this);
50713 this.fireEvent("activate", this);
50717 * Updates this panel's element
50718 * @param {String} content The new content
50719 * @param {Boolean} loadScripts (optional) true to look for and process scripts
50721 setContent : function(content, loadScripts){
50722 this.el.update(content, loadScripts);
50725 ignoreResize : function(w, h){
50726 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
50729 this.lastSize = {width: w, height: h};
50734 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
50735 * @return {Roo.UpdateManager} The UpdateManager
50737 getUpdateManager : function(){
50738 return this.el.getUpdateManager();
50741 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
50742 * @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:
50745 url: "your-url.php",
50746 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
50747 callback: yourFunction,
50748 scope: yourObject, //(optional scope)
50751 text: "Loading...",
50756 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
50757 * 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.
50758 * @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}
50759 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
50760 * @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.
50761 * @return {Roo.ContentPanel} this
50764 var um = this.el.getUpdateManager();
50765 um.update.apply(um, arguments);
50771 * 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.
50772 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
50773 * @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)
50774 * @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)
50775 * @return {Roo.UpdateManager} The UpdateManager
50777 setUrl : function(url, params, loadOnce){
50778 if(this.refreshDelegate){
50779 this.removeListener("activate", this.refreshDelegate);
50781 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
50782 this.on("activate", this.refreshDelegate);
50783 return this.el.getUpdateManager();
50786 _handleRefresh : function(url, params, loadOnce){
50787 if(!loadOnce || !this.loaded){
50788 var updater = this.el.getUpdateManager();
50789 updater.update(url, params, this._setLoaded.createDelegate(this));
50793 _setLoaded : function(){
50794 this.loaded = true;
50798 * Returns this panel's id
50801 getId : function(){
50806 * Returns this panel's element - used by regiosn to add.
50807 * @return {Roo.Element}
50809 getEl : function(){
50810 return this.wrapEl || this.el;
50813 adjustForComponents : function(width, height)
50815 //Roo.log('adjustForComponents ');
50816 if(this.resizeEl != this.el){
50817 width -= this.el.getFrameWidth('lr');
50818 height -= this.el.getFrameWidth('tb');
50821 var te = this.toolbar.getEl();
50822 height -= te.getHeight();
50823 te.setWidth(width);
50826 var te = this.footer.getEl();
50827 Roo.log("footer:" + te.getHeight());
50829 height -= te.getHeight();
50830 te.setWidth(width);
50834 if(this.adjustments){
50835 width += this.adjustments[0];
50836 height += this.adjustments[1];
50838 return {"width": width, "height": height};
50841 setSize : function(width, height){
50842 if(this.fitToFrame && !this.ignoreResize(width, height)){
50843 if(this.fitContainer && this.resizeEl != this.el){
50844 this.el.setSize(width, height);
50846 var size = this.adjustForComponents(width, height);
50847 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
50848 this.fireEvent('resize', this, size.width, size.height);
50853 * Returns this panel's title
50856 getTitle : function(){
50861 * Set this panel's title
50862 * @param {String} title
50864 setTitle : function(title){
50865 this.title = title;
50867 this.region.updatePanelTitle(this, title);
50872 * Returns true is this panel was configured to be closable
50873 * @return {Boolean}
50875 isClosable : function(){
50876 return this.closable;
50879 beforeSlide : function(){
50881 this.resizeEl.clip();
50884 afterSlide : function(){
50886 this.resizeEl.unclip();
50890 * Force a content refresh from the URL specified in the {@link #setUrl} method.
50891 * Will fail silently if the {@link #setUrl} method has not been called.
50892 * This does not activate the panel, just updates its content.
50894 refresh : function(){
50895 if(this.refreshDelegate){
50896 this.loaded = false;
50897 this.refreshDelegate();
50902 * Destroys this panel
50904 destroy : function(){
50905 this.el.removeAllListeners();
50906 var tempEl = document.createElement("span");
50907 tempEl.appendChild(this.el.dom);
50908 tempEl.innerHTML = "";
50914 * form - if the content panel contains a form - this is a reference to it.
50915 * @type {Roo.form.Form}
50919 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
50920 * This contains a reference to it.
50926 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
50936 * @param {Object} cfg Xtype definition of item to add.
50939 addxtype : function(cfg) {
50941 if (cfg.xtype.match(/^Form$/)) {
50944 //if (this.footer) {
50945 // el = this.footer.container.insertSibling(false, 'before');
50947 el = this.el.createChild();
50950 this.form = new Roo.form.Form(cfg);
50953 if ( this.form.allItems.length) this.form.render(el.dom);
50956 // should only have one of theses..
50957 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
50958 // views.. should not be just added - used named prop 'view''
50960 cfg.el = this.el.appendChild(document.createElement("div"));
50963 var ret = new Roo.factory(cfg);
50965 ret.render && ret.render(false, ''); // render blank..
50974 * @class Roo.GridPanel
50975 * @extends Roo.ContentPanel
50977 * Create a new GridPanel.
50978 * @param {Roo.grid.Grid} grid The grid for this panel
50979 * @param {String/Object} config A string to set only the panel's title, or a config object
50981 Roo.GridPanel = function(grid, config){
50984 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
50985 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
50987 this.wrapper.dom.appendChild(grid.getGridEl().dom);
50989 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
50992 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
50994 // xtype created footer. - not sure if will work as we normally have to render first..
50995 if (this.footer && !this.footer.el && this.footer.xtype) {
50997 this.footer.container = this.grid.getView().getFooterPanel(true);
50998 this.footer.dataSource = this.grid.dataSource;
50999 this.footer = Roo.factory(this.footer, Roo);
51003 grid.monitorWindowResize = false; // turn off autosizing
51004 grid.autoHeight = false;
51005 grid.autoWidth = false;
51007 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51010 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51011 getId : function(){
51012 return this.grid.id;
51016 * Returns the grid for this panel
51017 * @return {Roo.grid.Grid}
51019 getGrid : function(){
51023 setSize : function(width, height){
51024 if(!this.ignoreResize(width, height)){
51025 var grid = this.grid;
51026 var size = this.adjustForComponents(width, height);
51027 grid.getGridEl().setSize(size.width, size.height);
51032 beforeSlide : function(){
51033 this.grid.getView().scroller.clip();
51036 afterSlide : function(){
51037 this.grid.getView().scroller.unclip();
51040 destroy : function(){
51041 this.grid.destroy();
51043 Roo.GridPanel.superclass.destroy.call(this);
51049 * @class Roo.NestedLayoutPanel
51050 * @extends Roo.ContentPanel
51052 * Create a new NestedLayoutPanel.
51055 * @param {Roo.BorderLayout} layout The layout for this panel
51056 * @param {String/Object} config A string to set only the title or a config object
51058 Roo.NestedLayoutPanel = function(layout, config)
51060 // construct with only one argument..
51061 /* FIXME - implement nicer consturctors
51062 if (layout.layout) {
51064 layout = config.layout;
51065 delete config.layout;
51067 if (layout.xtype && !layout.getEl) {
51068 // then layout needs constructing..
51069 layout = Roo.factory(layout, Roo);
51074 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51076 layout.monitorWindowResize = false; // turn off autosizing
51077 this.layout = layout;
51078 this.layout.getEl().addClass("x-layout-nested-layout");
51085 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51087 setSize : function(width, height){
51088 if(!this.ignoreResize(width, height)){
51089 var size = this.adjustForComponents(width, height);
51090 var el = this.layout.getEl();
51091 el.setSize(size.width, size.height);
51092 var touch = el.dom.offsetWidth;
51093 this.layout.layout();
51094 // ie requires a double layout on the first pass
51095 if(Roo.isIE && !this.initialized){
51096 this.initialized = true;
51097 this.layout.layout();
51102 // activate all subpanels if not currently active..
51104 setActiveState : function(active){
51105 this.active = active;
51107 this.fireEvent("deactivate", this);
51111 this.fireEvent("activate", this);
51112 // not sure if this should happen before or after..
51113 if (!this.layout) {
51114 return; // should not happen..
51117 for (var r in this.layout.regions) {
51118 reg = this.layout.getRegion(r);
51119 if (reg.getActivePanel()) {
51120 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51121 reg.setActivePanel(reg.getActivePanel());
51124 if (!reg.panels.length) {
51127 reg.showPanel(reg.getPanel(0));
51136 * Returns the nested BorderLayout for this panel
51137 * @return {Roo.BorderLayout}
51139 getLayout : function(){
51140 return this.layout;
51144 * Adds a xtype elements to the layout of the nested panel
51148 xtype : 'ContentPanel',
51155 xtype : 'NestedLayoutPanel',
51161 items : [ ... list of content panels or nested layout panels.. ]
51165 * @param {Object} cfg Xtype definition of item to add.
51167 addxtype : function(cfg) {
51168 return this.layout.addxtype(cfg);
51173 Roo.ScrollPanel = function(el, config, content){
51174 config = config || {};
51175 config.fitToFrame = true;
51176 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
51178 this.el.dom.style.overflow = "hidden";
51179 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
51180 this.el.removeClass("x-layout-inactive-content");
51181 this.el.on("mousewheel", this.onWheel, this);
51183 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
51184 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
51185 up.unselectable(); down.unselectable();
51186 up.on("click", this.scrollUp, this);
51187 down.on("click", this.scrollDown, this);
51188 up.addClassOnOver("x-scroller-btn-over");
51189 down.addClassOnOver("x-scroller-btn-over");
51190 up.addClassOnClick("x-scroller-btn-click");
51191 down.addClassOnClick("x-scroller-btn-click");
51192 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
51194 this.resizeEl = this.el;
51195 this.el = wrap; this.up = up; this.down = down;
51198 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
51200 wheelIncrement : 5,
51201 scrollUp : function(){
51202 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
51205 scrollDown : function(){
51206 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
51209 afterScroll : function(){
51210 var el = this.resizeEl;
51211 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
51212 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51213 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51216 setSize : function(){
51217 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
51218 this.afterScroll();
51221 onWheel : function(e){
51222 var d = e.getWheelDelta();
51223 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
51224 this.afterScroll();
51228 setContent : function(content, loadScripts){
51229 this.resizeEl.update(content, loadScripts);
51243 * @class Roo.TreePanel
51244 * @extends Roo.ContentPanel
51246 * Create a new TreePanel. - defaults to fit/scoll contents.
51247 * @param {String/Object} config A string to set only the panel's title, or a config object
51248 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
51250 Roo.TreePanel = function(config){
51251 var el = config.el;
51252 var tree = config.tree;
51253 delete config.tree;
51254 delete config.el; // hopefull!
51256 // wrapper for IE7 strict & safari scroll issue
51258 var treeEl = el.createChild();
51259 config.resizeEl = treeEl;
51263 Roo.TreePanel.superclass.constructor.call(this, el, config);
51266 this.tree = new Roo.tree.TreePanel(treeEl , tree);
51267 //console.log(tree);
51268 this.on('activate', function()
51270 if (this.tree.rendered) {
51273 //console.log('render tree');
51274 this.tree.render();
51276 // this should not be needed.. - it's actually the 'el' that resizes?
51277 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
51279 //this.on('resize', function (cp, w, h) {
51280 // this.tree.innerCt.setWidth(w);
51281 // this.tree.innerCt.setHeight(h);
51282 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
51289 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
51306 * Ext JS Library 1.1.1
51307 * Copyright(c) 2006-2007, Ext JS, LLC.
51309 * Originally Released Under LGPL - original licence link has changed is not relivant.
51312 * <script type="text/javascript">
51317 * @class Roo.ReaderLayout
51318 * @extends Roo.BorderLayout
51319 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
51320 * center region containing two nested regions (a top one for a list view and one for item preview below),
51321 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
51322 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
51323 * expedites the setup of the overall layout and regions for this common application style.
51326 var reader = new Roo.ReaderLayout();
51327 var CP = Roo.ContentPanel; // shortcut for adding
51329 reader.beginUpdate();
51330 reader.add("north", new CP("north", "North"));
51331 reader.add("west", new CP("west", {title: "West"}));
51332 reader.add("east", new CP("east", {title: "East"}));
51334 reader.regions.listView.add(new CP("listView", "List"));
51335 reader.regions.preview.add(new CP("preview", "Preview"));
51336 reader.endUpdate();
51339 * Create a new ReaderLayout
51340 * @param {Object} config Configuration options
51341 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
51342 * document.body if omitted)
51344 Roo.ReaderLayout = function(config, renderTo){
51345 var c = config || {size:{}};
51346 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
51347 north: c.north !== false ? Roo.apply({
51351 }, c.north) : false,
51352 west: c.west !== false ? Roo.apply({
51360 margins:{left:5,right:0,bottom:5,top:5},
51361 cmargins:{left:5,right:5,bottom:5,top:5}
51362 }, c.west) : false,
51363 east: c.east !== false ? Roo.apply({
51371 margins:{left:0,right:5,bottom:5,top:5},
51372 cmargins:{left:5,right:5,bottom:5,top:5}
51373 }, c.east) : false,
51374 center: Roo.apply({
51375 tabPosition: 'top',
51379 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
51383 this.el.addClass('x-reader');
51385 this.beginUpdate();
51387 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
51388 south: c.preview !== false ? Roo.apply({
51395 cmargins:{top:5,left:0, right:0, bottom:0}
51396 }, c.preview) : false,
51397 center: Roo.apply({
51403 this.add('center', new Roo.NestedLayoutPanel(inner,
51404 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
51408 this.regions.preview = inner.getRegion('south');
51409 this.regions.listView = inner.getRegion('center');
51412 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
51414 * Ext JS Library 1.1.1
51415 * Copyright(c) 2006-2007, Ext JS, LLC.
51417 * Originally Released Under LGPL - original licence link has changed is not relivant.
51420 * <script type="text/javascript">
51424 * @class Roo.grid.Grid
51425 * @extends Roo.util.Observable
51426 * This class represents the primary interface of a component based grid control.
51427 * <br><br>Usage:<pre><code>
51428 var grid = new Roo.grid.Grid("my-container-id", {
51431 selModel: mySelectionModel,
51432 autoSizeColumns: true,
51433 monitorWindowResize: false,
51434 trackMouseOver: true
51439 * <b>Common Problems:</b><br/>
51440 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
51441 * element will correct this<br/>
51442 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
51443 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
51444 * are unpredictable.<br/>
51445 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
51446 * grid to calculate dimensions/offsets.<br/>
51448 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51449 * The container MUST have some type of size defined for the grid to fill. The container will be
51450 * automatically set to position relative if it isn't already.
51451 * @param {Object} config A config object that sets properties on this grid.
51453 Roo.grid.Grid = function(container, config){
51454 // initialize the container
51455 this.container = Roo.get(container);
51456 this.container.update("");
51457 this.container.setStyle("overflow", "hidden");
51458 this.container.addClass('x-grid-container');
51460 this.id = this.container.id;
51462 Roo.apply(this, config);
51463 // check and correct shorthanded configs
51465 this.dataSource = this.ds;
51469 this.colModel = this.cm;
51473 this.selModel = this.sm;
51477 if (this.selModel) {
51478 this.selModel = Roo.factory(this.selModel, Roo.grid);
51479 this.sm = this.selModel;
51480 this.sm.xmodule = this.xmodule || false;
51482 if (typeof(this.colModel.config) == 'undefined') {
51483 this.colModel = new Roo.grid.ColumnModel(this.colModel);
51484 this.cm = this.colModel;
51485 this.cm.xmodule = this.xmodule || false;
51487 if (this.dataSource) {
51488 this.dataSource= Roo.factory(this.dataSource, Roo.data);
51489 this.ds = this.dataSource;
51490 this.ds.xmodule = this.xmodule || false;
51497 this.container.setWidth(this.width);
51501 this.container.setHeight(this.height);
51508 * The raw click event for the entire grid.
51509 * @param {Roo.EventObject} e
51514 * The raw dblclick event for the entire grid.
51515 * @param {Roo.EventObject} e
51519 * @event contextmenu
51520 * The raw contextmenu event for the entire grid.
51521 * @param {Roo.EventObject} e
51523 "contextmenu" : true,
51526 * The raw mousedown event for the entire grid.
51527 * @param {Roo.EventObject} e
51529 "mousedown" : true,
51532 * The raw mouseup event for the entire grid.
51533 * @param {Roo.EventObject} e
51538 * The raw mouseover event for the entire grid.
51539 * @param {Roo.EventObject} e
51541 "mouseover" : true,
51544 * The raw mouseout event for the entire grid.
51545 * @param {Roo.EventObject} e
51550 * The raw keypress event for the entire grid.
51551 * @param {Roo.EventObject} e
51556 * The raw keydown event for the entire grid.
51557 * @param {Roo.EventObject} e
51565 * Fires when a cell is clicked
51566 * @param {Grid} this
51567 * @param {Number} rowIndex
51568 * @param {Number} columnIndex
51569 * @param {Roo.EventObject} e
51571 "cellclick" : true,
51573 * @event celldblclick
51574 * Fires when a cell is double clicked
51575 * @param {Grid} this
51576 * @param {Number} rowIndex
51577 * @param {Number} columnIndex
51578 * @param {Roo.EventObject} e
51580 "celldblclick" : true,
51583 * Fires when a row is clicked
51584 * @param {Grid} this
51585 * @param {Number} rowIndex
51586 * @param {Roo.EventObject} e
51590 * @event rowdblclick
51591 * Fires when a row is double clicked
51592 * @param {Grid} this
51593 * @param {Number} rowIndex
51594 * @param {Roo.EventObject} e
51596 "rowdblclick" : true,
51598 * @event headerclick
51599 * Fires when a header is clicked
51600 * @param {Grid} this
51601 * @param {Number} columnIndex
51602 * @param {Roo.EventObject} e
51604 "headerclick" : true,
51606 * @event headerdblclick
51607 * Fires when a header cell is double clicked
51608 * @param {Grid} this
51609 * @param {Number} columnIndex
51610 * @param {Roo.EventObject} e
51612 "headerdblclick" : true,
51614 * @event rowcontextmenu
51615 * Fires when a row is right clicked
51616 * @param {Grid} this
51617 * @param {Number} rowIndex
51618 * @param {Roo.EventObject} e
51620 "rowcontextmenu" : true,
51622 * @event cellcontextmenu
51623 * Fires when a cell is right clicked
51624 * @param {Grid} this
51625 * @param {Number} rowIndex
51626 * @param {Number} cellIndex
51627 * @param {Roo.EventObject} e
51629 "cellcontextmenu" : true,
51631 * @event headercontextmenu
51632 * Fires when a header is right clicked
51633 * @param {Grid} this
51634 * @param {Number} columnIndex
51635 * @param {Roo.EventObject} e
51637 "headercontextmenu" : true,
51639 * @event bodyscroll
51640 * Fires when the body element is scrolled
51641 * @param {Number} scrollLeft
51642 * @param {Number} scrollTop
51644 "bodyscroll" : true,
51646 * @event columnresize
51647 * Fires when the user resizes a column
51648 * @param {Number} columnIndex
51649 * @param {Number} newSize
51651 "columnresize" : true,
51653 * @event columnmove
51654 * Fires when the user moves a column
51655 * @param {Number} oldIndex
51656 * @param {Number} newIndex
51658 "columnmove" : true,
51661 * Fires when row(s) start being dragged
51662 * @param {Grid} this
51663 * @param {Roo.GridDD} dd The drag drop object
51664 * @param {event} e The raw browser event
51666 "startdrag" : true,
51669 * Fires when a drag operation is complete
51670 * @param {Grid} this
51671 * @param {Roo.GridDD} dd The drag drop object
51672 * @param {event} e The raw browser event
51677 * Fires when dragged row(s) are dropped on a valid DD target
51678 * @param {Grid} this
51679 * @param {Roo.GridDD} dd The drag drop object
51680 * @param {String} targetId The target drag drop object
51681 * @param {event} e The raw browser event
51686 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
51687 * @param {Grid} this
51688 * @param {Roo.GridDD} dd The drag drop object
51689 * @param {String} targetId The target drag drop object
51690 * @param {event} e The raw browser event
51695 * Fires when the dragged row(s) first cross another DD target while being dragged
51696 * @param {Grid} this
51697 * @param {Roo.GridDD} dd The drag drop object
51698 * @param {String} targetId The target drag drop object
51699 * @param {event} e The raw browser event
51701 "dragenter" : true,
51704 * Fires when the dragged row(s) leave another DD target while being dragged
51705 * @param {Grid} this
51706 * @param {Roo.GridDD} dd The drag drop object
51707 * @param {String} targetId The target drag drop object
51708 * @param {event} e The raw browser event
51713 * Fires when a row is rendered, so you can change add a style to it.
51714 * @param {GridView} gridview The grid view
51715 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
51721 * Fires when the grid is rendered
51722 * @param {Grid} grid
51727 Roo.grid.Grid.superclass.constructor.call(this);
51729 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
51732 * @cfg {String} ddGroup - drag drop group.
51736 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
51738 minColumnWidth : 25,
51741 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
51742 * <b>on initial render.</b> It is more efficient to explicitly size the columns
51743 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
51745 autoSizeColumns : false,
51748 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
51750 autoSizeHeaders : true,
51753 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
51755 monitorWindowResize : true,
51758 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
51759 * rows measured to get a columns size. Default is 0 (all rows).
51761 maxRowsToMeasure : 0,
51764 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
51766 trackMouseOver : true,
51769 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
51773 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
51775 enableDragDrop : false,
51778 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
51780 enableColumnMove : true,
51783 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
51785 enableColumnHide : true,
51788 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
51790 enableRowHeightSync : false,
51793 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
51798 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
51800 autoHeight : false,
51803 * @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.
51805 autoExpandColumn : false,
51808 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
51811 autoExpandMin : 50,
51814 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
51816 autoExpandMax : 1000,
51819 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
51824 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
51828 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
51838 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
51839 * of a fixed width. Default is false.
51842 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
51845 * Called once after all setup has been completed and the grid is ready to be rendered.
51846 * @return {Roo.grid.Grid} this
51848 render : function()
51850 var c = this.container;
51851 // try to detect autoHeight/width mode
51852 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
51853 this.autoHeight = true;
51855 var view = this.getView();
51858 c.on("click", this.onClick, this);
51859 c.on("dblclick", this.onDblClick, this);
51860 c.on("contextmenu", this.onContextMenu, this);
51861 c.on("keydown", this.onKeyDown, this);
51863 c.on("touchstart", this.onTouchStart, this);
51866 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
51868 this.getSelectionModel().init(this);
51873 this.loadMask = new Roo.LoadMask(this.container,
51874 Roo.apply({store:this.dataSource}, this.loadMask));
51878 if (this.toolbar && this.toolbar.xtype) {
51879 this.toolbar.container = this.getView().getHeaderPanel(true);
51880 this.toolbar = new Roo.Toolbar(this.toolbar);
51882 if (this.footer && this.footer.xtype) {
51883 this.footer.dataSource = this.getDataSource();
51884 this.footer.container = this.getView().getFooterPanel(true);
51885 this.footer = Roo.factory(this.footer, Roo);
51887 if (this.dropTarget && this.dropTarget.xtype) {
51888 delete this.dropTarget.xtype;
51889 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
51893 this.rendered = true;
51894 this.fireEvent('render', this);
51899 * Reconfigures the grid to use a different Store and Column Model.
51900 * The View will be bound to the new objects and refreshed.
51901 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
51902 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
51904 reconfigure : function(dataSource, colModel){
51906 this.loadMask.destroy();
51907 this.loadMask = new Roo.LoadMask(this.container,
51908 Roo.apply({store:dataSource}, this.loadMask));
51910 this.view.bind(dataSource, colModel);
51911 this.dataSource = dataSource;
51912 this.colModel = colModel;
51913 this.view.refresh(true);
51917 onKeyDown : function(e){
51918 this.fireEvent("keydown", e);
51922 * Destroy this grid.
51923 * @param {Boolean} removeEl True to remove the element
51925 destroy : function(removeEl, keepListeners){
51927 this.loadMask.destroy();
51929 var c = this.container;
51930 c.removeAllListeners();
51931 this.view.destroy();
51932 this.colModel.purgeListeners();
51933 if(!keepListeners){
51934 this.purgeListeners();
51937 if(removeEl === true){
51943 processEvent : function(name, e){
51944 // does this fire select???
51945 Roo.log('grid:processEvent ' + name);
51947 if (name != 'touchstart' ) {
51948 this.fireEvent(name, e);
51951 var t = e.getTarget();
51953 var header = v.findHeaderIndex(t);
51954 if(header !== false){
51955 var ename = name == 'touchstart' ? 'click' : name;
51957 this.fireEvent("header" + ename, this, header, e);
51959 var row = v.findRowIndex(t);
51960 var cell = v.findCellIndex(t);
51961 if (name == 'touchstart') {
51962 // first touch is always a click.
51963 // hopefull this happens after selection is updated.?
51966 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
51967 var cs = this.selModel.getSelectedCell();
51968 if (row == cs[0] && cell == cs[1]){
51972 if (typeof(this.selModel.getSelections) != 'undefined') {
51973 var cs = this.selModel.getSelections();
51974 var ds = this.dataSource;
51975 if (cs.length == 1 && ds.getAt(row) == cs[0]){
51986 this.fireEvent("row" + name, this, row, e);
51987 if(cell !== false){
51988 this.fireEvent("cell" + name, this, row, cell, e);
51995 onClick : function(e){
51996 this.processEvent("click", e);
51999 onTouchStart : function(e){
52000 this.processEvent("touchstart", e);
52004 onContextMenu : function(e, t){
52005 this.processEvent("contextmenu", e);
52009 onDblClick : function(e){
52010 this.processEvent("dblclick", e);
52014 walkCells : function(row, col, step, fn, scope){
52015 var cm = this.colModel, clen = cm.getColumnCount();
52016 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52028 if(fn.call(scope || this, row, col, cm) === true){
52046 if(fn.call(scope || this, row, col, cm) === true){
52058 getSelections : function(){
52059 return this.selModel.getSelections();
52063 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52064 * but if manual update is required this method will initiate it.
52066 autoSize : function(){
52068 this.view.layout();
52069 if(this.view.adjustForScroll){
52070 this.view.adjustForScroll();
52076 * Returns the grid's underlying element.
52077 * @return {Element} The element
52079 getGridEl : function(){
52080 return this.container;
52083 // private for compatibility, overridden by editor grid
52084 stopEditing : function(){},
52087 * Returns the grid's SelectionModel.
52088 * @return {SelectionModel}
52090 getSelectionModel : function(){
52091 if(!this.selModel){
52092 this.selModel = new Roo.grid.RowSelectionModel();
52094 return this.selModel;
52098 * Returns the grid's DataSource.
52099 * @return {DataSource}
52101 getDataSource : function(){
52102 return this.dataSource;
52106 * Returns the grid's ColumnModel.
52107 * @return {ColumnModel}
52109 getColumnModel : function(){
52110 return this.colModel;
52114 * Returns the grid's GridView object.
52115 * @return {GridView}
52117 getView : function(){
52119 this.view = new Roo.grid.GridView(this.viewConfig);
52124 * Called to get grid's drag proxy text, by default returns this.ddText.
52127 getDragDropText : function(){
52128 var count = this.selModel.getCount();
52129 return String.format(this.ddText, count, count == 1 ? '' : 's');
52133 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
52134 * %0 is replaced with the number of selected rows.
52137 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
52139 * Ext JS Library 1.1.1
52140 * Copyright(c) 2006-2007, Ext JS, LLC.
52142 * Originally Released Under LGPL - original licence link has changed is not relivant.
52145 * <script type="text/javascript">
52148 Roo.grid.AbstractGridView = function(){
52152 "beforerowremoved" : true,
52153 "beforerowsinserted" : true,
52154 "beforerefresh" : true,
52155 "rowremoved" : true,
52156 "rowsinserted" : true,
52157 "rowupdated" : true,
52160 Roo.grid.AbstractGridView.superclass.constructor.call(this);
52163 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
52164 rowClass : "x-grid-row",
52165 cellClass : "x-grid-cell",
52166 tdClass : "x-grid-td",
52167 hdClass : "x-grid-hd",
52168 splitClass : "x-grid-hd-split",
52170 init: function(grid){
52172 var cid = this.grid.getGridEl().id;
52173 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
52174 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
52175 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
52176 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
52179 getColumnRenderers : function(){
52180 var renderers = [];
52181 var cm = this.grid.colModel;
52182 var colCount = cm.getColumnCount();
52183 for(var i = 0; i < colCount; i++){
52184 renderers[i] = cm.getRenderer(i);
52189 getColumnIds : function(){
52191 var cm = this.grid.colModel;
52192 var colCount = cm.getColumnCount();
52193 for(var i = 0; i < colCount; i++){
52194 ids[i] = cm.getColumnId(i);
52199 getDataIndexes : function(){
52200 if(!this.indexMap){
52201 this.indexMap = this.buildIndexMap();
52203 return this.indexMap.colToData;
52206 getColumnIndexByDataIndex : function(dataIndex){
52207 if(!this.indexMap){
52208 this.indexMap = this.buildIndexMap();
52210 return this.indexMap.dataToCol[dataIndex];
52214 * Set a css style for a column dynamically.
52215 * @param {Number} colIndex The index of the column
52216 * @param {String} name The css property name
52217 * @param {String} value The css value
52219 setCSSStyle : function(colIndex, name, value){
52220 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
52221 Roo.util.CSS.updateRule(selector, name, value);
52224 generateRules : function(cm){
52225 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
52226 Roo.util.CSS.removeStyleSheet(rulesId);
52227 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52228 var cid = cm.getColumnId(i);
52229 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
52230 this.tdSelector, cid, " {\n}\n",
52231 this.hdSelector, cid, " {\n}\n",
52232 this.splitSelector, cid, " {\n}\n");
52234 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52238 * Ext JS Library 1.1.1
52239 * Copyright(c) 2006-2007, Ext JS, LLC.
52241 * Originally Released Under LGPL - original licence link has changed is not relivant.
52244 * <script type="text/javascript">
52248 // This is a support class used internally by the Grid components
52249 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
52251 this.view = grid.getView();
52252 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52253 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
52255 this.setHandleElId(Roo.id(hd));
52256 this.setOuterHandleElId(Roo.id(hd2));
52258 this.scroll = false;
52260 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
52262 getDragData : function(e){
52263 var t = Roo.lib.Event.getTarget(e);
52264 var h = this.view.findHeaderCell(t);
52266 return {ddel: h.firstChild, header:h};
52271 onInitDrag : function(e){
52272 this.view.headersDisabled = true;
52273 var clone = this.dragData.ddel.cloneNode(true);
52274 clone.id = Roo.id();
52275 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
52276 this.proxy.update(clone);
52280 afterValidDrop : function(){
52282 setTimeout(function(){
52283 v.headersDisabled = false;
52287 afterInvalidDrop : function(){
52289 setTimeout(function(){
52290 v.headersDisabled = false;
52296 * Ext JS Library 1.1.1
52297 * Copyright(c) 2006-2007, Ext JS, LLC.
52299 * Originally Released Under LGPL - original licence link has changed is not relivant.
52302 * <script type="text/javascript">
52305 // This is a support class used internally by the Grid components
52306 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
52308 this.view = grid.getView();
52309 // split the proxies so they don't interfere with mouse events
52310 this.proxyTop = Roo.DomHelper.append(document.body, {
52311 cls:"col-move-top", html:" "
52313 this.proxyBottom = Roo.DomHelper.append(document.body, {
52314 cls:"col-move-bottom", html:" "
52316 this.proxyTop.hide = this.proxyBottom.hide = function(){
52317 this.setLeftTop(-100,-100);
52318 this.setStyle("visibility", "hidden");
52320 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52321 // temporarily disabled
52322 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
52323 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
52325 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
52326 proxyOffsets : [-4, -9],
52327 fly: Roo.Element.fly,
52329 getTargetFromEvent : function(e){
52330 var t = Roo.lib.Event.getTarget(e);
52331 var cindex = this.view.findCellIndex(t);
52332 if(cindex !== false){
52333 return this.view.getHeaderCell(cindex);
52338 nextVisible : function(h){
52339 var v = this.view, cm = this.grid.colModel;
52342 if(!cm.isHidden(v.getCellIndex(h))){
52350 prevVisible : function(h){
52351 var v = this.view, cm = this.grid.colModel;
52354 if(!cm.isHidden(v.getCellIndex(h))){
52362 positionIndicator : function(h, n, e){
52363 var x = Roo.lib.Event.getPageX(e);
52364 var r = Roo.lib.Dom.getRegion(n.firstChild);
52365 var px, pt, py = r.top + this.proxyOffsets[1];
52366 if((r.right - x) <= (r.right-r.left)/2){
52367 px = r.right+this.view.borderWidth;
52373 var oldIndex = this.view.getCellIndex(h);
52374 var newIndex = this.view.getCellIndex(n);
52376 if(this.grid.colModel.isFixed(newIndex)){
52380 var locked = this.grid.colModel.isLocked(newIndex);
52385 if(oldIndex < newIndex){
52388 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
52391 px += this.proxyOffsets[0];
52392 this.proxyTop.setLeftTop(px, py);
52393 this.proxyTop.show();
52394 if(!this.bottomOffset){
52395 this.bottomOffset = this.view.mainHd.getHeight();
52397 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
52398 this.proxyBottom.show();
52402 onNodeEnter : function(n, dd, e, data){
52403 if(data.header != n){
52404 this.positionIndicator(data.header, n, e);
52408 onNodeOver : function(n, dd, e, data){
52409 var result = false;
52410 if(data.header != n){
52411 result = this.positionIndicator(data.header, n, e);
52414 this.proxyTop.hide();
52415 this.proxyBottom.hide();
52417 return result ? this.dropAllowed : this.dropNotAllowed;
52420 onNodeOut : function(n, dd, e, data){
52421 this.proxyTop.hide();
52422 this.proxyBottom.hide();
52425 onNodeDrop : function(n, dd, e, data){
52426 var h = data.header;
52428 var cm = this.grid.colModel;
52429 var x = Roo.lib.Event.getPageX(e);
52430 var r = Roo.lib.Dom.getRegion(n.firstChild);
52431 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
52432 var oldIndex = this.view.getCellIndex(h);
52433 var newIndex = this.view.getCellIndex(n);
52434 var locked = cm.isLocked(newIndex);
52438 if(oldIndex < newIndex){
52441 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
52444 cm.setLocked(oldIndex, locked, true);
52445 cm.moveColumn(oldIndex, newIndex);
52446 this.grid.fireEvent("columnmove", oldIndex, newIndex);
52454 * Ext JS Library 1.1.1
52455 * Copyright(c) 2006-2007, Ext JS, LLC.
52457 * Originally Released Under LGPL - original licence link has changed is not relivant.
52460 * <script type="text/javascript">
52464 * @class Roo.grid.GridView
52465 * @extends Roo.util.Observable
52468 * @param {Object} config
52470 Roo.grid.GridView = function(config){
52471 Roo.grid.GridView.superclass.constructor.call(this);
52474 Roo.apply(this, config);
52477 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
52479 unselectable : 'unselectable="on"',
52480 unselectableCls : 'x-unselectable',
52483 rowClass : "x-grid-row",
52485 cellClass : "x-grid-col",
52487 tdClass : "x-grid-td",
52489 hdClass : "x-grid-hd",
52491 splitClass : "x-grid-split",
52493 sortClasses : ["sort-asc", "sort-desc"],
52495 enableMoveAnim : false,
52499 dh : Roo.DomHelper,
52501 fly : Roo.Element.fly,
52503 css : Roo.util.CSS,
52509 scrollIncrement : 22,
52511 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
52513 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
52515 bind : function(ds, cm){
52517 this.ds.un("load", this.onLoad, this);
52518 this.ds.un("datachanged", this.onDataChange, this);
52519 this.ds.un("add", this.onAdd, this);
52520 this.ds.un("remove", this.onRemove, this);
52521 this.ds.un("update", this.onUpdate, this);
52522 this.ds.un("clear", this.onClear, this);
52525 ds.on("load", this.onLoad, this);
52526 ds.on("datachanged", this.onDataChange, this);
52527 ds.on("add", this.onAdd, this);
52528 ds.on("remove", this.onRemove, this);
52529 ds.on("update", this.onUpdate, this);
52530 ds.on("clear", this.onClear, this);
52535 this.cm.un("widthchange", this.onColWidthChange, this);
52536 this.cm.un("headerchange", this.onHeaderChange, this);
52537 this.cm.un("hiddenchange", this.onHiddenChange, this);
52538 this.cm.un("columnmoved", this.onColumnMove, this);
52539 this.cm.un("columnlockchange", this.onColumnLock, this);
52542 this.generateRules(cm);
52543 cm.on("widthchange", this.onColWidthChange, this);
52544 cm.on("headerchange", this.onHeaderChange, this);
52545 cm.on("hiddenchange", this.onHiddenChange, this);
52546 cm.on("columnmoved", this.onColumnMove, this);
52547 cm.on("columnlockchange", this.onColumnLock, this);
52552 init: function(grid){
52553 Roo.grid.GridView.superclass.init.call(this, grid);
52555 this.bind(grid.dataSource, grid.colModel);
52557 grid.on("headerclick", this.handleHeaderClick, this);
52559 if(grid.trackMouseOver){
52560 grid.on("mouseover", this.onRowOver, this);
52561 grid.on("mouseout", this.onRowOut, this);
52563 grid.cancelTextSelection = function(){};
52564 this.gridId = grid.id;
52566 var tpls = this.templates || {};
52569 tpls.master = new Roo.Template(
52570 '<div class="x-grid" hidefocus="true">',
52571 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
52572 '<div class="x-grid-topbar"></div>',
52573 '<div class="x-grid-scroller"><div></div></div>',
52574 '<div class="x-grid-locked">',
52575 '<div class="x-grid-header">{lockedHeader}</div>',
52576 '<div class="x-grid-body">{lockedBody}</div>',
52578 '<div class="x-grid-viewport">',
52579 '<div class="x-grid-header">{header}</div>',
52580 '<div class="x-grid-body">{body}</div>',
52582 '<div class="x-grid-bottombar"></div>',
52584 '<div class="x-grid-resize-proxy"> </div>',
52587 tpls.master.disableformats = true;
52591 tpls.header = new Roo.Template(
52592 '<table border="0" cellspacing="0" cellpadding="0">',
52593 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
52596 tpls.header.disableformats = true;
52598 tpls.header.compile();
52601 tpls.hcell = new Roo.Template(
52602 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
52603 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
52606 tpls.hcell.disableFormats = true;
52608 tpls.hcell.compile();
52611 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
52612 this.unselectableCls + '" ' + this.unselectable +'> </div>');
52613 tpls.hsplit.disableFormats = true;
52615 tpls.hsplit.compile();
52618 tpls.body = new Roo.Template(
52619 '<table border="0" cellspacing="0" cellpadding="0">',
52620 "<tbody>{rows}</tbody>",
52623 tpls.body.disableFormats = true;
52625 tpls.body.compile();
52628 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
52629 tpls.row.disableFormats = true;
52631 tpls.row.compile();
52634 tpls.cell = new Roo.Template(
52635 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
52636 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
52637 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
52640 tpls.cell.disableFormats = true;
52642 tpls.cell.compile();
52644 this.templates = tpls;
52647 // remap these for backwards compat
52648 onColWidthChange : function(){
52649 this.updateColumns.apply(this, arguments);
52651 onHeaderChange : function(){
52652 this.updateHeaders.apply(this, arguments);
52654 onHiddenChange : function(){
52655 this.handleHiddenChange.apply(this, arguments);
52657 onColumnMove : function(){
52658 this.handleColumnMove.apply(this, arguments);
52660 onColumnLock : function(){
52661 this.handleLockChange.apply(this, arguments);
52664 onDataChange : function(){
52666 this.updateHeaderSortState();
52669 onClear : function(){
52673 onUpdate : function(ds, record){
52674 this.refreshRow(record);
52677 refreshRow : function(record){
52678 var ds = this.ds, index;
52679 if(typeof record == 'number'){
52681 record = ds.getAt(index);
52683 index = ds.indexOf(record);
52685 this.insertRows(ds, index, index, true);
52686 this.onRemove(ds, record, index+1, true);
52687 this.syncRowHeights(index, index);
52689 this.fireEvent("rowupdated", this, index, record);
52692 onAdd : function(ds, records, index){
52693 this.insertRows(ds, index, index + (records.length-1));
52696 onRemove : function(ds, record, index, isUpdate){
52697 if(isUpdate !== true){
52698 this.fireEvent("beforerowremoved", this, index, record);
52700 var bt = this.getBodyTable(), lt = this.getLockedTable();
52701 if(bt.rows[index]){
52702 bt.firstChild.removeChild(bt.rows[index]);
52704 if(lt.rows[index]){
52705 lt.firstChild.removeChild(lt.rows[index]);
52707 if(isUpdate !== true){
52708 this.stripeRows(index);
52709 this.syncRowHeights(index, index);
52711 this.fireEvent("rowremoved", this, index, record);
52715 onLoad : function(){
52716 this.scrollToTop();
52720 * Scrolls the grid to the top
52722 scrollToTop : function(){
52724 this.scroller.dom.scrollTop = 0;
52730 * Gets a panel in the header of the grid that can be used for toolbars etc.
52731 * After modifying the contents of this panel a call to grid.autoSize() may be
52732 * required to register any changes in size.
52733 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
52734 * @return Roo.Element
52736 getHeaderPanel : function(doShow){
52738 this.headerPanel.show();
52740 return this.headerPanel;
52744 * Gets a panel in the footer of the grid that can be used for toolbars etc.
52745 * After modifying the contents of this panel a call to grid.autoSize() may be
52746 * required to register any changes in size.
52747 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
52748 * @return Roo.Element
52750 getFooterPanel : function(doShow){
52752 this.footerPanel.show();
52754 return this.footerPanel;
52757 initElements : function(){
52758 var E = Roo.Element;
52759 var el = this.grid.getGridEl().dom.firstChild;
52760 var cs = el.childNodes;
52762 this.el = new E(el);
52764 this.focusEl = new E(el.firstChild);
52765 this.focusEl.swallowEvent("click", true);
52767 this.headerPanel = new E(cs[1]);
52768 this.headerPanel.enableDisplayMode("block");
52770 this.scroller = new E(cs[2]);
52771 this.scrollSizer = new E(this.scroller.dom.firstChild);
52773 this.lockedWrap = new E(cs[3]);
52774 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
52775 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
52777 this.mainWrap = new E(cs[4]);
52778 this.mainHd = new E(this.mainWrap.dom.firstChild);
52779 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
52781 this.footerPanel = new E(cs[5]);
52782 this.footerPanel.enableDisplayMode("block");
52784 this.resizeProxy = new E(cs[6]);
52786 this.headerSelector = String.format(
52787 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
52788 this.lockedHd.id, this.mainHd.id
52791 this.splitterSelector = String.format(
52792 '#{0} div.x-grid-split, #{1} div.x-grid-split',
52793 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
52796 idToCssName : function(s)
52798 return s.replace(/[^a-z0-9]+/ig, '-');
52801 getHeaderCell : function(index){
52802 return Roo.DomQuery.select(this.headerSelector)[index];
52805 getHeaderCellMeasure : function(index){
52806 return this.getHeaderCell(index).firstChild;
52809 getHeaderCellText : function(index){
52810 return this.getHeaderCell(index).firstChild.firstChild;
52813 getLockedTable : function(){
52814 return this.lockedBody.dom.firstChild;
52817 getBodyTable : function(){
52818 return this.mainBody.dom.firstChild;
52821 getLockedRow : function(index){
52822 return this.getLockedTable().rows[index];
52825 getRow : function(index){
52826 return this.getBodyTable().rows[index];
52829 getRowComposite : function(index){
52831 this.rowEl = new Roo.CompositeElementLite();
52833 var els = [], lrow, mrow;
52834 if(lrow = this.getLockedRow(index)){
52837 if(mrow = this.getRow(index)){
52840 this.rowEl.elements = els;
52844 * Gets the 'td' of the cell
52846 * @param {Integer} rowIndex row to select
52847 * @param {Integer} colIndex column to select
52851 getCell : function(rowIndex, colIndex){
52852 var locked = this.cm.getLockedCount();
52854 if(colIndex < locked){
52855 source = this.lockedBody.dom.firstChild;
52857 source = this.mainBody.dom.firstChild;
52858 colIndex -= locked;
52860 return source.rows[rowIndex].childNodes[colIndex];
52863 getCellText : function(rowIndex, colIndex){
52864 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
52867 getCellBox : function(cell){
52868 var b = this.fly(cell).getBox();
52869 if(Roo.isOpera){ // opera fails to report the Y
52870 b.y = cell.offsetTop + this.mainBody.getY();
52875 getCellIndex : function(cell){
52876 var id = String(cell.className).match(this.cellRE);
52878 return parseInt(id[1], 10);
52883 findHeaderIndex : function(n){
52884 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
52885 return r ? this.getCellIndex(r) : false;
52888 findHeaderCell : function(n){
52889 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
52890 return r ? r : false;
52893 findRowIndex : function(n){
52897 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
52898 return r ? r.rowIndex : false;
52901 findCellIndex : function(node){
52902 var stop = this.el.dom;
52903 while(node && node != stop){
52904 if(this.findRE.test(node.className)){
52905 return this.getCellIndex(node);
52907 node = node.parentNode;
52912 getColumnId : function(index){
52913 return this.cm.getColumnId(index);
52916 getSplitters : function()
52918 if(this.splitterSelector){
52919 return Roo.DomQuery.select(this.splitterSelector);
52925 getSplitter : function(index){
52926 return this.getSplitters()[index];
52929 onRowOver : function(e, t){
52931 if((row = this.findRowIndex(t)) !== false){
52932 this.getRowComposite(row).addClass("x-grid-row-over");
52936 onRowOut : function(e, t){
52938 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
52939 this.getRowComposite(row).removeClass("x-grid-row-over");
52943 renderHeaders : function(){
52945 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
52946 var cb = [], lb = [], sb = [], lsb = [], p = {};
52947 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52948 p.cellId = "x-grid-hd-0-" + i;
52949 p.splitId = "x-grid-csplit-0-" + i;
52950 p.id = cm.getColumnId(i);
52951 p.title = cm.getColumnTooltip(i) || "";
52952 p.value = cm.getColumnHeader(i) || "";
52953 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
52954 if(!cm.isLocked(i)){
52955 cb[cb.length] = ct.apply(p);
52956 sb[sb.length] = st.apply(p);
52958 lb[lb.length] = ct.apply(p);
52959 lsb[lsb.length] = st.apply(p);
52962 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
52963 ht.apply({cells: cb.join(""), splits:sb.join("")})];
52966 updateHeaders : function(){
52967 var html = this.renderHeaders();
52968 this.lockedHd.update(html[0]);
52969 this.mainHd.update(html[1]);
52973 * Focuses the specified row.
52974 * @param {Number} row The row index
52976 focusRow : function(row)
52978 //Roo.log('GridView.focusRow');
52979 var x = this.scroller.dom.scrollLeft;
52980 this.focusCell(row, 0, false);
52981 this.scroller.dom.scrollLeft = x;
52985 * Focuses the specified cell.
52986 * @param {Number} row The row index
52987 * @param {Number} col The column index
52988 * @param {Boolean} hscroll false to disable horizontal scrolling
52990 focusCell : function(row, col, hscroll)
52992 //Roo.log('GridView.focusCell');
52993 var el = this.ensureVisible(row, col, hscroll);
52994 this.focusEl.alignTo(el, "tl-tl");
52996 this.focusEl.focus();
52998 this.focusEl.focus.defer(1, this.focusEl);
53003 * Scrolls the specified cell into view
53004 * @param {Number} row The row index
53005 * @param {Number} col The column index
53006 * @param {Boolean} hscroll false to disable horizontal scrolling
53008 ensureVisible : function(row, col, hscroll)
53010 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53011 //return null; //disable for testing.
53012 if(typeof row != "number"){
53013 row = row.rowIndex;
53015 if(row < 0 && row >= this.ds.getCount()){
53018 col = (col !== undefined ? col : 0);
53019 var cm = this.grid.colModel;
53020 while(cm.isHidden(col)){
53024 var el = this.getCell(row, col);
53028 var c = this.scroller.dom;
53030 var ctop = parseInt(el.offsetTop, 10);
53031 var cleft = parseInt(el.offsetLeft, 10);
53032 var cbot = ctop + el.offsetHeight;
53033 var cright = cleft + el.offsetWidth;
53035 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53036 var stop = parseInt(c.scrollTop, 10);
53037 var sleft = parseInt(c.scrollLeft, 10);
53038 var sbot = stop + ch;
53039 var sright = sleft + c.clientWidth;
53041 Roo.log('GridView.ensureVisible:' +
53043 ' c.clientHeight:' + c.clientHeight +
53044 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53052 c.scrollTop = ctop;
53053 //Roo.log("set scrolltop to ctop DISABLE?");
53054 }else if(cbot > sbot){
53055 //Roo.log("set scrolltop to cbot-ch");
53056 c.scrollTop = cbot-ch;
53059 if(hscroll !== false){
53061 c.scrollLeft = cleft;
53062 }else if(cright > sright){
53063 c.scrollLeft = cright-c.clientWidth;
53070 updateColumns : function(){
53071 this.grid.stopEditing();
53072 var cm = this.grid.colModel, colIds = this.getColumnIds();
53073 //var totalWidth = cm.getTotalWidth();
53075 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53076 //if(cm.isHidden(i)) continue;
53077 var w = cm.getColumnWidth(i);
53078 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53079 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53081 this.updateSplitters();
53084 generateRules : function(cm){
53085 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53086 Roo.util.CSS.removeStyleSheet(rulesId);
53087 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53088 var cid = cm.getColumnId(i);
53090 if(cm.config[i].align){
53091 align = 'text-align:'+cm.config[i].align+';';
53094 if(cm.isHidden(i)){
53095 hidden = 'display:none;';
53097 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53099 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53100 this.hdSelector, cid, " {\n", align, width, "}\n",
53101 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53102 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53104 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53107 updateSplitters : function(){
53108 var cm = this.cm, s = this.getSplitters();
53109 if(s){ // splitters not created yet
53110 var pos = 0, locked = true;
53111 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53112 if(cm.isHidden(i)) continue;
53113 var w = cm.getColumnWidth(i); // make sure it's a number
53114 if(!cm.isLocked(i) && locked){
53119 s[i].style.left = (pos-this.splitOffset) + "px";
53124 handleHiddenChange : function(colModel, colIndex, hidden){
53126 this.hideColumn(colIndex);
53128 this.unhideColumn(colIndex);
53132 hideColumn : function(colIndex){
53133 var cid = this.getColumnId(colIndex);
53134 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
53135 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
53137 this.updateHeaders();
53139 this.updateSplitters();
53143 unhideColumn : function(colIndex){
53144 var cid = this.getColumnId(colIndex);
53145 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
53146 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
53149 this.updateHeaders();
53151 this.updateSplitters();
53155 insertRows : function(dm, firstRow, lastRow, isUpdate){
53156 if(firstRow == 0 && lastRow == dm.getCount()-1){
53160 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
53162 var s = this.getScrollState();
53163 var markup = this.renderRows(firstRow, lastRow);
53164 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
53165 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
53166 this.restoreScroll(s);
53168 this.fireEvent("rowsinserted", this, firstRow, lastRow);
53169 this.syncRowHeights(firstRow, lastRow);
53170 this.stripeRows(firstRow);
53176 bufferRows : function(markup, target, index){
53177 var before = null, trows = target.rows, tbody = target.tBodies[0];
53178 if(index < trows.length){
53179 before = trows[index];
53181 var b = document.createElement("div");
53182 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
53183 var rows = b.firstChild.rows;
53184 for(var i = 0, len = rows.length; i < len; i++){
53186 tbody.insertBefore(rows[0], before);
53188 tbody.appendChild(rows[0]);
53195 deleteRows : function(dm, firstRow, lastRow){
53196 if(dm.getRowCount()<1){
53197 this.fireEvent("beforerefresh", this);
53198 this.mainBody.update("");
53199 this.lockedBody.update("");
53200 this.fireEvent("refresh", this);
53202 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
53203 var bt = this.getBodyTable();
53204 var tbody = bt.firstChild;
53205 var rows = bt.rows;
53206 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
53207 tbody.removeChild(rows[firstRow]);
53209 this.stripeRows(firstRow);
53210 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
53214 updateRows : function(dataSource, firstRow, lastRow){
53215 var s = this.getScrollState();
53217 this.restoreScroll(s);
53220 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
53224 this.updateHeaderSortState();
53227 getScrollState : function(){
53229 var sb = this.scroller.dom;
53230 return {left: sb.scrollLeft, top: sb.scrollTop};
53233 stripeRows : function(startRow){
53234 if(!this.grid.stripeRows || this.ds.getCount() < 1){
53237 startRow = startRow || 0;
53238 var rows = this.getBodyTable().rows;
53239 var lrows = this.getLockedTable().rows;
53240 var cls = ' x-grid-row-alt ';
53241 for(var i = startRow, len = rows.length; i < len; i++){
53242 var row = rows[i], lrow = lrows[i];
53243 var isAlt = ((i+1) % 2 == 0);
53244 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
53245 if(isAlt == hasAlt){
53249 row.className += " x-grid-row-alt";
53251 row.className = row.className.replace("x-grid-row-alt", "");
53254 lrow.className = row.className;
53259 restoreScroll : function(state){
53260 //Roo.log('GridView.restoreScroll');
53261 var sb = this.scroller.dom;
53262 sb.scrollLeft = state.left;
53263 sb.scrollTop = state.top;
53267 syncScroll : function(){
53268 //Roo.log('GridView.syncScroll');
53269 var sb = this.scroller.dom;
53270 var sh = this.mainHd.dom;
53271 var bs = this.mainBody.dom;
53272 var lv = this.lockedBody.dom;
53273 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
53274 lv.scrollTop = bs.scrollTop = sb.scrollTop;
53277 handleScroll : function(e){
53279 var sb = this.scroller.dom;
53280 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
53284 handleWheel : function(e){
53285 var d = e.getWheelDelta();
53286 this.scroller.dom.scrollTop -= d*22;
53287 // set this here to prevent jumpy scrolling on large tables
53288 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
53292 renderRows : function(startRow, endRow){
53293 // pull in all the crap needed to render rows
53294 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
53295 var colCount = cm.getColumnCount();
53297 if(ds.getCount() < 1){
53301 // build a map for all the columns
53303 for(var i = 0; i < colCount; i++){
53304 var name = cm.getDataIndex(i);
53306 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
53307 renderer : cm.getRenderer(i),
53308 id : cm.getColumnId(i),
53309 locked : cm.isLocked(i)
53313 startRow = startRow || 0;
53314 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
53316 // records to render
53317 var rs = ds.getRange(startRow, endRow);
53319 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
53322 // As much as I hate to duplicate code, this was branched because FireFox really hates
53323 // [].join("") on strings. The performance difference was substantial enough to
53324 // branch this function
53325 doRender : Roo.isGecko ?
53326 function(cs, rs, ds, startRow, colCount, stripe){
53327 var ts = this.templates, ct = ts.cell, rt = ts.row;
53329 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53331 var hasListener = this.grid.hasListener('rowclass');
53333 for(var j = 0, len = rs.length; j < len; j++){
53334 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
53335 for(var i = 0; i < colCount; i++){
53337 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53339 p.css = p.attr = "";
53340 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53341 if(p.value == undefined || p.value === "") p.value = " ";
53342 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53343 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53345 var markup = ct.apply(p);
53353 if(stripe && ((rowIndex+1) % 2 == 0)){
53354 alt.push("x-grid-row-alt")
53357 alt.push( " x-grid-dirty-row");
53360 if(this.getRowClass){
53361 alt.push(this.getRowClass(r, rowIndex));
53367 rowIndex : rowIndex,
53370 this.grid.fireEvent('rowclass', this, rowcfg);
53371 alt.push(rowcfg.rowClass);
53373 rp.alt = alt.join(" ");
53374 lbuf+= rt.apply(rp);
53376 buf+= rt.apply(rp);
53378 return [lbuf, buf];
53380 function(cs, rs, ds, startRow, colCount, stripe){
53381 var ts = this.templates, ct = ts.cell, rt = ts.row;
53383 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53384 var hasListener = this.grid.hasListener('rowclass');
53387 for(var j = 0, len = rs.length; j < len; j++){
53388 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
53389 for(var i = 0; i < colCount; i++){
53391 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53393 p.css = p.attr = "";
53394 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53395 if(p.value == undefined || p.value === "") p.value = " ";
53396 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53397 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53400 var markup = ct.apply(p);
53402 cb[cb.length] = markup;
53404 lcb[lcb.length] = markup;
53408 if(stripe && ((rowIndex+1) % 2 == 0)){
53409 alt.push( "x-grid-row-alt");
53412 alt.push(" x-grid-dirty-row");
53415 if(this.getRowClass){
53416 alt.push( this.getRowClass(r, rowIndex));
53422 rowIndex : rowIndex,
53425 this.grid.fireEvent('rowclass', this, rowcfg);
53426 alt.push(rowcfg.rowClass);
53428 rp.alt = alt.join(" ");
53429 rp.cells = lcb.join("");
53430 lbuf[lbuf.length] = rt.apply(rp);
53431 rp.cells = cb.join("");
53432 buf[buf.length] = rt.apply(rp);
53434 return [lbuf.join(""), buf.join("")];
53437 renderBody : function(){
53438 var markup = this.renderRows();
53439 var bt = this.templates.body;
53440 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
53444 * Refreshes the grid
53445 * @param {Boolean} headersToo
53447 refresh : function(headersToo){
53448 this.fireEvent("beforerefresh", this);
53449 this.grid.stopEditing();
53450 var result = this.renderBody();
53451 this.lockedBody.update(result[0]);
53452 this.mainBody.update(result[1]);
53453 if(headersToo === true){
53454 this.updateHeaders();
53455 this.updateColumns();
53456 this.updateSplitters();
53457 this.updateHeaderSortState();
53459 this.syncRowHeights();
53461 this.fireEvent("refresh", this);
53464 handleColumnMove : function(cm, oldIndex, newIndex){
53465 this.indexMap = null;
53466 var s = this.getScrollState();
53467 this.refresh(true);
53468 this.restoreScroll(s);
53469 this.afterMove(newIndex);
53472 afterMove : function(colIndex){
53473 if(this.enableMoveAnim && Roo.enableFx){
53474 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
53476 // if multisort - fix sortOrder, and reload..
53477 if (this.grid.dataSource.multiSort) {
53478 // the we can call sort again..
53479 var dm = this.grid.dataSource;
53480 var cm = this.grid.colModel;
53482 for(var i = 0; i < cm.config.length; i++ ) {
53484 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
53485 continue; // dont' bother, it's not in sort list or being set.
53488 so.push(cm.config[i].dataIndex);
53491 dm.load(dm.lastOptions);
53498 updateCell : function(dm, rowIndex, dataIndex){
53499 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
53500 if(typeof colIndex == "undefined"){ // not present in grid
53503 var cm = this.grid.colModel;
53504 var cell = this.getCell(rowIndex, colIndex);
53505 var cellText = this.getCellText(rowIndex, colIndex);
53508 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
53509 id : cm.getColumnId(colIndex),
53510 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
53512 var renderer = cm.getRenderer(colIndex);
53513 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
53514 if(typeof val == "undefined" || val === "") val = " ";
53515 cellText.innerHTML = val;
53516 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
53517 this.syncRowHeights(rowIndex, rowIndex);
53520 calcColumnWidth : function(colIndex, maxRowsToMeasure){
53522 if(this.grid.autoSizeHeaders){
53523 var h = this.getHeaderCellMeasure(colIndex);
53524 maxWidth = Math.max(maxWidth, h.scrollWidth);
53527 if(this.cm.isLocked(colIndex)){
53528 tb = this.getLockedTable();
53531 tb = this.getBodyTable();
53532 index = colIndex - this.cm.getLockedCount();
53535 var rows = tb.rows;
53536 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
53537 for(var i = 0; i < stopIndex; i++){
53538 var cell = rows[i].childNodes[index].firstChild;
53539 maxWidth = Math.max(maxWidth, cell.scrollWidth);
53542 return maxWidth + /*margin for error in IE*/ 5;
53545 * Autofit a column to its content.
53546 * @param {Number} colIndex
53547 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
53549 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
53550 if(this.cm.isHidden(colIndex)){
53551 return; // can't calc a hidden column
53554 var cid = this.cm.getColumnId(colIndex);
53555 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
53556 if(this.grid.autoSizeHeaders){
53557 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
53560 var newWidth = this.calcColumnWidth(colIndex);
53561 this.cm.setColumnWidth(colIndex,
53562 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
53563 if(!suppressEvent){
53564 this.grid.fireEvent("columnresize", colIndex, newWidth);
53569 * Autofits all columns to their content and then expands to fit any extra space in the grid
53571 autoSizeColumns : function(){
53572 var cm = this.grid.colModel;
53573 var colCount = cm.getColumnCount();
53574 for(var i = 0; i < colCount; i++){
53575 this.autoSizeColumn(i, true, true);
53577 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
53580 this.updateColumns();
53586 * Autofits all columns to the grid's width proportionate with their current size
53587 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
53589 fitColumns : function(reserveScrollSpace){
53590 var cm = this.grid.colModel;
53591 var colCount = cm.getColumnCount();
53595 for (i = 0; i < colCount; i++){
53596 if(!cm.isHidden(i) && !cm.isFixed(i)){
53597 w = cm.getColumnWidth(i);
53603 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
53604 if(reserveScrollSpace){
53607 var frac = (avail - cm.getTotalWidth())/width;
53608 while (cols.length){
53611 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
53613 this.updateColumns();
53617 onRowSelect : function(rowIndex){
53618 var row = this.getRowComposite(rowIndex);
53619 row.addClass("x-grid-row-selected");
53622 onRowDeselect : function(rowIndex){
53623 var row = this.getRowComposite(rowIndex);
53624 row.removeClass("x-grid-row-selected");
53627 onCellSelect : function(row, col){
53628 var cell = this.getCell(row, col);
53630 Roo.fly(cell).addClass("x-grid-cell-selected");
53634 onCellDeselect : function(row, col){
53635 var cell = this.getCell(row, col);
53637 Roo.fly(cell).removeClass("x-grid-cell-selected");
53641 updateHeaderSortState : function(){
53643 // sort state can be single { field: xxx, direction : yyy}
53644 // or { xxx=>ASC , yyy : DESC ..... }
53647 if (!this.ds.multiSort) {
53648 var state = this.ds.getSortState();
53652 mstate[state.field] = state.direction;
53653 // FIXME... - this is not used here.. but might be elsewhere..
53654 this.sortState = state;
53657 mstate = this.ds.sortToggle;
53659 //remove existing sort classes..
53661 var sc = this.sortClasses;
53662 var hds = this.el.select(this.headerSelector).removeClass(sc);
53664 for(var f in mstate) {
53666 var sortColumn = this.cm.findColumnIndex(f);
53668 if(sortColumn != -1){
53669 var sortDir = mstate[f];
53670 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
53679 handleHeaderClick : function(g, index,e){
53681 Roo.log("header click");
53684 // touch events on header are handled by context
53685 this.handleHdCtx(g,index,e);
53690 if(this.headersDisabled){
53693 var dm = g.dataSource, cm = g.colModel;
53694 if(!cm.isSortable(index)){
53699 if (dm.multiSort) {
53700 // update the sortOrder
53702 for(var i = 0; i < cm.config.length; i++ ) {
53704 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
53705 continue; // dont' bother, it's not in sort list or being set.
53708 so.push(cm.config[i].dataIndex);
53714 dm.sort(cm.getDataIndex(index));
53718 destroy : function(){
53720 this.colMenu.removeAll();
53721 Roo.menu.MenuMgr.unregister(this.colMenu);
53722 this.colMenu.getEl().remove();
53723 delete this.colMenu;
53726 this.hmenu.removeAll();
53727 Roo.menu.MenuMgr.unregister(this.hmenu);
53728 this.hmenu.getEl().remove();
53731 if(this.grid.enableColumnMove){
53732 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53734 for(var dd in dds){
53735 if(!dds[dd].config.isTarget && dds[dd].dragElId){
53736 var elid = dds[dd].dragElId;
53738 Roo.get(elid).remove();
53739 } else if(dds[dd].config.isTarget){
53740 dds[dd].proxyTop.remove();
53741 dds[dd].proxyBottom.remove();
53744 if(Roo.dd.DDM.locationCache[dd]){
53745 delete Roo.dd.DDM.locationCache[dd];
53748 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53751 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
53752 this.bind(null, null);
53753 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
53756 handleLockChange : function(){
53757 this.refresh(true);
53760 onDenyColumnLock : function(){
53764 onDenyColumnHide : function(){
53768 handleHdMenuClick : function(item){
53769 var index = this.hdCtxIndex;
53770 var cm = this.cm, ds = this.ds;
53773 ds.sort(cm.getDataIndex(index), "ASC");
53776 ds.sort(cm.getDataIndex(index), "DESC");
53779 var lc = cm.getLockedCount();
53780 if(cm.getColumnCount(true) <= lc+1){
53781 this.onDenyColumnLock();
53785 cm.setLocked(index, true, true);
53786 cm.moveColumn(index, lc);
53787 this.grid.fireEvent("columnmove", index, lc);
53789 cm.setLocked(index, true);
53793 var lc = cm.getLockedCount();
53794 if((lc-1) != index){
53795 cm.setLocked(index, false, true);
53796 cm.moveColumn(index, lc-1);
53797 this.grid.fireEvent("columnmove", index, lc-1);
53799 cm.setLocked(index, false);
53802 case 'wider': // used to expand cols on touch..
53804 var cw = cm.getColumnWidth(index);
53805 cw += (item.id == 'wider' ? 1 : -1) * 50;
53806 cw = Math.max(0, cw);
53807 cw = Math.min(cw,4000);
53808 cm.setColumnWidth(index, cw);
53812 index = cm.getIndexById(item.id.substr(4));
53814 if(item.checked && cm.getColumnCount(true) <= 1){
53815 this.onDenyColumnHide();
53818 cm.setHidden(index, item.checked);
53824 beforeColMenuShow : function(){
53825 var cm = this.cm, colCount = cm.getColumnCount();
53826 this.colMenu.removeAll();
53827 for(var i = 0; i < colCount; i++){
53828 this.colMenu.add(new Roo.menu.CheckItem({
53829 id: "col-"+cm.getColumnId(i),
53830 text: cm.getColumnHeader(i),
53831 checked: !cm.isHidden(i),
53837 handleHdCtx : function(g, index, e){
53839 var hd = this.getHeaderCell(index);
53840 this.hdCtxIndex = index;
53841 var ms = this.hmenu.items, cm = this.cm;
53842 ms.get("asc").setDisabled(!cm.isSortable(index));
53843 ms.get("desc").setDisabled(!cm.isSortable(index));
53844 if(this.grid.enableColLock !== false){
53845 ms.get("lock").setDisabled(cm.isLocked(index));
53846 ms.get("unlock").setDisabled(!cm.isLocked(index));
53848 this.hmenu.show(hd, "tl-bl");
53851 handleHdOver : function(e){
53852 var hd = this.findHeaderCell(e.getTarget());
53853 if(hd && !this.headersDisabled){
53854 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
53855 this.fly(hd).addClass("x-grid-hd-over");
53860 handleHdOut : function(e){
53861 var hd = this.findHeaderCell(e.getTarget());
53863 this.fly(hd).removeClass("x-grid-hd-over");
53867 handleSplitDblClick : function(e, t){
53868 var i = this.getCellIndex(t);
53869 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
53870 this.autoSizeColumn(i, true);
53875 render : function(){
53878 var colCount = cm.getColumnCount();
53880 if(this.grid.monitorWindowResize === true){
53881 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
53883 var header = this.renderHeaders();
53884 var body = this.templates.body.apply({rows:""});
53885 var html = this.templates.master.apply({
53888 lockedHeader: header[0],
53892 //this.updateColumns();
53894 this.grid.getGridEl().dom.innerHTML = html;
53896 this.initElements();
53898 // a kludge to fix the random scolling effect in webkit
53899 this.el.on("scroll", function() {
53900 this.el.dom.scrollTop=0; // hopefully not recursive..
53903 this.scroller.on("scroll", this.handleScroll, this);
53904 this.lockedBody.on("mousewheel", this.handleWheel, this);
53905 this.mainBody.on("mousewheel", this.handleWheel, this);
53907 this.mainHd.on("mouseover", this.handleHdOver, this);
53908 this.mainHd.on("mouseout", this.handleHdOut, this);
53909 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
53910 {delegate: "."+this.splitClass});
53912 this.lockedHd.on("mouseover", this.handleHdOver, this);
53913 this.lockedHd.on("mouseout", this.handleHdOut, this);
53914 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
53915 {delegate: "."+this.splitClass});
53917 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
53918 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53921 this.updateSplitters();
53923 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
53924 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53925 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53928 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
53929 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
53931 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
53932 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
53934 if(this.grid.enableColLock !== false){
53935 this.hmenu.add('-',
53936 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
53937 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
53941 this.hmenu.add('-',
53942 {id:"wider", text: this.columnsWiderText},
53943 {id:"narrow", text: this.columnsNarrowText }
53949 if(this.grid.enableColumnHide !== false){
53951 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
53952 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
53953 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
53955 this.hmenu.add('-',
53956 {id:"columns", text: this.columnsText, menu: this.colMenu}
53959 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
53961 this.grid.on("headercontextmenu", this.handleHdCtx, this);
53964 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
53965 this.dd = new Roo.grid.GridDragZone(this.grid, {
53966 ddGroup : this.grid.ddGroup || 'GridDD'
53972 for(var i = 0; i < colCount; i++){
53973 if(cm.isHidden(i)){
53974 this.hideColumn(i);
53976 if(cm.config[i].align){
53977 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
53978 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
53982 this.updateHeaderSortState();
53984 this.beforeInitialResize();
53987 // two part rendering gives faster view to the user
53988 this.renderPhase2.defer(1, this);
53991 renderPhase2 : function(){
53992 // render the rows now
53994 if(this.grid.autoSizeColumns){
53995 this.autoSizeColumns();
53999 beforeInitialResize : function(){
54003 onColumnSplitterMoved : function(i, w){
54004 this.userResized = true;
54005 var cm = this.grid.colModel;
54006 cm.setColumnWidth(i, w, true);
54007 var cid = cm.getColumnId(i);
54008 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54009 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54010 this.updateSplitters();
54012 this.grid.fireEvent("columnresize", i, w);
54015 syncRowHeights : function(startIndex, endIndex){
54016 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54017 startIndex = startIndex || 0;
54018 var mrows = this.getBodyTable().rows;
54019 var lrows = this.getLockedTable().rows;
54020 var len = mrows.length-1;
54021 endIndex = Math.min(endIndex || len, len);
54022 for(var i = startIndex; i <= endIndex; i++){
54023 var m = mrows[i], l = lrows[i];
54024 var h = Math.max(m.offsetHeight, l.offsetHeight);
54025 m.style.height = l.style.height = h + "px";
54030 layout : function(initialRender, is2ndPass){
54032 var auto = g.autoHeight;
54033 var scrollOffset = 16;
54034 var c = g.getGridEl(), cm = this.cm,
54035 expandCol = g.autoExpandColumn,
54037 //c.beginMeasure();
54039 if(!c.dom.offsetWidth){ // display:none?
54041 this.lockedWrap.show();
54042 this.mainWrap.show();
54047 var hasLock = this.cm.isLocked(0);
54049 var tbh = this.headerPanel.getHeight();
54050 var bbh = this.footerPanel.getHeight();
54053 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54054 var newHeight = ch + c.getBorderWidth("tb");
54056 newHeight = Math.min(g.maxHeight, newHeight);
54058 c.setHeight(newHeight);
54062 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54065 var s = this.scroller;
54067 var csize = c.getSize(true);
54069 this.el.setSize(csize.width, csize.height);
54071 this.headerPanel.setWidth(csize.width);
54072 this.footerPanel.setWidth(csize.width);
54074 var hdHeight = this.mainHd.getHeight();
54075 var vw = csize.width;
54076 var vh = csize.height - (tbh + bbh);
54080 var bt = this.getBodyTable();
54081 var ltWidth = hasLock ?
54082 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54084 var scrollHeight = bt.offsetHeight;
54085 var scrollWidth = ltWidth + bt.offsetWidth;
54086 var vscroll = false, hscroll = false;
54088 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54090 var lw = this.lockedWrap, mw = this.mainWrap;
54091 var lb = this.lockedBody, mb = this.mainBody;
54093 setTimeout(function(){
54094 var t = s.dom.offsetTop;
54095 var w = s.dom.clientWidth,
54096 h = s.dom.clientHeight;
54099 lw.setSize(ltWidth, h);
54101 mw.setLeftTop(ltWidth, t);
54102 mw.setSize(w-ltWidth, h);
54104 lb.setHeight(h-hdHeight);
54105 mb.setHeight(h-hdHeight);
54107 if(is2ndPass !== true && !gv.userResized && expandCol){
54108 // high speed resize without full column calculation
54110 var ci = cm.getIndexById(expandCol);
54112 ci = cm.findColumnIndex(expandCol);
54114 ci = Math.max(0, ci); // make sure it's got at least the first col.
54115 var expandId = cm.getColumnId(ci);
54116 var tw = cm.getTotalWidth(false);
54117 var currentWidth = cm.getColumnWidth(ci);
54118 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54119 if(currentWidth != cw){
54120 cm.setColumnWidth(ci, cw, true);
54121 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54122 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54123 gv.updateSplitters();
54124 gv.layout(false, true);
54136 onWindowResize : function(){
54137 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
54143 appendFooter : function(parentEl){
54147 sortAscText : "Sort Ascending",
54148 sortDescText : "Sort Descending",
54149 lockText : "Lock Column",
54150 unlockText : "Unlock Column",
54151 columnsText : "Columns",
54153 columnsWiderText : "Wider",
54154 columnsNarrowText : "Thinner"
54158 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
54159 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
54160 this.proxy.el.addClass('x-grid3-col-dd');
54163 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
54164 handleMouseDown : function(e){
54168 callHandleMouseDown : function(e){
54169 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
54174 * Ext JS Library 1.1.1
54175 * Copyright(c) 2006-2007, Ext JS, LLC.
54177 * Originally Released Under LGPL - original licence link has changed is not relivant.
54180 * <script type="text/javascript">
54184 // This is a support class used internally by the Grid components
54185 Roo.grid.SplitDragZone = function(grid, hd, hd2){
54187 this.view = grid.getView();
54188 this.proxy = this.view.resizeProxy;
54189 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
54190 "gridSplitters" + this.grid.getGridEl().id, {
54191 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
54193 this.setHandleElId(Roo.id(hd));
54194 this.setOuterHandleElId(Roo.id(hd2));
54195 this.scroll = false;
54197 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
54198 fly: Roo.Element.fly,
54200 b4StartDrag : function(x, y){
54201 this.view.headersDisabled = true;
54202 this.proxy.setHeight(this.view.mainWrap.getHeight());
54203 var w = this.cm.getColumnWidth(this.cellIndex);
54204 var minw = Math.max(w-this.grid.minColumnWidth, 0);
54205 this.resetConstraints();
54206 this.setXConstraint(minw, 1000);
54207 this.setYConstraint(0, 0);
54208 this.minX = x - minw;
54209 this.maxX = x + 1000;
54211 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
54215 handleMouseDown : function(e){
54216 ev = Roo.EventObject.setEvent(e);
54217 var t = this.fly(ev.getTarget());
54218 if(t.hasClass("x-grid-split")){
54219 this.cellIndex = this.view.getCellIndex(t.dom);
54220 this.split = t.dom;
54221 this.cm = this.grid.colModel;
54222 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
54223 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
54228 endDrag : function(e){
54229 this.view.headersDisabled = false;
54230 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
54231 var diff = endX - this.startPos;
54232 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
54235 autoOffset : function(){
54236 this.setDelta(0,0);
54240 * Ext JS Library 1.1.1
54241 * Copyright(c) 2006-2007, Ext JS, LLC.
54243 * Originally Released Under LGPL - original licence link has changed is not relivant.
54246 * <script type="text/javascript">
54250 // This is a support class used internally by the Grid components
54251 Roo.grid.GridDragZone = function(grid, config){
54252 this.view = grid.getView();
54253 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
54254 if(this.view.lockedBody){
54255 this.setHandleElId(Roo.id(this.view.mainBody.dom));
54256 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
54258 this.scroll = false;
54260 this.ddel = document.createElement('div');
54261 this.ddel.className = 'x-grid-dd-wrap';
54264 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
54265 ddGroup : "GridDD",
54267 getDragData : function(e){
54268 var t = Roo.lib.Event.getTarget(e);
54269 var rowIndex = this.view.findRowIndex(t);
54270 var sm = this.grid.selModel;
54272 //Roo.log(rowIndex);
54274 if (sm.getSelectedCell) {
54275 // cell selection..
54276 if (!sm.getSelectedCell()) {
54279 if (rowIndex != sm.getSelectedCell()[0]) {
54285 if(rowIndex !== false){
54290 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
54292 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
54295 if (e.hasModifier()){
54296 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
54299 Roo.log("getDragData");
54304 rowIndex: rowIndex,
54305 selections:sm.getSelections ? sm.getSelections() : (
54306 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
54313 onInitDrag : function(e){
54314 var data = this.dragData;
54315 this.ddel.innerHTML = this.grid.getDragDropText();
54316 this.proxy.update(this.ddel);
54317 // fire start drag?
54320 afterRepair : function(){
54321 this.dragging = false;
54324 getRepairXY : function(e, data){
54328 onEndDrag : function(data, e){
54332 onValidDrop : function(dd, e, id){
54337 beforeInvalidDrop : function(e, id){
54342 * Ext JS Library 1.1.1
54343 * Copyright(c) 2006-2007, Ext JS, LLC.
54345 * Originally Released Under LGPL - original licence link has changed is not relivant.
54348 * <script type="text/javascript">
54353 * @class Roo.grid.ColumnModel
54354 * @extends Roo.util.Observable
54355 * This is the default implementation of a ColumnModel used by the Grid. It defines
54356 * the columns in the grid.
54359 var colModel = new Roo.grid.ColumnModel([
54360 {header: "Ticker", width: 60, sortable: true, locked: true},
54361 {header: "Company Name", width: 150, sortable: true},
54362 {header: "Market Cap.", width: 100, sortable: true},
54363 {header: "$ Sales", width: 100, sortable: true, renderer: money},
54364 {header: "Employees", width: 100, sortable: true, resizable: false}
54369 * The config options listed for this class are options which may appear in each
54370 * individual column definition.
54371 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
54373 * @param {Object} config An Array of column config objects. See this class's
54374 * config objects for details.
54376 Roo.grid.ColumnModel = function(config){
54378 * The config passed into the constructor
54380 this.config = config;
54383 // if no id, create one
54384 // if the column does not have a dataIndex mapping,
54385 // map it to the order it is in the config
54386 for(var i = 0, len = config.length; i < len; i++){
54388 if(typeof c.dataIndex == "undefined"){
54391 if(typeof c.renderer == "string"){
54392 c.renderer = Roo.util.Format[c.renderer];
54394 if(typeof c.id == "undefined"){
54397 if(c.editor && c.editor.xtype){
54398 c.editor = Roo.factory(c.editor, Roo.grid);
54400 if(c.editor && c.editor.isFormField){
54401 c.editor = new Roo.grid.GridEditor(c.editor);
54403 this.lookup[c.id] = c;
54407 * The width of columns which have no width specified (defaults to 100)
54410 this.defaultWidth = 100;
54413 * Default sortable of columns which have no sortable specified (defaults to false)
54416 this.defaultSortable = false;
54420 * @event widthchange
54421 * Fires when the width of a column changes.
54422 * @param {ColumnModel} this
54423 * @param {Number} columnIndex The column index
54424 * @param {Number} newWidth The new width
54426 "widthchange": true,
54428 * @event headerchange
54429 * Fires when the text of a header changes.
54430 * @param {ColumnModel} this
54431 * @param {Number} columnIndex The column index
54432 * @param {Number} newText The new header text
54434 "headerchange": true,
54436 * @event hiddenchange
54437 * Fires when a column is hidden or "unhidden".
54438 * @param {ColumnModel} this
54439 * @param {Number} columnIndex The column index
54440 * @param {Boolean} hidden true if hidden, false otherwise
54442 "hiddenchange": true,
54444 * @event columnmoved
54445 * Fires when a column is moved.
54446 * @param {ColumnModel} this
54447 * @param {Number} oldIndex
54448 * @param {Number} newIndex
54450 "columnmoved" : true,
54452 * @event columlockchange
54453 * Fires when a column's locked state is changed
54454 * @param {ColumnModel} this
54455 * @param {Number} colIndex
54456 * @param {Boolean} locked true if locked
54458 "columnlockchange" : true
54460 Roo.grid.ColumnModel.superclass.constructor.call(this);
54462 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
54464 * @cfg {String} header The header text to display in the Grid view.
54467 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
54468 * {@link Roo.data.Record} definition from which to draw the column's value. If not
54469 * specified, the column's index is used as an index into the Record's data Array.
54472 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
54473 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
54476 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
54477 * Defaults to the value of the {@link #defaultSortable} property.
54478 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
54481 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
54484 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
54487 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
54490 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
54493 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
54494 * given the cell's data value. See {@link #setRenderer}. If not specified, the
54495 * default renderer uses the raw data value.
54498 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
54501 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
54505 * Returns the id of the column at the specified index.
54506 * @param {Number} index The column index
54507 * @return {String} the id
54509 getColumnId : function(index){
54510 return this.config[index].id;
54514 * Returns the column for a specified id.
54515 * @param {String} id The column id
54516 * @return {Object} the column
54518 getColumnById : function(id){
54519 return this.lookup[id];
54524 * Returns the column for a specified dataIndex.
54525 * @param {String} dataIndex The column dataIndex
54526 * @return {Object|Boolean} the column or false if not found
54528 getColumnByDataIndex: function(dataIndex){
54529 var index = this.findColumnIndex(dataIndex);
54530 return index > -1 ? this.config[index] : false;
54534 * Returns the index for a specified column id.
54535 * @param {String} id The column id
54536 * @return {Number} the index, or -1 if not found
54538 getIndexById : function(id){
54539 for(var i = 0, len = this.config.length; i < len; i++){
54540 if(this.config[i].id == id){
54548 * Returns the index for a specified column dataIndex.
54549 * @param {String} dataIndex The column dataIndex
54550 * @return {Number} the index, or -1 if not found
54553 findColumnIndex : function(dataIndex){
54554 for(var i = 0, len = this.config.length; i < len; i++){
54555 if(this.config[i].dataIndex == dataIndex){
54563 moveColumn : function(oldIndex, newIndex){
54564 var c = this.config[oldIndex];
54565 this.config.splice(oldIndex, 1);
54566 this.config.splice(newIndex, 0, c);
54567 this.dataMap = null;
54568 this.fireEvent("columnmoved", this, oldIndex, newIndex);
54571 isLocked : function(colIndex){
54572 return this.config[colIndex].locked === true;
54575 setLocked : function(colIndex, value, suppressEvent){
54576 if(this.isLocked(colIndex) == value){
54579 this.config[colIndex].locked = value;
54580 if(!suppressEvent){
54581 this.fireEvent("columnlockchange", this, colIndex, value);
54585 getTotalLockedWidth : function(){
54586 var totalWidth = 0;
54587 for(var i = 0; i < this.config.length; i++){
54588 if(this.isLocked(i) && !this.isHidden(i)){
54589 this.totalWidth += this.getColumnWidth(i);
54595 getLockedCount : function(){
54596 for(var i = 0, len = this.config.length; i < len; i++){
54597 if(!this.isLocked(i)){
54604 * Returns the number of columns.
54607 getColumnCount : function(visibleOnly){
54608 if(visibleOnly === true){
54610 for(var i = 0, len = this.config.length; i < len; i++){
54611 if(!this.isHidden(i)){
54617 return this.config.length;
54621 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
54622 * @param {Function} fn
54623 * @param {Object} scope (optional)
54624 * @return {Array} result
54626 getColumnsBy : function(fn, scope){
54628 for(var i = 0, len = this.config.length; i < len; i++){
54629 var c = this.config[i];
54630 if(fn.call(scope||this, c, i) === true){
54638 * Returns true if the specified column is sortable.
54639 * @param {Number} col The column index
54640 * @return {Boolean}
54642 isSortable : function(col){
54643 if(typeof this.config[col].sortable == "undefined"){
54644 return this.defaultSortable;
54646 return this.config[col].sortable;
54650 * Returns the rendering (formatting) function defined for the column.
54651 * @param {Number} col The column index.
54652 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
54654 getRenderer : function(col){
54655 if(!this.config[col].renderer){
54656 return Roo.grid.ColumnModel.defaultRenderer;
54658 return this.config[col].renderer;
54662 * Sets the rendering (formatting) function for a column.
54663 * @param {Number} col The column index
54664 * @param {Function} fn The function to use to process the cell's raw data
54665 * to return HTML markup for the grid view. The render function is called with
54666 * the following parameters:<ul>
54667 * <li>Data value.</li>
54668 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
54669 * <li>css A CSS style string to apply to the table cell.</li>
54670 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
54671 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
54672 * <li>Row index</li>
54673 * <li>Column index</li>
54674 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
54676 setRenderer : function(col, fn){
54677 this.config[col].renderer = fn;
54681 * Returns the width for the specified column.
54682 * @param {Number} col The column index
54685 getColumnWidth : function(col){
54686 return this.config[col].width * 1 || this.defaultWidth;
54690 * Sets the width for a column.
54691 * @param {Number} col The column index
54692 * @param {Number} width The new width
54694 setColumnWidth : function(col, width, suppressEvent){
54695 this.config[col].width = width;
54696 this.totalWidth = null;
54697 if(!suppressEvent){
54698 this.fireEvent("widthchange", this, col, width);
54703 * Returns the total width of all columns.
54704 * @param {Boolean} includeHidden True to include hidden column widths
54707 getTotalWidth : function(includeHidden){
54708 if(!this.totalWidth){
54709 this.totalWidth = 0;
54710 for(var i = 0, len = this.config.length; i < len; i++){
54711 if(includeHidden || !this.isHidden(i)){
54712 this.totalWidth += this.getColumnWidth(i);
54716 return this.totalWidth;
54720 * Returns the header for the specified column.
54721 * @param {Number} col The column index
54724 getColumnHeader : function(col){
54725 return this.config[col].header;
54729 * Sets the header for a column.
54730 * @param {Number} col The column index
54731 * @param {String} header The new header
54733 setColumnHeader : function(col, header){
54734 this.config[col].header = header;
54735 this.fireEvent("headerchange", this, col, header);
54739 * Returns the tooltip for the specified column.
54740 * @param {Number} col The column index
54743 getColumnTooltip : function(col){
54744 return this.config[col].tooltip;
54747 * Sets the tooltip for a column.
54748 * @param {Number} col The column index
54749 * @param {String} tooltip The new tooltip
54751 setColumnTooltip : function(col, tooltip){
54752 this.config[col].tooltip = tooltip;
54756 * Returns the dataIndex for the specified column.
54757 * @param {Number} col The column index
54760 getDataIndex : function(col){
54761 return this.config[col].dataIndex;
54765 * Sets the dataIndex for a column.
54766 * @param {Number} col The column index
54767 * @param {Number} dataIndex The new dataIndex
54769 setDataIndex : function(col, dataIndex){
54770 this.config[col].dataIndex = dataIndex;
54776 * Returns true if the cell is editable.
54777 * @param {Number} colIndex The column index
54778 * @param {Number} rowIndex The row index
54779 * @return {Boolean}
54781 isCellEditable : function(colIndex, rowIndex){
54782 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
54786 * Returns the editor defined for the cell/column.
54787 * return false or null to disable editing.
54788 * @param {Number} colIndex The column index
54789 * @param {Number} rowIndex The row index
54792 getCellEditor : function(colIndex, rowIndex){
54793 return this.config[colIndex].editor;
54797 * Sets if a column is editable.
54798 * @param {Number} col The column index
54799 * @param {Boolean} editable True if the column is editable
54801 setEditable : function(col, editable){
54802 this.config[col].editable = editable;
54807 * Returns true if the column is hidden.
54808 * @param {Number} colIndex The column index
54809 * @return {Boolean}
54811 isHidden : function(colIndex){
54812 return this.config[colIndex].hidden;
54817 * Returns true if the column width cannot be changed
54819 isFixed : function(colIndex){
54820 return this.config[colIndex].fixed;
54824 * Returns true if the column can be resized
54825 * @return {Boolean}
54827 isResizable : function(colIndex){
54828 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
54831 * Sets if a column is hidden.
54832 * @param {Number} colIndex The column index
54833 * @param {Boolean} hidden True if the column is hidden
54835 setHidden : function(colIndex, hidden){
54836 this.config[colIndex].hidden = hidden;
54837 this.totalWidth = null;
54838 this.fireEvent("hiddenchange", this, colIndex, hidden);
54842 * Sets the editor for a column.
54843 * @param {Number} col The column index
54844 * @param {Object} editor The editor object
54846 setEditor : function(col, editor){
54847 this.config[col].editor = editor;
54851 Roo.grid.ColumnModel.defaultRenderer = function(value){
54852 if(typeof value == "string" && value.length < 1){
54858 // Alias for backwards compatibility
54859 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
54862 * Ext JS Library 1.1.1
54863 * Copyright(c) 2006-2007, Ext JS, LLC.
54865 * Originally Released Under LGPL - original licence link has changed is not relivant.
54868 * <script type="text/javascript">
54872 * @class Roo.grid.AbstractSelectionModel
54873 * @extends Roo.util.Observable
54874 * Abstract base class for grid SelectionModels. It provides the interface that should be
54875 * implemented by descendant classes. This class should not be directly instantiated.
54878 Roo.grid.AbstractSelectionModel = function(){
54879 this.locked = false;
54880 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
54883 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
54884 /** @ignore Called by the grid automatically. Do not call directly. */
54885 init : function(grid){
54891 * Locks the selections.
54894 this.locked = true;
54898 * Unlocks the selections.
54900 unlock : function(){
54901 this.locked = false;
54905 * Returns true if the selections are locked.
54906 * @return {Boolean}
54908 isLocked : function(){
54909 return this.locked;
54913 * Ext JS Library 1.1.1
54914 * Copyright(c) 2006-2007, Ext JS, LLC.
54916 * Originally Released Under LGPL - original licence link has changed is not relivant.
54919 * <script type="text/javascript">
54922 * @extends Roo.grid.AbstractSelectionModel
54923 * @class Roo.grid.RowSelectionModel
54924 * The default SelectionModel used by {@link Roo.grid.Grid}.
54925 * It supports multiple selections and keyboard selection/navigation.
54927 * @param {Object} config
54929 Roo.grid.RowSelectionModel = function(config){
54930 Roo.apply(this, config);
54931 this.selections = new Roo.util.MixedCollection(false, function(o){
54936 this.lastActive = false;
54940 * @event selectionchange
54941 * Fires when the selection changes
54942 * @param {SelectionModel} this
54944 "selectionchange" : true,
54946 * @event afterselectionchange
54947 * Fires after the selection changes (eg. by key press or clicking)
54948 * @param {SelectionModel} this
54950 "afterselectionchange" : true,
54952 * @event beforerowselect
54953 * Fires when a row is selected being selected, return false to cancel.
54954 * @param {SelectionModel} this
54955 * @param {Number} rowIndex The selected index
54956 * @param {Boolean} keepExisting False if other selections will be cleared
54958 "beforerowselect" : true,
54961 * Fires when a row is selected.
54962 * @param {SelectionModel} this
54963 * @param {Number} rowIndex The selected index
54964 * @param {Roo.data.Record} r The record
54966 "rowselect" : true,
54968 * @event rowdeselect
54969 * Fires when a row is deselected.
54970 * @param {SelectionModel} this
54971 * @param {Number} rowIndex The selected index
54973 "rowdeselect" : true
54975 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
54976 this.locked = false;
54979 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
54981 * @cfg {Boolean} singleSelect
54982 * True to allow selection of only one row at a time (defaults to false)
54984 singleSelect : false,
54987 initEvents : function(){
54989 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
54990 this.grid.on("mousedown", this.handleMouseDown, this);
54991 }else{ // allow click to work like normal
54992 this.grid.on("rowclick", this.handleDragableRowClick, this);
54995 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
54996 "up" : function(e){
54998 this.selectPrevious(e.shiftKey);
54999 }else if(this.last !== false && this.lastActive !== false){
55000 var last = this.last;
55001 this.selectRange(this.last, this.lastActive-1);
55002 this.grid.getView().focusRow(this.lastActive);
55003 if(last !== false){
55007 this.selectFirstRow();
55009 this.fireEvent("afterselectionchange", this);
55011 "down" : function(e){
55013 this.selectNext(e.shiftKey);
55014 }else if(this.last !== false && this.lastActive !== false){
55015 var last = this.last;
55016 this.selectRange(this.last, this.lastActive+1);
55017 this.grid.getView().focusRow(this.lastActive);
55018 if(last !== false){
55022 this.selectFirstRow();
55024 this.fireEvent("afterselectionchange", this);
55029 var view = this.grid.view;
55030 view.on("refresh", this.onRefresh, this);
55031 view.on("rowupdated", this.onRowUpdated, this);
55032 view.on("rowremoved", this.onRemove, this);
55036 onRefresh : function(){
55037 var ds = this.grid.dataSource, i, v = this.grid.view;
55038 var s = this.selections;
55039 s.each(function(r){
55040 if((i = ds.indexOfId(r.id)) != -1){
55049 onRemove : function(v, index, r){
55050 this.selections.remove(r);
55054 onRowUpdated : function(v, index, r){
55055 if(this.isSelected(r)){
55056 v.onRowSelect(index);
55062 * @param {Array} records The records to select
55063 * @param {Boolean} keepExisting (optional) True to keep existing selections
55065 selectRecords : function(records, keepExisting){
55067 this.clearSelections();
55069 var ds = this.grid.dataSource;
55070 for(var i = 0, len = records.length; i < len; i++){
55071 this.selectRow(ds.indexOf(records[i]), true);
55076 * Gets the number of selected rows.
55079 getCount : function(){
55080 return this.selections.length;
55084 * Selects the first row in the grid.
55086 selectFirstRow : function(){
55091 * Select the last row.
55092 * @param {Boolean} keepExisting (optional) True to keep existing selections
55094 selectLastRow : function(keepExisting){
55095 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55099 * Selects the row immediately following the last selected row.
55100 * @param {Boolean} keepExisting (optional) True to keep existing selections
55102 selectNext : function(keepExisting){
55103 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55104 this.selectRow(this.last+1, keepExisting);
55105 this.grid.getView().focusRow(this.last);
55110 * Selects the row that precedes the last selected row.
55111 * @param {Boolean} keepExisting (optional) True to keep existing selections
55113 selectPrevious : function(keepExisting){
55115 this.selectRow(this.last-1, keepExisting);
55116 this.grid.getView().focusRow(this.last);
55121 * Returns the selected records
55122 * @return {Array} Array of selected records
55124 getSelections : function(){
55125 return [].concat(this.selections.items);
55129 * Returns the first selected record.
55132 getSelected : function(){
55133 return this.selections.itemAt(0);
55138 * Clears all selections.
55140 clearSelections : function(fast){
55141 if(this.locked) return;
55143 var ds = this.grid.dataSource;
55144 var s = this.selections;
55145 s.each(function(r){
55146 this.deselectRow(ds.indexOfId(r.id));
55150 this.selections.clear();
55157 * Selects all rows.
55159 selectAll : function(){
55160 if(this.locked) return;
55161 this.selections.clear();
55162 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
55163 this.selectRow(i, true);
55168 * Returns True if there is a selection.
55169 * @return {Boolean}
55171 hasSelection : function(){
55172 return this.selections.length > 0;
55176 * Returns True if the specified row is selected.
55177 * @param {Number/Record} record The record or index of the record to check
55178 * @return {Boolean}
55180 isSelected : function(index){
55181 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
55182 return (r && this.selections.key(r.id) ? true : false);
55186 * Returns True if the specified record id is selected.
55187 * @param {String} id The id of record to check
55188 * @return {Boolean}
55190 isIdSelected : function(id){
55191 return (this.selections.key(id) ? true : false);
55195 handleMouseDown : function(e, t){
55196 var view = this.grid.getView(), rowIndex;
55197 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
55200 if(e.shiftKey && this.last !== false){
55201 var last = this.last;
55202 this.selectRange(last, rowIndex, e.ctrlKey);
55203 this.last = last; // reset the last
55204 view.focusRow(rowIndex);
55206 var isSelected = this.isSelected(rowIndex);
55207 if(e.button !== 0 && isSelected){
55208 view.focusRow(rowIndex);
55209 }else if(e.ctrlKey && isSelected){
55210 this.deselectRow(rowIndex);
55211 }else if(!isSelected){
55212 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
55213 view.focusRow(rowIndex);
55216 this.fireEvent("afterselectionchange", this);
55219 handleDragableRowClick : function(grid, rowIndex, e)
55221 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
55222 this.selectRow(rowIndex, false);
55223 grid.view.focusRow(rowIndex);
55224 this.fireEvent("afterselectionchange", this);
55229 * Selects multiple rows.
55230 * @param {Array} rows Array of the indexes of the row to select
55231 * @param {Boolean} keepExisting (optional) True to keep existing selections
55233 selectRows : function(rows, keepExisting){
55235 this.clearSelections();
55237 for(var i = 0, len = rows.length; i < len; i++){
55238 this.selectRow(rows[i], true);
55243 * Selects a range of rows. All rows in between startRow and endRow are also selected.
55244 * @param {Number} startRow The index of the first row in the range
55245 * @param {Number} endRow The index of the last row in the range
55246 * @param {Boolean} keepExisting (optional) True to retain existing selections
55248 selectRange : function(startRow, endRow, keepExisting){
55249 if(this.locked) return;
55251 this.clearSelections();
55253 if(startRow <= endRow){
55254 for(var i = startRow; i <= endRow; i++){
55255 this.selectRow(i, true);
55258 for(var i = startRow; i >= endRow; i--){
55259 this.selectRow(i, true);
55265 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
55266 * @param {Number} startRow The index of the first row in the range
55267 * @param {Number} endRow The index of the last row in the range
55269 deselectRange : function(startRow, endRow, preventViewNotify){
55270 if(this.locked) return;
55271 for(var i = startRow; i <= endRow; i++){
55272 this.deselectRow(i, preventViewNotify);
55278 * @param {Number} row The index of the row to select
55279 * @param {Boolean} keepExisting (optional) True to keep existing selections
55281 selectRow : function(index, keepExisting, preventViewNotify){
55282 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
55283 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
55284 if(!keepExisting || this.singleSelect){
55285 this.clearSelections();
55287 var r = this.grid.dataSource.getAt(index);
55288 this.selections.add(r);
55289 this.last = this.lastActive = index;
55290 if(!preventViewNotify){
55291 this.grid.getView().onRowSelect(index);
55293 this.fireEvent("rowselect", this, index, r);
55294 this.fireEvent("selectionchange", this);
55300 * @param {Number} row The index of the row to deselect
55302 deselectRow : function(index, preventViewNotify){
55303 if(this.locked) return;
55304 if(this.last == index){
55307 if(this.lastActive == index){
55308 this.lastActive = false;
55310 var r = this.grid.dataSource.getAt(index);
55311 this.selections.remove(r);
55312 if(!preventViewNotify){
55313 this.grid.getView().onRowDeselect(index);
55315 this.fireEvent("rowdeselect", this, index);
55316 this.fireEvent("selectionchange", this);
55320 restoreLast : function(){
55322 this.last = this._last;
55327 acceptsNav : function(row, col, cm){
55328 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55332 onEditorKey : function(field, e){
55333 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
55338 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55340 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55342 }else if(k == e.ENTER && !e.ctrlKey){
55346 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
55348 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
55350 }else if(k == e.ESC){
55354 g.startEditing(newCell[0], newCell[1]);
55359 * Ext JS Library 1.1.1
55360 * Copyright(c) 2006-2007, Ext JS, LLC.
55362 * Originally Released Under LGPL - original licence link has changed is not relivant.
55365 * <script type="text/javascript">
55368 * @class Roo.grid.CellSelectionModel
55369 * @extends Roo.grid.AbstractSelectionModel
55370 * This class provides the basic implementation for cell selection in a grid.
55372 * @param {Object} config The object containing the configuration of this model.
55373 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
55375 Roo.grid.CellSelectionModel = function(config){
55376 Roo.apply(this, config);
55378 this.selection = null;
55382 * @event beforerowselect
55383 * Fires before a cell is selected.
55384 * @param {SelectionModel} this
55385 * @param {Number} rowIndex The selected row index
55386 * @param {Number} colIndex The selected cell index
55388 "beforecellselect" : true,
55390 * @event cellselect
55391 * Fires when a cell is selected.
55392 * @param {SelectionModel} this
55393 * @param {Number} rowIndex The selected row index
55394 * @param {Number} colIndex The selected cell index
55396 "cellselect" : true,
55398 * @event selectionchange
55399 * Fires when the active selection changes.
55400 * @param {SelectionModel} this
55401 * @param {Object} selection null for no selection or an object (o) with two properties
55403 <li>o.record: the record object for the row the selection is in</li>
55404 <li>o.cell: An array of [rowIndex, columnIndex]</li>
55407 "selectionchange" : true,
55410 * Fires when the tab (or enter) was pressed on the last editable cell
55411 * You can use this to trigger add new row.
55412 * @param {SelectionModel} this
55416 * @event beforeeditnext
55417 * Fires before the next editable sell is made active
55418 * You can use this to skip to another cell or fire the tabend
55419 * if you set cell to false
55420 * @param {Object} eventdata object : { cell : [ row, col ] }
55422 "beforeeditnext" : true
55424 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
55427 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
55429 enter_is_tab: false,
55432 initEvents : function(){
55433 this.grid.on("mousedown", this.handleMouseDown, this);
55434 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
55435 var view = this.grid.view;
55436 view.on("refresh", this.onViewChange, this);
55437 view.on("rowupdated", this.onRowUpdated, this);
55438 view.on("beforerowremoved", this.clearSelections, this);
55439 view.on("beforerowsinserted", this.clearSelections, this);
55440 if(this.grid.isEditor){
55441 this.grid.on("beforeedit", this.beforeEdit, this);
55446 beforeEdit : function(e){
55447 this.select(e.row, e.column, false, true, e.record);
55451 onRowUpdated : function(v, index, r){
55452 if(this.selection && this.selection.record == r){
55453 v.onCellSelect(index, this.selection.cell[1]);
55458 onViewChange : function(){
55459 this.clearSelections(true);
55463 * Returns the currently selected cell,.
55464 * @return {Array} The selected cell (row, column) or null if none selected.
55466 getSelectedCell : function(){
55467 return this.selection ? this.selection.cell : null;
55471 * Clears all selections.
55472 * @param {Boolean} true to prevent the gridview from being notified about the change.
55474 clearSelections : function(preventNotify){
55475 var s = this.selection;
55477 if(preventNotify !== true){
55478 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
55480 this.selection = null;
55481 this.fireEvent("selectionchange", this, null);
55486 * Returns true if there is a selection.
55487 * @return {Boolean}
55489 hasSelection : function(){
55490 return this.selection ? true : false;
55494 handleMouseDown : function(e, t){
55495 var v = this.grid.getView();
55496 if(this.isLocked()){
55499 var row = v.findRowIndex(t);
55500 var cell = v.findCellIndex(t);
55501 if(row !== false && cell !== false){
55502 this.select(row, cell);
55508 * @param {Number} rowIndex
55509 * @param {Number} collIndex
55511 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
55512 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
55513 this.clearSelections();
55514 r = r || this.grid.dataSource.getAt(rowIndex);
55517 cell : [rowIndex, colIndex]
55519 if(!preventViewNotify){
55520 var v = this.grid.getView();
55521 v.onCellSelect(rowIndex, colIndex);
55522 if(preventFocus !== true){
55523 v.focusCell(rowIndex, colIndex);
55526 this.fireEvent("cellselect", this, rowIndex, colIndex);
55527 this.fireEvent("selectionchange", this, this.selection);
55532 isSelectable : function(rowIndex, colIndex, cm){
55533 return !cm.isHidden(colIndex);
55537 handleKeyDown : function(e){
55538 //Roo.log('Cell Sel Model handleKeyDown');
55539 if(!e.isNavKeyPress()){
55542 var g = this.grid, s = this.selection;
55545 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
55547 this.select(cell[0], cell[1]);
55552 var walk = function(row, col, step){
55553 return g.walkCells(row, col, step, sm.isSelectable, sm);
55555 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
55562 // handled by onEditorKey
55563 if (g.isEditor && g.editing) {
55567 newCell = walk(r, c-1, -1);
55569 newCell = walk(r, c+1, 1);
55574 newCell = walk(r+1, c, 1);
55578 newCell = walk(r-1, c, -1);
55582 newCell = walk(r, c+1, 1);
55586 newCell = walk(r, c-1, -1);
55591 if(g.isEditor && !g.editing){
55592 g.startEditing(r, c);
55601 this.select(newCell[0], newCell[1]);
55607 acceptsNav : function(row, col, cm){
55608 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55612 * @param {Number} field (not used) - as it's normally used as a listener
55613 * @param {Number} e - event - fake it by using
55615 * var e = Roo.EventObjectImpl.prototype;
55616 * e.keyCode = e.TAB
55620 onEditorKey : function(field, e){
55622 var k = e.getKey(),
55625 ed = g.activeEditor,
55627 ///Roo.log('onEditorKey' + k);
55630 if (this.enter_is_tab && k == e.ENTER) {
55636 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55638 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55644 } else if(k == e.ENTER && !e.ctrlKey){
55647 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55649 } else if(k == e.ESC){
55654 var ecall = { cell : newCell, forward : forward };
55655 this.fireEvent('beforeeditnext', ecall );
55656 newCell = ecall.cell;
55657 forward = ecall.forward;
55661 //Roo.log('next cell after edit');
55662 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
55663 } else if (forward) {
55664 // tabbed past last
55665 this.fireEvent.defer(100, this, ['tabend',this]);
55670 * Ext JS Library 1.1.1
55671 * Copyright(c) 2006-2007, Ext JS, LLC.
55673 * Originally Released Under LGPL - original licence link has changed is not relivant.
55676 * <script type="text/javascript">
55680 * @class Roo.grid.EditorGrid
55681 * @extends Roo.grid.Grid
55682 * Class for creating and editable grid.
55683 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55684 * The container MUST have some type of size defined for the grid to fill. The container will be
55685 * automatically set to position relative if it isn't already.
55686 * @param {Object} dataSource The data model to bind to
55687 * @param {Object} colModel The column model with info about this grid's columns
55689 Roo.grid.EditorGrid = function(container, config){
55690 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
55691 this.getGridEl().addClass("xedit-grid");
55693 if(!this.selModel){
55694 this.selModel = new Roo.grid.CellSelectionModel();
55697 this.activeEditor = null;
55701 * @event beforeedit
55702 * Fires before cell editing is triggered. The edit event object has the following properties <br />
55703 * <ul style="padding:5px;padding-left:16px;">
55704 * <li>grid - This grid</li>
55705 * <li>record - The record being edited</li>
55706 * <li>field - The field name being edited</li>
55707 * <li>value - The value for the field being edited.</li>
55708 * <li>row - The grid row index</li>
55709 * <li>column - The grid column index</li>
55710 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55712 * @param {Object} e An edit event (see above for description)
55714 "beforeedit" : true,
55717 * Fires after a cell is edited. <br />
55718 * <ul style="padding:5px;padding-left:16px;">
55719 * <li>grid - This grid</li>
55720 * <li>record - The record being edited</li>
55721 * <li>field - The field name being edited</li>
55722 * <li>value - The value being set</li>
55723 * <li>originalValue - The original value for the field, before the edit.</li>
55724 * <li>row - The grid row index</li>
55725 * <li>column - The grid column index</li>
55727 * @param {Object} e An edit event (see above for description)
55729 "afteredit" : true,
55731 * @event validateedit
55732 * Fires after a cell is edited, but before the value is set in the record.
55733 * You can use this to modify the value being set in the field, Return false
55734 * to cancel the change. The edit event object has the following properties <br />
55735 * <ul style="padding:5px;padding-left:16px;">
55736 * <li>editor - This editor</li>
55737 * <li>grid - This grid</li>
55738 * <li>record - The record being edited</li>
55739 * <li>field - The field name being edited</li>
55740 * <li>value - The value being set</li>
55741 * <li>originalValue - The original value for the field, before the edit.</li>
55742 * <li>row - The grid row index</li>
55743 * <li>column - The grid column index</li>
55744 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55746 * @param {Object} e An edit event (see above for description)
55748 "validateedit" : true
55750 this.on("bodyscroll", this.stopEditing, this);
55751 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
55754 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
55756 * @cfg {Number} clicksToEdit
55757 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
55764 trackMouseOver: false, // causes very odd FF errors
55766 onCellDblClick : function(g, row, col){
55767 this.startEditing(row, col);
55770 onEditComplete : function(ed, value, startValue){
55771 this.editing = false;
55772 this.activeEditor = null;
55773 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
55775 var field = this.colModel.getDataIndex(ed.col);
55780 originalValue: startValue,
55787 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
55790 if(String(value) !== String(startValue)){
55792 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
55793 r.set(field, e.value);
55794 // if we are dealing with a combo box..
55795 // then we also set the 'name' colum to be the displayField
55796 if (ed.field.displayField && ed.field.name) {
55797 r.set(ed.field.name, ed.field.el.dom.value);
55800 delete e.cancel; //?? why!!!
55801 this.fireEvent("afteredit", e);
55804 this.fireEvent("afteredit", e); // always fire it!
55806 this.view.focusCell(ed.row, ed.col);
55810 * Starts editing the specified for the specified row/column
55811 * @param {Number} rowIndex
55812 * @param {Number} colIndex
55814 startEditing : function(row, col){
55815 this.stopEditing();
55816 if(this.colModel.isCellEditable(col, row)){
55817 this.view.ensureVisible(row, col, true);
55819 var r = this.dataSource.getAt(row);
55820 var field = this.colModel.getDataIndex(col);
55821 var cell = Roo.get(this.view.getCell(row,col));
55826 value: r.data[field],
55831 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
55832 this.editing = true;
55833 var ed = this.colModel.getCellEditor(col, row);
55839 ed.render(ed.parentEl || document.body);
55845 (function(){ // complex but required for focus issues in safari, ie and opera
55849 ed.on("complete", this.onEditComplete, this, {single: true});
55850 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
55851 this.activeEditor = ed;
55852 var v = r.data[field];
55853 ed.startEdit(this.view.getCell(row, col), v);
55854 // combo's with 'displayField and name set
55855 if (ed.field.displayField && ed.field.name) {
55856 ed.field.el.dom.value = r.data[ed.field.name];
55860 }).defer(50, this);
55866 * Stops any active editing
55868 stopEditing : function(){
55869 if(this.activeEditor){
55870 this.activeEditor.completeEdit();
55872 this.activeEditor = null;
55876 * Called to get grid's drag proxy text, by default returns this.ddText.
55879 getDragDropText : function(){
55880 var count = this.selModel.getSelectedCell() ? 1 : 0;
55881 return String.format(this.ddText, count, count == 1 ? '' : 's');
55886 * Ext JS Library 1.1.1
55887 * Copyright(c) 2006-2007, Ext JS, LLC.
55889 * Originally Released Under LGPL - original licence link has changed is not relivant.
55892 * <script type="text/javascript">
55895 // private - not really -- you end up using it !
55896 // This is a support class used internally by the Grid components
55899 * @class Roo.grid.GridEditor
55900 * @extends Roo.Editor
55901 * Class for creating and editable grid elements.
55902 * @param {Object} config any settings (must include field)
55904 Roo.grid.GridEditor = function(field, config){
55905 if (!config && field.field) {
55907 field = Roo.factory(config.field, Roo.form);
55909 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
55910 field.monitorTab = false;
55913 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
55916 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
55919 alignment: "tl-tl",
55922 cls: "x-small-editor x-grid-editor",
55927 * Ext JS Library 1.1.1
55928 * Copyright(c) 2006-2007, Ext JS, LLC.
55930 * Originally Released Under LGPL - original licence link has changed is not relivant.
55933 * <script type="text/javascript">
55938 Roo.grid.PropertyRecord = Roo.data.Record.create([
55939 {name:'name',type:'string'}, 'value'
55943 Roo.grid.PropertyStore = function(grid, source){
55945 this.store = new Roo.data.Store({
55946 recordType : Roo.grid.PropertyRecord
55948 this.store.on('update', this.onUpdate, this);
55950 this.setSource(source);
55952 Roo.grid.PropertyStore.superclass.constructor.call(this);
55957 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
55958 setSource : function(o){
55960 this.store.removeAll();
55963 if(this.isEditableValue(o[k])){
55964 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
55967 this.store.loadRecords({records: data}, {}, true);
55970 onUpdate : function(ds, record, type){
55971 if(type == Roo.data.Record.EDIT){
55972 var v = record.data['value'];
55973 var oldValue = record.modified['value'];
55974 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
55975 this.source[record.id] = v;
55977 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
55984 getProperty : function(row){
55985 return this.store.getAt(row);
55988 isEditableValue: function(val){
55989 if(val && val instanceof Date){
55991 }else if(typeof val == 'object' || typeof val == 'function'){
55997 setValue : function(prop, value){
55998 this.source[prop] = value;
55999 this.store.getById(prop).set('value', value);
56002 getSource : function(){
56003 return this.source;
56007 Roo.grid.PropertyColumnModel = function(grid, store){
56010 g.PropertyColumnModel.superclass.constructor.call(this, [
56011 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56012 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56014 this.store = store;
56015 this.bselect = Roo.DomHelper.append(document.body, {
56016 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56017 {tag: 'option', value: 'true', html: 'true'},
56018 {tag: 'option', value: 'false', html: 'false'}
56021 Roo.id(this.bselect);
56024 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56025 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56026 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56027 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56028 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56030 this.renderCellDelegate = this.renderCell.createDelegate(this);
56031 this.renderPropDelegate = this.renderProp.createDelegate(this);
56034 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56038 valueText : 'Value',
56040 dateFormat : 'm/j/Y',
56043 renderDate : function(dateVal){
56044 return dateVal.dateFormat(this.dateFormat);
56047 renderBool : function(bVal){
56048 return bVal ? 'true' : 'false';
56051 isCellEditable : function(colIndex, rowIndex){
56052 return colIndex == 1;
56055 getRenderer : function(col){
56057 this.renderCellDelegate : this.renderPropDelegate;
56060 renderProp : function(v){
56061 return this.getPropertyName(v);
56064 renderCell : function(val){
56066 if(val instanceof Date){
56067 rv = this.renderDate(val);
56068 }else if(typeof val == 'boolean'){
56069 rv = this.renderBool(val);
56071 return Roo.util.Format.htmlEncode(rv);
56074 getPropertyName : function(name){
56075 var pn = this.grid.propertyNames;
56076 return pn && pn[name] ? pn[name] : name;
56079 getCellEditor : function(colIndex, rowIndex){
56080 var p = this.store.getProperty(rowIndex);
56081 var n = p.data['name'], val = p.data['value'];
56083 if(typeof(this.grid.customEditors[n]) == 'string'){
56084 return this.editors[this.grid.customEditors[n]];
56086 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56087 return this.grid.customEditors[n];
56089 if(val instanceof Date){
56090 return this.editors['date'];
56091 }else if(typeof val == 'number'){
56092 return this.editors['number'];
56093 }else if(typeof val == 'boolean'){
56094 return this.editors['boolean'];
56096 return this.editors['string'];
56102 * @class Roo.grid.PropertyGrid
56103 * @extends Roo.grid.EditorGrid
56104 * This class represents the interface of a component based property grid control.
56105 * <br><br>Usage:<pre><code>
56106 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56114 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56115 * The container MUST have some type of size defined for the grid to fill. The container will be
56116 * automatically set to position relative if it isn't already.
56117 * @param {Object} config A config object that sets properties on this grid.
56119 Roo.grid.PropertyGrid = function(container, config){
56120 config = config || {};
56121 var store = new Roo.grid.PropertyStore(this);
56122 this.store = store;
56123 var cm = new Roo.grid.PropertyColumnModel(this, store);
56124 store.store.sort('name', 'ASC');
56125 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
56128 enableColLock:false,
56129 enableColumnMove:false,
56131 trackMouseOver: false,
56134 this.getGridEl().addClass('x-props-grid');
56135 this.lastEditRow = null;
56136 this.on('columnresize', this.onColumnResize, this);
56139 * @event beforepropertychange
56140 * Fires before a property changes (return false to stop?)
56141 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56142 * @param {String} id Record Id
56143 * @param {String} newval New Value
56144 * @param {String} oldval Old Value
56146 "beforepropertychange": true,
56148 * @event propertychange
56149 * Fires after a property changes
56150 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56151 * @param {String} id Record Id
56152 * @param {String} newval New Value
56153 * @param {String} oldval Old Value
56155 "propertychange": true
56157 this.customEditors = this.customEditors || {};
56159 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
56162 * @cfg {Object} customEditors map of colnames=> custom editors.
56163 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
56164 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
56165 * false disables editing of the field.
56169 * @cfg {Object} propertyNames map of property Names to their displayed value
56172 render : function(){
56173 Roo.grid.PropertyGrid.superclass.render.call(this);
56174 this.autoSize.defer(100, this);
56177 autoSize : function(){
56178 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
56180 this.view.fitColumns();
56184 onColumnResize : function(){
56185 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
56189 * Sets the data for the Grid
56190 * accepts a Key => Value object of all the elements avaiable.
56191 * @param {Object} data to appear in grid.
56193 setSource : function(source){
56194 this.store.setSource(source);
56198 * Gets all the data from the grid.
56199 * @return {Object} data data stored in grid
56201 getSource : function(){
56202 return this.store.getSource();
56211 * @class Roo.grid.Calendar
56212 * @extends Roo.util.Grid
56213 * This class extends the Grid to provide a calendar widget
56214 * <br><br>Usage:<pre><code>
56215 var grid = new Roo.grid.Calendar("my-container-id", {
56218 selModel: mySelectionModel,
56219 autoSizeColumns: true,
56220 monitorWindowResize: false,
56221 trackMouseOver: true
56222 eventstore : real data store..
56228 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56229 * The container MUST have some type of size defined for the grid to fill. The container will be
56230 * automatically set to position relative if it isn't already.
56231 * @param {Object} config A config object that sets properties on this grid.
56233 Roo.grid.Calendar = function(container, config){
56234 // initialize the container
56235 this.container = Roo.get(container);
56236 this.container.update("");
56237 this.container.setStyle("overflow", "hidden");
56238 this.container.addClass('x-grid-container');
56240 this.id = this.container.id;
56242 Roo.apply(this, config);
56243 // check and correct shorthanded configs
56247 for (var r = 0;r < 6;r++) {
56250 for (var c =0;c < 7;c++) {
56254 if (this.eventStore) {
56255 this.eventStore= Roo.factory(this.eventStore, Roo.data);
56256 this.eventStore.on('load',this.onLoad, this);
56257 this.eventStore.on('beforeload',this.clearEvents, this);
56261 this.dataSource = new Roo.data.Store({
56262 proxy: new Roo.data.MemoryProxy(rows),
56263 reader: new Roo.data.ArrayReader({}, [
56264 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
56267 this.dataSource.load();
56268 this.ds = this.dataSource;
56269 this.ds.xmodule = this.xmodule || false;
56272 var cellRender = function(v,x,r)
56274 return String.format(
56275 '<div class="fc-day fc-widget-content"><div>' +
56276 '<div class="fc-event-container"></div>' +
56277 '<div class="fc-day-number">{0}</div>'+
56279 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
56280 '</div></div>', v);
56285 this.colModel = new Roo.grid.ColumnModel( [
56287 xtype: 'ColumnModel',
56289 dataIndex : 'weekday0',
56291 renderer : cellRender
56294 xtype: 'ColumnModel',
56296 dataIndex : 'weekday1',
56298 renderer : cellRender
56301 xtype: 'ColumnModel',
56303 dataIndex : 'weekday2',
56304 header : 'Tuesday',
56305 renderer : cellRender
56308 xtype: 'ColumnModel',
56310 dataIndex : 'weekday3',
56311 header : 'Wednesday',
56312 renderer : cellRender
56315 xtype: 'ColumnModel',
56317 dataIndex : 'weekday4',
56318 header : 'Thursday',
56319 renderer : cellRender
56322 xtype: 'ColumnModel',
56324 dataIndex : 'weekday5',
56326 renderer : cellRender
56329 xtype: 'ColumnModel',
56331 dataIndex : 'weekday6',
56332 header : 'Saturday',
56333 renderer : cellRender
56336 this.cm = this.colModel;
56337 this.cm.xmodule = this.xmodule || false;
56341 //this.selModel = new Roo.grid.CellSelectionModel();
56342 //this.sm = this.selModel;
56343 //this.selModel.init(this);
56347 this.container.setWidth(this.width);
56351 this.container.setHeight(this.height);
56358 * The raw click event for the entire grid.
56359 * @param {Roo.EventObject} e
56364 * The raw dblclick event for the entire grid.
56365 * @param {Roo.EventObject} e
56369 * @event contextmenu
56370 * The raw contextmenu event for the entire grid.
56371 * @param {Roo.EventObject} e
56373 "contextmenu" : true,
56376 * The raw mousedown event for the entire grid.
56377 * @param {Roo.EventObject} e
56379 "mousedown" : true,
56382 * The raw mouseup event for the entire grid.
56383 * @param {Roo.EventObject} e
56388 * The raw mouseover event for the entire grid.
56389 * @param {Roo.EventObject} e
56391 "mouseover" : true,
56394 * The raw mouseout event for the entire grid.
56395 * @param {Roo.EventObject} e
56400 * The raw keypress event for the entire grid.
56401 * @param {Roo.EventObject} e
56406 * The raw keydown event for the entire grid.
56407 * @param {Roo.EventObject} e
56415 * Fires when a cell is clicked
56416 * @param {Grid} this
56417 * @param {Number} rowIndex
56418 * @param {Number} columnIndex
56419 * @param {Roo.EventObject} e
56421 "cellclick" : true,
56423 * @event celldblclick
56424 * Fires when a cell is double clicked
56425 * @param {Grid} this
56426 * @param {Number} rowIndex
56427 * @param {Number} columnIndex
56428 * @param {Roo.EventObject} e
56430 "celldblclick" : true,
56433 * Fires when a row is clicked
56434 * @param {Grid} this
56435 * @param {Number} rowIndex
56436 * @param {Roo.EventObject} e
56440 * @event rowdblclick
56441 * Fires when a row is double clicked
56442 * @param {Grid} this
56443 * @param {Number} rowIndex
56444 * @param {Roo.EventObject} e
56446 "rowdblclick" : true,
56448 * @event headerclick
56449 * Fires when a header is clicked
56450 * @param {Grid} this
56451 * @param {Number} columnIndex
56452 * @param {Roo.EventObject} e
56454 "headerclick" : true,
56456 * @event headerdblclick
56457 * Fires when a header cell is double clicked
56458 * @param {Grid} this
56459 * @param {Number} columnIndex
56460 * @param {Roo.EventObject} e
56462 "headerdblclick" : true,
56464 * @event rowcontextmenu
56465 * Fires when a row is right clicked
56466 * @param {Grid} this
56467 * @param {Number} rowIndex
56468 * @param {Roo.EventObject} e
56470 "rowcontextmenu" : true,
56472 * @event cellcontextmenu
56473 * Fires when a cell is right clicked
56474 * @param {Grid} this
56475 * @param {Number} rowIndex
56476 * @param {Number} cellIndex
56477 * @param {Roo.EventObject} e
56479 "cellcontextmenu" : true,
56481 * @event headercontextmenu
56482 * Fires when a header is right clicked
56483 * @param {Grid} this
56484 * @param {Number} columnIndex
56485 * @param {Roo.EventObject} e
56487 "headercontextmenu" : true,
56489 * @event bodyscroll
56490 * Fires when the body element is scrolled
56491 * @param {Number} scrollLeft
56492 * @param {Number} scrollTop
56494 "bodyscroll" : true,
56496 * @event columnresize
56497 * Fires when the user resizes a column
56498 * @param {Number} columnIndex
56499 * @param {Number} newSize
56501 "columnresize" : true,
56503 * @event columnmove
56504 * Fires when the user moves a column
56505 * @param {Number} oldIndex
56506 * @param {Number} newIndex
56508 "columnmove" : true,
56511 * Fires when row(s) start being dragged
56512 * @param {Grid} this
56513 * @param {Roo.GridDD} dd The drag drop object
56514 * @param {event} e The raw browser event
56516 "startdrag" : true,
56519 * Fires when a drag operation is complete
56520 * @param {Grid} this
56521 * @param {Roo.GridDD} dd The drag drop object
56522 * @param {event} e The raw browser event
56527 * Fires when dragged row(s) are dropped on a valid DD target
56528 * @param {Grid} this
56529 * @param {Roo.GridDD} dd The drag drop object
56530 * @param {String} targetId The target drag drop object
56531 * @param {event} e The raw browser event
56536 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
56537 * @param {Grid} this
56538 * @param {Roo.GridDD} dd The drag drop object
56539 * @param {String} targetId The target drag drop object
56540 * @param {event} e The raw browser event
56545 * Fires when the dragged row(s) first cross another DD target while being dragged
56546 * @param {Grid} this
56547 * @param {Roo.GridDD} dd The drag drop object
56548 * @param {String} targetId The target drag drop object
56549 * @param {event} e The raw browser event
56551 "dragenter" : true,
56554 * Fires when the dragged row(s) leave another DD target while being dragged
56555 * @param {Grid} this
56556 * @param {Roo.GridDD} dd The drag drop object
56557 * @param {String} targetId The target drag drop object
56558 * @param {event} e The raw browser event
56563 * Fires when a row is rendered, so you can change add a style to it.
56564 * @param {GridView} gridview The grid view
56565 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
56571 * Fires when the grid is rendered
56572 * @param {Grid} grid
56577 * Fires when a date is selected
56578 * @param {DatePicker} this
56579 * @param {Date} date The selected date
56583 * @event monthchange
56584 * Fires when the displayed month changes
56585 * @param {DatePicker} this
56586 * @param {Date} date The selected month
56588 'monthchange': true,
56590 * @event evententer
56591 * Fires when mouse over an event
56592 * @param {Calendar} this
56593 * @param {event} Event
56595 'evententer': true,
56597 * @event eventleave
56598 * Fires when the mouse leaves an
56599 * @param {Calendar} this
56602 'eventleave': true,
56604 * @event eventclick
56605 * Fires when the mouse click an
56606 * @param {Calendar} this
56609 'eventclick': true,
56611 * @event eventrender
56612 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
56613 * @param {Calendar} this
56614 * @param {data} data to be modified
56616 'eventrender': true
56620 Roo.grid.Grid.superclass.constructor.call(this);
56621 this.on('render', function() {
56622 this.view.el.addClass('x-grid-cal');
56624 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
56628 if (!Roo.grid.Calendar.style) {
56629 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
56632 '.x-grid-cal .x-grid-col' : {
56633 height: 'auto !important',
56634 'vertical-align': 'top'
56636 '.x-grid-cal .fc-event-hori' : {
56647 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
56649 * @cfg {Store} eventStore The store that loads events.
56654 activeDate : false,
56657 monitorWindowResize : false,
56660 resizeColumns : function() {
56661 var col = (this.view.el.getWidth() / 7) - 3;
56662 // loop through cols, and setWidth
56663 for(var i =0 ; i < 7 ; i++){
56664 this.cm.setColumnWidth(i, col);
56667 setDate :function(date) {
56669 Roo.log('setDate?');
56671 this.resizeColumns();
56672 var vd = this.activeDate;
56673 this.activeDate = date;
56674 // if(vd && this.el){
56675 // var t = date.getTime();
56676 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
56677 // Roo.log('using add remove');
56679 // this.fireEvent('monthchange', this, date);
56681 // this.cells.removeClass("fc-state-highlight");
56682 // this.cells.each(function(c){
56683 // if(c.dateValue == t){
56684 // c.addClass("fc-state-highlight");
56685 // setTimeout(function(){
56686 // try{c.dom.firstChild.focus();}catch(e){}
56696 var days = date.getDaysInMonth();
56698 var firstOfMonth = date.getFirstDateOfMonth();
56699 var startingPos = firstOfMonth.getDay()-this.startDay;
56701 if(startingPos < this.startDay){
56705 var pm = date.add(Date.MONTH, -1);
56706 var prevStart = pm.getDaysInMonth()-startingPos;
56710 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
56712 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
56713 //this.cells.addClassOnOver('fc-state-hover');
56715 var cells = this.cells.elements;
56716 var textEls = this.textNodes;
56718 //Roo.each(cells, function(cell){
56719 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
56722 days += startingPos;
56724 // convert everything to numbers so it's fast
56725 var day = 86400000;
56726 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
56729 //Roo.log(prevStart);
56731 var today = new Date().clearTime().getTime();
56732 var sel = date.clearTime().getTime();
56733 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
56734 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
56735 var ddMatch = this.disabledDatesRE;
56736 var ddText = this.disabledDatesText;
56737 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
56738 var ddaysText = this.disabledDaysText;
56739 var format = this.format;
56741 var setCellClass = function(cal, cell){
56743 //Roo.log('set Cell Class');
56745 var t = d.getTime();
56750 cell.dateValue = t;
56752 cell.className += " fc-today";
56753 cell.className += " fc-state-highlight";
56754 cell.title = cal.todayText;
56757 // disable highlight in other month..
56758 cell.className += " fc-state-highlight";
56763 //cell.className = " fc-state-disabled";
56764 cell.title = cal.minText;
56768 //cell.className = " fc-state-disabled";
56769 cell.title = cal.maxText;
56773 if(ddays.indexOf(d.getDay()) != -1){
56774 // cell.title = ddaysText;
56775 // cell.className = " fc-state-disabled";
56778 if(ddMatch && format){
56779 var fvalue = d.dateFormat(format);
56780 if(ddMatch.test(fvalue)){
56781 cell.title = ddText.replace("%0", fvalue);
56782 cell.className = " fc-state-disabled";
56786 if (!cell.initialClassName) {
56787 cell.initialClassName = cell.dom.className;
56790 cell.dom.className = cell.initialClassName + ' ' + cell.className;
56795 for(; i < startingPos; i++) {
56796 cells[i].dayName = (++prevStart);
56797 Roo.log(textEls[i]);
56798 d.setDate(d.getDate()+1);
56800 //cells[i].className = "fc-past fc-other-month";
56801 setCellClass(this, cells[i]);
56806 for(; i < days; i++){
56807 intDay = i - startingPos + 1;
56808 cells[i].dayName = (intDay);
56809 d.setDate(d.getDate()+1);
56811 cells[i].className = ''; // "x-date-active";
56812 setCellClass(this, cells[i]);
56816 for(; i < 42; i++) {
56817 //textEls[i].innerHTML = (++extraDays);
56819 d.setDate(d.getDate()+1);
56820 cells[i].dayName = (++extraDays);
56821 cells[i].className = "fc-future fc-other-month";
56822 setCellClass(this, cells[i]);
56825 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
56827 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
56829 // this will cause all the cells to mis
56832 for (var r = 0;r < 6;r++) {
56833 for (var c =0;c < 7;c++) {
56834 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
56838 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
56839 for(i=0;i<cells.length;i++) {
56841 this.cells.elements[i].dayName = cells[i].dayName ;
56842 this.cells.elements[i].className = cells[i].className;
56843 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
56844 this.cells.elements[i].title = cells[i].title ;
56845 this.cells.elements[i].dateValue = cells[i].dateValue ;
56851 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
56852 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
56854 ////if(totalRows != 6){
56855 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
56856 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
56859 this.fireEvent('monthchange', this, date);
56864 * Returns the grid's SelectionModel.
56865 * @return {SelectionModel}
56867 getSelectionModel : function(){
56868 if(!this.selModel){
56869 this.selModel = new Roo.grid.CellSelectionModel();
56871 return this.selModel;
56875 this.eventStore.load()
56881 findCell : function(dt) {
56882 dt = dt.clearTime().getTime();
56884 this.cells.each(function(c){
56885 //Roo.log("check " +c.dateValue + '?=' + dt);
56886 if(c.dateValue == dt){
56896 findCells : function(rec) {
56897 var s = rec.data.start_dt.clone().clearTime().getTime();
56899 var e= rec.data.end_dt.clone().clearTime().getTime();
56902 this.cells.each(function(c){
56903 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
56905 if(c.dateValue > e){
56908 if(c.dateValue < s){
56917 findBestRow: function(cells)
56921 for (var i =0 ; i < cells.length;i++) {
56922 ret = Math.max(cells[i].rows || 0,ret);
56929 addItem : function(rec)
56931 // look for vertical location slot in
56932 var cells = this.findCells(rec);
56934 rec.row = this.findBestRow(cells);
56936 // work out the location.
56940 for(var i =0; i < cells.length; i++) {
56948 if (crow.start.getY() == cells[i].getY()) {
56950 crow.end = cells[i];
56966 for (var i = 0; i < cells.length;i++) {
56967 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
56974 clearEvents: function() {
56976 if (!this.eventStore.getCount()) {
56979 // reset number of rows in cells.
56980 Roo.each(this.cells.elements, function(c){
56984 this.eventStore.each(function(e) {
56985 this.clearEvent(e);
56990 clearEvent : function(ev)
56993 Roo.each(ev.els, function(el) {
56994 el.un('mouseenter' ,this.onEventEnter, this);
56995 el.un('mouseleave' ,this.onEventLeave, this);
57003 renderEvent : function(ev,ctr) {
57005 ctr = this.view.el.select('.fc-event-container',true).first();
57009 this.clearEvent(ev);
57015 var cells = ev.cells;
57016 var rows = ev.rows;
57017 this.fireEvent('eventrender', this, ev);
57019 for(var i =0; i < rows.length; i++) {
57023 cls += ' fc-event-start';
57025 if ((i+1) == rows.length) {
57026 cls += ' fc-event-end';
57029 //Roo.log(ev.data);
57030 // how many rows should it span..
57031 var cg = this.eventTmpl.append(ctr,Roo.apply({
57034 }, ev.data) , true);
57037 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57038 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57039 cg.on('click', this.onEventClick, this, ev);
57043 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57044 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57047 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57048 cg.setWidth(ebox.right - sbox.x -2);
57052 renderEvents: function()
57054 // first make sure there is enough space..
57056 if (!this.eventTmpl) {
57057 this.eventTmpl = new Roo.Template(
57058 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57059 '<div class="fc-event-inner">' +
57060 '<span class="fc-event-time">{time}</span>' +
57061 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57063 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57071 this.cells.each(function(c) {
57072 //Roo.log(c.select('.fc-day-content div',true).first());
57073 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57076 var ctr = this.view.el.select('.fc-event-container',true).first();
57079 this.eventStore.each(function(ev){
57081 this.renderEvent(ev);
57085 this.view.layout();
57089 onEventEnter: function (e, el,event,d) {
57090 this.fireEvent('evententer', this, el, event);
57093 onEventLeave: function (e, el,event,d) {
57094 this.fireEvent('eventleave', this, el, event);
57097 onEventClick: function (e, el,event,d) {
57098 this.fireEvent('eventclick', this, el, event);
57101 onMonthChange: function () {
57105 onLoad: function () {
57107 //Roo.log('calendar onload');
57109 if(this.eventStore.getCount() > 0){
57113 this.eventStore.each(function(d){
57118 if (typeof(add.end_dt) == 'undefined') {
57119 Roo.log("Missing End time in calendar data: ");
57123 if (typeof(add.start_dt) == 'undefined') {
57124 Roo.log("Missing Start time in calendar data: ");
57128 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
57129 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
57130 add.id = add.id || d.id;
57131 add.title = add.title || '??';
57139 this.renderEvents();
57149 render : function ()
57153 if (!this.view.el.hasClass('course-timesheet')) {
57154 this.view.el.addClass('course-timesheet');
57156 if (this.tsStyle) {
57161 Roo.log(_this.grid.view.el.getWidth());
57164 this.tsStyle = Roo.util.CSS.createStyleSheet({
57165 '.course-timesheet .x-grid-row' : {
57168 '.x-grid-row td' : {
57169 'vertical-align' : 0
57171 '.course-edit-link' : {
57173 'text-overflow' : 'ellipsis',
57174 'overflow' : 'hidden',
57175 'white-space' : 'nowrap',
57176 'cursor' : 'pointer'
57181 '.de-act-sup-link' : {
57182 'color' : 'purple',
57183 'text-decoration' : 'line-through'
57187 'text-decoration' : 'line-through'
57189 '.course-timesheet .course-highlight' : {
57190 'border-top-style': 'dashed !important',
57191 'border-bottom-bottom': 'dashed !important'
57193 '.course-timesheet .course-item' : {
57194 'font-family' : 'tahoma, arial, helvetica',
57195 'font-size' : '11px',
57196 'overflow' : 'hidden',
57197 'padding-left' : '10px',
57198 'padding-right' : '10px',
57199 'padding-top' : '10px'
57207 monitorWindowResize : false,
57208 cellrenderer : function(v,x,r)
57213 xtype: 'CellSelectionModel',
57220 beforeload : function (_self, options)
57222 options.params = options.params || {};
57223 options.params._month = _this.monthField.getValue();
57224 options.params.limit = 9999;
57225 options.params['sort'] = 'when_dt';
57226 options.params['dir'] = 'ASC';
57227 this.proxy.loadResponse = this.loadResponse;
57229 //this.addColumns();
57231 load : function (_self, records, options)
57233 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
57234 // if you click on the translation.. you can edit it...
57235 var el = Roo.get(this);
57236 var id = el.dom.getAttribute('data-id');
57237 var d = el.dom.getAttribute('data-date');
57238 var t = el.dom.getAttribute('data-time');
57239 //var id = this.child('span').dom.textContent;
57242 Pman.Dialog.CourseCalendar.show({
57246 productitem_active : id ? 1 : 0
57248 _this.grid.ds.load({});
57253 _this.panel.fireEvent('resize', [ '', '' ]);
57256 loadResponse : function(o, success, response){
57257 // this is overridden on before load..
57259 Roo.log("our code?");
57260 //Roo.log(success);
57261 //Roo.log(response)
57262 delete this.activeRequest;
57264 this.fireEvent("loadexception", this, o, response);
57265 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57270 result = o.reader.read(response);
57272 Roo.log("load exception?");
57273 this.fireEvent("loadexception", this, o, response, e);
57274 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57277 Roo.log("ready...");
57278 // loop through result.records;
57279 // and set this.tdate[date] = [] << array of records..
57281 Roo.each(result.records, function(r){
57283 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
57284 _this.tdata[r.data.when_dt.format('j')] = [];
57286 _this.tdata[r.data.when_dt.format('j')].push(r.data);
57289 //Roo.log(_this.tdata);
57291 result.records = [];
57292 result.totalRecords = 6;
57294 // let's generate some duumy records for the rows.
57295 //var st = _this.dateField.getValue();
57297 // work out monday..
57298 //st = st.add(Date.DAY, -1 * st.format('w'));
57300 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57302 var firstOfMonth = date.getFirstDayOfMonth();
57303 var days = date.getDaysInMonth();
57305 var firstAdded = false;
57306 for (var i = 0; i < result.totalRecords ; i++) {
57307 //var d= st.add(Date.DAY, i);
57310 for(var w = 0 ; w < 7 ; w++){
57311 if(!firstAdded && firstOfMonth != w){
57318 var dd = (d > 0 && d < 10) ? "0"+d : d;
57319 row['weekday'+w] = String.format(
57320 '<span style="font-size: 16px;"><b>{0}</b></span>'+
57321 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
57323 date.format('Y-m-')+dd
57326 if(typeof(_this.tdata[d]) != 'undefined'){
57327 Roo.each(_this.tdata[d], function(r){
57331 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
57332 if(r.parent_id*1>0){
57333 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
57336 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
57337 deactive = 'de-act-link';
57340 row['weekday'+w] += String.format(
57341 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
57343 r.product_id_name, //1
57344 r.when_dt.format('h:ia'), //2
57354 // only do this if something added..
57356 result.records.push(_this.grid.dataSource.reader.newRow(row));
57360 // push it twice. (second one with an hour..
57364 this.fireEvent("load", this, o, o.request.arg);
57365 o.request.callback.call(o.request.scope, result, o.request.arg, true);
57367 sortInfo : {field: 'when_dt', direction : 'ASC' },
57369 xtype: 'HttpProxy',
57372 url : baseURL + '/Roo/Shop_course.php'
57375 xtype: 'JsonReader',
57392 'name': 'parent_id',
57396 'name': 'product_id',
57400 'name': 'productitem_id',
57418 click : function (_self, e)
57420 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57421 sd.setMonth(sd.getMonth()-1);
57422 _this.monthField.setValue(sd.format('Y-m-d'));
57423 _this.grid.ds.load({});
57429 xtype: 'Separator',
57433 xtype: 'MonthField',
57436 render : function (_self)
57438 _this.monthField = _self;
57439 // _this.monthField.set today
57441 select : function (combo, date)
57443 _this.grid.ds.load({});
57446 value : (function() { return new Date(); })()
57449 xtype: 'Separator',
57455 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
57465 click : function (_self, e)
57467 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57468 sd.setMonth(sd.getMonth()+1);
57469 _this.monthField.setValue(sd.format('Y-m-d'));
57470 _this.grid.ds.load({});
57483 * Ext JS Library 1.1.1
57484 * Copyright(c) 2006-2007, Ext JS, LLC.
57486 * Originally Released Under LGPL - original licence link has changed is not relivant.
57489 * <script type="text/javascript">
57493 * @class Roo.LoadMask
57494 * A simple utility class for generically masking elements while loading data. If the element being masked has
57495 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
57496 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
57497 * element's UpdateManager load indicator and will be destroyed after the initial load.
57499 * Create a new LoadMask
57500 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
57501 * @param {Object} config The config object
57503 Roo.LoadMask = function(el, config){
57504 this.el = Roo.get(el);
57505 Roo.apply(this, config);
57507 this.store.on('beforeload', this.onBeforeLoad, this);
57508 this.store.on('load', this.onLoad, this);
57509 this.store.on('loadexception', this.onLoadException, this);
57510 this.removeMask = false;
57512 var um = this.el.getUpdateManager();
57513 um.showLoadIndicator = false; // disable the default indicator
57514 um.on('beforeupdate', this.onBeforeLoad, this);
57515 um.on('update', this.onLoad, this);
57516 um.on('failure', this.onLoad, this);
57517 this.removeMask = true;
57521 Roo.LoadMask.prototype = {
57523 * @cfg {Boolean} removeMask
57524 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
57525 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
57528 * @cfg {String} msg
57529 * The text to display in a centered loading message box (defaults to 'Loading...')
57531 msg : 'Loading...',
57533 * @cfg {String} msgCls
57534 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
57536 msgCls : 'x-mask-loading',
57539 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
57545 * Disables the mask to prevent it from being displayed
57547 disable : function(){
57548 this.disabled = true;
57552 * Enables the mask so that it can be displayed
57554 enable : function(){
57555 this.disabled = false;
57558 onLoadException : function()
57560 Roo.log(arguments);
57562 if (typeof(arguments[3]) != 'undefined') {
57563 Roo.MessageBox.alert("Error loading",arguments[3]);
57567 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
57568 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
57577 this.el.unmask(this.removeMask);
57580 onLoad : function()
57582 this.el.unmask(this.removeMask);
57586 onBeforeLoad : function(){
57587 if(!this.disabled){
57588 this.el.mask(this.msg, this.msgCls);
57593 destroy : function(){
57595 this.store.un('beforeload', this.onBeforeLoad, this);
57596 this.store.un('load', this.onLoad, this);
57597 this.store.un('loadexception', this.onLoadException, this);
57599 var um = this.el.getUpdateManager();
57600 um.un('beforeupdate', this.onBeforeLoad, this);
57601 um.un('update', this.onLoad, this);
57602 um.un('failure', this.onLoad, this);
57607 * Ext JS Library 1.1.1
57608 * Copyright(c) 2006-2007, Ext JS, LLC.
57610 * Originally Released Under LGPL - original licence link has changed is not relivant.
57613 * <script type="text/javascript">
57618 * @class Roo.XTemplate
57619 * @extends Roo.Template
57620 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
57622 var t = new Roo.XTemplate(
57623 '<select name="{name}">',
57624 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
57628 // then append, applying the master template values
57631 * Supported features:
57636 {a_variable} - output encoded.
57637 {a_variable.format:("Y-m-d")} - call a method on the variable
57638 {a_variable:raw} - unencoded output
57639 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
57640 {a_variable:this.method_on_template(...)} - call a method on the template object.
57645 <tpl for="a_variable or condition.."></tpl>
57646 <tpl if="a_variable or condition"></tpl>
57647 <tpl exec="some javascript"></tpl>
57648 <tpl name="named_template"></tpl> (experimental)
57650 <tpl for="."></tpl> - just iterate the property..
57651 <tpl for=".."></tpl> - iterates with the parent (probably the template)
57655 Roo.XTemplate = function()
57657 Roo.XTemplate.superclass.constructor.apply(this, arguments);
57664 Roo.extend(Roo.XTemplate, Roo.Template, {
57667 * The various sub templates
57672 * basic tag replacing syntax
57675 * // you can fake an object call by doing this
57679 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
57682 * compile the template
57684 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
57687 compile: function()
57691 s = ['<tpl>', s, '</tpl>'].join('');
57693 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
57694 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
57695 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
57696 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
57697 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
57702 while(true == !!(m = s.match(re))){
57703 var forMatch = m[0].match(nameRe),
57704 ifMatch = m[0].match(ifRe),
57705 execMatch = m[0].match(execRe),
57706 namedMatch = m[0].match(namedRe),
57711 name = forMatch && forMatch[1] ? forMatch[1] : '';
57714 // if - puts fn into test..
57715 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
57717 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
57722 // exec - calls a function... returns empty if true is returned.
57723 exp = execMatch && execMatch[1] ? execMatch[1] : null;
57725 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
57733 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
57734 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
57735 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
57738 var uid = namedMatch ? namedMatch[1] : id;
57742 id: namedMatch ? namedMatch[1] : id,
57749 s = s.replace(m[0], '');
57751 s = s.replace(m[0], '{xtpl'+ id + '}');
57756 for(var i = tpls.length-1; i >= 0; --i){
57757 this.compileTpl(tpls[i]);
57758 this.tpls[tpls[i].id] = tpls[i];
57760 this.master = tpls[tpls.length-1];
57764 * same as applyTemplate, except it's done to one of the subTemplates
57765 * when using named templates, you can do:
57767 * var str = pl.applySubTemplate('your-name', values);
57770 * @param {Number} id of the template
57771 * @param {Object} values to apply to template
57772 * @param {Object} parent (normaly the instance of this object)
57774 applySubTemplate : function(id, values, parent)
57778 var t = this.tpls[id];
57782 if(t.test && !t.test.call(this, values, parent)){
57786 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
57787 Roo.log(e.toString());
57793 if(t.exec && t.exec.call(this, values, parent)){
57797 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
57798 Roo.log(e.toString());
57803 var vs = t.target ? t.target.call(this, values, parent) : values;
57804 parent = t.target ? values : parent;
57805 if(t.target && vs instanceof Array){
57807 for(var i = 0, len = vs.length; i < len; i++){
57808 buf[buf.length] = t.compiled.call(this, vs[i], parent);
57810 return buf.join('');
57812 return t.compiled.call(this, vs, parent);
57814 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
57815 Roo.log(e.toString());
57816 Roo.log(t.compiled);
57821 compileTpl : function(tpl)
57823 var fm = Roo.util.Format;
57824 var useF = this.disableFormats !== true;
57825 var sep = Roo.isGecko ? "+" : ",";
57826 var undef = function(str) {
57827 Roo.log("Property not found :" + str);
57831 var fn = function(m, name, format, args)
57833 //Roo.log(arguments);
57834 args = args ? args.replace(/\\'/g,"'") : args;
57835 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
57836 if (typeof(format) == 'undefined') {
57837 format= 'htmlEncode';
57839 if (format == 'raw' ) {
57843 if(name.substr(0, 4) == 'xtpl'){
57844 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
57847 // build an array of options to determine if value is undefined..
57849 // basically get 'xxxx.yyyy' then do
57850 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
57851 // (function () { Roo.log("Property not found"); return ''; })() :
57856 Roo.each(name.split('.'), function(st) {
57857 lookfor += (lookfor.length ? '.': '') + st;
57858 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
57861 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
57864 if(format && useF){
57866 args = args ? ',' + args : "";
57868 if(format.substr(0, 5) != "this."){
57869 format = "fm." + format + '(';
57871 format = 'this.call("'+ format.substr(5) + '", ';
57875 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
57879 // called with xxyx.yuu:(test,test)
57881 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
57883 // raw.. - :raw modifier..
57884 return "'"+ sep + udef_st + name + ")"+sep+"'";
57888 // branched to use + in gecko and [].join() in others
57890 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
57891 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
57894 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
57895 body.push(tpl.body.replace(/(\r\n|\n)/g,
57896 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
57897 body.push("'].join('');};};");
57898 body = body.join('');
57901 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
57903 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
57909 applyTemplate : function(values){
57910 return this.master.compiled.call(this, values, {});
57911 //var s = this.subs;
57914 apply : function(){
57915 return this.applyTemplate.apply(this, arguments);
57920 Roo.XTemplate.from = function(el){
57921 el = Roo.getDom(el);
57922 return new Roo.XTemplate(el.value || el.innerHTML);