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;
3521 * Portions of this file are based on pieces of Yahoo User Interface Library
3522 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3523 * YUI licensed under the BSD License:
3524 * http://developer.yahoo.net/yui/license.txt
3525 * <script type="text/javascript">
3528 Roo.lib.Bezier = new function() {
3530 this.getPosition = function(points, t) {
3531 var n = points.length;
3534 for (var i = 0; i < n; ++i) {
3535 tmp[i] = [points[i][0], points[i][1]];
3538 for (var j = 1; j < n; ++j) {
3539 for (i = 0; i < n - j; ++i) {
3540 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3541 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3545 return [ tmp[0][0], tmp[0][1] ];
3549 * Portions of this file are based on pieces of Yahoo User Interface Library
3550 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3551 * YUI licensed under the BSD License:
3552 * http://developer.yahoo.net/yui/license.txt
3553 * <script type="text/javascript">
3558 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3559 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3562 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3564 var fly = Roo.lib.AnimBase.fly;
3566 var superclass = Y.ColorAnim.superclass;
3567 var proto = Y.ColorAnim.prototype;
3569 proto.toString = function() {
3570 var el = this.getEl();
3571 var id = el.id || el.tagName;
3572 return ("ColorAnim " + id);
3575 proto.patterns.color = /color$/i;
3576 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3577 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3578 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3579 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3582 proto.parseColor = function(s) {
3583 if (s.length == 3) {
3587 var c = this.patterns.hex.exec(s);
3588 if (c && c.length == 4) {
3589 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3592 c = this.patterns.rgb.exec(s);
3593 if (c && c.length == 4) {
3594 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3597 c = this.patterns.hex3.exec(s);
3598 if (c && c.length == 4) {
3599 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3604 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3605 proto.getAttribute = function(attr) {
3606 var el = this.getEl();
3607 if (this.patterns.color.test(attr)) {
3608 var val = fly(el).getStyle(attr);
3610 if (this.patterns.transparent.test(val)) {
3611 var parent = el.parentNode;
3612 val = fly(parent).getStyle(attr);
3614 while (parent && this.patterns.transparent.test(val)) {
3615 parent = parent.parentNode;
3616 val = fly(parent).getStyle(attr);
3617 if (parent.tagName.toUpperCase() == 'HTML') {
3623 val = superclass.getAttribute.call(this, attr);
3628 proto.getAttribute = function(attr) {
3629 var el = this.getEl();
3630 if (this.patterns.color.test(attr)) {
3631 var val = fly(el).getStyle(attr);
3633 if (this.patterns.transparent.test(val)) {
3634 var parent = el.parentNode;
3635 val = fly(parent).getStyle(attr);
3637 while (parent && this.patterns.transparent.test(val)) {
3638 parent = parent.parentNode;
3639 val = fly(parent).getStyle(attr);
3640 if (parent.tagName.toUpperCase() == 'HTML') {
3646 val = superclass.getAttribute.call(this, attr);
3652 proto.doMethod = function(attr, start, end) {
3655 if (this.patterns.color.test(attr)) {
3657 for (var i = 0, len = start.length; i < len; ++i) {
3658 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3661 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3664 val = superclass.doMethod.call(this, attr, start, end);
3670 proto.setRuntimeAttribute = function(attr) {
3671 superclass.setRuntimeAttribute.call(this, attr);
3673 if (this.patterns.color.test(attr)) {
3674 var attributes = this.attributes;
3675 var start = this.parseColor(this.runtimeAttributes[attr].start);
3676 var end = this.parseColor(this.runtimeAttributes[attr].end);
3678 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3679 end = this.parseColor(attributes[attr].by);
3681 for (var i = 0, len = start.length; i < len; ++i) {
3682 end[i] = start[i] + end[i];
3686 this.runtimeAttributes[attr].start = start;
3687 this.runtimeAttributes[attr].end = end;
3693 * Portions of this file are based on pieces of Yahoo User Interface Library
3694 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3695 * YUI licensed under the BSD License:
3696 * http://developer.yahoo.net/yui/license.txt
3697 * <script type="text/javascript">
3703 easeNone: function (t, b, c, d) {
3704 return c * t / d + b;
3708 easeIn: function (t, b, c, d) {
3709 return c * (t /= d) * t + b;
3713 easeOut: function (t, b, c, d) {
3714 return -c * (t /= d) * (t - 2) + b;
3718 easeBoth: function (t, b, c, d) {
3719 if ((t /= d / 2) < 1) {
3720 return c / 2 * t * t + b;
3723 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3727 easeInStrong: function (t, b, c, d) {
3728 return c * (t /= d) * t * t * t + b;
3732 easeOutStrong: function (t, b, c, d) {
3733 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3737 easeBothStrong: function (t, b, c, d) {
3738 if ((t /= d / 2) < 1) {
3739 return c / 2 * t * t * t * t + b;
3742 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3747 elasticIn: function (t, b, c, d, a, p) {
3751 if ((t /= d) == 1) {
3758 if (!a || a < Math.abs(c)) {
3763 var s = p / (2 * Math.PI) * Math.asin(c / a);
3766 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3770 elasticOut: function (t, b, c, d, a, p) {
3774 if ((t /= d) == 1) {
3781 if (!a || a < Math.abs(c)) {
3786 var s = p / (2 * Math.PI) * Math.asin(c / a);
3789 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3793 elasticBoth: function (t, b, c, d, a, p) {
3798 if ((t /= d / 2) == 2) {
3806 if (!a || a < Math.abs(c)) {
3811 var s = p / (2 * Math.PI) * Math.asin(c / a);
3815 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3816 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3818 return a * Math.pow(2, -10 * (t -= 1)) *
3819 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3824 backIn: function (t, b, c, d, s) {
3825 if (typeof s == 'undefined') {
3828 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3832 backOut: function (t, b, c, d, s) {
3833 if (typeof s == 'undefined') {
3836 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3840 backBoth: function (t, b, c, d, s) {
3841 if (typeof s == 'undefined') {
3845 if ((t /= d / 2 ) < 1) {
3846 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3848 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3852 bounceIn: function (t, b, c, d) {
3853 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3857 bounceOut: function (t, b, c, d) {
3858 if ((t /= d) < (1 / 2.75)) {
3859 return c * (7.5625 * t * t) + b;
3860 } else if (t < (2 / 2.75)) {
3861 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3862 } else if (t < (2.5 / 2.75)) {
3863 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3865 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3869 bounceBoth: function (t, b, c, d) {
3871 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3873 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3876 * Portions of this file are based on pieces of Yahoo User Interface Library
3877 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3878 * YUI licensed under the BSD License:
3879 * http://developer.yahoo.net/yui/license.txt
3880 * <script type="text/javascript">
3884 Roo.lib.Motion = function(el, attributes, duration, method) {
3886 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3890 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3894 var superclass = Y.Motion.superclass;
3895 var proto = Y.Motion.prototype;
3897 proto.toString = function() {
3898 var el = this.getEl();
3899 var id = el.id || el.tagName;
3900 return ("Motion " + id);
3903 proto.patterns.points = /^points$/i;
3905 proto.setAttribute = function(attr, val, unit) {
3906 if (this.patterns.points.test(attr)) {
3907 unit = unit || 'px';
3908 superclass.setAttribute.call(this, 'left', val[0], unit);
3909 superclass.setAttribute.call(this, 'top', val[1], unit);
3911 superclass.setAttribute.call(this, attr, val, unit);
3915 proto.getAttribute = function(attr) {
3916 if (this.patterns.points.test(attr)) {
3918 superclass.getAttribute.call(this, 'left'),
3919 superclass.getAttribute.call(this, 'top')
3922 val = superclass.getAttribute.call(this, attr);
3928 proto.doMethod = function(attr, start, end) {
3931 if (this.patterns.points.test(attr)) {
3932 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3933 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3935 val = superclass.doMethod.call(this, attr, start, end);
3940 proto.setRuntimeAttribute = function(attr) {
3941 if (this.patterns.points.test(attr)) {
3942 var el = this.getEl();
3943 var attributes = this.attributes;
3945 var control = attributes['points']['control'] || [];
3949 if (control.length > 0 && !(control[0] instanceof Array)) {
3950 control = [control];
3953 for (i = 0,len = control.length; i < len; ++i) {
3954 tmp[i] = control[i];
3959 Roo.fly(el).position();
3961 if (isset(attributes['points']['from'])) {
3962 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3965 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3968 start = this.getAttribute('points');
3971 if (isset(attributes['points']['to'])) {
3972 end = translateValues.call(this, attributes['points']['to'], start);
3974 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3975 for (i = 0,len = control.length; i < len; ++i) {
3976 control[i] = translateValues.call(this, control[i], start);
3980 } else if (isset(attributes['points']['by'])) {
3981 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3983 for (i = 0,len = control.length; i < len; ++i) {
3984 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3988 this.runtimeAttributes[attr] = [start];
3990 if (control.length > 0) {
3991 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3994 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3997 superclass.setRuntimeAttribute.call(this, attr);
4001 var translateValues = function(val, start) {
4002 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4003 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4008 var isset = function(prop) {
4009 return (typeof prop !== 'undefined');
4013 * Portions of this file are based on pieces of Yahoo User Interface Library
4014 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4015 * YUI licensed under the BSD License:
4016 * http://developer.yahoo.net/yui/license.txt
4017 * <script type="text/javascript">
4021 Roo.lib.Scroll = function(el, attributes, duration, method) {
4023 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4027 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4031 var superclass = Y.Scroll.superclass;
4032 var proto = Y.Scroll.prototype;
4034 proto.toString = function() {
4035 var el = this.getEl();
4036 var id = el.id || el.tagName;
4037 return ("Scroll " + id);
4040 proto.doMethod = function(attr, start, end) {
4043 if (attr == 'scroll') {
4045 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4046 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4050 val = superclass.doMethod.call(this, attr, start, end);
4055 proto.getAttribute = function(attr) {
4057 var el = this.getEl();
4059 if (attr == 'scroll') {
4060 val = [ el.scrollLeft, el.scrollTop ];
4062 val = superclass.getAttribute.call(this, attr);
4068 proto.setAttribute = function(attr, val, unit) {
4069 var el = this.getEl();
4071 if (attr == 'scroll') {
4072 el.scrollLeft = val[0];
4073 el.scrollTop = val[1];
4075 superclass.setAttribute.call(this, attr, val, unit);
4081 * Ext JS Library 1.1.1
4082 * Copyright(c) 2006-2007, Ext JS, LLC.
4084 * Originally Released Under LGPL - original licence link has changed is not relivant.
4087 * <script type="text/javascript">
4091 // nasty IE9 hack - what a pile of crap that is..
4093 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4094 Range.prototype.createContextualFragment = function (html) {
4095 var doc = window.document;
4096 var container = doc.createElement("div");
4097 container.innerHTML = html;
4098 var frag = doc.createDocumentFragment(), n;
4099 while ((n = container.firstChild)) {
4100 frag.appendChild(n);
4107 * @class Roo.DomHelper
4108 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4109 * 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>.
4112 Roo.DomHelper = function(){
4113 var tempTableEl = null;
4114 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4115 var tableRe = /^table|tbody|tr|td$/i;
4117 // build as innerHTML where available
4119 var createHtml = function(o){
4120 if(typeof o == 'string'){
4129 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4130 if(attr == "style"){
4132 if(typeof s == "function"){
4135 if(typeof s == "string"){
4136 b += ' style="' + s + '"';
4137 }else if(typeof s == "object"){
4140 if(typeof s[key] != "function"){
4141 b += key + ":" + s[key] + ";";
4148 b += ' class="' + o["cls"] + '"';
4149 }else if(attr == "htmlFor"){
4150 b += ' for="' + o["htmlFor"] + '"';
4152 b += " " + attr + '="' + o[attr] + '"';
4156 if(emptyTags.test(o.tag)){
4160 var cn = o.children || o.cn;
4162 //http://bugs.kde.org/show_bug.cgi?id=71506
4163 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4164 for(var i = 0, len = cn.length; i < len; i++) {
4165 b += createHtml(cn[i], b);
4168 b += createHtml(cn, b);
4174 b += "</" + o.tag + ">";
4181 var createDom = function(o, parentNode){
4183 // defininition craeted..
4185 if (o.ns && o.ns != 'html') {
4187 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4188 xmlns[o.ns] = o.xmlns;
4191 if (typeof(xmlns[o.ns]) == 'undefined') {
4192 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4198 if (typeof(o) == 'string') {
4199 return parentNode.appendChild(document.createTextNode(o));
4201 o.tag = o.tag || div;
4202 if (o.ns && Roo.isIE) {
4204 o.tag = o.ns + ':' + o.tag;
4207 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4208 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4211 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4212 attr == "style" || typeof o[attr] == "function") continue;
4214 if(attr=="cls" && Roo.isIE){
4215 el.className = o["cls"];
4217 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4218 else el[attr] = o[attr];
4221 Roo.DomHelper.applyStyles(el, o.style);
4222 var cn = o.children || o.cn;
4224 //http://bugs.kde.org/show_bug.cgi?id=71506
4225 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4226 for(var i = 0, len = cn.length; i < len; i++) {
4227 createDom(cn[i], el);
4234 el.innerHTML = o.html;
4237 parentNode.appendChild(el);
4242 var ieTable = function(depth, s, h, e){
4243 tempTableEl.innerHTML = [s, h, e].join('');
4244 var i = -1, el = tempTableEl;
4251 // kill repeat to save bytes
4255 tbe = '</tbody>'+te,
4261 * Nasty code for IE's broken table implementation
4263 var insertIntoTable = function(tag, where, el, html){
4265 tempTableEl = document.createElement('div');
4270 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4273 if(where == 'beforebegin'){
4277 before = el.nextSibling;
4280 node = ieTable(4, trs, html, tre);
4282 else if(tag == 'tr'){
4283 if(where == 'beforebegin'){
4286 node = ieTable(3, tbs, html, tbe);
4287 } else if(where == 'afterend'){
4288 before = el.nextSibling;
4290 node = ieTable(3, tbs, html, tbe);
4291 } else{ // INTO a TR
4292 if(where == 'afterbegin'){
4293 before = el.firstChild;
4295 node = ieTable(4, trs, html, tre);
4297 } else if(tag == 'tbody'){
4298 if(where == 'beforebegin'){
4301 node = ieTable(2, ts, html, te);
4302 } else if(where == 'afterend'){
4303 before = el.nextSibling;
4305 node = ieTable(2, ts, html, te);
4307 if(where == 'afterbegin'){
4308 before = el.firstChild;
4310 node = ieTable(3, tbs, html, tbe);
4313 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4316 if(where == 'afterbegin'){
4317 before = el.firstChild;
4319 node = ieTable(2, ts, html, te);
4321 el.insertBefore(node, before);
4326 /** True to force the use of DOM instead of html fragments @type Boolean */
4330 * Returns the markup for the passed Element(s) config
4331 * @param {Object} o The Dom object spec (and children)
4334 markup : function(o){
4335 return createHtml(o);
4339 * Applies a style specification to an element
4340 * @param {String/HTMLElement} el The element to apply styles to
4341 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4342 * a function which returns such a specification.
4344 applyStyles : function(el, styles){
4347 if(typeof styles == "string"){
4348 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4350 while ((matches = re.exec(styles)) != null){
4351 el.setStyle(matches[1], matches[2]);
4353 }else if (typeof styles == "object"){
4354 for (var style in styles){
4355 el.setStyle(style, styles[style]);
4357 }else if (typeof styles == "function"){
4358 Roo.DomHelper.applyStyles(el, styles.call());
4364 * Inserts an HTML fragment into the Dom
4365 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4366 * @param {HTMLElement} el The context element
4367 * @param {String} html The HTML fragmenet
4368 * @return {HTMLElement} The new node
4370 insertHtml : function(where, el, html){
4371 where = where.toLowerCase();
4372 if(el.insertAdjacentHTML){
4373 if(tableRe.test(el.tagName)){
4375 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4381 el.insertAdjacentHTML('BeforeBegin', html);
4382 return el.previousSibling;
4384 el.insertAdjacentHTML('AfterBegin', html);
4385 return el.firstChild;
4387 el.insertAdjacentHTML('BeforeEnd', html);
4388 return el.lastChild;
4390 el.insertAdjacentHTML('AfterEnd', html);
4391 return el.nextSibling;
4393 throw 'Illegal insertion point -> "' + where + '"';
4395 var range = el.ownerDocument.createRange();
4399 range.setStartBefore(el);
4400 frag = range.createContextualFragment(html);
4401 el.parentNode.insertBefore(frag, el);
4402 return el.previousSibling;
4405 range.setStartBefore(el.firstChild);
4406 frag = range.createContextualFragment(html);
4407 el.insertBefore(frag, el.firstChild);
4408 return el.firstChild;
4410 el.innerHTML = html;
4411 return el.firstChild;
4415 range.setStartAfter(el.lastChild);
4416 frag = range.createContextualFragment(html);
4417 el.appendChild(frag);
4418 return el.lastChild;
4420 el.innerHTML = html;
4421 return el.lastChild;
4424 range.setStartAfter(el);
4425 frag = range.createContextualFragment(html);
4426 el.parentNode.insertBefore(frag, el.nextSibling);
4427 return el.nextSibling;
4429 throw 'Illegal insertion point -> "' + where + '"';
4433 * Creates new Dom element(s) and inserts them before el
4434 * @param {String/HTMLElement/Element} el The context element
4435 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4436 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4437 * @return {HTMLElement/Roo.Element} The new node
4439 insertBefore : function(el, o, returnElement){
4440 return this.doInsert(el, o, returnElement, "beforeBegin");
4444 * Creates new Dom element(s) and inserts them after el
4445 * @param {String/HTMLElement/Element} el The context element
4446 * @param {Object} o The Dom object spec (and children)
4447 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4448 * @return {HTMLElement/Roo.Element} The new node
4450 insertAfter : function(el, o, returnElement){
4451 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4455 * Creates new Dom element(s) and inserts them as the first child of el
4456 * @param {String/HTMLElement/Element} el The context element
4457 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4458 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4459 * @return {HTMLElement/Roo.Element} The new node
4461 insertFirst : function(el, o, returnElement){
4462 return this.doInsert(el, o, returnElement, "afterBegin");
4466 doInsert : function(el, o, returnElement, pos, sibling){
4467 el = Roo.getDom(el);
4469 if(this.useDom || o.ns){
4470 newNode = createDom(o, null);
4471 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4473 var html = createHtml(o);
4474 newNode = this.insertHtml(pos, el, html);
4476 return returnElement ? Roo.get(newNode, true) : newNode;
4480 * Creates new Dom element(s) and appends them to el
4481 * @param {String/HTMLElement/Element} el The context element
4482 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4483 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4484 * @return {HTMLElement/Roo.Element} The new node
4486 append : function(el, o, returnElement){
4487 el = Roo.getDom(el);
4489 if(this.useDom || o.ns){
4490 newNode = createDom(o, null);
4491 el.appendChild(newNode);
4493 var html = createHtml(o);
4494 newNode = this.insertHtml("beforeEnd", el, html);
4496 return returnElement ? Roo.get(newNode, true) : newNode;
4500 * Creates new Dom element(s) and overwrites the contents of el with them
4501 * @param {String/HTMLElement/Element} el The context element
4502 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4503 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4504 * @return {HTMLElement/Roo.Element} The new node
4506 overwrite : function(el, o, returnElement){
4507 el = Roo.getDom(el);
4510 while (el.childNodes.length) {
4511 el.removeChild(el.firstChild);
4515 el.innerHTML = createHtml(o);
4518 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4522 * Creates a new Roo.DomHelper.Template from the Dom object spec
4523 * @param {Object} o The Dom object spec (and children)
4524 * @return {Roo.DomHelper.Template} The new template
4526 createTemplate : function(o){
4527 var html = createHtml(o);
4528 return new Roo.Template(html);
4534 * Ext JS Library 1.1.1
4535 * Copyright(c) 2006-2007, Ext JS, LLC.
4537 * Originally Released Under LGPL - original licence link has changed is not relivant.
4540 * <script type="text/javascript">
4544 * @class Roo.Template
4545 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4546 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4549 var t = new Roo.Template({
4550 html : '<div name="{id}">' +
4551 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4553 myformat: function (value, allValues) {
4554 return 'XX' + value;
4557 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4559 * For more information see this blog post with examples:
4560 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4561 - Create Elements using DOM, HTML fragments and Templates</a>.
4563 * @param {Object} cfg - Configuration object.
4565 Roo.Template = function(cfg){
4567 if(cfg instanceof Array){
4569 }else if(arguments.length > 1){
4570 cfg = Array.prototype.join.call(arguments, "");
4574 if (typeof(cfg) == 'object') {
4585 Roo.Template.prototype = {
4588 * @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..
4589 * it should be fixed so that template is observable...
4593 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4597 * Returns an HTML fragment of this template with the specified values applied.
4598 * @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'})
4599 * @return {String} The HTML fragment
4601 applyTemplate : function(values){
4605 return this.compiled(values);
4607 var useF = this.disableFormats !== true;
4608 var fm = Roo.util.Format, tpl = this;
4609 var fn = function(m, name, format, args){
4611 if(format.substr(0, 5) == "this."){
4612 return tpl.call(format.substr(5), values[name], values);
4615 // quoted values are required for strings in compiled templates,
4616 // but for non compiled we need to strip them
4617 // quoted reversed for jsmin
4618 var re = /^\s*['"](.*)["']\s*$/;
4619 args = args.split(',');
4620 for(var i = 0, len = args.length; i < len; i++){
4621 args[i] = args[i].replace(re, "$1");
4623 args = [values[name]].concat(args);
4625 args = [values[name]];
4627 return fm[format].apply(fm, args);
4630 return values[name] !== undefined ? values[name] : "";
4633 return this.html.replace(this.re, fn);
4651 this.loading = true;
4652 this.compiled = false;
4654 var cx = new Roo.data.Connection();
4658 success : function (response) {
4660 _t.html = response.responseText;
4664 failure : function(response) {
4665 Roo.log("Template failed to load from " + _t.url);
4672 * Sets the HTML used as the template and optionally compiles it.
4673 * @param {String} html
4674 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4675 * @return {Roo.Template} this
4677 set : function(html, compile){
4679 this.compiled = null;
4687 * True to disable format functions (defaults to false)
4690 disableFormats : false,
4693 * The regular expression used to match template variables
4697 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4700 * Compiles the template into an internal function, eliminating the RegEx overhead.
4701 * @return {Roo.Template} this
4703 compile : function(){
4704 var fm = Roo.util.Format;
4705 var useF = this.disableFormats !== true;
4706 var sep = Roo.isGecko ? "+" : ",";
4707 var fn = function(m, name, format, args){
4709 args = args ? ',' + args : "";
4710 if(format.substr(0, 5) != "this."){
4711 format = "fm." + format + '(';
4713 format = 'this.call("'+ format.substr(5) + '", ';
4717 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4719 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4722 // branched to use + in gecko and [].join() in others
4724 body = "this.compiled = function(values){ return '" +
4725 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4728 body = ["this.compiled = function(values){ return ['"];
4729 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4730 body.push("'].join('');};");
4731 body = body.join('');
4741 // private function used to call members
4742 call : function(fnName, value, allValues){
4743 return this[fnName](value, allValues);
4747 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4748 * @param {String/HTMLElement/Roo.Element} el The context element
4749 * @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'})
4750 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4751 * @return {HTMLElement/Roo.Element} The new node or Element
4753 insertFirst: function(el, values, returnElement){
4754 return this.doInsert('afterBegin', el, values, returnElement);
4758 * Applies the supplied values to the template and inserts the new node(s) before el.
4759 * @param {String/HTMLElement/Roo.Element} el The context element
4760 * @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'})
4761 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4762 * @return {HTMLElement/Roo.Element} The new node or Element
4764 insertBefore: function(el, values, returnElement){
4765 return this.doInsert('beforeBegin', el, values, returnElement);
4769 * Applies the supplied values to the template and inserts the new node(s) after el.
4770 * @param {String/HTMLElement/Roo.Element} el The context element
4771 * @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'})
4772 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4773 * @return {HTMLElement/Roo.Element} The new node or Element
4775 insertAfter : function(el, values, returnElement){
4776 return this.doInsert('afterEnd', el, values, returnElement);
4780 * Applies the supplied values to the template and appends the new node(s) to el.
4781 * @param {String/HTMLElement/Roo.Element} el The context element
4782 * @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'})
4783 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4784 * @return {HTMLElement/Roo.Element} The new node or Element
4786 append : function(el, values, returnElement){
4787 return this.doInsert('beforeEnd', el, values, returnElement);
4790 doInsert : function(where, el, values, returnEl){
4791 el = Roo.getDom(el);
4792 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4793 return returnEl ? Roo.get(newNode, true) : newNode;
4797 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4798 * @param {String/HTMLElement/Roo.Element} el The context element
4799 * @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'})
4800 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4801 * @return {HTMLElement/Roo.Element} The new node or Element
4803 overwrite : function(el, values, returnElement){
4804 el = Roo.getDom(el);
4805 el.innerHTML = this.applyTemplate(values);
4806 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4810 * Alias for {@link #applyTemplate}
4813 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4816 Roo.DomHelper.Template = Roo.Template;
4819 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4820 * @param {String/HTMLElement} el A DOM element or its id
4821 * @returns {Roo.Template} The created template
4824 Roo.Template.from = function(el){
4825 el = Roo.getDom(el);
4826 return new Roo.Template(el.value || el.innerHTML);
4829 * Ext JS Library 1.1.1
4830 * Copyright(c) 2006-2007, Ext JS, LLC.
4832 * Originally Released Under LGPL - original licence link has changed is not relivant.
4835 * <script type="text/javascript">
4840 * This is code is also distributed under MIT license for use
4841 * with jQuery and prototype JavaScript libraries.
4844 * @class Roo.DomQuery
4845 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).
4847 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>
4850 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.
4852 <h4>Element Selectors:</h4>
4854 <li> <b>*</b> any element</li>
4855 <li> <b>E</b> an element with the tag E</li>
4856 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4857 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4858 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4859 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4861 <h4>Attribute Selectors:</h4>
4862 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4864 <li> <b>E[foo]</b> has an attribute "foo"</li>
4865 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4866 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4867 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4868 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4869 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4870 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4872 <h4>Pseudo Classes:</h4>
4874 <li> <b>E:first-child</b> E is the first child of its parent</li>
4875 <li> <b>E:last-child</b> E is the last child of its parent</li>
4876 <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>
4877 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4878 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4879 <li> <b>E:only-child</b> E is the only child of its parent</li>
4880 <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>
4881 <li> <b>E:first</b> the first E in the resultset</li>
4882 <li> <b>E:last</b> the last E in the resultset</li>
4883 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4884 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4885 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4886 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4887 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4888 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4889 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4890 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4891 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4893 <h4>CSS Value Selectors:</h4>
4895 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4896 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4897 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4898 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4899 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4900 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4904 Roo.DomQuery = function(){
4905 var cache = {}, simpleCache = {}, valueCache = {};
4906 var nonSpace = /\S/;
4907 var trimRe = /^\s+|\s+$/g;
4908 var tplRe = /\{(\d+)\}/g;
4909 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4910 var tagTokenRe = /^(#)?([\w-\*]+)/;
4911 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4913 function child(p, index){
4915 var n = p.firstChild;
4917 if(n.nodeType == 1){
4928 while((n = n.nextSibling) && n.nodeType != 1);
4933 while((n = n.previousSibling) && n.nodeType != 1);
4937 function children(d){
4938 var n = d.firstChild, ni = -1;
4940 var nx = n.nextSibling;
4941 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4951 function byClassName(c, a, v){
4955 var r = [], ri = -1, cn;
4956 for(var i = 0, ci; ci = c[i]; i++){
4957 if((' '+ci.className+' ').indexOf(v) != -1){
4964 function attrValue(n, attr){
4965 if(!n.tagName && typeof n.length != "undefined"){
4974 if(attr == "class" || attr == "className"){
4977 return n.getAttribute(attr) || n[attr];
4981 function getNodes(ns, mode, tagName){
4982 var result = [], ri = -1, cs;
4986 tagName = tagName || "*";
4987 if(typeof ns.getElementsByTagName != "undefined"){
4991 for(var i = 0, ni; ni = ns[i]; i++){
4992 cs = ni.getElementsByTagName(tagName);
4993 for(var j = 0, ci; ci = cs[j]; j++){
4997 }else if(mode == "/" || mode == ">"){
4998 var utag = tagName.toUpperCase();
4999 for(var i = 0, ni, cn; ni = ns[i]; i++){
5000 cn = ni.children || ni.childNodes;
5001 for(var j = 0, cj; cj = cn[j]; j++){
5002 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5007 }else if(mode == "+"){
5008 var utag = tagName.toUpperCase();
5009 for(var i = 0, n; n = ns[i]; i++){
5010 while((n = n.nextSibling) && n.nodeType != 1);
5011 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5015 }else if(mode == "~"){
5016 for(var i = 0, n; n = ns[i]; i++){
5017 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5026 function concat(a, b){
5030 for(var i = 0, l = b.length; i < l; i++){
5036 function byTag(cs, tagName){
5037 if(cs.tagName || cs == document){
5043 var r = [], ri = -1;
5044 tagName = tagName.toLowerCase();
5045 for(var i = 0, ci; ci = cs[i]; i++){
5046 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5053 function byId(cs, attr, id){
5054 if(cs.tagName || cs == document){
5060 var r = [], ri = -1;
5061 for(var i = 0,ci; ci = cs[i]; i++){
5062 if(ci && ci.id == id){
5070 function byAttribute(cs, attr, value, op, custom){
5071 var r = [], ri = -1, st = custom=="{";
5072 var f = Roo.DomQuery.operators[op];
5073 for(var i = 0, ci; ci = cs[i]; i++){
5076 a = Roo.DomQuery.getStyle(ci, attr);
5078 else if(attr == "class" || attr == "className"){
5080 }else if(attr == "for"){
5082 }else if(attr == "href"){
5083 a = ci.getAttribute("href", 2);
5085 a = ci.getAttribute(attr);
5087 if((f && f(a, value)) || (!f && a)){
5094 function byPseudo(cs, name, value){
5095 return Roo.DomQuery.pseudos[name](cs, value);
5098 // This is for IE MSXML which does not support expandos.
5099 // IE runs the same speed using setAttribute, however FF slows way down
5100 // and Safari completely fails so they need to continue to use expandos.
5101 var isIE = window.ActiveXObject ? true : false;
5103 // this eval is stop the compressor from
5104 // renaming the variable to something shorter
5106 /** eval:var:batch */
5111 function nodupIEXml(cs){
5113 cs[0].setAttribute("_nodup", d);
5115 for(var i = 1, len = cs.length; i < len; i++){
5117 if(!c.getAttribute("_nodup") != d){
5118 c.setAttribute("_nodup", d);
5122 for(var i = 0, len = cs.length; i < len; i++){
5123 cs[i].removeAttribute("_nodup");
5132 var len = cs.length, c, i, r = cs, cj, ri = -1;
5133 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5136 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5137 return nodupIEXml(cs);
5141 for(i = 1; c = cs[i]; i++){
5146 for(var j = 0; j < i; j++){
5149 for(j = i+1; cj = cs[j]; j++){
5161 function quickDiffIEXml(c1, c2){
5163 for(var i = 0, len = c1.length; i < len; i++){
5164 c1[i].setAttribute("_qdiff", d);
5167 for(var i = 0, len = c2.length; i < len; i++){
5168 if(c2[i].getAttribute("_qdiff") != d){
5169 r[r.length] = c2[i];
5172 for(var i = 0, len = c1.length; i < len; i++){
5173 c1[i].removeAttribute("_qdiff");
5178 function quickDiff(c1, c2){
5179 var len1 = c1.length;
5183 if(isIE && c1[0].selectSingleNode){
5184 return quickDiffIEXml(c1, c2);
5187 for(var i = 0; i < len1; i++){
5191 for(var i = 0, len = c2.length; i < len; i++){
5192 if(c2[i]._qdiff != d){
5193 r[r.length] = c2[i];
5199 function quickId(ns, mode, root, id){
5201 var d = root.ownerDocument || root;
5202 return d.getElementById(id);
5204 ns = getNodes(ns, mode, "*");
5205 return byId(ns, null, id);
5209 getStyle : function(el, name){
5210 return Roo.fly(el).getStyle(name);
5213 * Compiles a selector/xpath query into a reusable function. The returned function
5214 * takes one parameter "root" (optional), which is the context node from where the query should start.
5215 * @param {String} selector The selector/xpath query
5216 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5217 * @return {Function}
5219 compile : function(path, type){
5220 type = type || "select";
5222 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5223 var q = path, mode, lq;
5224 var tk = Roo.DomQuery.matchers;
5225 var tklen = tk.length;
5228 // accept leading mode switch
5229 var lmode = q.match(modeRe);
5230 if(lmode && lmode[1]){
5231 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5232 q = q.replace(lmode[1], "");
5234 // strip leading slashes
5235 while(path.substr(0, 1)=="/"){
5236 path = path.substr(1);
5239 while(q && lq != q){
5241 var tm = q.match(tagTokenRe);
5242 if(type == "select"){
5245 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5247 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5249 q = q.replace(tm[0], "");
5250 }else if(q.substr(0, 1) != '@'){
5251 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5256 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5258 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5260 q = q.replace(tm[0], "");
5263 while(!(mm = q.match(modeRe))){
5264 var matched = false;
5265 for(var j = 0; j < tklen; j++){
5267 var m = q.match(t.re);
5269 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5272 q = q.replace(m[0], "");
5277 // prevent infinite loop on bad selector
5279 throw 'Error parsing selector, parsing failed at "' + q + '"';
5283 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5284 q = q.replace(mm[1], "");
5287 fn[fn.length] = "return nodup(n);\n}";
5290 * list of variables that need from compression as they are used by eval.
5300 * eval:var:byClassName
5302 * eval:var:byAttribute
5303 * eval:var:attrValue
5311 * Selects a group of elements.
5312 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5313 * @param {Node} root (optional) The start of the query (defaults to document).
5316 select : function(path, root, type){
5317 if(!root || root == document){
5320 if(typeof root == "string"){
5321 root = document.getElementById(root);
5323 var paths = path.split(",");
5325 for(var i = 0, len = paths.length; i < len; i++){
5326 var p = paths[i].replace(trimRe, "");
5328 cache[p] = Roo.DomQuery.compile(p);
5330 throw p + " is not a valid selector";
5333 var result = cache[p](root);
5334 if(result && result != document){
5335 results = results.concat(result);
5338 if(paths.length > 1){
5339 return nodup(results);
5345 * Selects a single element.
5346 * @param {String} selector The selector/xpath query
5347 * @param {Node} root (optional) The start of the query (defaults to document).
5350 selectNode : function(path, root){
5351 return Roo.DomQuery.select(path, root)[0];
5355 * Selects the value of a node, optionally replacing null with the defaultValue.
5356 * @param {String} selector The selector/xpath query
5357 * @param {Node} root (optional) The start of the query (defaults to document).
5358 * @param {String} defaultValue
5360 selectValue : function(path, root, defaultValue){
5361 path = path.replace(trimRe, "");
5362 if(!valueCache[path]){
5363 valueCache[path] = Roo.DomQuery.compile(path, "select");
5365 var n = valueCache[path](root);
5366 n = n[0] ? n[0] : n;
5367 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5368 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5372 * Selects the value of a node, parsing integers and floats.
5373 * @param {String} selector The selector/xpath query
5374 * @param {Node} root (optional) The start of the query (defaults to document).
5375 * @param {Number} defaultValue
5378 selectNumber : function(path, root, defaultValue){
5379 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5380 return parseFloat(v);
5384 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5385 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5386 * @param {String} selector The simple selector to test
5389 is : function(el, ss){
5390 if(typeof el == "string"){
5391 el = document.getElementById(el);
5393 var isArray = (el instanceof Array);
5394 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5395 return isArray ? (result.length == el.length) : (result.length > 0);
5399 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5400 * @param {Array} el An array of elements to filter
5401 * @param {String} selector The simple selector to test
5402 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5403 * the selector instead of the ones that match
5406 filter : function(els, ss, nonMatches){
5407 ss = ss.replace(trimRe, "");
5408 if(!simpleCache[ss]){
5409 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5411 var result = simpleCache[ss](els);
5412 return nonMatches ? quickDiff(result, els) : result;
5416 * Collection of matching regular expressions and code snippets.
5420 select: 'n = byClassName(n, null, " {1} ");'
5422 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5423 select: 'n = byPseudo(n, "{1}", "{2}");'
5425 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5426 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5429 select: 'n = byId(n, null, "{1}");'
5432 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5437 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5438 * 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, > <.
5441 "=" : function(a, v){
5444 "!=" : function(a, v){
5447 "^=" : function(a, v){
5448 return a && a.substr(0, v.length) == v;
5450 "$=" : function(a, v){
5451 return a && a.substr(a.length-v.length) == v;
5453 "*=" : function(a, v){
5454 return a && a.indexOf(v) !== -1;
5456 "%=" : function(a, v){
5457 return (a % v) == 0;
5459 "|=" : function(a, v){
5460 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5462 "~=" : function(a, v){
5463 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5468 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5469 * and the argument (if any) supplied in the selector.
5472 "first-child" : function(c){
5473 var r = [], ri = -1, n;
5474 for(var i = 0, ci; ci = n = c[i]; i++){
5475 while((n = n.previousSibling) && n.nodeType != 1);
5483 "last-child" : function(c){
5484 var r = [], ri = -1, n;
5485 for(var i = 0, ci; ci = n = c[i]; i++){
5486 while((n = n.nextSibling) && n.nodeType != 1);
5494 "nth-child" : function(c, a) {
5495 var r = [], ri = -1;
5496 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5497 var f = (m[1] || 1) - 0, l = m[2] - 0;
5498 for(var i = 0, n; n = c[i]; i++){
5499 var pn = n.parentNode;
5500 if (batch != pn._batch) {
5502 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5503 if(cn.nodeType == 1){
5510 if (l == 0 || n.nodeIndex == l){
5513 } else if ((n.nodeIndex + l) % f == 0){
5521 "only-child" : function(c){
5522 var r = [], ri = -1;;
5523 for(var i = 0, ci; ci = c[i]; i++){
5524 if(!prev(ci) && !next(ci)){
5531 "empty" : function(c){
5532 var r = [], ri = -1;
5533 for(var i = 0, ci; ci = c[i]; i++){
5534 var cns = ci.childNodes, j = 0, cn, empty = true;
5537 if(cn.nodeType == 1 || cn.nodeType == 3){
5549 "contains" : function(c, v){
5550 var r = [], ri = -1;
5551 for(var i = 0, ci; ci = c[i]; i++){
5552 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5559 "nodeValue" : function(c, v){
5560 var r = [], ri = -1;
5561 for(var i = 0, ci; ci = c[i]; i++){
5562 if(ci.firstChild && ci.firstChild.nodeValue == v){
5569 "checked" : function(c){
5570 var r = [], ri = -1;
5571 for(var i = 0, ci; ci = c[i]; i++){
5572 if(ci.checked == true){
5579 "not" : function(c, ss){
5580 return Roo.DomQuery.filter(c, ss, true);
5583 "odd" : function(c){
5584 return this["nth-child"](c, "odd");
5587 "even" : function(c){
5588 return this["nth-child"](c, "even");
5591 "nth" : function(c, a){
5592 return c[a-1] || [];
5595 "first" : function(c){
5599 "last" : function(c){
5600 return c[c.length-1] || [];
5603 "has" : function(c, ss){
5604 var s = Roo.DomQuery.select;
5605 var r = [], ri = -1;
5606 for(var i = 0, ci; ci = c[i]; i++){
5607 if(s(ss, ci).length > 0){
5614 "next" : function(c, ss){
5615 var is = Roo.DomQuery.is;
5616 var r = [], ri = -1;
5617 for(var i = 0, ci; ci = c[i]; i++){
5626 "prev" : function(c, ss){
5627 var is = Roo.DomQuery.is;
5628 var r = [], ri = -1;
5629 for(var i = 0, ci; ci = c[i]; i++){
5642 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5643 * @param {String} path The selector/xpath query
5644 * @param {Node} root (optional) The start of the query (defaults to document).
5649 Roo.query = Roo.DomQuery.select;
5652 * Ext JS Library 1.1.1
5653 * Copyright(c) 2006-2007, Ext JS, LLC.
5655 * Originally Released Under LGPL - original licence link has changed is not relivant.
5658 * <script type="text/javascript">
5662 * @class Roo.util.Observable
5663 * Base class that provides a common interface for publishing events. Subclasses are expected to
5664 * to have a property "events" with all the events defined.<br>
5667 Employee = function(name){
5674 Roo.extend(Employee, Roo.util.Observable);
5676 * @param {Object} config properties to use (incuding events / listeners)
5679 Roo.util.Observable = function(cfg){
5682 this.addEvents(cfg.events || {});
5684 delete cfg.events; // make sure
5687 Roo.apply(this, cfg);
5690 this.on(this.listeners);
5691 delete this.listeners;
5694 Roo.util.Observable.prototype = {
5696 * @cfg {Object} listeners list of events and functions to call for this object,
5700 'click' : function(e) {
5710 * Fires the specified event with the passed parameters (minus the event name).
5711 * @param {String} eventName
5712 * @param {Object...} args Variable number of parameters are passed to handlers
5713 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5715 fireEvent : function(){
5716 var ce = this.events[arguments[0].toLowerCase()];
5717 if(typeof ce == "object"){
5718 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5725 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5728 * Appends an event handler to this component
5729 * @param {String} eventName The type of event to listen for
5730 * @param {Function} handler The method the event invokes
5731 * @param {Object} scope (optional) The scope in which to execute the handler
5732 * function. The handler function's "this" context.
5733 * @param {Object} options (optional) An object containing handler configuration
5734 * properties. This may contain any of the following properties:<ul>
5735 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5736 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5737 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5738 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5739 * by the specified number of milliseconds. If the event fires again within that time, the original
5740 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5743 * <b>Combining Options</b><br>
5744 * Using the options argument, it is possible to combine different types of listeners:<br>
5746 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5748 el.on('click', this.onClick, this, {
5755 * <b>Attaching multiple handlers in 1 call</b><br>
5756 * The method also allows for a single argument to be passed which is a config object containing properties
5757 * which specify multiple handlers.
5766 fn: this.onMouseOver,
5770 fn: this.onMouseOut,
5776 * Or a shorthand syntax which passes the same scope object to all handlers:
5779 'click': this.onClick,
5780 'mouseover': this.onMouseOver,
5781 'mouseout': this.onMouseOut,
5786 addListener : function(eventName, fn, scope, o){
5787 if(typeof eventName == "object"){
5790 if(this.filterOptRe.test(e)){
5793 if(typeof o[e] == "function"){
5795 this.addListener(e, o[e], o.scope, o);
5797 // individual options
5798 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5803 o = (!o || typeof o == "boolean") ? {} : o;
5804 eventName = eventName.toLowerCase();
5805 var ce = this.events[eventName] || true;
5806 if(typeof ce == "boolean"){
5807 ce = new Roo.util.Event(this, eventName);
5808 this.events[eventName] = ce;
5810 ce.addListener(fn, scope, o);
5814 * Removes a listener
5815 * @param {String} eventName The type of event to listen for
5816 * @param {Function} handler The handler to remove
5817 * @param {Object} scope (optional) The scope (this object) for the handler
5819 removeListener : function(eventName, fn, scope){
5820 var ce = this.events[eventName.toLowerCase()];
5821 if(typeof ce == "object"){
5822 ce.removeListener(fn, scope);
5827 * Removes all listeners for this object
5829 purgeListeners : function(){
5830 for(var evt in this.events){
5831 if(typeof this.events[evt] == "object"){
5832 this.events[evt].clearListeners();
5837 relayEvents : function(o, events){
5838 var createHandler = function(ename){
5840 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5843 for(var i = 0, len = events.length; i < len; i++){
5844 var ename = events[i];
5845 if(!this.events[ename]){ this.events[ename] = true; };
5846 o.on(ename, createHandler(ename), this);
5851 * Used to define events on this Observable
5852 * @param {Object} object The object with the events defined
5854 addEvents : function(o){
5858 Roo.applyIf(this.events, o);
5862 * Checks to see if this object has any listeners for a specified event
5863 * @param {String} eventName The name of the event to check for
5864 * @return {Boolean} True if the event is being listened for, else false
5866 hasListener : function(eventName){
5867 var e = this.events[eventName];
5868 return typeof e == "object" && e.listeners.length > 0;
5872 * Appends an event handler to this element (shorthand for addListener)
5873 * @param {String} eventName The type of event to listen for
5874 * @param {Function} handler The method the event invokes
5875 * @param {Object} scope (optional) The scope in which to execute the handler
5876 * function. The handler function's "this" context.
5877 * @param {Object} options (optional)
5880 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5882 * Removes a listener (shorthand for removeListener)
5883 * @param {String} eventName The type of event to listen for
5884 * @param {Function} handler The handler to remove
5885 * @param {Object} scope (optional) The scope (this object) for the handler
5888 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5891 * Starts capture on the specified Observable. All events will be passed
5892 * to the supplied function with the event name + standard signature of the event
5893 * <b>before</b> the event is fired. If the supplied function returns false,
5894 * the event will not fire.
5895 * @param {Observable} o The Observable to capture
5896 * @param {Function} fn The function to call
5897 * @param {Object} scope (optional) The scope (this object) for the fn
5900 Roo.util.Observable.capture = function(o, fn, scope){
5901 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5905 * Removes <b>all</b> added captures from the Observable.
5906 * @param {Observable} o The Observable to release
5909 Roo.util.Observable.releaseCapture = function(o){
5910 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5915 var createBuffered = function(h, o, scope){
5916 var task = new Roo.util.DelayedTask();
5918 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5922 var createSingle = function(h, e, fn, scope){
5924 e.removeListener(fn, scope);
5925 return h.apply(scope, arguments);
5929 var createDelayed = function(h, o, scope){
5931 var args = Array.prototype.slice.call(arguments, 0);
5932 setTimeout(function(){
5933 h.apply(scope, args);
5938 Roo.util.Event = function(obj, name){
5941 this.listeners = [];
5944 Roo.util.Event.prototype = {
5945 addListener : function(fn, scope, options){
5946 var o = options || {};
5947 scope = scope || this.obj;
5948 if(!this.isListening(fn, scope)){
5949 var l = {fn: fn, scope: scope, options: o};
5952 h = createDelayed(h, o, scope);
5955 h = createSingle(h, this, fn, scope);
5958 h = createBuffered(h, o, scope);
5961 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5962 this.listeners.push(l);
5964 this.listeners = this.listeners.slice(0);
5965 this.listeners.push(l);
5970 findListener : function(fn, scope){
5971 scope = scope || this.obj;
5972 var ls = this.listeners;
5973 for(var i = 0, len = ls.length; i < len; i++){
5975 if(l.fn == fn && l.scope == scope){
5982 isListening : function(fn, scope){
5983 return this.findListener(fn, scope) != -1;
5986 removeListener : function(fn, scope){
5988 if((index = this.findListener(fn, scope)) != -1){
5990 this.listeners.splice(index, 1);
5992 this.listeners = this.listeners.slice(0);
5993 this.listeners.splice(index, 1);
6000 clearListeners : function(){
6001 this.listeners = [];
6005 var ls = this.listeners, scope, len = ls.length;
6008 var args = Array.prototype.slice.call(arguments, 0);
6009 for(var i = 0; i < len; i++){
6011 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6012 this.firing = false;
6016 this.firing = false;
6023 * Ext JS Library 1.1.1
6024 * Copyright(c) 2006-2007, Ext JS, LLC.
6026 * Originally Released Under LGPL - original licence link has changed is not relivant.
6029 * <script type="text/javascript">
6033 * @class Roo.EventManager
6034 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6035 * several useful events directly.
6036 * See {@link Roo.EventObject} for more details on normalized event objects.
6039 Roo.EventManager = function(){
6040 var docReadyEvent, docReadyProcId, docReadyState = false;
6041 var resizeEvent, resizeTask, textEvent, textSize;
6042 var E = Roo.lib.Event;
6043 var D = Roo.lib.Dom;
6046 var fireDocReady = function(){
6048 docReadyState = true;
6051 clearInterval(docReadyProcId);
6053 if(Roo.isGecko || Roo.isOpera) {
6054 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6057 var defer = document.getElementById("ie-deferred-loader");
6059 defer.onreadystatechange = null;
6060 defer.parentNode.removeChild(defer);
6064 docReadyEvent.fire();
6065 docReadyEvent.clearListeners();
6070 var initDocReady = function(){
6071 docReadyEvent = new Roo.util.Event();
6072 if(Roo.isGecko || Roo.isOpera) {
6073 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6075 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6076 var defer = document.getElementById("ie-deferred-loader");
6077 defer.onreadystatechange = function(){
6078 if(this.readyState == "complete"){
6082 }else if(Roo.isSafari){
6083 docReadyProcId = setInterval(function(){
6084 var rs = document.readyState;
6085 if(rs == "complete") {
6090 // no matter what, make sure it fires on load
6091 E.on(window, "load", fireDocReady);
6094 var createBuffered = function(h, o){
6095 var task = new Roo.util.DelayedTask(h);
6097 // create new event object impl so new events don't wipe out properties
6098 e = new Roo.EventObjectImpl(e);
6099 task.delay(o.buffer, h, null, [e]);
6103 var createSingle = function(h, el, ename, fn){
6105 Roo.EventManager.removeListener(el, ename, fn);
6110 var createDelayed = function(h, o){
6112 // create new event object impl so new events don't wipe out properties
6113 e = new Roo.EventObjectImpl(e);
6114 setTimeout(function(){
6120 var listen = function(element, ename, opt, fn, scope){
6121 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6122 fn = fn || o.fn; scope = scope || o.scope;
6123 var el = Roo.getDom(element);
6125 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6127 var h = function(e){
6128 e = Roo.EventObject.setEvent(e);
6131 t = e.getTarget(o.delegate, el);
6138 if(o.stopEvent === true){
6141 if(o.preventDefault === true){
6144 if(o.stopPropagation === true){
6145 e.stopPropagation();
6148 if(o.normalized === false){
6152 fn.call(scope || el, e, t, o);
6155 h = createDelayed(h, o);
6158 h = createSingle(h, el, ename, fn);
6161 h = createBuffered(h, o);
6163 fn._handlers = fn._handlers || [];
6164 fn._handlers.push([Roo.id(el), ename, h]);
6167 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6168 el.addEventListener("DOMMouseScroll", h, false);
6169 E.on(window, 'unload', function(){
6170 el.removeEventListener("DOMMouseScroll", h, false);
6173 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6174 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6179 var stopListening = function(el, ename, fn){
6180 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6182 for(var i = 0, len = hds.length; i < len; i++){
6184 if(h[0] == id && h[1] == ename){
6191 E.un(el, ename, hd);
6192 el = Roo.getDom(el);
6193 if(ename == "mousewheel" && el.addEventListener){
6194 el.removeEventListener("DOMMouseScroll", hd, false);
6196 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6197 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6201 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6208 * @scope Roo.EventManager
6213 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6214 * object with a Roo.EventObject
6215 * @param {Function} fn The method the event invokes
6216 * @param {Object} scope An object that becomes the scope of the handler
6217 * @param {boolean} override If true, the obj passed in becomes
6218 * the execution scope of the listener
6219 * @return {Function} The wrapped function
6222 wrap : function(fn, scope, override){
6224 Roo.EventObject.setEvent(e);
6225 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6230 * Appends an event handler to an element (shorthand for addListener)
6231 * @param {String/HTMLElement} element The html element or id to assign the
6232 * @param {String} eventName The type of event to listen for
6233 * @param {Function} handler The method the event invokes
6234 * @param {Object} scope (optional) The scope in which to execute the handler
6235 * function. The handler function's "this" context.
6236 * @param {Object} options (optional) An object containing handler configuration
6237 * properties. This may contain any of the following properties:<ul>
6238 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6239 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6240 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6241 * <li>preventDefault {Boolean} True to prevent the default action</li>
6242 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6243 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6244 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6245 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6246 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6247 * by the specified number of milliseconds. If the event fires again within that time, the original
6248 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6251 * <b>Combining Options</b><br>
6252 * Using the options argument, it is possible to combine different types of listeners:<br>
6254 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6256 el.on('click', this.onClick, this, {
6263 * <b>Attaching multiple handlers in 1 call</b><br>
6264 * The method also allows for a single argument to be passed which is a config object containing properties
6265 * which specify multiple handlers.
6275 fn: this.onMouseOver
6284 * Or a shorthand syntax:<br>
6287 'click' : this.onClick,
6288 'mouseover' : this.onMouseOver,
6289 'mouseout' : this.onMouseOut
6293 addListener : function(element, eventName, fn, scope, options){
6294 if(typeof eventName == "object"){
6300 if(typeof o[e] == "function"){
6302 listen(element, e, o, o[e], o.scope);
6304 // individual options
6305 listen(element, e, o[e]);
6310 return listen(element, eventName, options, fn, scope);
6314 * Removes an event handler
6316 * @param {String/HTMLElement} element The id or html element to remove the
6318 * @param {String} eventName The type of event
6319 * @param {Function} fn
6320 * @return {Boolean} True if a listener was actually removed
6322 removeListener : function(element, eventName, fn){
6323 return stopListening(element, eventName, fn);
6327 * Fires when the document is ready (before onload and before images are loaded). Can be
6328 * accessed shorthanded Roo.onReady().
6329 * @param {Function} fn The method the event invokes
6330 * @param {Object} scope An object that becomes the scope of the handler
6331 * @param {boolean} options
6333 onDocumentReady : function(fn, scope, options){
6334 if(docReadyState){ // if it already fired
6335 docReadyEvent.addListener(fn, scope, options);
6336 docReadyEvent.fire();
6337 docReadyEvent.clearListeners();
6343 docReadyEvent.addListener(fn, scope, options);
6347 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6348 * @param {Function} fn The method the event invokes
6349 * @param {Object} scope An object that becomes the scope of the handler
6350 * @param {boolean} options
6352 onWindowResize : function(fn, scope, options){
6354 resizeEvent = new Roo.util.Event();
6355 resizeTask = new Roo.util.DelayedTask(function(){
6356 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6358 E.on(window, "resize", function(){
6360 resizeTask.delay(50);
6362 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6366 resizeEvent.addListener(fn, scope, options);
6370 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6371 * @param {Function} fn The method the event invokes
6372 * @param {Object} scope An object that becomes the scope of the handler
6373 * @param {boolean} options
6375 onTextResize : function(fn, scope, options){
6377 textEvent = new Roo.util.Event();
6378 var textEl = new Roo.Element(document.createElement('div'));
6379 textEl.dom.className = 'x-text-resize';
6380 textEl.dom.innerHTML = 'X';
6381 textEl.appendTo(document.body);
6382 textSize = textEl.dom.offsetHeight;
6383 setInterval(function(){
6384 if(textEl.dom.offsetHeight != textSize){
6385 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6387 }, this.textResizeInterval);
6389 textEvent.addListener(fn, scope, options);
6393 * Removes the passed window resize listener.
6394 * @param {Function} fn The method the event invokes
6395 * @param {Object} scope The scope of handler
6397 removeResizeListener : function(fn, scope){
6399 resizeEvent.removeListener(fn, scope);
6404 fireResize : function(){
6406 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6410 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6414 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6416 textResizeInterval : 50
6421 * @scopeAlias pub=Roo.EventManager
6425 * Appends an event handler to an element (shorthand for addListener)
6426 * @param {String/HTMLElement} element The html element or id to assign the
6427 * @param {String} eventName The type of event to listen for
6428 * @param {Function} handler The method the event invokes
6429 * @param {Object} scope (optional) The scope in which to execute the handler
6430 * function. The handler function's "this" context.
6431 * @param {Object} options (optional) An object containing handler configuration
6432 * properties. This may contain any of the following properties:<ul>
6433 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6434 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6435 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6436 * <li>preventDefault {Boolean} True to prevent the default action</li>
6437 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6438 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6439 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6440 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6441 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6442 * by the specified number of milliseconds. If the event fires again within that time, the original
6443 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6446 * <b>Combining Options</b><br>
6447 * Using the options argument, it is possible to combine different types of listeners:<br>
6449 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6451 el.on('click', this.onClick, this, {
6458 * <b>Attaching multiple handlers in 1 call</b><br>
6459 * The method also allows for a single argument to be passed which is a config object containing properties
6460 * which specify multiple handlers.
6470 fn: this.onMouseOver
6479 * Or a shorthand syntax:<br>
6482 'click' : this.onClick,
6483 'mouseover' : this.onMouseOver,
6484 'mouseout' : this.onMouseOut
6488 pub.on = pub.addListener;
6489 pub.un = pub.removeListener;
6491 pub.stoppedMouseDownEvent = new Roo.util.Event();
6495 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6496 * @param {Function} fn The method the event invokes
6497 * @param {Object} scope An object that becomes the scope of the handler
6498 * @param {boolean} override If true, the obj passed in becomes
6499 * the execution scope of the listener
6503 Roo.onReady = Roo.EventManager.onDocumentReady;
6505 Roo.onReady(function(){
6506 var bd = Roo.get(document.body);
6511 : Roo.isGecko ? "roo-gecko"
6512 : Roo.isOpera ? "roo-opera"
6513 : Roo.isSafari ? "roo-safari" : ""];
6516 cls.push("roo-mac");
6519 cls.push("roo-linux");
6521 if(Roo.isBorderBox){
6522 cls.push('roo-border-box');
6524 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6525 var p = bd.dom.parentNode;
6527 p.className += ' roo-strict';
6530 bd.addClass(cls.join(' '));
6534 * @class Roo.EventObject
6535 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6536 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6539 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6541 var target = e.getTarget();
6544 var myDiv = Roo.get("myDiv");
6545 myDiv.on("click", handleClick);
6547 Roo.EventManager.on("myDiv", 'click', handleClick);
6548 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6552 Roo.EventObject = function(){
6554 var E = Roo.lib.Event;
6556 // safari keypress events for special keys return bad keycodes
6559 63235 : 39, // right
6562 63276 : 33, // page up
6563 63277 : 34, // page down
6564 63272 : 46, // delete
6569 // normalize button clicks
6570 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6571 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6573 Roo.EventObjectImpl = function(e){
6575 this.setEvent(e.browserEvent || e);
6578 Roo.EventObjectImpl.prototype = {
6580 * Used to fix doc tools.
6581 * @scope Roo.EventObject.prototype
6587 /** The normal browser event */
6588 browserEvent : null,
6589 /** The button pressed in a mouse event */
6591 /** True if the shift key was down during the event */
6593 /** True if the control key was down during the event */
6595 /** True if the alt key was down during the event */
6654 setEvent : function(e){
6655 if(e == this || (e && e.browserEvent)){ // already wrapped
6658 this.browserEvent = e;
6660 // normalize buttons
6661 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6662 if(e.type == 'click' && this.button == -1){
6666 this.shiftKey = e.shiftKey;
6667 // mac metaKey behaves like ctrlKey
6668 this.ctrlKey = e.ctrlKey || e.metaKey;
6669 this.altKey = e.altKey;
6670 // in getKey these will be normalized for the mac
6671 this.keyCode = e.keyCode;
6672 // keyup warnings on firefox.
6673 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6674 // cache the target for the delayed and or buffered events
6675 this.target = E.getTarget(e);
6677 this.xy = E.getXY(e);
6680 this.shiftKey = false;
6681 this.ctrlKey = false;
6682 this.altKey = false;
6692 * Stop the event (preventDefault and stopPropagation)
6694 stopEvent : function(){
6695 if(this.browserEvent){
6696 if(this.browserEvent.type == 'mousedown'){
6697 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6699 E.stopEvent(this.browserEvent);
6704 * Prevents the browsers default handling of the event.
6706 preventDefault : function(){
6707 if(this.browserEvent){
6708 E.preventDefault(this.browserEvent);
6713 isNavKeyPress : function(){
6714 var k = this.keyCode;
6715 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6716 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6719 isSpecialKey : function(){
6720 var k = this.keyCode;
6721 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6722 (k == 16) || (k == 17) ||
6723 (k >= 18 && k <= 20) ||
6724 (k >= 33 && k <= 35) ||
6725 (k >= 36 && k <= 39) ||
6726 (k >= 44 && k <= 45);
6729 * Cancels bubbling of the event.
6731 stopPropagation : function(){
6732 if(this.browserEvent){
6733 if(this.type == 'mousedown'){
6734 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6736 E.stopPropagation(this.browserEvent);
6741 * Gets the key code for the event.
6744 getCharCode : function(){
6745 return this.charCode || this.keyCode;
6749 * Returns a normalized keyCode for the event.
6750 * @return {Number} The key code
6752 getKey : function(){
6753 var k = this.keyCode || this.charCode;
6754 return Roo.isSafari ? (safariKeys[k] || k) : k;
6758 * Gets the x coordinate of the event.
6761 getPageX : function(){
6766 * Gets the y coordinate of the event.
6769 getPageY : function(){
6774 * Gets the time of the event.
6777 getTime : function(){
6778 if(this.browserEvent){
6779 return E.getTime(this.browserEvent);
6785 * Gets the page coordinates of the event.
6786 * @return {Array} The xy values like [x, y]
6793 * Gets the target for the event.
6794 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6795 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6796 search as a number or element (defaults to 10 || document.body)
6797 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6798 * @return {HTMLelement}
6800 getTarget : function(selector, maxDepth, returnEl){
6801 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6804 * Gets the related target.
6805 * @return {HTMLElement}
6807 getRelatedTarget : function(){
6808 if(this.browserEvent){
6809 return E.getRelatedTarget(this.browserEvent);
6815 * Normalizes mouse wheel delta across browsers
6816 * @return {Number} The delta
6818 getWheelDelta : function(){
6819 var e = this.browserEvent;
6821 if(e.wheelDelta){ /* IE/Opera. */
6822 delta = e.wheelDelta/120;
6823 }else if(e.detail){ /* Mozilla case. */
6824 delta = -e.detail/3;
6830 * Returns true if the control, meta, shift or alt key was pressed during this event.
6833 hasModifier : function(){
6834 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6838 * Returns true if the target of this event equals el or is a child of el
6839 * @param {String/HTMLElement/Element} el
6840 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6843 within : function(el, related){
6844 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6845 return t && Roo.fly(el).contains(t);
6848 getPoint : function(){
6849 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6853 return new Roo.EventObjectImpl();
6858 * Ext JS Library 1.1.1
6859 * Copyright(c) 2006-2007, Ext JS, LLC.
6861 * Originally Released Under LGPL - original licence link has changed is not relivant.
6864 * <script type="text/javascript">
6868 // was in Composite Element!??!?!
6871 var D = Roo.lib.Dom;
6872 var E = Roo.lib.Event;
6873 var A = Roo.lib.Anim;
6875 // local style camelizing for speed
6877 var camelRe = /(-[a-z])/gi;
6878 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6879 var view = document.defaultView;
6882 * @class Roo.Element
6883 * Represents an Element in the DOM.<br><br>
6886 var el = Roo.get("my-div");
6889 var el = getEl("my-div");
6891 // or with a DOM element
6892 var el = Roo.get(myDivElement);
6894 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6895 * each call instead of constructing a new one.<br><br>
6896 * <b>Animations</b><br />
6897 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6898 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6900 Option Default Description
6901 --------- -------- ---------------------------------------------
6902 duration .35 The duration of the animation in seconds
6903 easing easeOut The YUI easing method
6904 callback none A function to execute when the anim completes
6905 scope this The scope (this) of the callback function
6907 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6908 * manipulate the animation. Here's an example:
6910 var el = Roo.get("my-div");
6915 // default animation
6916 el.setWidth(100, true);
6918 // animation with some options set
6925 // using the "anim" property to get the Anim object
6931 el.setWidth(100, opt);
6933 if(opt.anim.isAnimated()){
6937 * <b> Composite (Collections of) Elements</b><br />
6938 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6939 * @constructor Create a new Element directly.
6940 * @param {String/HTMLElement} element
6941 * @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).
6943 Roo.Element = function(element, forceNew){
6944 var dom = typeof element == "string" ?
6945 document.getElementById(element) : element;
6946 if(!dom){ // invalid id/element
6950 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6951 return Roo.Element.cache[id];
6961 * The DOM element ID
6964 this.id = id || Roo.id(dom);
6967 var El = Roo.Element;
6971 * The element's default display mode (defaults to "")
6974 originalDisplay : "",
6978 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6983 * Sets the element's visibility mode. When setVisible() is called it
6984 * will use this to determine whether to set the visibility or the display property.
6985 * @param visMode Element.VISIBILITY or Element.DISPLAY
6986 * @return {Roo.Element} this
6988 setVisibilityMode : function(visMode){
6989 this.visibilityMode = visMode;
6993 * Convenience method for setVisibilityMode(Element.DISPLAY)
6994 * @param {String} display (optional) What to set display to when visible
6995 * @return {Roo.Element} this
6997 enableDisplayMode : function(display){
6998 this.setVisibilityMode(El.DISPLAY);
6999 if(typeof display != "undefined") this.originalDisplay = display;
7004 * 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)
7005 * @param {String} selector The simple selector to test
7006 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7007 search as a number or element (defaults to 10 || document.body)
7008 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7009 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7011 findParent : function(simpleSelector, maxDepth, returnEl){
7012 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7013 maxDepth = maxDepth || 50;
7014 if(typeof maxDepth != "number"){
7015 stopEl = Roo.getDom(maxDepth);
7018 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7019 if(dq.is(p, simpleSelector)){
7020 return returnEl ? Roo.get(p) : p;
7030 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7031 * @param {String} selector The simple selector to test
7032 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7033 search as a number or element (defaults to 10 || document.body)
7034 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7035 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7037 findParentNode : function(simpleSelector, maxDepth, returnEl){
7038 var p = Roo.fly(this.dom.parentNode, '_internal');
7039 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7043 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7044 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7045 * @param {String} selector The simple selector to test
7046 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7047 search as a number or element (defaults to 10 || document.body)
7048 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7050 up : function(simpleSelector, maxDepth){
7051 return this.findParentNode(simpleSelector, maxDepth, true);
7057 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7058 * @param {String} selector The simple selector to test
7059 * @return {Boolean} True if this element matches the selector, else false
7061 is : function(simpleSelector){
7062 return Roo.DomQuery.is(this.dom, simpleSelector);
7066 * Perform animation on this element.
7067 * @param {Object} args The YUI animation control args
7068 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7069 * @param {Function} onComplete (optional) Function to call when animation completes
7070 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7071 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7072 * @return {Roo.Element} this
7074 animate : function(args, duration, onComplete, easing, animType){
7075 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7080 * @private Internal animation call
7082 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7083 animType = animType || 'run';
7085 var anim = Roo.lib.Anim[animType](
7087 (opt.duration || defaultDur) || .35,
7088 (opt.easing || defaultEase) || 'easeOut',
7090 Roo.callback(cb, this);
7091 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7099 // private legacy anim prep
7100 preanim : function(a, i){
7101 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7105 * Removes worthless text nodes
7106 * @param {Boolean} forceReclean (optional) By default the element
7107 * keeps track if it has been cleaned already so
7108 * you can call this over and over. However, if you update the element and
7109 * need to force a reclean, you can pass true.
7111 clean : function(forceReclean){
7112 if(this.isCleaned && forceReclean !== true){
7116 var d = this.dom, n = d.firstChild, ni = -1;
7118 var nx = n.nextSibling;
7119 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7126 this.isCleaned = true;
7131 calcOffsetsTo : function(el){
7134 var restorePos = false;
7135 if(el.getStyle('position') == 'static'){
7136 el.position('relative');
7141 while(op && op != d && op.tagName != 'HTML'){
7144 op = op.offsetParent;
7147 el.position('static');
7153 * Scrolls this element into view within the passed container.
7154 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7155 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7156 * @return {Roo.Element} this
7158 scrollIntoView : function(container, hscroll){
7159 var c = Roo.getDom(container) || document.body;
7162 var o = this.calcOffsetsTo(c),
7165 b = t+el.offsetHeight,
7166 r = l+el.offsetWidth;
7168 var ch = c.clientHeight;
7169 var ct = parseInt(c.scrollTop, 10);
7170 var cl = parseInt(c.scrollLeft, 10);
7172 var cr = cl + c.clientWidth;
7180 if(hscroll !== false){
7184 c.scrollLeft = r-c.clientWidth;
7191 scrollChildIntoView : function(child, hscroll){
7192 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7196 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7197 * the new height may not be available immediately.
7198 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7199 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7200 * @param {Function} onComplete (optional) Function to call when animation completes
7201 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7202 * @return {Roo.Element} this
7204 autoHeight : function(animate, duration, onComplete, easing){
7205 var oldHeight = this.getHeight();
7207 this.setHeight(1); // force clipping
7208 setTimeout(function(){
7209 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7211 this.setHeight(height);
7213 if(typeof onComplete == "function"){
7217 this.setHeight(oldHeight); // restore original height
7218 this.setHeight(height, animate, duration, function(){
7220 if(typeof onComplete == "function") onComplete();
7221 }.createDelegate(this), easing);
7223 }.createDelegate(this), 0);
7228 * Returns true if this element is an ancestor of the passed element
7229 * @param {HTMLElement/String} el The element to check
7230 * @return {Boolean} True if this element is an ancestor of el, else false
7232 contains : function(el){
7233 if(!el){return false;}
7234 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7238 * Checks whether the element is currently visible using both visibility and display properties.
7239 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7240 * @return {Boolean} True if the element is currently visible, else false
7242 isVisible : function(deep) {
7243 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7244 if(deep !== true || !vis){
7247 var p = this.dom.parentNode;
7248 while(p && p.tagName.toLowerCase() != "body"){
7249 if(!Roo.fly(p, '_isVisible').isVisible()){
7258 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7259 * @param {String} selector The CSS selector
7260 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7261 * @return {CompositeElement/CompositeElementLite} The composite element
7263 select : function(selector, unique){
7264 return El.select(selector, unique, this.dom);
7268 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7269 * @param {String} selector The CSS selector
7270 * @return {Array} An array of the matched nodes
7272 query : function(selector, unique){
7273 return Roo.DomQuery.select(selector, this.dom);
7277 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7278 * @param {String} selector The CSS selector
7279 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7280 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7282 child : function(selector, returnDom){
7283 var n = Roo.DomQuery.selectNode(selector, this.dom);
7284 return returnDom ? n : Roo.get(n);
7288 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7289 * @param {String} selector The CSS selector
7290 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7291 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7293 down : function(selector, returnDom){
7294 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7295 return returnDom ? n : Roo.get(n);
7299 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7300 * @param {String} group The group the DD object is member of
7301 * @param {Object} config The DD config object
7302 * @param {Object} overrides An object containing methods to override/implement on the DD object
7303 * @return {Roo.dd.DD} The DD object
7305 initDD : function(group, config, overrides){
7306 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7307 return Roo.apply(dd, overrides);
7311 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7312 * @param {String} group The group the DDProxy object is member of
7313 * @param {Object} config The DDProxy config object
7314 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7315 * @return {Roo.dd.DDProxy} The DDProxy object
7317 initDDProxy : function(group, config, overrides){
7318 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7319 return Roo.apply(dd, overrides);
7323 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7324 * @param {String} group The group the DDTarget object is member of
7325 * @param {Object} config The DDTarget config object
7326 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7327 * @return {Roo.dd.DDTarget} The DDTarget object
7329 initDDTarget : function(group, config, overrides){
7330 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7331 return Roo.apply(dd, overrides);
7335 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7336 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7337 * @param {Boolean} visible Whether the element is visible
7338 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7339 * @return {Roo.Element} this
7341 setVisible : function(visible, animate){
7343 if(this.visibilityMode == El.DISPLAY){
7344 this.setDisplayed(visible);
7347 this.dom.style.visibility = visible ? "visible" : "hidden";
7350 // closure for composites
7352 var visMode = this.visibilityMode;
7354 this.setOpacity(.01);
7355 this.setVisible(true);
7357 this.anim({opacity: { to: (visible?1:0) }},
7358 this.preanim(arguments, 1),
7359 null, .35, 'easeIn', function(){
7361 if(visMode == El.DISPLAY){
7362 dom.style.display = "none";
7364 dom.style.visibility = "hidden";
7366 Roo.get(dom).setOpacity(1);
7374 * Returns true if display is not "none"
7377 isDisplayed : function() {
7378 return this.getStyle("display") != "none";
7382 * Toggles the element's visibility or display, depending on visibility mode.
7383 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7384 * @return {Roo.Element} this
7386 toggle : function(animate){
7387 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7392 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7393 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7394 * @return {Roo.Element} this
7396 setDisplayed : function(value) {
7397 if(typeof value == "boolean"){
7398 value = value ? this.originalDisplay : "none";
7400 this.setStyle("display", value);
7405 * Tries to focus the element. Any exceptions are caught and ignored.
7406 * @return {Roo.Element} this
7408 focus : function() {
7416 * Tries to blur the element. Any exceptions are caught and ignored.
7417 * @return {Roo.Element} this
7427 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7428 * @param {String/Array} className The CSS class to add, or an array of classes
7429 * @return {Roo.Element} this
7431 addClass : function(className){
7432 if(className instanceof Array){
7433 for(var i = 0, len = className.length; i < len; i++) {
7434 this.addClass(className[i]);
7437 if(className && !this.hasClass(className)){
7438 this.dom.className = this.dom.className + " " + className;
7445 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7446 * @param {String/Array} className The CSS class to add, or an array of classes
7447 * @return {Roo.Element} this
7449 radioClass : function(className){
7450 var siblings = this.dom.parentNode.childNodes;
7451 for(var i = 0; i < siblings.length; i++) {
7452 var s = siblings[i];
7453 if(s.nodeType == 1){
7454 Roo.get(s).removeClass(className);
7457 this.addClass(className);
7462 * Removes one or more CSS classes from the element.
7463 * @param {String/Array} className The CSS class to remove, or an array of classes
7464 * @return {Roo.Element} this
7466 removeClass : function(className){
7467 if(!className || !this.dom.className){
7470 if(className instanceof Array){
7471 for(var i = 0, len = className.length; i < len; i++) {
7472 this.removeClass(className[i]);
7475 if(this.hasClass(className)){
7476 var re = this.classReCache[className];
7478 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7479 this.classReCache[className] = re;
7481 this.dom.className =
7482 this.dom.className.replace(re, " ");
7492 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7493 * @param {String} className The CSS class to toggle
7494 * @return {Roo.Element} this
7496 toggleClass : function(className){
7497 if(this.hasClass(className)){
7498 this.removeClass(className);
7500 this.addClass(className);
7506 * Checks if the specified CSS class exists on this element's DOM node.
7507 * @param {String} className The CSS class to check for
7508 * @return {Boolean} True if the class exists, else false
7510 hasClass : function(className){
7511 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7515 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7516 * @param {String} oldClassName The CSS class to replace
7517 * @param {String} newClassName The replacement CSS class
7518 * @return {Roo.Element} this
7520 replaceClass : function(oldClassName, newClassName){
7521 this.removeClass(oldClassName);
7522 this.addClass(newClassName);
7527 * Returns an object with properties matching the styles requested.
7528 * For example, el.getStyles('color', 'font-size', 'width') might return
7529 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7530 * @param {String} style1 A style name
7531 * @param {String} style2 A style name
7532 * @param {String} etc.
7533 * @return {Object} The style object
7535 getStyles : function(){
7536 var a = arguments, len = a.length, r = {};
7537 for(var i = 0; i < len; i++){
7538 r[a[i]] = this.getStyle(a[i]);
7544 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7545 * @param {String} property The style property whose value is returned.
7546 * @return {String} The current value of the style property for this element.
7548 getStyle : function(){
7549 return view && view.getComputedStyle ?
7551 var el = this.dom, v, cs, camel;
7552 if(prop == 'float'){
7555 if(el.style && (v = el.style[prop])){
7558 if(cs = view.getComputedStyle(el, "")){
7559 if(!(camel = propCache[prop])){
7560 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7567 var el = this.dom, v, cs, camel;
7568 if(prop == 'opacity'){
7569 if(typeof el.style.filter == 'string'){
7570 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7572 var fv = parseFloat(m[1]);
7574 return fv ? fv / 100 : 0;
7579 }else if(prop == 'float'){
7580 prop = "styleFloat";
7582 if(!(camel = propCache[prop])){
7583 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7585 if(v = el.style[camel]){
7588 if(cs = el.currentStyle){
7596 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7597 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7598 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7599 * @return {Roo.Element} this
7601 setStyle : function(prop, value){
7602 if(typeof prop == "string"){
7604 if (prop == 'float') {
7605 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7610 if(!(camel = propCache[prop])){
7611 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7614 if(camel == 'opacity') {
7615 this.setOpacity(value);
7617 this.dom.style[camel] = value;
7620 for(var style in prop){
7621 if(typeof prop[style] != "function"){
7622 this.setStyle(style, prop[style]);
7630 * More flexible version of {@link #setStyle} for setting style properties.
7631 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7632 * a function which returns such a specification.
7633 * @return {Roo.Element} this
7635 applyStyles : function(style){
7636 Roo.DomHelper.applyStyles(this.dom, style);
7641 * 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).
7642 * @return {Number} The X position of the element
7645 return D.getX(this.dom);
7649 * 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).
7650 * @return {Number} The Y position of the element
7653 return D.getY(this.dom);
7657 * 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).
7658 * @return {Array} The XY position of the element
7661 return D.getXY(this.dom);
7665 * 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).
7666 * @param {Number} The X position of the element
7667 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7668 * @return {Roo.Element} this
7670 setX : function(x, animate){
7672 D.setX(this.dom, x);
7674 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7680 * 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).
7681 * @param {Number} The Y position of the element
7682 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7683 * @return {Roo.Element} this
7685 setY : function(y, animate){
7687 D.setY(this.dom, y);
7689 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7695 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7696 * @param {String} left The left CSS property value
7697 * @return {Roo.Element} this
7699 setLeft : function(left){
7700 this.setStyle("left", this.addUnits(left));
7705 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7706 * @param {String} top The top CSS property value
7707 * @return {Roo.Element} this
7709 setTop : function(top){
7710 this.setStyle("top", this.addUnits(top));
7715 * Sets the element's CSS right style.
7716 * @param {String} right The right CSS property value
7717 * @return {Roo.Element} this
7719 setRight : function(right){
7720 this.setStyle("right", this.addUnits(right));
7725 * Sets the element's CSS bottom style.
7726 * @param {String} bottom The bottom CSS property value
7727 * @return {Roo.Element} this
7729 setBottom : function(bottom){
7730 this.setStyle("bottom", this.addUnits(bottom));
7735 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7736 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7737 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7738 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7739 * @return {Roo.Element} this
7741 setXY : function(pos, animate){
7743 D.setXY(this.dom, pos);
7745 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7751 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7752 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7753 * @param {Number} x X value for new position (coordinates are page-based)
7754 * @param {Number} y Y value for new position (coordinates are page-based)
7755 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7756 * @return {Roo.Element} this
7758 setLocation : function(x, y, animate){
7759 this.setXY([x, y], this.preanim(arguments, 2));
7764 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7765 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7766 * @param {Number} x X value for new position (coordinates are page-based)
7767 * @param {Number} y Y value for new position (coordinates are page-based)
7768 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7769 * @return {Roo.Element} this
7771 moveTo : function(x, y, animate){
7772 this.setXY([x, y], this.preanim(arguments, 2));
7777 * Returns the region of the given element.
7778 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7779 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7781 getRegion : function(){
7782 return D.getRegion(this.dom);
7786 * Returns the offset height of the element
7787 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7788 * @return {Number} The element's height
7790 getHeight : function(contentHeight){
7791 var h = this.dom.offsetHeight || 0;
7792 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7796 * Returns the offset width of the element
7797 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7798 * @return {Number} The element's width
7800 getWidth : function(contentWidth){
7801 var w = this.dom.offsetWidth || 0;
7802 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7806 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7807 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7808 * if a height has not been set using CSS.
7811 getComputedHeight : function(){
7812 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7814 h = parseInt(this.getStyle('height'), 10) || 0;
7815 if(!this.isBorderBox()){
7816 h += this.getFrameWidth('tb');
7823 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7824 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7825 * if a width has not been set using CSS.
7828 getComputedWidth : function(){
7829 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7831 w = parseInt(this.getStyle('width'), 10) || 0;
7832 if(!this.isBorderBox()){
7833 w += this.getFrameWidth('lr');
7840 * Returns the size of the element.
7841 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7842 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7844 getSize : function(contentSize){
7845 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7849 * Returns the width and height of the viewport.
7850 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7852 getViewSize : function(){
7853 var d = this.dom, doc = document, aw = 0, ah = 0;
7854 if(d == doc || d == doc.body){
7855 return {width : D.getViewWidth(), height: D.getViewHeight()};
7858 width : d.clientWidth,
7859 height: d.clientHeight
7865 * Returns the value of the "value" attribute
7866 * @param {Boolean} asNumber true to parse the value as a number
7867 * @return {String/Number}
7869 getValue : function(asNumber){
7870 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7874 adjustWidth : function(width){
7875 if(typeof width == "number"){
7876 if(this.autoBoxAdjust && !this.isBorderBox()){
7877 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7887 adjustHeight : function(height){
7888 if(typeof height == "number"){
7889 if(this.autoBoxAdjust && !this.isBorderBox()){
7890 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7900 * Set the width of the element
7901 * @param {Number} width The new width
7902 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7903 * @return {Roo.Element} this
7905 setWidth : function(width, animate){
7906 width = this.adjustWidth(width);
7908 this.dom.style.width = this.addUnits(width);
7910 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7916 * Set the height of the element
7917 * @param {Number} height The new height
7918 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7919 * @return {Roo.Element} this
7921 setHeight : function(height, animate){
7922 height = this.adjustHeight(height);
7924 this.dom.style.height = this.addUnits(height);
7926 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7932 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7933 * @param {Number} width The new width
7934 * @param {Number} height The new height
7935 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7936 * @return {Roo.Element} this
7938 setSize : function(width, height, animate){
7939 if(typeof width == "object"){ // in case of object from getSize()
7940 height = width.height; width = width.width;
7942 width = this.adjustWidth(width); height = this.adjustHeight(height);
7944 this.dom.style.width = this.addUnits(width);
7945 this.dom.style.height = this.addUnits(height);
7947 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7953 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7954 * @param {Number} x X value for new position (coordinates are page-based)
7955 * @param {Number} y Y value for new position (coordinates are page-based)
7956 * @param {Number} width The new width
7957 * @param {Number} height The new height
7958 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7959 * @return {Roo.Element} this
7961 setBounds : function(x, y, width, height, animate){
7963 this.setSize(width, height);
7964 this.setLocation(x, y);
7966 width = this.adjustWidth(width); height = this.adjustHeight(height);
7967 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7968 this.preanim(arguments, 4), 'motion');
7974 * 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.
7975 * @param {Roo.lib.Region} region The region to fill
7976 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7977 * @return {Roo.Element} this
7979 setRegion : function(region, animate){
7980 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7985 * Appends an event handler
7987 * @param {String} eventName The type of event to append
7988 * @param {Function} fn The method the event invokes
7989 * @param {Object} scope (optional) The scope (this object) of the fn
7990 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7992 addListener : function(eventName, fn, scope, options){
7994 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7999 * Removes an event handler from this element
8000 * @param {String} eventName the type of event to remove
8001 * @param {Function} fn the method the event invokes
8002 * @return {Roo.Element} this
8004 removeListener : function(eventName, fn){
8005 Roo.EventManager.removeListener(this.dom, eventName, fn);
8010 * Removes all previous added listeners from this element
8011 * @return {Roo.Element} this
8013 removeAllListeners : function(){
8014 E.purgeElement(this.dom);
8018 relayEvent : function(eventName, observable){
8019 this.on(eventName, function(e){
8020 observable.fireEvent(eventName, e);
8025 * Set the opacity of the element
8026 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8027 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8028 * @return {Roo.Element} this
8030 setOpacity : function(opacity, animate){
8032 var s = this.dom.style;
8035 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8036 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8038 s.opacity = opacity;
8041 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8047 * Gets the left X coordinate
8048 * @param {Boolean} local True to get the local css position instead of page coordinate
8051 getLeft : function(local){
8055 return parseInt(this.getStyle("left"), 10) || 0;
8060 * Gets the right X coordinate of the element (element X position + element width)
8061 * @param {Boolean} local True to get the local css position instead of page coordinate
8064 getRight : function(local){
8066 return this.getX() + this.getWidth();
8068 return (this.getLeft(true) + this.getWidth()) || 0;
8073 * Gets the top Y coordinate
8074 * @param {Boolean} local True to get the local css position instead of page coordinate
8077 getTop : function(local) {
8081 return parseInt(this.getStyle("top"), 10) || 0;
8086 * Gets the bottom Y coordinate of the element (element Y position + element height)
8087 * @param {Boolean} local True to get the local css position instead of page coordinate
8090 getBottom : function(local){
8092 return this.getY() + this.getHeight();
8094 return (this.getTop(true) + this.getHeight()) || 0;
8099 * Initializes positioning on this element. If a desired position is not passed, it will make the
8100 * the element positioned relative IF it is not already positioned.
8101 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8102 * @param {Number} zIndex (optional) The zIndex to apply
8103 * @param {Number} x (optional) Set the page X position
8104 * @param {Number} y (optional) Set the page Y position
8106 position : function(pos, zIndex, x, y){
8108 if(this.getStyle('position') == 'static'){
8109 this.setStyle('position', 'relative');
8112 this.setStyle("position", pos);
8115 this.setStyle("z-index", zIndex);
8117 if(x !== undefined && y !== undefined){
8119 }else if(x !== undefined){
8121 }else if(y !== undefined){
8127 * Clear positioning back to the default when the document was loaded
8128 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8129 * @return {Roo.Element} this
8131 clearPositioning : function(value){
8139 "position" : "static"
8145 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8146 * snapshot before performing an update and then restoring the element.
8149 getPositioning : function(){
8150 var l = this.getStyle("left");
8151 var t = this.getStyle("top");
8153 "position" : this.getStyle("position"),
8155 "right" : l ? "" : this.getStyle("right"),
8157 "bottom" : t ? "" : this.getStyle("bottom"),
8158 "z-index" : this.getStyle("z-index")
8163 * Gets the width of the border(s) for the specified side(s)
8164 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8165 * passing lr would get the border (l)eft width + the border (r)ight width.
8166 * @return {Number} The width of the sides passed added together
8168 getBorderWidth : function(side){
8169 return this.addStyles(side, El.borders);
8173 * Gets the width of the padding(s) for the specified side(s)
8174 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8175 * passing lr would get the padding (l)eft + the padding (r)ight.
8176 * @return {Number} The padding of the sides passed added together
8178 getPadding : function(side){
8179 return this.addStyles(side, El.paddings);
8183 * Set positioning with an object returned by getPositioning().
8184 * @param {Object} posCfg
8185 * @return {Roo.Element} this
8187 setPositioning : function(pc){
8188 this.applyStyles(pc);
8189 if(pc.right == "auto"){
8190 this.dom.style.right = "";
8192 if(pc.bottom == "auto"){
8193 this.dom.style.bottom = "";
8199 fixDisplay : function(){
8200 if(this.getStyle("display") == "none"){
8201 this.setStyle("visibility", "hidden");
8202 this.setStyle("display", this.originalDisplay); // first try reverting to default
8203 if(this.getStyle("display") == "none"){ // if that fails, default to block
8204 this.setStyle("display", "block");
8210 * Quick set left and top adding default units
8211 * @param {String} left The left CSS property value
8212 * @param {String} top The top CSS property value
8213 * @return {Roo.Element} this
8215 setLeftTop : function(left, top){
8216 this.dom.style.left = this.addUnits(left);
8217 this.dom.style.top = this.addUnits(top);
8222 * Move this element relative to its current position.
8223 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8224 * @param {Number} distance How far to move the element in pixels
8225 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8226 * @return {Roo.Element} this
8228 move : function(direction, distance, animate){
8229 var xy = this.getXY();
8230 direction = direction.toLowerCase();
8234 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8238 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8243 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8248 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8255 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8256 * @return {Roo.Element} this
8259 if(!this.isClipped){
8260 this.isClipped = true;
8261 this.originalClip = {
8262 "o": this.getStyle("overflow"),
8263 "x": this.getStyle("overflow-x"),
8264 "y": this.getStyle("overflow-y")
8266 this.setStyle("overflow", "hidden");
8267 this.setStyle("overflow-x", "hidden");
8268 this.setStyle("overflow-y", "hidden");
8274 * Return clipping (overflow) to original clipping before clip() was called
8275 * @return {Roo.Element} this
8277 unclip : function(){
8279 this.isClipped = false;
8280 var o = this.originalClip;
8281 if(o.o){this.setStyle("overflow", o.o);}
8282 if(o.x){this.setStyle("overflow-x", o.x);}
8283 if(o.y){this.setStyle("overflow-y", o.y);}
8290 * Gets the x,y coordinates specified by the anchor position on the element.
8291 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8292 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8293 * {width: (target width), height: (target height)} (defaults to the element's current size)
8294 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8295 * @return {Array} [x, y] An array containing the element's x and y coordinates
8297 getAnchorXY : function(anchor, local, s){
8298 //Passing a different size is useful for pre-calculating anchors,
8299 //especially for anchored animations that change the el size.
8301 var w, h, vp = false;
8304 if(d == document.body || d == document){
8306 w = D.getViewWidth(); h = D.getViewHeight();
8308 w = this.getWidth(); h = this.getHeight();
8311 w = s.width; h = s.height;
8313 var x = 0, y = 0, r = Math.round;
8314 switch((anchor || "tl").toLowerCase()){
8356 var sc = this.getScroll();
8357 return [x + sc.left, y + sc.top];
8359 //Add the element's offset xy
8360 var o = this.getXY();
8361 return [x+o[0], y+o[1]];
8365 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8366 * supported position values.
8367 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8368 * @param {String} position The position to align to.
8369 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8370 * @return {Array} [x, y]
8372 getAlignToXY : function(el, p, o){
8376 throw "Element.alignTo with an element that doesn't exist";
8378 var c = false; //constrain to viewport
8379 var p1 = "", p2 = "";
8386 }else if(p.indexOf("-") == -1){
8389 p = p.toLowerCase();
8390 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8392 throw "Element.alignTo with an invalid alignment " + p;
8394 p1 = m[1]; p2 = m[2]; c = !!m[3];
8396 //Subtract the aligned el's internal xy from the target's offset xy
8397 //plus custom offset to get the aligned el's new offset xy
8398 var a1 = this.getAnchorXY(p1, true);
8399 var a2 = el.getAnchorXY(p2, false);
8400 var x = a2[0] - a1[0] + o[0];
8401 var y = a2[1] - a1[1] + o[1];
8403 //constrain the aligned el to viewport if necessary
8404 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8405 // 5px of margin for ie
8406 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8408 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8409 //perpendicular to the vp border, allow the aligned el to slide on that border,
8410 //otherwise swap the aligned el to the opposite border of the target.
8411 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8412 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8413 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8414 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8417 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8418 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8420 if((x+w) > dw + scrollX){
8421 x = swapX ? r.left-w : dw+scrollX-w;
8424 x = swapX ? r.right : scrollX;
8426 if((y+h) > dh + scrollY){
8427 y = swapY ? r.top-h : dh+scrollY-h;
8430 y = swapY ? r.bottom : scrollY;
8437 getConstrainToXY : function(){
8438 var os = {top:0, left:0, bottom:0, right: 0};
8440 return function(el, local, offsets, proposedXY){
8442 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8444 var vw, vh, vx = 0, vy = 0;
8445 if(el.dom == document.body || el.dom == document){
8446 vw = Roo.lib.Dom.getViewWidth();
8447 vh = Roo.lib.Dom.getViewHeight();
8449 vw = el.dom.clientWidth;
8450 vh = el.dom.clientHeight;
8452 var vxy = el.getXY();
8458 var s = el.getScroll();
8460 vx += offsets.left + s.left;
8461 vy += offsets.top + s.top;
8463 vw -= offsets.right;
8464 vh -= offsets.bottom;
8469 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8470 var x = xy[0], y = xy[1];
8471 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8473 // only move it if it needs it
8476 // first validate right/bottom
8485 // then make sure top/left isn't negative
8494 return moved ? [x, y] : false;
8499 adjustForConstraints : function(xy, parent, offsets){
8500 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8504 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8505 * document it aligns it to the viewport.
8506 * The position parameter is optional, and can be specified in any one of the following formats:
8508 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8509 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8510 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8511 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8512 * <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
8513 * element's anchor point, and the second value is used as the target's anchor point.</li>
8515 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8516 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8517 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8518 * that specified in order to enforce the viewport constraints.
8519 * Following are all of the supported anchor positions:
8522 ----- -----------------------------
8523 tl The top left corner (default)
8524 t The center of the top edge
8525 tr The top right corner
8526 l The center of the left edge
8527 c In the center of the element
8528 r The center of the right edge
8529 bl The bottom left corner
8530 b The center of the bottom edge
8531 br The bottom right corner
8535 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8536 el.alignTo("other-el");
8538 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8539 el.alignTo("other-el", "tr?");
8541 // align the bottom right corner of el with the center left edge of other-el
8542 el.alignTo("other-el", "br-l?");
8544 // align the center of el with the bottom left corner of other-el and
8545 // adjust the x position by -6 pixels (and the y position by 0)
8546 el.alignTo("other-el", "c-bl", [-6, 0]);
8548 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8549 * @param {String} position The position to align to.
8550 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8551 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8552 * @return {Roo.Element} this
8554 alignTo : function(element, position, offsets, animate){
8555 var xy = this.getAlignToXY(element, position, offsets);
8556 this.setXY(xy, this.preanim(arguments, 3));
8561 * Anchors an element to another element and realigns it when the window is resized.
8562 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8563 * @param {String} position The position to align to.
8564 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8565 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8566 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8567 * is a number, it is used as the buffer delay (defaults to 50ms).
8568 * @param {Function} callback The function to call after the animation finishes
8569 * @return {Roo.Element} this
8571 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8572 var action = function(){
8573 this.alignTo(el, alignment, offsets, animate);
8574 Roo.callback(callback, this);
8576 Roo.EventManager.onWindowResize(action, this);
8577 var tm = typeof monitorScroll;
8578 if(tm != 'undefined'){
8579 Roo.EventManager.on(window, 'scroll', action, this,
8580 {buffer: tm == 'number' ? monitorScroll : 50});
8582 action.call(this); // align immediately
8586 * Clears any opacity settings from this element. Required in some cases for IE.
8587 * @return {Roo.Element} this
8589 clearOpacity : function(){
8590 if (window.ActiveXObject) {
8591 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8592 this.dom.style.filter = "";
8595 this.dom.style.opacity = "";
8596 this.dom.style["-moz-opacity"] = "";
8597 this.dom.style["-khtml-opacity"] = "";
8603 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8604 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8605 * @return {Roo.Element} this
8607 hide : function(animate){
8608 this.setVisible(false, this.preanim(arguments, 0));
8613 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8614 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8615 * @return {Roo.Element} this
8617 show : function(animate){
8618 this.setVisible(true, this.preanim(arguments, 0));
8623 * @private Test if size has a unit, otherwise appends the default
8625 addUnits : function(size){
8626 return Roo.Element.addUnits(size, this.defaultUnit);
8630 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8631 * @return {Roo.Element} this
8633 beginMeasure : function(){
8635 if(el.offsetWidth || el.offsetHeight){
8636 return this; // offsets work already
8639 var p = this.dom, b = document.body; // start with this element
8640 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8641 var pe = Roo.get(p);
8642 if(pe.getStyle('display') == 'none'){
8643 changed.push({el: p, visibility: pe.getStyle("visibility")});
8644 p.style.visibility = "hidden";
8645 p.style.display = "block";
8649 this._measureChanged = changed;
8655 * Restores displays to before beginMeasure was called
8656 * @return {Roo.Element} this
8658 endMeasure : function(){
8659 var changed = this._measureChanged;
8661 for(var i = 0, len = changed.length; i < len; i++) {
8663 r.el.style.visibility = r.visibility;
8664 r.el.style.display = "none";
8666 this._measureChanged = null;
8672 * Update the innerHTML of this element, optionally searching for and processing scripts
8673 * @param {String} html The new HTML
8674 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8675 * @param {Function} callback For async script loading you can be noticed when the update completes
8676 * @return {Roo.Element} this
8678 update : function(html, loadScripts, callback){
8679 if(typeof html == "undefined"){
8682 if(loadScripts !== true){
8683 this.dom.innerHTML = html;
8684 if(typeof callback == "function"){
8692 html += '<span id="' + id + '"></span>';
8694 E.onAvailable(id, function(){
8695 var hd = document.getElementsByTagName("head")[0];
8696 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8697 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8698 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8701 while(match = re.exec(html)){
8702 var attrs = match[1];
8703 var srcMatch = attrs ? attrs.match(srcRe) : false;
8704 if(srcMatch && srcMatch[2]){
8705 var s = document.createElement("script");
8706 s.src = srcMatch[2];
8707 var typeMatch = attrs.match(typeRe);
8708 if(typeMatch && typeMatch[2]){
8709 s.type = typeMatch[2];
8712 }else if(match[2] && match[2].length > 0){
8713 if(window.execScript) {
8714 window.execScript(match[2]);
8722 window.eval(match[2]);
8726 var el = document.getElementById(id);
8727 if(el){el.parentNode.removeChild(el);}
8728 if(typeof callback == "function"){
8732 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8737 * Direct access to the UpdateManager update() method (takes the same parameters).
8738 * @param {String/Function} url The url for this request or a function to call to get the url
8739 * @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}
8740 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8741 * @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.
8742 * @return {Roo.Element} this
8745 var um = this.getUpdateManager();
8746 um.update.apply(um, arguments);
8751 * Gets this element's UpdateManager
8752 * @return {Roo.UpdateManager} The UpdateManager
8754 getUpdateManager : function(){
8755 if(!this.updateManager){
8756 this.updateManager = new Roo.UpdateManager(this);
8758 return this.updateManager;
8762 * Disables text selection for this element (normalized across browsers)
8763 * @return {Roo.Element} this
8765 unselectable : function(){
8766 this.dom.unselectable = "on";
8767 this.swallowEvent("selectstart", true);
8768 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8769 this.addClass("x-unselectable");
8774 * Calculates the x, y to center this element on the screen
8775 * @return {Array} The x, y values [x, y]
8777 getCenterXY : function(){
8778 return this.getAlignToXY(document, 'c-c');
8782 * Centers the Element in either the viewport, or another Element.
8783 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8785 center : function(centerIn){
8786 this.alignTo(centerIn || document, 'c-c');
8791 * Tests various css rules/browsers to determine if this element uses a border box
8794 isBorderBox : function(){
8795 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8799 * Return a box {x, y, width, height} that can be used to set another elements
8800 * size/location to match this element.
8801 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8802 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8803 * @return {Object} box An object in the format {x, y, width, height}
8805 getBox : function(contentBox, local){
8810 var left = parseInt(this.getStyle("left"), 10) || 0;
8811 var top = parseInt(this.getStyle("top"), 10) || 0;
8814 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8816 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8818 var l = this.getBorderWidth("l")+this.getPadding("l");
8819 var r = this.getBorderWidth("r")+this.getPadding("r");
8820 var t = this.getBorderWidth("t")+this.getPadding("t");
8821 var b = this.getBorderWidth("b")+this.getPadding("b");
8822 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)};
8824 bx.right = bx.x + bx.width;
8825 bx.bottom = bx.y + bx.height;
8830 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8831 for more information about the sides.
8832 * @param {String} sides
8835 getFrameWidth : function(sides, onlyContentBox){
8836 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8840 * 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.
8841 * @param {Object} box The box to fill {x, y, width, height}
8842 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8843 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8844 * @return {Roo.Element} this
8846 setBox : function(box, adjust, animate){
8847 var w = box.width, h = box.height;
8848 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8849 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8850 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8852 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8857 * Forces the browser to repaint this element
8858 * @return {Roo.Element} this
8860 repaint : function(){
8862 this.addClass("x-repaint");
8863 setTimeout(function(){
8864 Roo.get(dom).removeClass("x-repaint");
8870 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8871 * then it returns the calculated width of the sides (see getPadding)
8872 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8873 * @return {Object/Number}
8875 getMargins : function(side){
8878 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8879 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8880 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8881 right: parseInt(this.getStyle("margin-right"), 10) || 0
8884 return this.addStyles(side, El.margins);
8889 addStyles : function(sides, styles){
8891 for(var i = 0, len = sides.length; i < len; i++){
8892 v = this.getStyle(styles[sides.charAt(i)]);
8894 w = parseInt(v, 10);
8902 * Creates a proxy element of this element
8903 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8904 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8905 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8906 * @return {Roo.Element} The new proxy element
8908 createProxy : function(config, renderTo, matchBox){
8910 renderTo = Roo.getDom(renderTo);
8912 renderTo = document.body;
8914 config = typeof config == "object" ?
8915 config : {tag : "div", cls: config};
8916 var proxy = Roo.DomHelper.append(renderTo, config, true);
8918 proxy.setBox(this.getBox());
8924 * Puts a mask over this element to disable user interaction. Requires core.css.
8925 * This method can only be applied to elements which accept child nodes.
8926 * @param {String} msg (optional) A message to display in the mask
8927 * @param {String} msgCls (optional) A css class to apply to the msg element
8928 * @return {Element} The mask element
8930 mask : function(msg, msgCls)
8932 if(this.getStyle("position") == "static"){
8933 this.setStyle("position", "relative");
8936 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8938 this.addClass("x-masked");
8939 this._mask.setDisplayed(true);
8944 while (dom && dom.style) {
8945 if (!isNaN(parseInt(dom.style.zIndex))) {
8946 z = Math.max(z, parseInt(dom.style.zIndex));
8948 dom = dom.parentNode;
8950 // if we are masking the body - then it hides everything..
8951 if (this.dom == document.body) {
8953 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8954 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8957 if(typeof msg == 'string'){
8959 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8961 var mm = this._maskMsg;
8962 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8963 mm.dom.firstChild.innerHTML = msg;
8964 mm.setDisplayed(true);
8966 mm.setStyle('z-index', z + 102);
8968 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8969 this._mask.setHeight(this.getHeight());
8971 this._mask.setStyle('z-index', z + 100);
8977 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8978 * it is cached for reuse.
8980 unmask : function(removeEl){
8982 if(removeEl === true){
8983 this._mask.remove();
8986 this._maskMsg.remove();
8987 delete this._maskMsg;
8990 this._mask.setDisplayed(false);
8992 this._maskMsg.setDisplayed(false);
8996 this.removeClass("x-masked");
9000 * Returns true if this element is masked
9003 isMasked : function(){
9004 return this._mask && this._mask.isVisible();
9008 * Creates an iframe shim for this element to keep selects and other windowed objects from
9010 * @return {Roo.Element} The new shim element
9012 createShim : function(){
9013 var el = document.createElement('iframe');
9014 el.frameBorder = 'no';
9015 el.className = 'roo-shim';
9016 if(Roo.isIE && Roo.isSecure){
9017 el.src = Roo.SSL_SECURE_URL;
9019 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9020 shim.autoBoxAdjust = false;
9025 * Removes this element from the DOM and deletes it from the cache
9027 remove : function(){
9028 if(this.dom.parentNode){
9029 this.dom.parentNode.removeChild(this.dom);
9031 delete El.cache[this.dom.id];
9035 * Sets up event handlers to add and remove a css class when the mouse is over this element
9036 * @param {String} className
9037 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9038 * mouseout events for children elements
9039 * @return {Roo.Element} this
9041 addClassOnOver : function(className, preventFlicker){
9042 this.on("mouseover", function(){
9043 Roo.fly(this, '_internal').addClass(className);
9045 var removeFn = function(e){
9046 if(preventFlicker !== true || !e.within(this, true)){
9047 Roo.fly(this, '_internal').removeClass(className);
9050 this.on("mouseout", removeFn, this.dom);
9055 * Sets up event handlers to add and remove a css class when this element has the focus
9056 * @param {String} className
9057 * @return {Roo.Element} this
9059 addClassOnFocus : function(className){
9060 this.on("focus", function(){
9061 Roo.fly(this, '_internal').addClass(className);
9063 this.on("blur", function(){
9064 Roo.fly(this, '_internal').removeClass(className);
9069 * 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)
9070 * @param {String} className
9071 * @return {Roo.Element} this
9073 addClassOnClick : function(className){
9075 this.on("mousedown", function(){
9076 Roo.fly(dom, '_internal').addClass(className);
9077 var d = Roo.get(document);
9078 var fn = function(){
9079 Roo.fly(dom, '_internal').removeClass(className);
9080 d.removeListener("mouseup", fn);
9082 d.on("mouseup", fn);
9088 * Stops the specified event from bubbling and optionally prevents the default action
9089 * @param {String} eventName
9090 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9091 * @return {Roo.Element} this
9093 swallowEvent : function(eventName, preventDefault){
9094 var fn = function(e){
9095 e.stopPropagation();
9100 if(eventName instanceof Array){
9101 for(var i = 0, len = eventName.length; i < len; i++){
9102 this.on(eventName[i], fn);
9106 this.on(eventName, fn);
9113 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9116 * Sizes this element to its parent element's dimensions performing
9117 * neccessary box adjustments.
9118 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9119 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9120 * @return {Roo.Element} this
9122 fitToParent : function(monitorResize, targetParent) {
9123 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9124 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9125 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9128 var p = Roo.get(targetParent || this.dom.parentNode);
9129 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9130 if (monitorResize === true) {
9131 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9132 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9138 * Gets the next sibling, skipping text nodes
9139 * @return {HTMLElement} The next sibling or null
9141 getNextSibling : function(){
9142 var n = this.dom.nextSibling;
9143 while(n && n.nodeType != 1){
9150 * Gets the previous sibling, skipping text nodes
9151 * @return {HTMLElement} The previous sibling or null
9153 getPrevSibling : function(){
9154 var n = this.dom.previousSibling;
9155 while(n && n.nodeType != 1){
9156 n = n.previousSibling;
9163 * Appends the passed element(s) to this element
9164 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9165 * @return {Roo.Element} this
9167 appendChild: function(el){
9174 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9175 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9176 * automatically generated with the specified attributes.
9177 * @param {HTMLElement} insertBefore (optional) a child element of this element
9178 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9179 * @return {Roo.Element} The new child element
9181 createChild: function(config, insertBefore, returnDom){
9182 config = config || {tag:'div'};
9184 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9186 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9190 * Appends this element to the passed element
9191 * @param {String/HTMLElement/Element} el The new parent element
9192 * @return {Roo.Element} this
9194 appendTo: function(el){
9195 el = Roo.getDom(el);
9196 el.appendChild(this.dom);
9201 * Inserts this element before the passed element in the DOM
9202 * @param {String/HTMLElement/Element} el The element to insert before
9203 * @return {Roo.Element} this
9205 insertBefore: function(el){
9206 el = Roo.getDom(el);
9207 el.parentNode.insertBefore(this.dom, el);
9212 * Inserts this element after the passed element in the DOM
9213 * @param {String/HTMLElement/Element} el The element to insert after
9214 * @return {Roo.Element} this
9216 insertAfter: function(el){
9217 el = Roo.getDom(el);
9218 el.parentNode.insertBefore(this.dom, el.nextSibling);
9223 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9224 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9225 * @return {Roo.Element} The new child
9227 insertFirst: function(el, returnDom){
9229 if(typeof el == 'object' && !el.nodeType){ // dh config
9230 return this.createChild(el, this.dom.firstChild, returnDom);
9232 el = Roo.getDom(el);
9233 this.dom.insertBefore(el, this.dom.firstChild);
9234 return !returnDom ? Roo.get(el) : el;
9239 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9240 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9241 * @param {String} where (optional) 'before' or 'after' defaults to before
9242 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9243 * @return {Roo.Element} the inserted Element
9245 insertSibling: function(el, where, returnDom){
9246 where = where ? where.toLowerCase() : 'before';
9248 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9250 if(typeof el == 'object' && !el.nodeType){ // dh config
9251 if(where == 'after' && !this.dom.nextSibling){
9252 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9254 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9258 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9259 where == 'before' ? this.dom : this.dom.nextSibling);
9268 * Creates and wraps this element with another element
9269 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9270 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9271 * @return {HTMLElement/Element} The newly created wrapper element
9273 wrap: function(config, returnDom){
9275 config = {tag: "div"};
9277 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9278 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9283 * Replaces the passed element with this element
9284 * @param {String/HTMLElement/Element} el The element to replace
9285 * @return {Roo.Element} this
9287 replace: function(el){
9289 this.insertBefore(el);
9295 * Inserts an html fragment into this element
9296 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9297 * @param {String} html The HTML fragment
9298 * @param {Boolean} returnEl True to return an Roo.Element
9299 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9301 insertHtml : function(where, html, returnEl){
9302 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9303 return returnEl ? Roo.get(el) : el;
9307 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9308 * @param {Object} o The object with the attributes
9309 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9310 * @return {Roo.Element} this
9312 set : function(o, useSet){
9314 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9316 if(attr == "style" || typeof o[attr] == "function") continue;
9318 el.className = o["cls"];
9320 if(useSet) el.setAttribute(attr, o[attr]);
9321 else el[attr] = o[attr];
9325 Roo.DomHelper.applyStyles(el, o.style);
9331 * Convenience method for constructing a KeyMap
9332 * @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:
9333 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9334 * @param {Function} fn The function to call
9335 * @param {Object} scope (optional) The scope of the function
9336 * @return {Roo.KeyMap} The KeyMap created
9338 addKeyListener : function(key, fn, scope){
9340 if(typeof key != "object" || key instanceof Array){
9356 return new Roo.KeyMap(this, config);
9360 * Creates a KeyMap for this element
9361 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9362 * @return {Roo.KeyMap} The KeyMap created
9364 addKeyMap : function(config){
9365 return new Roo.KeyMap(this, config);
9369 * Returns true if this element is scrollable.
9372 isScrollable : function(){
9374 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9378 * 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().
9379 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9380 * @param {Number} value The new scroll value
9381 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9382 * @return {Element} this
9385 scrollTo : function(side, value, animate){
9386 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9388 this.dom[prop] = value;
9390 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9391 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9397 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9398 * within this element's scrollable range.
9399 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9400 * @param {Number} distance How far to scroll the element in pixels
9401 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9402 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9403 * was scrolled as far as it could go.
9405 scroll : function(direction, distance, animate){
9406 if(!this.isScrollable()){
9410 var l = el.scrollLeft, t = el.scrollTop;
9411 var w = el.scrollWidth, h = el.scrollHeight;
9412 var cw = el.clientWidth, ch = el.clientHeight;
9413 direction = direction.toLowerCase();
9414 var scrolled = false;
9415 var a = this.preanim(arguments, 2);
9420 var v = Math.min(l + distance, w-cw);
9421 this.scrollTo("left", v, a);
9428 var v = Math.max(l - distance, 0);
9429 this.scrollTo("left", v, a);
9437 var v = Math.max(t - distance, 0);
9438 this.scrollTo("top", v, a);
9446 var v = Math.min(t + distance, h-ch);
9447 this.scrollTo("top", v, a);
9456 * Translates the passed page coordinates into left/top css values for this element
9457 * @param {Number/Array} x The page x or an array containing [x, y]
9458 * @param {Number} y The page y
9459 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9461 translatePoints : function(x, y){
9462 if(typeof x == 'object' || x instanceof Array){
9465 var p = this.getStyle('position');
9466 var o = this.getXY();
9468 var l = parseInt(this.getStyle('left'), 10);
9469 var t = parseInt(this.getStyle('top'), 10);
9472 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9475 t = (p == "relative") ? 0 : this.dom.offsetTop;
9478 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9482 * Returns the current scroll position of the element.
9483 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9485 getScroll : function(){
9486 var d = this.dom, doc = document;
9487 if(d == doc || d == doc.body){
9488 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9489 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9490 return {left: l, top: t};
9492 return {left: d.scrollLeft, top: d.scrollTop};
9497 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9498 * are convert to standard 6 digit hex color.
9499 * @param {String} attr The css attribute
9500 * @param {String} defaultValue The default value to use when a valid color isn't found
9501 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9504 getColor : function(attr, defaultValue, prefix){
9505 var v = this.getStyle(attr);
9506 if(!v || v == "transparent" || v == "inherit") {
9507 return defaultValue;
9509 var color = typeof prefix == "undefined" ? "#" : prefix;
9510 if(v.substr(0, 4) == "rgb("){
9511 var rvs = v.slice(4, v.length -1).split(",");
9512 for(var i = 0; i < 3; i++){
9513 var h = parseInt(rvs[i]).toString(16);
9520 if(v.substr(0, 1) == "#"){
9522 for(var i = 1; i < 4; i++){
9523 var c = v.charAt(i);
9526 }else if(v.length == 7){
9527 color += v.substr(1);
9531 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9535 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9536 * gradient background, rounded corners and a 4-way shadow.
9537 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9538 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9539 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9540 * @return {Roo.Element} this
9542 boxWrap : function(cls){
9543 cls = cls || 'x-box';
9544 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9545 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9550 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9551 * @param {String} namespace The namespace in which to look for the attribute
9552 * @param {String} name The attribute name
9553 * @return {String} The attribute value
9555 getAttributeNS : Roo.isIE ? function(ns, name){
9557 var type = typeof d[ns+":"+name];
9558 if(type != 'undefined' && type != 'unknown'){
9559 return d[ns+":"+name];
9562 } : function(ns, name){
9564 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9569 * Sets or Returns the value the dom attribute value
9570 * @param {String} name The attribute name
9571 * @param {String} value (optional) The value to set the attribute to
9572 * @return {String} The attribute value
9574 attr : function(name){
9575 if (arguments.length > 1) {
9576 this.dom.setAttribute(name, arguments[1]);
9577 return arguments[1];
9579 if (!this.dom.hasAttribute(name)) {
9582 return this.dom.getAttribute(name);
9589 var ep = El.prototype;
9592 * Appends an event handler (Shorthand for addListener)
9593 * @param {String} eventName The type of event to append
9594 * @param {Function} fn The method the event invokes
9595 * @param {Object} scope (optional) The scope (this object) of the fn
9596 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9599 ep.on = ep.addListener;
9601 ep.mon = ep.addListener;
9604 * Removes an event handler from this element (shorthand for removeListener)
9605 * @param {String} eventName the type of event to remove
9606 * @param {Function} fn the method the event invokes
9607 * @return {Roo.Element} this
9610 ep.un = ep.removeListener;
9613 * true to automatically adjust width and height settings for box-model issues (default to true)
9615 ep.autoBoxAdjust = true;
9618 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9621 El.addUnits = function(v, defaultUnit){
9622 if(v === "" || v == "auto"){
9625 if(v === undefined){
9628 if(typeof v == "number" || !El.unitPattern.test(v)){
9629 return v + (defaultUnit || 'px');
9634 // special markup used throughout Roo when box wrapping elements
9635 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>';
9637 * Visibility mode constant - Use visibility to hide element
9643 * Visibility mode constant - Use display to hide element
9649 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9650 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9651 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9663 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9664 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9665 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9666 * @return {Element} The Element object
9669 El.get = function(el){
9671 if(!el){ return null; }
9672 if(typeof el == "string"){ // element id
9673 if(!(elm = document.getElementById(el))){
9676 if(ex = El.cache[el]){
9679 ex = El.cache[el] = new El(elm);
9682 }else if(el.tagName){ // dom element
9686 if(ex = El.cache[id]){
9689 ex = El.cache[id] = new El(el);
9692 }else if(el instanceof El){
9694 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9695 // catch case where it hasn't been appended
9696 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9699 }else if(el.isComposite){
9701 }else if(el instanceof Array){
9702 return El.select(el);
9703 }else if(el == document){
9704 // create a bogus element object representing the document object
9706 var f = function(){};
9707 f.prototype = El.prototype;
9709 docEl.dom = document;
9717 El.uncache = function(el){
9718 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9720 delete El.cache[a[i].id || a[i]];
9726 // Garbage collection - uncache elements/purge listeners on orphaned elements
9727 // so we don't hold a reference and cause the browser to retain them
9728 El.garbageCollect = function(){
9729 if(!Roo.enableGarbageCollector){
9730 clearInterval(El.collectorThread);
9733 for(var eid in El.cache){
9734 var el = El.cache[eid], d = el.dom;
9735 // -------------------------------------------------------
9736 // Determining what is garbage:
9737 // -------------------------------------------------------
9739 // dom node is null, definitely garbage
9740 // -------------------------------------------------------
9742 // no parentNode == direct orphan, definitely garbage
9743 // -------------------------------------------------------
9744 // !d.offsetParent && !document.getElementById(eid)
9745 // display none elements have no offsetParent so we will
9746 // also try to look it up by it's id. However, check
9747 // offsetParent first so we don't do unneeded lookups.
9748 // This enables collection of elements that are not orphans
9749 // directly, but somewhere up the line they have an orphan
9751 // -------------------------------------------------------
9752 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9753 delete El.cache[eid];
9754 if(d && Roo.enableListenerCollection){
9760 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9764 El.Flyweight = function(dom){
9767 El.Flyweight.prototype = El.prototype;
9769 El._flyweights = {};
9771 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9772 * the dom node can be overwritten by other code.
9773 * @param {String/HTMLElement} el The dom node or id
9774 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9775 * prevent conflicts (e.g. internally Roo uses "_internal")
9777 * @return {Element} The shared Element object
9779 El.fly = function(el, named){
9780 named = named || '_global';
9781 el = Roo.getDom(el);
9785 if(!El._flyweights[named]){
9786 El._flyweights[named] = new El.Flyweight();
9788 El._flyweights[named].dom = el;
9789 return El._flyweights[named];
9793 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9794 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9795 * Shorthand of {@link Roo.Element#get}
9796 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9797 * @return {Element} The Element object
9803 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9804 * the dom node can be overwritten by other code.
9805 * Shorthand of {@link Roo.Element#fly}
9806 * @param {String/HTMLElement} el The dom node or id
9807 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9808 * prevent conflicts (e.g. internally Roo uses "_internal")
9810 * @return {Element} The shared Element object
9816 // speedy lookup for elements never to box adjust
9817 var noBoxAdjust = Roo.isStrict ? {
9820 input:1, select:1, textarea:1
9822 if(Roo.isIE || Roo.isGecko){
9823 noBoxAdjust['button'] = 1;
9827 Roo.EventManager.on(window, 'unload', function(){
9829 delete El._flyweights;
9837 Roo.Element.selectorFunction = Roo.DomQuery.select;
9840 Roo.Element.select = function(selector, unique, root){
9842 if(typeof selector == "string"){
9843 els = Roo.Element.selectorFunction(selector, root);
9844 }else if(selector.length !== undefined){
9847 throw "Invalid selector";
9849 if(unique === true){
9850 return new Roo.CompositeElement(els);
9852 return new Roo.CompositeElementLite(els);
9856 * Selects elements based on the passed CSS selector to enable working on them as 1.
9857 * @param {String/Array} selector The CSS selector or an array of elements
9858 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9859 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9860 * @return {CompositeElementLite/CompositeElement}
9864 Roo.select = Roo.Element.select;
9881 * Ext JS Library 1.1.1
9882 * Copyright(c) 2006-2007, Ext JS, LLC.
9884 * Originally Released Under LGPL - original licence link has changed is not relivant.
9887 * <script type="text/javascript">
9892 //Notifies Element that fx methods are available
9893 Roo.enableFx = true;
9897 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9898 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9899 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9900 * Element effects to work.</p><br/>
9902 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9903 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9904 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9905 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9906 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9907 * expected results and should be done with care.</p><br/>
9909 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9910 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9913 ----- -----------------------------
9914 tl The top left corner
9915 t The center of the top edge
9916 tr The top right corner
9917 l The center of the left edge
9918 r The center of the right edge
9919 bl The bottom left corner
9920 b The center of the bottom edge
9921 br The bottom right corner
9923 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9924 * below are common options that can be passed to any Fx method.</b>
9925 * @cfg {Function} callback A function called when the effect is finished
9926 * @cfg {Object} scope The scope of the effect function
9927 * @cfg {String} easing A valid Easing value for the effect
9928 * @cfg {String} afterCls A css class to apply after the effect
9929 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9930 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9931 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9932 * effects that end with the element being visually hidden, ignored otherwise)
9933 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9934 * a function which returns such a specification that will be applied to the Element after the effect finishes
9935 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9936 * @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
9937 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9941 * Slides the element into view. An anchor point can be optionally passed to set the point of
9942 * origin for the slide effect. This function automatically handles wrapping the element with
9943 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9946 // default: slide the element in from the top
9949 // custom: slide the element in from the right with a 2-second duration
9950 el.slideIn('r', { duration: 2 });
9952 // common config options shown with default values
9958 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9959 * @param {Object} options (optional) Object literal with any of the Fx config options
9960 * @return {Roo.Element} The Element
9962 slideIn : function(anchor, o){
9963 var el = this.getFxEl();
9966 el.queueFx(o, function(){
9968 anchor = anchor || "t";
9970 // fix display to visibility
9973 // restore values after effect
9974 var r = this.getFxRestore();
9975 var b = this.getBox();
9976 // fixed size for slide
9980 var wrap = this.fxWrap(r.pos, o, "hidden");
9982 var st = this.dom.style;
9983 st.visibility = "visible";
9984 st.position = "absolute";
9986 // clear out temp styles after slide and unwrap
9987 var after = function(){
9988 el.fxUnwrap(wrap, r.pos, o);
9990 st.height = r.height;
9993 // time to calc the positions
9994 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9996 switch(anchor.toLowerCase()){
9998 wrap.setSize(b.width, 0);
9999 st.left = st.bottom = "0";
10003 wrap.setSize(0, b.height);
10004 st.right = st.top = "0";
10008 wrap.setSize(0, b.height);
10009 wrap.setX(b.right);
10010 st.left = st.top = "0";
10011 a = {width: bw, points: pt};
10014 wrap.setSize(b.width, 0);
10015 wrap.setY(b.bottom);
10016 st.left = st.top = "0";
10017 a = {height: bh, points: pt};
10020 wrap.setSize(0, 0);
10021 st.right = st.bottom = "0";
10022 a = {width: bw, height: bh};
10025 wrap.setSize(0, 0);
10026 wrap.setY(b.y+b.height);
10027 st.right = st.top = "0";
10028 a = {width: bw, height: bh, points: pt};
10031 wrap.setSize(0, 0);
10032 wrap.setXY([b.right, b.bottom]);
10033 st.left = st.top = "0";
10034 a = {width: bw, height: bh, points: pt};
10037 wrap.setSize(0, 0);
10038 wrap.setX(b.x+b.width);
10039 st.left = st.bottom = "0";
10040 a = {width: bw, height: bh, points: pt};
10043 this.dom.style.visibility = "visible";
10046 arguments.callee.anim = wrap.fxanim(a,
10056 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10057 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10058 * 'hidden') but block elements will still take up space in the document. The element must be removed
10059 * from the DOM using the 'remove' config option if desired. This function automatically handles
10060 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10063 // default: slide the element out to the top
10066 // custom: slide the element out to the right with a 2-second duration
10067 el.slideOut('r', { duration: 2 });
10069 // common config options shown with default values
10077 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10078 * @param {Object} options (optional) Object literal with any of the Fx config options
10079 * @return {Roo.Element} The Element
10081 slideOut : function(anchor, o){
10082 var el = this.getFxEl();
10085 el.queueFx(o, function(){
10087 anchor = anchor || "t";
10089 // restore values after effect
10090 var r = this.getFxRestore();
10092 var b = this.getBox();
10093 // fixed size for slide
10097 var wrap = this.fxWrap(r.pos, o, "visible");
10099 var st = this.dom.style;
10100 st.visibility = "visible";
10101 st.position = "absolute";
10105 var after = function(){
10107 el.setDisplayed(false);
10112 el.fxUnwrap(wrap, r.pos, o);
10114 st.width = r.width;
10115 st.height = r.height;
10120 var a, zero = {to: 0};
10121 switch(anchor.toLowerCase()){
10123 st.left = st.bottom = "0";
10124 a = {height: zero};
10127 st.right = st.top = "0";
10131 st.left = st.top = "0";
10132 a = {width: zero, points: {to:[b.right, b.y]}};
10135 st.left = st.top = "0";
10136 a = {height: zero, points: {to:[b.x, b.bottom]}};
10139 st.right = st.bottom = "0";
10140 a = {width: zero, height: zero};
10143 st.right = st.top = "0";
10144 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10147 st.left = st.top = "0";
10148 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10151 st.left = st.bottom = "0";
10152 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10156 arguments.callee.anim = wrap.fxanim(a,
10166 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10167 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10168 * The element must be removed from the DOM using the 'remove' config option if desired.
10174 // common config options shown with default values
10182 * @param {Object} options (optional) Object literal with any of the Fx config options
10183 * @return {Roo.Element} The Element
10185 puff : function(o){
10186 var el = this.getFxEl();
10189 el.queueFx(o, function(){
10190 this.clearOpacity();
10193 // restore values after effect
10194 var r = this.getFxRestore();
10195 var st = this.dom.style;
10197 var after = function(){
10199 el.setDisplayed(false);
10206 el.setPositioning(r.pos);
10207 st.width = r.width;
10208 st.height = r.height;
10213 var width = this.getWidth();
10214 var height = this.getHeight();
10216 arguments.callee.anim = this.fxanim({
10217 width : {to: this.adjustWidth(width * 2)},
10218 height : {to: this.adjustHeight(height * 2)},
10219 points : {by: [-(width * .5), -(height * .5)]},
10221 fontSize: {to:200, unit: "%"}
10232 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10233 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10234 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10240 // all config options shown with default values
10248 * @param {Object} options (optional) Object literal with any of the Fx config options
10249 * @return {Roo.Element} The Element
10251 switchOff : function(o){
10252 var el = this.getFxEl();
10255 el.queueFx(o, function(){
10256 this.clearOpacity();
10259 // restore values after effect
10260 var r = this.getFxRestore();
10261 var st = this.dom.style;
10263 var after = function(){
10265 el.setDisplayed(false);
10271 el.setPositioning(r.pos);
10272 st.width = r.width;
10273 st.height = r.height;
10278 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10279 this.clearOpacity();
10283 points:{by:[0, this.getHeight() * .5]}
10284 }, o, 'motion', 0.3, 'easeIn', after);
10285 }).defer(100, this);
10292 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10293 * changed using the "attr" config option) and then fading back to the original color. If no original
10294 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10297 // default: highlight background to yellow
10300 // custom: highlight foreground text to blue for 2 seconds
10301 el.highlight("0000ff", { attr: 'color', duration: 2 });
10303 // common config options shown with default values
10304 el.highlight("ffff9c", {
10305 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10306 endColor: (current color) or "ffffff",
10311 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10312 * @param {Object} options (optional) Object literal with any of the Fx config options
10313 * @return {Roo.Element} The Element
10315 highlight : function(color, o){
10316 var el = this.getFxEl();
10319 el.queueFx(o, function(){
10320 color = color || "ffff9c";
10321 attr = o.attr || "backgroundColor";
10323 this.clearOpacity();
10326 var origColor = this.getColor(attr);
10327 var restoreColor = this.dom.style[attr];
10328 endColor = (o.endColor || origColor) || "ffffff";
10330 var after = function(){
10331 el.dom.style[attr] = restoreColor;
10336 a[attr] = {from: color, to: endColor};
10337 arguments.callee.anim = this.fxanim(a,
10347 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10350 // default: a single light blue ripple
10353 // custom: 3 red ripples lasting 3 seconds total
10354 el.frame("ff0000", 3, { duration: 3 });
10356 // common config options shown with default values
10357 el.frame("C3DAF9", 1, {
10358 duration: 1 //duration of entire animation (not each individual ripple)
10359 // Note: Easing is not configurable and will be ignored if included
10362 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10363 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10364 * @param {Object} options (optional) Object literal with any of the Fx config options
10365 * @return {Roo.Element} The Element
10367 frame : function(color, count, o){
10368 var el = this.getFxEl();
10371 el.queueFx(o, function(){
10372 color = color || "#C3DAF9";
10373 if(color.length == 6){
10374 color = "#" + color;
10376 count = count || 1;
10377 duration = o.duration || 1;
10380 var b = this.getBox();
10381 var animFn = function(){
10382 var proxy = this.createProxy({
10385 visbility:"hidden",
10386 position:"absolute",
10387 "z-index":"35000", // yee haw
10388 border:"0px solid " + color
10391 var scale = Roo.isBorderBox ? 2 : 1;
10393 top:{from:b.y, to:b.y - 20},
10394 left:{from:b.x, to:b.x - 20},
10395 borderWidth:{from:0, to:10},
10396 opacity:{from:1, to:0},
10397 height:{from:b.height, to:(b.height + (20*scale))},
10398 width:{from:b.width, to:(b.width + (20*scale))}
10399 }, duration, function(){
10403 animFn.defer((duration/2)*1000, this);
10414 * Creates a pause before any subsequent queued effects begin. If there are
10415 * no effects queued after the pause it will have no effect.
10420 * @param {Number} seconds The length of time to pause (in seconds)
10421 * @return {Roo.Element} The Element
10423 pause : function(seconds){
10424 var el = this.getFxEl();
10427 el.queueFx(o, function(){
10428 setTimeout(function(){
10430 }, seconds * 1000);
10436 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10437 * using the "endOpacity" config option.
10440 // default: fade in from opacity 0 to 100%
10443 // custom: fade in from opacity 0 to 75% over 2 seconds
10444 el.fadeIn({ endOpacity: .75, duration: 2});
10446 // common config options shown with default values
10448 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10453 * @param {Object} options (optional) Object literal with any of the Fx config options
10454 * @return {Roo.Element} The Element
10456 fadeIn : function(o){
10457 var el = this.getFxEl();
10459 el.queueFx(o, function(){
10460 this.setOpacity(0);
10462 this.dom.style.visibility = 'visible';
10463 var to = o.endOpacity || 1;
10464 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10465 o, null, .5, "easeOut", function(){
10467 this.clearOpacity();
10476 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10477 * using the "endOpacity" config option.
10480 // default: fade out from the element's current opacity to 0
10483 // custom: fade out from the element's current opacity to 25% over 2 seconds
10484 el.fadeOut({ endOpacity: .25, duration: 2});
10486 // common config options shown with default values
10488 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10495 * @param {Object} options (optional) Object literal with any of the Fx config options
10496 * @return {Roo.Element} The Element
10498 fadeOut : function(o){
10499 var el = this.getFxEl();
10501 el.queueFx(o, function(){
10502 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10503 o, null, .5, "easeOut", function(){
10504 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10505 this.dom.style.display = "none";
10507 this.dom.style.visibility = "hidden";
10509 this.clearOpacity();
10517 * Animates the transition of an element's dimensions from a starting height/width
10518 * to an ending height/width.
10521 // change height and width to 100x100 pixels
10522 el.scale(100, 100);
10524 // common config options shown with default values. The height and width will default to
10525 // the element's existing values if passed as null.
10528 [element's height], {
10533 * @param {Number} width The new width (pass undefined to keep the original width)
10534 * @param {Number} height The new height (pass undefined to keep the original height)
10535 * @param {Object} options (optional) Object literal with any of the Fx config options
10536 * @return {Roo.Element} The Element
10538 scale : function(w, h, o){
10539 this.shift(Roo.apply({}, o, {
10547 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10548 * Any of these properties not specified in the config object will not be changed. This effect
10549 * requires that at least one new dimension, position or opacity setting must be passed in on
10550 * the config object in order for the function to have any effect.
10553 // slide the element horizontally to x position 200 while changing the height and opacity
10554 el.shift({ x: 200, height: 50, opacity: .8 });
10556 // common config options shown with default values.
10558 width: [element's width],
10559 height: [element's height],
10560 x: [element's x position],
10561 y: [element's y position],
10562 opacity: [element's opacity],
10567 * @param {Object} options Object literal with any of the Fx config options
10568 * @return {Roo.Element} The Element
10570 shift : function(o){
10571 var el = this.getFxEl();
10573 el.queueFx(o, function(){
10574 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10575 if(w !== undefined){
10576 a.width = {to: this.adjustWidth(w)};
10578 if(h !== undefined){
10579 a.height = {to: this.adjustHeight(h)};
10581 if(x !== undefined || y !== undefined){
10583 x !== undefined ? x : this.getX(),
10584 y !== undefined ? y : this.getY()
10587 if(op !== undefined){
10588 a.opacity = {to: op};
10590 if(o.xy !== undefined){
10591 a.points = {to: o.xy};
10593 arguments.callee.anim = this.fxanim(a,
10594 o, 'motion', .35, "easeOut", function(){
10602 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10603 * ending point of the effect.
10606 // default: slide the element downward while fading out
10609 // custom: slide the element out to the right with a 2-second duration
10610 el.ghost('r', { duration: 2 });
10612 // common config options shown with default values
10620 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10621 * @param {Object} options (optional) Object literal with any of the Fx config options
10622 * @return {Roo.Element} The Element
10624 ghost : function(anchor, o){
10625 var el = this.getFxEl();
10628 el.queueFx(o, function(){
10629 anchor = anchor || "b";
10631 // restore values after effect
10632 var r = this.getFxRestore();
10633 var w = this.getWidth(),
10634 h = this.getHeight();
10636 var st = this.dom.style;
10638 var after = function(){
10640 el.setDisplayed(false);
10646 el.setPositioning(r.pos);
10647 st.width = r.width;
10648 st.height = r.height;
10653 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10654 switch(anchor.toLowerCase()){
10681 arguments.callee.anim = this.fxanim(a,
10691 * Ensures that all effects queued after syncFx is called on the element are
10692 * run concurrently. This is the opposite of {@link #sequenceFx}.
10693 * @return {Roo.Element} The Element
10695 syncFx : function(){
10696 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10705 * Ensures that all effects queued after sequenceFx is called on the element are
10706 * run in sequence. This is the opposite of {@link #syncFx}.
10707 * @return {Roo.Element} The Element
10709 sequenceFx : function(){
10710 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10712 concurrent : false,
10719 nextFx : function(){
10720 var ef = this.fxQueue[0];
10727 * Returns true if the element has any effects actively running or queued, else returns false.
10728 * @return {Boolean} True if element has active effects, else false
10730 hasActiveFx : function(){
10731 return this.fxQueue && this.fxQueue[0];
10735 * Stops any running effects and clears the element's internal effects queue if it contains
10736 * any additional effects that haven't started yet.
10737 * @return {Roo.Element} The Element
10739 stopFx : function(){
10740 if(this.hasActiveFx()){
10741 var cur = this.fxQueue[0];
10742 if(cur && cur.anim && cur.anim.isAnimated()){
10743 this.fxQueue = [cur]; // clear out others
10744 cur.anim.stop(true);
10751 beforeFx : function(o){
10752 if(this.hasActiveFx() && !o.concurrent){
10763 * Returns true if the element is currently blocking so that no other effect can be queued
10764 * until this effect is finished, else returns false if blocking is not set. This is commonly
10765 * used to ensure that an effect initiated by a user action runs to completion prior to the
10766 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10767 * @return {Boolean} True if blocking, else false
10769 hasFxBlock : function(){
10770 var q = this.fxQueue;
10771 return q && q[0] && q[0].block;
10775 queueFx : function(o, fn){
10779 if(!this.hasFxBlock()){
10780 Roo.applyIf(o, this.fxDefaults);
10782 var run = this.beforeFx(o);
10783 fn.block = o.block;
10784 this.fxQueue.push(fn);
10796 fxWrap : function(pos, o, vis){
10798 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10801 wrapXY = this.getXY();
10803 var div = document.createElement("div");
10804 div.style.visibility = vis;
10805 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10806 wrap.setPositioning(pos);
10807 if(wrap.getStyle("position") == "static"){
10808 wrap.position("relative");
10810 this.clearPositioning('auto');
10812 wrap.dom.appendChild(this.dom);
10814 wrap.setXY(wrapXY);
10821 fxUnwrap : function(wrap, pos, o){
10822 this.clearPositioning();
10823 this.setPositioning(pos);
10825 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10831 getFxRestore : function(){
10832 var st = this.dom.style;
10833 return {pos: this.getPositioning(), width: st.width, height : st.height};
10837 afterFx : function(o){
10839 this.applyStyles(o.afterStyle);
10842 this.addClass(o.afterCls);
10844 if(o.remove === true){
10847 Roo.callback(o.callback, o.scope, [this]);
10849 this.fxQueue.shift();
10855 getFxEl : function(){ // support for composite element fx
10856 return Roo.get(this.dom);
10860 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10861 animType = animType || 'run';
10863 var anim = Roo.lib.Anim[animType](
10865 (opt.duration || defaultDur) || .35,
10866 (opt.easing || defaultEase) || 'easeOut',
10868 Roo.callback(cb, this);
10877 // backwords compat
10878 Roo.Fx.resize = Roo.Fx.scale;
10880 //When included, Roo.Fx is automatically applied to Element so that all basic
10881 //effects are available directly via the Element API
10882 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10884 * Ext JS Library 1.1.1
10885 * Copyright(c) 2006-2007, Ext JS, LLC.
10887 * Originally Released Under LGPL - original licence link has changed is not relivant.
10890 * <script type="text/javascript">
10895 * @class Roo.CompositeElement
10896 * Standard composite class. Creates a Roo.Element for every element in the collection.
10898 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10899 * actions will be performed on all the elements in this collection.</b>
10901 * All methods return <i>this</i> and can be chained.
10903 var els = Roo.select("#some-el div.some-class", true);
10904 // or select directly from an existing element
10905 var el = Roo.get('some-el');
10906 el.select('div.some-class', true);
10908 els.setWidth(100); // all elements become 100 width
10909 els.hide(true); // all elements fade out and hide
10911 els.setWidth(100).hide(true);
10914 Roo.CompositeElement = function(els){
10915 this.elements = [];
10916 this.addElements(els);
10918 Roo.CompositeElement.prototype = {
10920 addElements : function(els){
10921 if(!els) return this;
10922 if(typeof els == "string"){
10923 els = Roo.Element.selectorFunction(els);
10925 var yels = this.elements;
10926 var index = yels.length-1;
10927 for(var i = 0, len = els.length; i < len; i++) {
10928 yels[++index] = Roo.get(els[i]);
10934 * Clears this composite and adds the elements returned by the passed selector.
10935 * @param {String/Array} els A string CSS selector, an array of elements or an element
10936 * @return {CompositeElement} this
10938 fill : function(els){
10939 this.elements = [];
10945 * Filters this composite to only elements that match the passed selector.
10946 * @param {String} selector A string CSS selector
10947 * @return {CompositeElement} this
10949 filter : function(selector){
10951 this.each(function(el){
10952 if(el.is(selector)){
10953 els[els.length] = el.dom;
10960 invoke : function(fn, args){
10961 var els = this.elements;
10962 for(var i = 0, len = els.length; i < len; i++) {
10963 Roo.Element.prototype[fn].apply(els[i], args);
10968 * Adds elements to this composite.
10969 * @param {String/Array} els A string CSS selector, an array of elements or an element
10970 * @return {CompositeElement} this
10972 add : function(els){
10973 if(typeof els == "string"){
10974 this.addElements(Roo.Element.selectorFunction(els));
10975 }else if(els.length !== undefined){
10976 this.addElements(els);
10978 this.addElements([els]);
10983 * Calls the passed function passing (el, this, index) for each element in this composite.
10984 * @param {Function} fn The function to call
10985 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10986 * @return {CompositeElement} this
10988 each : function(fn, scope){
10989 var els = this.elements;
10990 for(var i = 0, len = els.length; i < len; i++){
10991 if(fn.call(scope || els[i], els[i], this, i) === false) {
10999 * Returns the Element object at the specified index
11000 * @param {Number} index
11001 * @return {Roo.Element}
11003 item : function(index){
11004 return this.elements[index] || null;
11008 * Returns the first Element
11009 * @return {Roo.Element}
11011 first : function(){
11012 return this.item(0);
11016 * Returns the last Element
11017 * @return {Roo.Element}
11020 return this.item(this.elements.length-1);
11024 * Returns the number of elements in this composite
11027 getCount : function(){
11028 return this.elements.length;
11032 * Returns true if this composite contains the passed element
11035 contains : function(el){
11036 return this.indexOf(el) !== -1;
11040 * Returns true if this composite contains the passed element
11043 indexOf : function(el){
11044 return this.elements.indexOf(Roo.get(el));
11049 * Removes the specified element(s).
11050 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11051 * or an array of any of those.
11052 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11053 * @return {CompositeElement} this
11055 removeElement : function(el, removeDom){
11056 if(el instanceof Array){
11057 for(var i = 0, len = el.length; i < len; i++){
11058 this.removeElement(el[i]);
11062 var index = typeof el == 'number' ? el : this.indexOf(el);
11065 var d = this.elements[index];
11069 d.parentNode.removeChild(d);
11072 this.elements.splice(index, 1);
11078 * Replaces the specified element with the passed element.
11079 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11081 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11082 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11083 * @return {CompositeElement} this
11085 replaceElement : function(el, replacement, domReplace){
11086 var index = typeof el == 'number' ? el : this.indexOf(el);
11089 this.elements[index].replaceWith(replacement);
11091 this.elements.splice(index, 1, Roo.get(replacement))
11098 * Removes all elements.
11100 clear : function(){
11101 this.elements = [];
11105 Roo.CompositeElement.createCall = function(proto, fnName){
11106 if(!proto[fnName]){
11107 proto[fnName] = function(){
11108 return this.invoke(fnName, arguments);
11112 for(var fnName in Roo.Element.prototype){
11113 if(typeof Roo.Element.prototype[fnName] == "function"){
11114 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11120 * Ext JS Library 1.1.1
11121 * Copyright(c) 2006-2007, Ext JS, LLC.
11123 * Originally Released Under LGPL - original licence link has changed is not relivant.
11126 * <script type="text/javascript">
11130 * @class Roo.CompositeElementLite
11131 * @extends Roo.CompositeElement
11132 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11134 var els = Roo.select("#some-el div.some-class");
11135 // or select directly from an existing element
11136 var el = Roo.get('some-el');
11137 el.select('div.some-class');
11139 els.setWidth(100); // all elements become 100 width
11140 els.hide(true); // all elements fade out and hide
11142 els.setWidth(100).hide(true);
11143 </code></pre><br><br>
11144 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11145 * actions will be performed on all the elements in this collection.</b>
11147 Roo.CompositeElementLite = function(els){
11148 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11149 this.el = new Roo.Element.Flyweight();
11151 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11152 addElements : function(els){
11154 if(els instanceof Array){
11155 this.elements = this.elements.concat(els);
11157 var yels = this.elements;
11158 var index = yels.length-1;
11159 for(var i = 0, len = els.length; i < len; i++) {
11160 yels[++index] = els[i];
11166 invoke : function(fn, args){
11167 var els = this.elements;
11169 for(var i = 0, len = els.length; i < len; i++) {
11171 Roo.Element.prototype[fn].apply(el, args);
11176 * Returns a flyweight Element of the dom element object at the specified index
11177 * @param {Number} index
11178 * @return {Roo.Element}
11180 item : function(index){
11181 if(!this.elements[index]){
11184 this.el.dom = this.elements[index];
11188 // fixes scope with flyweight
11189 addListener : function(eventName, handler, scope, opt){
11190 var els = this.elements;
11191 for(var i = 0, len = els.length; i < len; i++) {
11192 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11198 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11199 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11200 * a reference to the dom node, use el.dom.</b>
11201 * @param {Function} fn The function to call
11202 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11203 * @return {CompositeElement} this
11205 each : function(fn, scope){
11206 var els = this.elements;
11208 for(var i = 0, len = els.length; i < len; i++){
11210 if(fn.call(scope || el, el, this, i) === false){
11217 indexOf : function(el){
11218 return this.elements.indexOf(Roo.getDom(el));
11221 replaceElement : function(el, replacement, domReplace){
11222 var index = typeof el == 'number' ? el : this.indexOf(el);
11224 replacement = Roo.getDom(replacement);
11226 var d = this.elements[index];
11227 d.parentNode.insertBefore(replacement, d);
11228 d.parentNode.removeChild(d);
11230 this.elements.splice(index, 1, replacement);
11235 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11239 * Ext JS Library 1.1.1
11240 * Copyright(c) 2006-2007, Ext JS, LLC.
11242 * Originally Released Under LGPL - original licence link has changed is not relivant.
11245 * <script type="text/javascript">
11251 * @class Roo.data.Connection
11252 * @extends Roo.util.Observable
11253 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11254 * either to a configured URL, or to a URL specified at request time.<br><br>
11256 * Requests made by this class are asynchronous, and will return immediately. No data from
11257 * the server will be available to the statement immediately following the {@link #request} call.
11258 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11260 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11261 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11262 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11263 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11264 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11265 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11266 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11267 * standard DOM methods.
11269 * @param {Object} config a configuration object.
11271 Roo.data.Connection = function(config){
11272 Roo.apply(this, config);
11275 * @event beforerequest
11276 * Fires before a network request is made to retrieve a data object.
11277 * @param {Connection} conn This Connection object.
11278 * @param {Object} options The options config object passed to the {@link #request} method.
11280 "beforerequest" : true,
11282 * @event requestcomplete
11283 * Fires if the request was successfully completed.
11284 * @param {Connection} conn This Connection object.
11285 * @param {Object} response The XHR object containing the response data.
11286 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11287 * @param {Object} options The options config object passed to the {@link #request} method.
11289 "requestcomplete" : true,
11291 * @event requestexception
11292 * Fires if an error HTTP status was returned from the server.
11293 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11294 * @param {Connection} conn This Connection object.
11295 * @param {Object} response The XHR object containing the response data.
11296 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11297 * @param {Object} options The options config object passed to the {@link #request} method.
11299 "requestexception" : true
11301 Roo.data.Connection.superclass.constructor.call(this);
11304 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11306 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11309 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11310 * extra parameters to each request made by this object. (defaults to undefined)
11313 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11314 * to each request made by this object. (defaults to undefined)
11317 * @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)
11320 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11324 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11330 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11333 disableCaching: true,
11336 * Sends an HTTP request to a remote server.
11337 * @param {Object} options An object which may contain the following properties:<ul>
11338 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11339 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11340 * request, a url encoded string or a function to call to get either.</li>
11341 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11342 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11343 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11344 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11345 * <li>options {Object} The parameter to the request call.</li>
11346 * <li>success {Boolean} True if the request succeeded.</li>
11347 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11349 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11350 * The callback is passed the following parameters:<ul>
11351 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11352 * <li>options {Object} The parameter to the request call.</li>
11354 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure 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>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11360 * for the callback function. Defaults to the browser window.</li>
11361 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11362 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11363 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11364 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11365 * params for the post data. Any params will be appended to the URL.</li>
11366 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11368 * @return {Number} transactionId
11370 request : function(o){
11371 if(this.fireEvent("beforerequest", this, o) !== false){
11374 if(typeof p == "function"){
11375 p = p.call(o.scope||window, o);
11377 if(typeof p == "object"){
11378 p = Roo.urlEncode(o.params);
11380 if(this.extraParams){
11381 var extras = Roo.urlEncode(this.extraParams);
11382 p = p ? (p + '&' + extras) : extras;
11385 var url = o.url || this.url;
11386 if(typeof url == 'function'){
11387 url = url.call(o.scope||window, o);
11391 var form = Roo.getDom(o.form);
11392 url = url || form.action;
11394 var enctype = form.getAttribute("enctype");
11395 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11396 return this.doFormUpload(o, p, url);
11398 var f = Roo.lib.Ajax.serializeForm(form);
11399 p = p ? (p + '&' + f) : f;
11402 var hs = o.headers;
11403 if(this.defaultHeaders){
11404 hs = Roo.apply(hs || {}, this.defaultHeaders);
11411 success: this.handleResponse,
11412 failure: this.handleFailure,
11414 argument: {options: o},
11415 timeout : o.timeout || this.timeout
11418 var method = o.method||this.method||(p ? "POST" : "GET");
11420 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11421 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11424 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11428 }else if(this.autoAbort !== false){
11432 if((method == 'GET' && p) || o.xmlData){
11433 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11436 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11437 return this.transId;
11439 Roo.callback(o.callback, o.scope, [o, null, null]);
11445 * Determine whether this object has a request outstanding.
11446 * @param {Number} transactionId (Optional) defaults to the last transaction
11447 * @return {Boolean} True if there is an outstanding request.
11449 isLoading : function(transId){
11451 return Roo.lib.Ajax.isCallInProgress(transId);
11453 return this.transId ? true : false;
11458 * Aborts any outstanding request.
11459 * @param {Number} transactionId (Optional) defaults to the last transaction
11461 abort : function(transId){
11462 if(transId || this.isLoading()){
11463 Roo.lib.Ajax.abort(transId || this.transId);
11468 handleResponse : function(response){
11469 this.transId = false;
11470 var options = response.argument.options;
11471 response.argument = options ? options.argument : null;
11472 this.fireEvent("requestcomplete", this, response, options);
11473 Roo.callback(options.success, options.scope, [response, options]);
11474 Roo.callback(options.callback, options.scope, [options, true, response]);
11478 handleFailure : function(response, e){
11479 this.transId = false;
11480 var options = response.argument.options;
11481 response.argument = options ? options.argument : null;
11482 this.fireEvent("requestexception", this, response, options, e);
11483 Roo.callback(options.failure, options.scope, [response, options]);
11484 Roo.callback(options.callback, options.scope, [options, false, response]);
11488 doFormUpload : function(o, ps, url){
11490 var frame = document.createElement('iframe');
11493 frame.className = 'x-hidden';
11495 frame.src = Roo.SSL_SECURE_URL;
11497 document.body.appendChild(frame);
11500 document.frames[id].name = id;
11503 var form = Roo.getDom(o.form);
11505 form.method = 'POST';
11506 form.enctype = form.encoding = 'multipart/form-data';
11512 if(ps){ // add dynamic params
11514 ps = Roo.urlDecode(ps, false);
11516 if(ps.hasOwnProperty(k)){
11517 hd = document.createElement('input');
11518 hd.type = 'hidden';
11521 form.appendChild(hd);
11528 var r = { // bogus response object
11533 r.argument = o ? o.argument : null;
11538 doc = frame.contentWindow.document;
11540 doc = (frame.contentDocument || window.frames[id].document);
11542 if(doc && doc.body){
11543 r.responseText = doc.body.innerHTML;
11545 if(doc && doc.XMLDocument){
11546 r.responseXML = doc.XMLDocument;
11548 r.responseXML = doc;
11555 Roo.EventManager.removeListener(frame, 'load', cb, this);
11557 this.fireEvent("requestcomplete", this, r, o);
11558 Roo.callback(o.success, o.scope, [r, o]);
11559 Roo.callback(o.callback, o.scope, [o, true, r]);
11561 setTimeout(function(){document.body.removeChild(frame);}, 100);
11564 Roo.EventManager.on(frame, 'load', cb, this);
11567 if(hiddens){ // remove dynamic params
11568 for(var i = 0, len = hiddens.length; i < len; i++){
11569 form.removeChild(hiddens[i]);
11576 * Ext JS Library 1.1.1
11577 * Copyright(c) 2006-2007, Ext JS, LLC.
11579 * Originally Released Under LGPL - original licence link has changed is not relivant.
11582 * <script type="text/javascript">
11586 * Global Ajax request class.
11589 * @extends Roo.data.Connection
11592 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11593 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11594 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11595 * @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)
11596 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11597 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11598 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11600 Roo.Ajax = new Roo.data.Connection({
11609 * Serialize the passed form into a url encoded string
11611 * @param {String/HTMLElement} form
11614 serializeForm : function(form){
11615 return Roo.lib.Ajax.serializeForm(form);
11619 * Ext JS Library 1.1.1
11620 * Copyright(c) 2006-2007, Ext JS, LLC.
11622 * Originally Released Under LGPL - original licence link has changed is not relivant.
11625 * <script type="text/javascript">
11630 * @class Roo.UpdateManager
11631 * @extends Roo.util.Observable
11632 * Provides AJAX-style update for Element object.<br><br>
11635 * // Get it from a Roo.Element object
11636 * var el = Roo.get("foo");
11637 * var mgr = el.getUpdateManager();
11638 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11640 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11642 * // or directly (returns the same UpdateManager instance)
11643 * var mgr = new Roo.UpdateManager("myElementId");
11644 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11645 * mgr.on("update", myFcnNeedsToKnow);
11647 // short handed call directly from the element object
11648 Roo.get("foo").load({
11652 text: "Loading Foo..."
11656 * Create new UpdateManager directly.
11657 * @param {String/HTMLElement/Roo.Element} el The element to update
11658 * @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).
11660 Roo.UpdateManager = function(el, forceNew){
11662 if(!forceNew && el.updateManager){
11663 return el.updateManager;
11666 * The Element object
11667 * @type Roo.Element
11671 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11674 this.defaultUrl = null;
11678 * @event beforeupdate
11679 * Fired before an update is made, return false from your handler and the update is cancelled.
11680 * @param {Roo.Element} el
11681 * @param {String/Object/Function} url
11682 * @param {String/Object} params
11684 "beforeupdate": true,
11687 * Fired after successful update is made.
11688 * @param {Roo.Element} el
11689 * @param {Object} oResponseObject The response Object
11694 * Fired on update failure.
11695 * @param {Roo.Element} el
11696 * @param {Object} oResponseObject The response Object
11700 var d = Roo.UpdateManager.defaults;
11702 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11705 this.sslBlankUrl = d.sslBlankUrl;
11707 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11710 this.disableCaching = d.disableCaching;
11712 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11715 this.indicatorText = d.indicatorText;
11717 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11720 this.showLoadIndicator = d.showLoadIndicator;
11722 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11725 this.timeout = d.timeout;
11728 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11731 this.loadScripts = d.loadScripts;
11734 * Transaction object of current executing transaction
11736 this.transaction = null;
11741 this.autoRefreshProcId = null;
11743 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11746 this.refreshDelegate = this.refresh.createDelegate(this);
11748 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11751 this.updateDelegate = this.update.createDelegate(this);
11753 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11756 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11760 this.successDelegate = this.processSuccess.createDelegate(this);
11764 this.failureDelegate = this.processFailure.createDelegate(this);
11766 if(!this.renderer){
11768 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11770 this.renderer = new Roo.UpdateManager.BasicRenderer();
11773 Roo.UpdateManager.superclass.constructor.call(this);
11776 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11778 * Get the Element this UpdateManager is bound to
11779 * @return {Roo.Element} The element
11781 getEl : function(){
11785 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11786 * @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:
11789 url: "your-url.php",<br/>
11790 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11791 callback: yourFunction,<br/>
11792 scope: yourObject, //(optional scope) <br/>
11793 discardUrl: false, <br/>
11794 nocache: false,<br/>
11795 text: "Loading...",<br/>
11797 scripts: false<br/>
11800 * The only required property is url. The optional properties nocache, text and scripts
11801 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11802 * @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}
11803 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11804 * @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.
11806 update : function(url, params, callback, discardUrl){
11807 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11808 var method = this.method,
11810 if(typeof url == "object"){ // must be config object
11813 params = params || cfg.params;
11814 callback = callback || cfg.callback;
11815 discardUrl = discardUrl || cfg.discardUrl;
11816 if(callback && cfg.scope){
11817 callback = callback.createDelegate(cfg.scope);
11819 if(typeof cfg.method != "undefined"){method = cfg.method;};
11820 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11821 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11822 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11823 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11825 this.showLoading();
11827 this.defaultUrl = url;
11829 if(typeof url == "function"){
11830 url = url.call(this);
11833 method = method || (params ? "POST" : "GET");
11834 if(method == "GET"){
11835 url = this.prepareUrl(url);
11838 var o = Roo.apply(cfg ||{}, {
11841 success: this.successDelegate,
11842 failure: this.failureDelegate,
11843 callback: undefined,
11844 timeout: (this.timeout*1000),
11845 argument: {"url": url, "form": null, "callback": callback, "params": params}
11847 Roo.log("updated manager called with timeout of " + o.timeout);
11848 this.transaction = Roo.Ajax.request(o);
11853 * 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.
11854 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11855 * @param {String/HTMLElement} form The form Id or form element
11856 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11857 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11858 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11860 formUpdate : function(form, url, reset, callback){
11861 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11862 if(typeof url == "function"){
11863 url = url.call(this);
11865 form = Roo.getDom(form);
11866 this.transaction = Roo.Ajax.request({
11869 success: this.successDelegate,
11870 failure: this.failureDelegate,
11871 timeout: (this.timeout*1000),
11872 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11874 this.showLoading.defer(1, this);
11879 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11880 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11882 refresh : function(callback){
11883 if(this.defaultUrl == null){
11886 this.update(this.defaultUrl, null, callback, true);
11890 * Set this element to auto refresh.
11891 * @param {Number} interval How often to update (in seconds).
11892 * @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)
11893 * @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}
11894 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11895 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11897 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11899 this.update(url || this.defaultUrl, params, callback, true);
11901 if(this.autoRefreshProcId){
11902 clearInterval(this.autoRefreshProcId);
11904 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11908 * Stop auto refresh on this element.
11910 stopAutoRefresh : function(){
11911 if(this.autoRefreshProcId){
11912 clearInterval(this.autoRefreshProcId);
11913 delete this.autoRefreshProcId;
11917 isAutoRefreshing : function(){
11918 return this.autoRefreshProcId ? true : false;
11921 * Called to update the element to "Loading" state. Override to perform custom action.
11923 showLoading : function(){
11924 if(this.showLoadIndicator){
11925 this.el.update(this.indicatorText);
11930 * Adds unique parameter to query string if disableCaching = true
11933 prepareUrl : function(url){
11934 if(this.disableCaching){
11935 var append = "_dc=" + (new Date().getTime());
11936 if(url.indexOf("?") !== -1){
11937 url += "&" + append;
11939 url += "?" + append;
11948 processSuccess : function(response){
11949 this.transaction = null;
11950 if(response.argument.form && response.argument.reset){
11951 try{ // put in try/catch since some older FF releases had problems with this
11952 response.argument.form.reset();
11955 if(this.loadScripts){
11956 this.renderer.render(this.el, response, this,
11957 this.updateComplete.createDelegate(this, [response]));
11959 this.renderer.render(this.el, response, this);
11960 this.updateComplete(response);
11964 updateComplete : function(response){
11965 this.fireEvent("update", this.el, response);
11966 if(typeof response.argument.callback == "function"){
11967 response.argument.callback(this.el, true, response);
11974 processFailure : function(response){
11975 this.transaction = null;
11976 this.fireEvent("failure", this.el, response);
11977 if(typeof response.argument.callback == "function"){
11978 response.argument.callback(this.el, false, response);
11983 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11984 * @param {Object} renderer The object implementing the render() method
11986 setRenderer : function(renderer){
11987 this.renderer = renderer;
11990 getRenderer : function(){
11991 return this.renderer;
11995 * Set the defaultUrl used for updates
11996 * @param {String/Function} defaultUrl The url or a function to call to get the url
11998 setDefaultUrl : function(defaultUrl){
11999 this.defaultUrl = defaultUrl;
12003 * Aborts the executing transaction
12005 abort : function(){
12006 if(this.transaction){
12007 Roo.Ajax.abort(this.transaction);
12012 * Returns true if an update is in progress
12013 * @return {Boolean}
12015 isUpdating : function(){
12016 if(this.transaction){
12017 return Roo.Ajax.isLoading(this.transaction);
12024 * @class Roo.UpdateManager.defaults
12025 * @static (not really - but it helps the doc tool)
12026 * The defaults collection enables customizing the default properties of UpdateManager
12028 Roo.UpdateManager.defaults = {
12030 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12036 * True to process scripts by default (Defaults to false).
12039 loadScripts : false,
12042 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12045 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12047 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12050 disableCaching : false,
12052 * Whether to show indicatorText when loading (Defaults to true).
12055 showLoadIndicator : true,
12057 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12060 indicatorText : '<div class="loading-indicator">Loading...</div>'
12064 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12066 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12067 * @param {String/HTMLElement/Roo.Element} el The element to update
12068 * @param {String} url The url
12069 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12070 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12073 * @member Roo.UpdateManager
12075 Roo.UpdateManager.updateElement = function(el, url, params, options){
12076 var um = Roo.get(el, true).getUpdateManager();
12077 Roo.apply(um, options);
12078 um.update(url, params, options ? options.callback : null);
12080 // alias for backwards compat
12081 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12083 * @class Roo.UpdateManager.BasicRenderer
12084 * Default Content renderer. Updates the elements innerHTML with the responseText.
12086 Roo.UpdateManager.BasicRenderer = function(){};
12088 Roo.UpdateManager.BasicRenderer.prototype = {
12090 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12091 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12092 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12093 * @param {Roo.Element} el The element being rendered
12094 * @param {Object} response The YUI Connect response object
12095 * @param {UpdateManager} updateManager The calling update manager
12096 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12098 render : function(el, response, updateManager, callback){
12099 el.update(response.responseText, updateManager.loadScripts, callback);
12105 * (c)) Alan Knowles
12111 * @class Roo.DomTemplate
12112 * @extends Roo.Template
12113 * An effort at a dom based template engine..
12115 * Similar to XTemplate, except it uses dom parsing to create the template..
12117 * Supported features:
12122 {a_variable} - output encoded.
12123 {a_variable.format:("Y-m-d")} - call a method on the variable
12124 {a_variable:raw} - unencoded output
12125 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12126 {a_variable:this.method_on_template(...)} - call a method on the template object.
12131 <div roo-for="a_variable or condition.."></div>
12132 <div roo-if="a_variable or condition"></div>
12133 <div roo-exec="some javascript"></div>
12134 <div roo-name="named_template"></div>
12139 Roo.DomTemplate = function()
12141 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12148 Roo.extend(Roo.DomTemplate, Roo.Template, {
12150 * id counter for sub templates.
12154 * flag to indicate if dom parser is inside a pre,
12155 * it will strip whitespace if not.
12160 * The various sub templates
12168 * basic tag replacing syntax
12171 * // you can fake an object call by doing this
12175 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12176 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12178 iterChild : function (node, method) {
12180 var oldPre = this.inPre;
12181 if (node.tagName == 'PRE') {
12184 for( var i = 0; i < node.childNodes.length; i++) {
12185 method.call(this, node.childNodes[i]);
12187 this.inPre = oldPre;
12193 * compile the template
12195 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12198 compile: function()
12202 // covert the html into DOM...
12206 doc = document.implementation.createHTMLDocument("");
12207 doc.documentElement.innerHTML = this.html ;
12208 div = doc.documentElement;
12210 // old IE... - nasty -- it causes all sorts of issues.. with
12211 // images getting pulled from server..
12212 div = document.createElement('div');
12213 div.innerHTML = this.html;
12215 //doc.documentElement.innerHTML = htmlBody
12221 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12223 var tpls = this.tpls;
12225 // create a top level template from the snippet..
12227 //Roo.log(div.innerHTML);
12234 body : div.innerHTML,
12247 Roo.each(tpls, function(tp){
12248 this.compileTpl(tp);
12249 this.tpls[tp.id] = tp;
12252 this.master = tpls[0];
12258 compileNode : function(node, istop) {
12263 // skip anything not a tag..
12264 if (node.nodeType != 1) {
12265 if (node.nodeType == 3 && !this.inPre) {
12266 // reduce white space..
12267 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12290 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12291 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12292 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12293 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12299 // just itterate children..
12300 this.iterChild(node,this.compileNode);
12303 tpl.uid = this.id++;
12304 tpl.value = node.getAttribute('roo-' + tpl.attr);
12305 node.removeAttribute('roo-'+ tpl.attr);
12306 if (tpl.attr != 'name') {
12307 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12308 node.parentNode.replaceChild(placeholder, node);
12311 var placeholder = document.createElement('span');
12312 placeholder.className = 'roo-tpl-' + tpl.value;
12313 node.parentNode.replaceChild(placeholder, node);
12316 // parent now sees '{domtplXXXX}
12317 this.iterChild(node,this.compileNode);
12319 // we should now have node body...
12320 var div = document.createElement('div');
12321 div.appendChild(node);
12323 // this has the unfortunate side effect of converting tagged attributes
12324 // eg. href="{...}" into %7C...%7D
12325 // this has been fixed by searching for those combo's although it's a bit hacky..
12328 tpl.body = div.innerHTML;
12335 switch (tpl.value) {
12336 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12337 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12338 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12343 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12347 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12351 tpl.id = tpl.value; // replace non characters???
12357 this.tpls.push(tpl);
12367 * Compile a segment of the template into a 'sub-template'
12373 compileTpl : function(tpl)
12375 var fm = Roo.util.Format;
12376 var useF = this.disableFormats !== true;
12378 var sep = Roo.isGecko ? "+\n" : ",\n";
12380 var undef = function(str) {
12381 Roo.debug && Roo.log("Property not found :" + str);
12385 //Roo.log(tpl.body);
12389 var fn = function(m, lbrace, name, format, args)
12392 //Roo.log(arguments);
12393 args = args ? args.replace(/\\'/g,"'") : args;
12394 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12395 if (typeof(format) == 'undefined') {
12396 format = 'htmlEncode';
12398 if (format == 'raw' ) {
12402 if(name.substr(0, 6) == 'domtpl'){
12403 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12406 // build an array of options to determine if value is undefined..
12408 // basically get 'xxxx.yyyy' then do
12409 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12410 // (function () { Roo.log("Property not found"); return ''; })() :
12415 Roo.each(name.split('.'), function(st) {
12416 lookfor += (lookfor.length ? '.': '') + st;
12417 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12420 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12423 if(format && useF){
12425 args = args ? ',' + args : "";
12427 if(format.substr(0, 5) != "this."){
12428 format = "fm." + format + '(';
12430 format = 'this.call("'+ format.substr(5) + '", ';
12434 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12437 if (args && args.length) {
12438 // called with xxyx.yuu:(test,test)
12440 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12442 // raw.. - :raw modifier..
12443 return "'"+ sep + udef_st + name + ")"+sep+"'";
12447 // branched to use + in gecko and [].join() in others
12449 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12450 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12453 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12454 body.push(tpl.body.replace(/(\r\n|\n)/g,
12455 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12456 body.push("'].join('');};};");
12457 body = body.join('');
12460 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12462 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12469 * same as applyTemplate, except it's done to one of the subTemplates
12470 * when using named templates, you can do:
12472 * var str = pl.applySubTemplate('your-name', values);
12475 * @param {Number} id of the template
12476 * @param {Object} values to apply to template
12477 * @param {Object} parent (normaly the instance of this object)
12479 applySubTemplate : function(id, values, parent)
12483 var t = this.tpls[id];
12487 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12488 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12492 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12499 if(t.execCall && t.execCall.call(this, values, parent)){
12503 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12509 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12510 parent = t.target ? values : parent;
12511 if(t.forCall && vs instanceof Array){
12513 for(var i = 0, len = vs.length; i < len; i++){
12515 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12517 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12519 //Roo.log(t.compiled);
12523 return buf.join('');
12526 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12531 return t.compiled.call(this, vs, parent);
12533 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12535 //Roo.log(t.compiled);
12543 applyTemplate : function(values){
12544 return this.master.compiled.call(this, values, {});
12545 //var s = this.subs;
12548 apply : function(){
12549 return this.applyTemplate.apply(this, arguments);
12554 Roo.DomTemplate.from = function(el){
12555 el = Roo.getDom(el);
12556 return new Roo.Domtemplate(el.value || el.innerHTML);
12559 * Ext JS Library 1.1.1
12560 * Copyright(c) 2006-2007, Ext JS, LLC.
12562 * Originally Released Under LGPL - original licence link has changed is not relivant.
12565 * <script type="text/javascript">
12569 * @class Roo.util.DelayedTask
12570 * Provides a convenient method of performing setTimeout where a new
12571 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12572 * You can use this class to buffer
12573 * the keypress events for a certain number of milliseconds, and perform only if they stop
12574 * for that amount of time.
12575 * @constructor The parameters to this constructor serve as defaults and are not required.
12576 * @param {Function} fn (optional) The default function to timeout
12577 * @param {Object} scope (optional) The default scope of that timeout
12578 * @param {Array} args (optional) The default Array of arguments
12580 Roo.util.DelayedTask = function(fn, scope, args){
12581 var id = null, d, t;
12583 var call = function(){
12584 var now = new Date().getTime();
12588 fn.apply(scope, args || []);
12592 * Cancels any pending timeout and queues a new one
12593 * @param {Number} delay The milliseconds to delay
12594 * @param {Function} newFn (optional) Overrides function passed to constructor
12595 * @param {Object} newScope (optional) Overrides scope passed to constructor
12596 * @param {Array} newArgs (optional) Overrides args passed to constructor
12598 this.delay = function(delay, newFn, newScope, newArgs){
12599 if(id && delay != d){
12603 t = new Date().getTime();
12605 scope = newScope || scope;
12606 args = newArgs || args;
12608 id = setInterval(call, d);
12613 * Cancel the last queued timeout
12615 this.cancel = function(){
12623 * Ext JS Library 1.1.1
12624 * Copyright(c) 2006-2007, Ext JS, LLC.
12626 * Originally Released Under LGPL - original licence link has changed is not relivant.
12629 * <script type="text/javascript">
12633 Roo.util.TaskRunner = function(interval){
12634 interval = interval || 10;
12635 var tasks = [], removeQueue = [];
12637 var running = false;
12639 var stopThread = function(){
12645 var startThread = function(){
12648 id = setInterval(runTasks, interval);
12652 var removeTask = function(task){
12653 removeQueue.push(task);
12659 var runTasks = function(){
12660 if(removeQueue.length > 0){
12661 for(var i = 0, len = removeQueue.length; i < len; i++){
12662 tasks.remove(removeQueue[i]);
12665 if(tasks.length < 1){
12670 var now = new Date().getTime();
12671 for(var i = 0, len = tasks.length; i < len; ++i){
12673 var itime = now - t.taskRunTime;
12674 if(t.interval <= itime){
12675 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12676 t.taskRunTime = now;
12677 if(rt === false || t.taskRunCount === t.repeat){
12682 if(t.duration && t.duration <= (now - t.taskStartTime)){
12689 * Queues a new task.
12690 * @param {Object} task
12692 this.start = function(task){
12694 task.taskStartTime = new Date().getTime();
12695 task.taskRunTime = 0;
12696 task.taskRunCount = 0;
12701 this.stop = function(task){
12706 this.stopAll = function(){
12708 for(var i = 0, len = tasks.length; i < len; i++){
12709 if(tasks[i].onStop){
12718 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12720 * Ext JS Library 1.1.1
12721 * Copyright(c) 2006-2007, Ext JS, LLC.
12723 * Originally Released Under LGPL - original licence link has changed is not relivant.
12726 * <script type="text/javascript">
12731 * @class Roo.util.MixedCollection
12732 * @extends Roo.util.Observable
12733 * A Collection class that maintains both numeric indexes and keys and exposes events.
12735 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12736 * collection (defaults to false)
12737 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12738 * and return the key value for that item. This is used when available to look up the key on items that
12739 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12740 * equivalent to providing an implementation for the {@link #getKey} method.
12742 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12750 * Fires when the collection is cleared.
12755 * Fires when an item is added to the collection.
12756 * @param {Number} index The index at which the item was added.
12757 * @param {Object} o The item added.
12758 * @param {String} key The key associated with the added item.
12763 * Fires when an item is replaced in the collection.
12764 * @param {String} key he key associated with the new added.
12765 * @param {Object} old The item being replaced.
12766 * @param {Object} new The new item.
12771 * Fires when an item is removed from the collection.
12772 * @param {Object} o The item being removed.
12773 * @param {String} key (optional) The key associated with the removed item.
12778 this.allowFunctions = allowFunctions === true;
12780 this.getKey = keyFn;
12782 Roo.util.MixedCollection.superclass.constructor.call(this);
12785 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12786 allowFunctions : false,
12789 * Adds an item to the collection.
12790 * @param {String} key The key to associate with the item
12791 * @param {Object} o The item to add.
12792 * @return {Object} The item added.
12794 add : function(key, o){
12795 if(arguments.length == 1){
12797 key = this.getKey(o);
12799 if(typeof key == "undefined" || key === null){
12801 this.items.push(o);
12802 this.keys.push(null);
12804 var old = this.map[key];
12806 return this.replace(key, o);
12809 this.items.push(o);
12811 this.keys.push(key);
12813 this.fireEvent("add", this.length-1, o, key);
12818 * MixedCollection has a generic way to fetch keys if you implement getKey.
12821 var mc = new Roo.util.MixedCollection();
12822 mc.add(someEl.dom.id, someEl);
12823 mc.add(otherEl.dom.id, otherEl);
12827 var mc = new Roo.util.MixedCollection();
12828 mc.getKey = function(el){
12834 // or via the constructor
12835 var mc = new Roo.util.MixedCollection(false, function(el){
12841 * @param o {Object} The item for which to find the key.
12842 * @return {Object} The key for the passed item.
12844 getKey : function(o){
12849 * Replaces an item in the collection.
12850 * @param {String} key The key associated with the item to replace, or the item to replace.
12851 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12852 * @return {Object} The new item.
12854 replace : function(key, o){
12855 if(arguments.length == 1){
12857 key = this.getKey(o);
12859 var old = this.item(key);
12860 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12861 return this.add(key, o);
12863 var index = this.indexOfKey(key);
12864 this.items[index] = o;
12866 this.fireEvent("replace", key, old, o);
12871 * Adds all elements of an Array or an Object to the collection.
12872 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12873 * an Array of values, each of which are added to the collection.
12875 addAll : function(objs){
12876 if(arguments.length > 1 || objs instanceof Array){
12877 var args = arguments.length > 1 ? arguments : objs;
12878 for(var i = 0, len = args.length; i < len; i++){
12882 for(var key in objs){
12883 if(this.allowFunctions || typeof objs[key] != "function"){
12884 this.add(key, objs[key]);
12891 * Executes the specified function once for every item in the collection, passing each
12892 * item as the first and only parameter. returning false from the function will stop the iteration.
12893 * @param {Function} fn The function to execute for each item.
12894 * @param {Object} scope (optional) The scope in which to execute the function.
12896 each : function(fn, scope){
12897 var items = [].concat(this.items); // each safe for removal
12898 for(var i = 0, len = items.length; i < len; i++){
12899 if(fn.call(scope || items[i], items[i], i, len) === false){
12906 * Executes the specified function once for every key in the collection, passing each
12907 * key, and its associated item as the first two parameters.
12908 * @param {Function} fn The function to execute for each item.
12909 * @param {Object} scope (optional) The scope in which to execute the function.
12911 eachKey : function(fn, scope){
12912 for(var i = 0, len = this.keys.length; i < len; i++){
12913 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12918 * Returns the first item in the collection which elicits a true return value from the
12919 * passed selection function.
12920 * @param {Function} fn The selection function to execute for each item.
12921 * @param {Object} scope (optional) The scope in which to execute the function.
12922 * @return {Object} The first item in the collection which returned true from the selection function.
12924 find : function(fn, scope){
12925 for(var i = 0, len = this.items.length; i < len; i++){
12926 if(fn.call(scope || window, this.items[i], this.keys[i])){
12927 return this.items[i];
12934 * Inserts an item at the specified index in the collection.
12935 * @param {Number} index The index to insert the item at.
12936 * @param {String} key The key to associate with the new item, or the item itself.
12937 * @param {Object} o (optional) If the second parameter was a key, the new item.
12938 * @return {Object} The item inserted.
12940 insert : function(index, key, o){
12941 if(arguments.length == 2){
12943 key = this.getKey(o);
12945 if(index >= this.length){
12946 return this.add(key, o);
12949 this.items.splice(index, 0, o);
12950 if(typeof key != "undefined" && key != null){
12953 this.keys.splice(index, 0, key);
12954 this.fireEvent("add", index, o, key);
12959 * Removed an item from the collection.
12960 * @param {Object} o The item to remove.
12961 * @return {Object} The item removed.
12963 remove : function(o){
12964 return this.removeAt(this.indexOf(o));
12968 * Remove an item from a specified index in the collection.
12969 * @param {Number} index The index within the collection of the item to remove.
12971 removeAt : function(index){
12972 if(index < this.length && index >= 0){
12974 var o = this.items[index];
12975 this.items.splice(index, 1);
12976 var key = this.keys[index];
12977 if(typeof key != "undefined"){
12978 delete this.map[key];
12980 this.keys.splice(index, 1);
12981 this.fireEvent("remove", o, key);
12986 * Removed an item associated with the passed key fom the collection.
12987 * @param {String} key The key of the item to remove.
12989 removeKey : function(key){
12990 return this.removeAt(this.indexOfKey(key));
12994 * Returns the number of items in the collection.
12995 * @return {Number} the number of items in the collection.
12997 getCount : function(){
12998 return this.length;
13002 * Returns index within the collection of the passed Object.
13003 * @param {Object} o The item to find the index of.
13004 * @return {Number} index of the item.
13006 indexOf : function(o){
13007 if(!this.items.indexOf){
13008 for(var i = 0, len = this.items.length; i < len; i++){
13009 if(this.items[i] == o) return i;
13013 return this.items.indexOf(o);
13018 * Returns index within the collection of the passed key.
13019 * @param {String} key The key to find the index of.
13020 * @return {Number} index of the key.
13022 indexOfKey : function(key){
13023 if(!this.keys.indexOf){
13024 for(var i = 0, len = this.keys.length; i < len; i++){
13025 if(this.keys[i] == key) return i;
13029 return this.keys.indexOf(key);
13034 * Returns the item associated with the passed key OR index. Key has priority over index.
13035 * @param {String/Number} key The key or index of the item.
13036 * @return {Object} The item associated with the passed key.
13038 item : function(key){
13039 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13040 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13044 * Returns the item at the specified index.
13045 * @param {Number} index The index of the item.
13048 itemAt : function(index){
13049 return this.items[index];
13053 * Returns the item associated with the passed key.
13054 * @param {String/Number} key The key of the item.
13055 * @return {Object} The item associated with the passed key.
13057 key : function(key){
13058 return this.map[key];
13062 * Returns true if the collection contains the passed Object as an item.
13063 * @param {Object} o The Object to look for in the collection.
13064 * @return {Boolean} True if the collection contains the Object as an item.
13066 contains : function(o){
13067 return this.indexOf(o) != -1;
13071 * Returns true if the collection contains the passed Object as a key.
13072 * @param {String} key The key to look for in the collection.
13073 * @return {Boolean} True if the collection contains the Object as a key.
13075 containsKey : function(key){
13076 return typeof this.map[key] != "undefined";
13080 * Removes all items from the collection.
13082 clear : function(){
13087 this.fireEvent("clear");
13091 * Returns the first item in the collection.
13092 * @return {Object} the first item in the collection..
13094 first : function(){
13095 return this.items[0];
13099 * Returns the last item in the collection.
13100 * @return {Object} the last item in the collection..
13103 return this.items[this.length-1];
13106 _sort : function(property, dir, fn){
13107 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13108 fn = fn || function(a, b){
13111 var c = [], k = this.keys, items = this.items;
13112 for(var i = 0, len = items.length; i < len; i++){
13113 c[c.length] = {key: k[i], value: items[i], index: i};
13115 c.sort(function(a, b){
13116 var v = fn(a[property], b[property]) * dsc;
13118 v = (a.index < b.index ? -1 : 1);
13122 for(var i = 0, len = c.length; i < len; i++){
13123 items[i] = c[i].value;
13126 this.fireEvent("sort", this);
13130 * Sorts this collection with the passed comparison function
13131 * @param {String} direction (optional) "ASC" or "DESC"
13132 * @param {Function} fn (optional) comparison function
13134 sort : function(dir, fn){
13135 this._sort("value", dir, fn);
13139 * Sorts this collection by keys
13140 * @param {String} direction (optional) "ASC" or "DESC"
13141 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13143 keySort : function(dir, fn){
13144 this._sort("key", dir, fn || function(a, b){
13145 return String(a).toUpperCase()-String(b).toUpperCase();
13150 * Returns a range of items in this collection
13151 * @param {Number} startIndex (optional) defaults to 0
13152 * @param {Number} endIndex (optional) default to the last item
13153 * @return {Array} An array of items
13155 getRange : function(start, end){
13156 var items = this.items;
13157 if(items.length < 1){
13160 start = start || 0;
13161 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13164 for(var i = start; i <= end; i++) {
13165 r[r.length] = items[i];
13168 for(var i = start; i >= end; i--) {
13169 r[r.length] = items[i];
13176 * Filter the <i>objects</i> in this collection by a specific property.
13177 * Returns a new collection that has been filtered.
13178 * @param {String} property A property on your objects
13179 * @param {String/RegExp} value Either string that the property values
13180 * should start with or a RegExp to test against the property
13181 * @return {MixedCollection} The new filtered collection
13183 filter : function(property, value){
13184 if(!value.exec){ // not a regex
13185 value = String(value);
13186 if(value.length == 0){
13187 return this.clone();
13189 value = new RegExp("^" + Roo.escapeRe(value), "i");
13191 return this.filterBy(function(o){
13192 return o && value.test(o[property]);
13197 * Filter by a function. * Returns a new collection that has been filtered.
13198 * The passed function will be called with each
13199 * object in the collection. If the function returns true, the value is included
13200 * otherwise it is filtered.
13201 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13202 * @param {Object} scope (optional) The scope of the function (defaults to this)
13203 * @return {MixedCollection} The new filtered collection
13205 filterBy : function(fn, scope){
13206 var r = new Roo.util.MixedCollection();
13207 r.getKey = this.getKey;
13208 var k = this.keys, it = this.items;
13209 for(var i = 0, len = it.length; i < len; i++){
13210 if(fn.call(scope||this, it[i], k[i])){
13211 r.add(k[i], it[i]);
13218 * Creates a duplicate of this collection
13219 * @return {MixedCollection}
13221 clone : function(){
13222 var r = new Roo.util.MixedCollection();
13223 var k = this.keys, it = this.items;
13224 for(var i = 0, len = it.length; i < len; i++){
13225 r.add(k[i], it[i]);
13227 r.getKey = this.getKey;
13232 * Returns the item associated with the passed key or index.
13234 * @param {String/Number} key The key or index of the item.
13235 * @return {Object} The item associated with the passed key.
13237 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13239 * Ext JS Library 1.1.1
13240 * Copyright(c) 2006-2007, Ext JS, LLC.
13242 * Originally Released Under LGPL - original licence link has changed is not relivant.
13245 * <script type="text/javascript">
13248 * @class Roo.util.JSON
13249 * Modified version of Douglas Crockford"s json.js that doesn"t
13250 * mess with the Object prototype
13251 * http://www.json.org/js.html
13254 Roo.util.JSON = new (function(){
13255 var useHasOwn = {}.hasOwnProperty ? true : false;
13257 // crashes Safari in some instances
13258 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13260 var pad = function(n) {
13261 return n < 10 ? "0" + n : n;
13274 var encodeString = function(s){
13275 if (/["\\\x00-\x1f]/.test(s)) {
13276 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13281 c = b.charCodeAt();
13283 Math.floor(c / 16).toString(16) +
13284 (c % 16).toString(16);
13287 return '"' + s + '"';
13290 var encodeArray = function(o){
13291 var a = ["["], b, i, l = o.length, v;
13292 for (i = 0; i < l; i += 1) {
13294 switch (typeof v) {
13303 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13311 var encodeDate = function(o){
13312 return '"' + o.getFullYear() + "-" +
13313 pad(o.getMonth() + 1) + "-" +
13314 pad(o.getDate()) + "T" +
13315 pad(o.getHours()) + ":" +
13316 pad(o.getMinutes()) + ":" +
13317 pad(o.getSeconds()) + '"';
13321 * Encodes an Object, Array or other value
13322 * @param {Mixed} o The variable to encode
13323 * @return {String} The JSON string
13325 this.encode = function(o)
13327 // should this be extended to fully wrap stringify..
13329 if(typeof o == "undefined" || o === null){
13331 }else if(o instanceof Array){
13332 return encodeArray(o);
13333 }else if(o instanceof Date){
13334 return encodeDate(o);
13335 }else if(typeof o == "string"){
13336 return encodeString(o);
13337 }else if(typeof o == "number"){
13338 return isFinite(o) ? String(o) : "null";
13339 }else if(typeof o == "boolean"){
13342 var a = ["{"], b, i, v;
13344 if(!useHasOwn || o.hasOwnProperty(i)) {
13346 switch (typeof v) {
13355 a.push(this.encode(i), ":",
13356 v === null ? "null" : this.encode(v));
13367 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13368 * @param {String} json The JSON string
13369 * @return {Object} The resulting object
13371 this.decode = function(json){
13373 return /** eval:var:json */ eval("(" + json + ')');
13377 * Shorthand for {@link Roo.util.JSON#encode}
13378 * @member Roo encode
13380 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13382 * Shorthand for {@link Roo.util.JSON#decode}
13383 * @member Roo decode
13385 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13388 * Ext JS Library 1.1.1
13389 * Copyright(c) 2006-2007, Ext JS, LLC.
13391 * Originally Released Under LGPL - original licence link has changed is not relivant.
13394 * <script type="text/javascript">
13398 * @class Roo.util.Format
13399 * Reusable data formatting functions
13402 Roo.util.Format = function(){
13403 var trimRe = /^\s+|\s+$/g;
13406 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13407 * @param {String} value The string to truncate
13408 * @param {Number} length The maximum length to allow before truncating
13409 * @return {String} The converted text
13411 ellipsis : function(value, len){
13412 if(value && value.length > len){
13413 return value.substr(0, len-3)+"...";
13419 * Checks a reference and converts it to empty string if it is undefined
13420 * @param {Mixed} value Reference to check
13421 * @return {Mixed} Empty string if converted, otherwise the original value
13423 undef : function(value){
13424 return typeof value != "undefined" ? value : "";
13428 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13429 * @param {String} value The string to encode
13430 * @return {String} The encoded text
13432 htmlEncode : function(value){
13433 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13437 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13438 * @param {String} value The string to decode
13439 * @return {String} The decoded text
13441 htmlDecode : function(value){
13442 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13446 * Trims any whitespace from either side of a string
13447 * @param {String} value The text to trim
13448 * @return {String} The trimmed text
13450 trim : function(value){
13451 return String(value).replace(trimRe, "");
13455 * Returns a substring from within an original string
13456 * @param {String} value The original text
13457 * @param {Number} start The start index of the substring
13458 * @param {Number} length The length of the substring
13459 * @return {String} The substring
13461 substr : function(value, start, length){
13462 return String(value).substr(start, length);
13466 * Converts a string to all lower case letters
13467 * @param {String} value The text to convert
13468 * @return {String} The converted text
13470 lowercase : function(value){
13471 return String(value).toLowerCase();
13475 * Converts a string to all upper case letters
13476 * @param {String} value The text to convert
13477 * @return {String} The converted text
13479 uppercase : function(value){
13480 return String(value).toUpperCase();
13484 * Converts the first character only of a string to upper case
13485 * @param {String} value The text to convert
13486 * @return {String} The converted text
13488 capitalize : function(value){
13489 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13493 call : function(value, fn){
13494 if(arguments.length > 2){
13495 var args = Array.prototype.slice.call(arguments, 2);
13496 args.unshift(value);
13498 return /** eval:var:value */ eval(fn).apply(window, args);
13500 /** eval:var:value */
13501 return /** eval:var:value */ eval(fn).call(window, value);
13507 * safer version of Math.toFixed..??/
13508 * @param {Number/String} value The numeric value to format
13509 * @param {Number/String} value Decimal places
13510 * @return {String} The formatted currency string
13512 toFixed : function(v, n)
13514 // why not use to fixed - precision is buggered???
13516 return Math.round(v-0);
13518 var fact = Math.pow(10,n+1);
13519 v = (Math.round((v-0)*fact))/fact;
13520 var z = (''+fact).substring(2);
13521 if (v == Math.floor(v)) {
13522 return Math.floor(v) + '.' + z;
13525 // now just padd decimals..
13526 var ps = String(v).split('.');
13527 var fd = (ps[1] + z);
13528 var r = fd.substring(0,n);
13529 var rm = fd.substring(n);
13531 return ps[0] + '.' + r;
13533 r*=1; // turn it into a number;
13535 if (String(r).length != n) {
13538 r = String(r).substring(1); // chop the end off.
13541 return ps[0] + '.' + r;
13546 * Format a number as US currency
13547 * @param {Number/String} value The numeric value to format
13548 * @return {String} The formatted currency string
13550 usMoney : function(v){
13551 return '$' + Roo.util.Format.number(v);
13556 * eventually this should probably emulate php's number_format
13557 * @param {Number/String} value The numeric value to format
13558 * @param {Number} decimals number of decimal places
13559 * @return {String} The formatted currency string
13561 number : function(v,decimals)
13563 // multiply and round.
13564 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13565 var mul = Math.pow(10, decimals);
13566 var zero = String(mul).substring(1);
13567 v = (Math.round((v-0)*mul))/mul;
13569 // if it's '0' number.. then
13571 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13573 var ps = v.split('.');
13577 var r = /(\d+)(\d{3})/;
13579 while (r.test(whole)) {
13580 whole = whole.replace(r, '$1' + ',' + '$2');
13586 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13587 // does not have decimals
13588 (decimals ? ('.' + zero) : '');
13591 return whole + sub ;
13595 * Parse a value into a formatted date using the specified format pattern.
13596 * @param {Mixed} value The value to format
13597 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13598 * @return {String} The formatted date string
13600 date : function(v, format){
13604 if(!(v instanceof Date)){
13605 v = new Date(Date.parse(v));
13607 return v.dateFormat(format || "m/d/Y");
13611 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13612 * @param {String} format Any valid date format string
13613 * @return {Function} The date formatting function
13615 dateRenderer : function(format){
13616 return function(v){
13617 return Roo.util.Format.date(v, format);
13622 stripTagsRE : /<\/?[^>]+>/gi,
13625 * Strips all HTML tags
13626 * @param {Mixed} value The text from which to strip tags
13627 * @return {String} The stripped text
13629 stripTags : function(v){
13630 return !v ? v : String(v).replace(this.stripTagsRE, "");
13635 * Ext JS Library 1.1.1
13636 * Copyright(c) 2006-2007, Ext JS, LLC.
13638 * Originally Released Under LGPL - original licence link has changed is not relivant.
13641 * <script type="text/javascript">
13648 * @class Roo.MasterTemplate
13649 * @extends Roo.Template
13650 * Provides a template that can have child templates. The syntax is:
13652 var t = new Roo.MasterTemplate(
13653 '<select name="{name}">',
13654 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13657 t.add('options', {value: 'foo', text: 'bar'});
13658 // or you can add multiple child elements in one shot
13659 t.addAll('options', [
13660 {value: 'foo', text: 'bar'},
13661 {value: 'foo2', text: 'bar2'},
13662 {value: 'foo3', text: 'bar3'}
13664 // then append, applying the master template values
13665 t.append('my-form', {name: 'my-select'});
13667 * A name attribute for the child template is not required if you have only one child
13668 * template or you want to refer to them by index.
13670 Roo.MasterTemplate = function(){
13671 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13672 this.originalHtml = this.html;
13674 var m, re = this.subTemplateRe;
13677 while(m = re.exec(this.html)){
13678 var name = m[1], content = m[2];
13683 tpl : new Roo.Template(content)
13686 st[name] = st[subIndex];
13688 st[subIndex].tpl.compile();
13689 st[subIndex].tpl.call = this.call.createDelegate(this);
13692 this.subCount = subIndex;
13695 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13697 * The regular expression used to match sub templates
13701 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13704 * Applies the passed values to a child template.
13705 * @param {String/Number} name (optional) The name or index of the child template
13706 * @param {Array/Object} values The values to be applied to the template
13707 * @return {MasterTemplate} this
13709 add : function(name, values){
13710 if(arguments.length == 1){
13711 values = arguments[0];
13714 var s = this.subs[name];
13715 s.buffer[s.buffer.length] = s.tpl.apply(values);
13720 * Applies all the passed values to a child template.
13721 * @param {String/Number} name (optional) The name or index of the child template
13722 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13723 * @param {Boolean} reset (optional) True to reset the template first
13724 * @return {MasterTemplate} this
13726 fill : function(name, values, reset){
13728 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13736 for(var i = 0, len = values.length; i < len; i++){
13737 this.add(name, values[i]);
13743 * Resets the template for reuse
13744 * @return {MasterTemplate} this
13746 reset : function(){
13748 for(var i = 0; i < this.subCount; i++){
13754 applyTemplate : function(values){
13756 var replaceIndex = -1;
13757 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13758 return s[++replaceIndex].buffer.join("");
13760 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13763 apply : function(){
13764 return this.applyTemplate.apply(this, arguments);
13767 compile : function(){return this;}
13771 * Alias for fill().
13774 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13776 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13777 * var tpl = Roo.MasterTemplate.from('element-id');
13778 * @param {String/HTMLElement} el
13779 * @param {Object} config
13782 Roo.MasterTemplate.from = function(el, config){
13783 el = Roo.getDom(el);
13784 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13787 * Ext JS Library 1.1.1
13788 * Copyright(c) 2006-2007, Ext JS, LLC.
13790 * Originally Released Under LGPL - original licence link has changed is not relivant.
13793 * <script type="text/javascript">
13798 * @class Roo.util.CSS
13799 * Utility class for manipulating CSS rules
13802 Roo.util.CSS = function(){
13804 var doc = document;
13806 var camelRe = /(-[a-z])/gi;
13807 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13811 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13812 * tag and appended to the HEAD of the document.
13813 * @param {String|Object} cssText The text containing the css rules
13814 * @param {String} id An id to add to the stylesheet for later removal
13815 * @return {StyleSheet}
13817 createStyleSheet : function(cssText, id){
13819 var head = doc.getElementsByTagName("head")[0];
13820 var nrules = doc.createElement("style");
13821 nrules.setAttribute("type", "text/css");
13823 nrules.setAttribute("id", id);
13825 if (typeof(cssText) != 'string') {
13826 // support object maps..
13827 // not sure if this a good idea..
13828 // perhaps it should be merged with the general css handling
13829 // and handle js style props.
13830 var cssTextNew = [];
13831 for(var n in cssText) {
13833 for(var k in cssText[n]) {
13834 citems.push( k + ' : ' +cssText[n][k] + ';' );
13836 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13839 cssText = cssTextNew.join("\n");
13845 head.appendChild(nrules);
13846 ss = nrules.styleSheet;
13847 ss.cssText = cssText;
13850 nrules.appendChild(doc.createTextNode(cssText));
13852 nrules.cssText = cssText;
13854 head.appendChild(nrules);
13855 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13857 this.cacheStyleSheet(ss);
13862 * Removes a style or link tag by id
13863 * @param {String} id The id of the tag
13865 removeStyleSheet : function(id){
13866 var existing = doc.getElementById(id);
13868 existing.parentNode.removeChild(existing);
13873 * Dynamically swaps an existing stylesheet reference for a new one
13874 * @param {String} id The id of an existing link tag to remove
13875 * @param {String} url The href of the new stylesheet to include
13877 swapStyleSheet : function(id, url){
13878 this.removeStyleSheet(id);
13879 var ss = doc.createElement("link");
13880 ss.setAttribute("rel", "stylesheet");
13881 ss.setAttribute("type", "text/css");
13882 ss.setAttribute("id", id);
13883 ss.setAttribute("href", url);
13884 doc.getElementsByTagName("head")[0].appendChild(ss);
13888 * Refresh the rule cache if you have dynamically added stylesheets
13889 * @return {Object} An object (hash) of rules indexed by selector
13891 refreshCache : function(){
13892 return this.getRules(true);
13896 cacheStyleSheet : function(stylesheet){
13900 try{// try catch for cross domain access issue
13901 var ssRules = stylesheet.cssRules || stylesheet.rules;
13902 for(var j = ssRules.length-1; j >= 0; --j){
13903 rules[ssRules[j].selectorText] = ssRules[j];
13909 * Gets all css rules for the document
13910 * @param {Boolean} refreshCache true to refresh the internal cache
13911 * @return {Object} An object (hash) of rules indexed by selector
13913 getRules : function(refreshCache){
13914 if(rules == null || refreshCache){
13916 var ds = doc.styleSheets;
13917 for(var i =0, len = ds.length; i < len; i++){
13919 this.cacheStyleSheet(ds[i]);
13927 * Gets an an individual CSS rule by selector(s)
13928 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13929 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13930 * @return {CSSRule} The CSS rule or null if one is not found
13932 getRule : function(selector, refreshCache){
13933 var rs = this.getRules(refreshCache);
13934 if(!(selector instanceof Array)){
13935 return rs[selector];
13937 for(var i = 0; i < selector.length; i++){
13938 if(rs[selector[i]]){
13939 return rs[selector[i]];
13947 * Updates a rule property
13948 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13949 * @param {String} property The css property
13950 * @param {String} value The new value for the property
13951 * @return {Boolean} true If a rule was found and updated
13953 updateRule : function(selector, property, value){
13954 if(!(selector instanceof Array)){
13955 var rule = this.getRule(selector);
13957 rule.style[property.replace(camelRe, camelFn)] = value;
13961 for(var i = 0; i < selector.length; i++){
13962 if(this.updateRule(selector[i], property, value)){
13972 * Ext JS Library 1.1.1
13973 * Copyright(c) 2006-2007, Ext JS, LLC.
13975 * Originally Released Under LGPL - original licence link has changed is not relivant.
13978 * <script type="text/javascript">
13984 * @class Roo.util.ClickRepeater
13985 * @extends Roo.util.Observable
13987 * A wrapper class which can be applied to any element. Fires a "click" event while the
13988 * mouse is pressed. The interval between firings may be specified in the config but
13989 * defaults to 10 milliseconds.
13991 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13993 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13994 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13995 * Similar to an autorepeat key delay.
13996 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13997 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13998 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13999 * "interval" and "delay" are ignored. "immediate" is honored.
14000 * @cfg {Boolean} preventDefault True to prevent the default click event
14001 * @cfg {Boolean} stopDefault True to stop the default click event
14004 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14005 * 2007-02-02 jvs Renamed to ClickRepeater
14006 * 2007-02-03 jvs Modifications for FF Mac and Safari
14009 * @param {String/HTMLElement/Element} el The element to listen on
14010 * @param {Object} config
14012 Roo.util.ClickRepeater = function(el, config)
14014 this.el = Roo.get(el);
14015 this.el.unselectable();
14017 Roo.apply(this, config);
14022 * Fires when the mouse button is depressed.
14023 * @param {Roo.util.ClickRepeater} this
14025 "mousedown" : true,
14028 * Fires on a specified interval during the time the element is pressed.
14029 * @param {Roo.util.ClickRepeater} this
14034 * Fires when the mouse key is released.
14035 * @param {Roo.util.ClickRepeater} this
14040 this.el.on("mousedown", this.handleMouseDown, this);
14041 if(this.preventDefault || this.stopDefault){
14042 this.el.on("click", function(e){
14043 if(this.preventDefault){
14044 e.preventDefault();
14046 if(this.stopDefault){
14052 // allow inline handler
14054 this.on("click", this.handler, this.scope || this);
14057 Roo.util.ClickRepeater.superclass.constructor.call(this);
14060 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14063 preventDefault : true,
14064 stopDefault : false,
14068 handleMouseDown : function(){
14069 clearTimeout(this.timer);
14071 if(this.pressClass){
14072 this.el.addClass(this.pressClass);
14074 this.mousedownTime = new Date();
14076 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14077 this.el.on("mouseout", this.handleMouseOut, this);
14079 this.fireEvent("mousedown", this);
14080 this.fireEvent("click", this);
14082 this.timer = this.click.defer(this.delay || this.interval, this);
14086 click : function(){
14087 this.fireEvent("click", this);
14088 this.timer = this.click.defer(this.getInterval(), this);
14092 getInterval: function(){
14093 if(!this.accelerate){
14094 return this.interval;
14096 var pressTime = this.mousedownTime.getElapsed();
14097 if(pressTime < 500){
14099 }else if(pressTime < 1700){
14101 }else if(pressTime < 2600){
14103 }else if(pressTime < 3500){
14105 }else if(pressTime < 4400){
14107 }else if(pressTime < 5300){
14109 }else if(pressTime < 6200){
14117 handleMouseOut : function(){
14118 clearTimeout(this.timer);
14119 if(this.pressClass){
14120 this.el.removeClass(this.pressClass);
14122 this.el.on("mouseover", this.handleMouseReturn, this);
14126 handleMouseReturn : function(){
14127 this.el.un("mouseover", this.handleMouseReturn);
14128 if(this.pressClass){
14129 this.el.addClass(this.pressClass);
14135 handleMouseUp : function(){
14136 clearTimeout(this.timer);
14137 this.el.un("mouseover", this.handleMouseReturn);
14138 this.el.un("mouseout", this.handleMouseOut);
14139 Roo.get(document).un("mouseup", this.handleMouseUp);
14140 this.el.removeClass(this.pressClass);
14141 this.fireEvent("mouseup", this);
14145 * Ext JS Library 1.1.1
14146 * Copyright(c) 2006-2007, Ext JS, LLC.
14148 * Originally Released Under LGPL - original licence link has changed is not relivant.
14151 * <script type="text/javascript">
14156 * @class Roo.KeyNav
14157 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14158 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14159 * way to implement custom navigation schemes for any UI component.</p>
14160 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14161 * pageUp, pageDown, del, home, end. Usage:</p>
14163 var nav = new Roo.KeyNav("my-element", {
14164 "left" : function(e){
14165 this.moveLeft(e.ctrlKey);
14167 "right" : function(e){
14168 this.moveRight(e.ctrlKey);
14170 "enter" : function(e){
14177 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14178 * @param {Object} config The config
14180 Roo.KeyNav = function(el, config){
14181 this.el = Roo.get(el);
14182 Roo.apply(this, config);
14183 if(!this.disabled){
14184 this.disabled = true;
14189 Roo.KeyNav.prototype = {
14191 * @cfg {Boolean} disabled
14192 * True to disable this KeyNav instance (defaults to false)
14196 * @cfg {String} defaultEventAction
14197 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14198 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14199 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14201 defaultEventAction: "stopEvent",
14203 * @cfg {Boolean} forceKeyDown
14204 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14205 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14206 * handle keydown instead of keypress.
14208 forceKeyDown : false,
14211 prepareEvent : function(e){
14212 var k = e.getKey();
14213 var h = this.keyToHandler[k];
14214 //if(h && this[h]){
14215 // e.stopPropagation();
14217 if(Roo.isSafari && h && k >= 37 && k <= 40){
14223 relay : function(e){
14224 var k = e.getKey();
14225 var h = this.keyToHandler[k];
14227 if(this.doRelay(e, this[h], h) !== true){
14228 e[this.defaultEventAction]();
14234 doRelay : function(e, h, hname){
14235 return h.call(this.scope || this, e);
14238 // possible handlers
14252 // quick lookup hash
14269 * Enable this KeyNav
14271 enable: function(){
14273 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14274 // the EventObject will normalize Safari automatically
14275 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14276 this.el.on("keydown", this.relay, this);
14278 this.el.on("keydown", this.prepareEvent, this);
14279 this.el.on("keypress", this.relay, this);
14281 this.disabled = false;
14286 * Disable this KeyNav
14288 disable: function(){
14289 if(!this.disabled){
14290 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14291 this.el.un("keydown", this.relay);
14293 this.el.un("keydown", this.prepareEvent);
14294 this.el.un("keypress", this.relay);
14296 this.disabled = true;
14301 * Ext JS Library 1.1.1
14302 * Copyright(c) 2006-2007, Ext JS, LLC.
14304 * Originally Released Under LGPL - original licence link has changed is not relivant.
14307 * <script type="text/javascript">
14312 * @class Roo.KeyMap
14313 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14314 * The constructor accepts the same config object as defined by {@link #addBinding}.
14315 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14316 * combination it will call the function with this signature (if the match is a multi-key
14317 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14318 * A KeyMap can also handle a string representation of keys.<br />
14321 // map one key by key code
14322 var map = new Roo.KeyMap("my-element", {
14323 key: 13, // or Roo.EventObject.ENTER
14328 // map multiple keys to one action by string
14329 var map = new Roo.KeyMap("my-element", {
14335 // map multiple keys to multiple actions by strings and array of codes
14336 var map = new Roo.KeyMap("my-element", [
14339 fn: function(){ alert("Return was pressed"); }
14342 fn: function(){ alert('a, b or c was pressed'); }
14347 fn: function(){ alert('Control + shift + tab was pressed.'); }
14351 * <b>Note: A KeyMap starts enabled</b>
14353 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14354 * @param {Object} config The config (see {@link #addBinding})
14355 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14357 Roo.KeyMap = function(el, config, eventName){
14358 this.el = Roo.get(el);
14359 this.eventName = eventName || "keydown";
14360 this.bindings = [];
14362 this.addBinding(config);
14367 Roo.KeyMap.prototype = {
14369 * True to stop the event from bubbling and prevent the default browser action if the
14370 * key was handled by the KeyMap (defaults to false)
14376 * Add a new binding to this KeyMap. The following config object properties are supported:
14378 Property Type Description
14379 ---------- --------------- ----------------------------------------------------------------------
14380 key String/Array A single keycode or an array of keycodes to handle
14381 shift Boolean True to handle key only when shift is pressed (defaults to false)
14382 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14383 alt Boolean True to handle key only when alt is pressed (defaults to false)
14384 fn Function The function to call when KeyMap finds the expected key combination
14385 scope Object The scope of the callback function
14391 var map = new Roo.KeyMap(document, {
14392 key: Roo.EventObject.ENTER,
14397 //Add a new binding to the existing KeyMap later
14405 * @param {Object/Array} config A single KeyMap config or an array of configs
14407 addBinding : function(config){
14408 if(config instanceof Array){
14409 for(var i = 0, len = config.length; i < len; i++){
14410 this.addBinding(config[i]);
14414 var keyCode = config.key,
14415 shift = config.shift,
14416 ctrl = config.ctrl,
14419 scope = config.scope;
14420 if(typeof keyCode == "string"){
14422 var keyString = keyCode.toUpperCase();
14423 for(var j = 0, len = keyString.length; j < len; j++){
14424 ks.push(keyString.charCodeAt(j));
14428 var keyArray = keyCode instanceof Array;
14429 var handler = function(e){
14430 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14431 var k = e.getKey();
14433 for(var i = 0, len = keyCode.length; i < len; i++){
14434 if(keyCode[i] == k){
14435 if(this.stopEvent){
14438 fn.call(scope || window, k, e);
14444 if(this.stopEvent){
14447 fn.call(scope || window, k, e);
14452 this.bindings.push(handler);
14456 * Shorthand for adding a single key listener
14457 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14458 * following options:
14459 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14460 * @param {Function} fn The function to call
14461 * @param {Object} scope (optional) The scope of the function
14463 on : function(key, fn, scope){
14464 var keyCode, shift, ctrl, alt;
14465 if(typeof key == "object" && !(key instanceof Array)){
14484 handleKeyDown : function(e){
14485 if(this.enabled){ //just in case
14486 var b = this.bindings;
14487 for(var i = 0, len = b.length; i < len; i++){
14488 b[i].call(this, e);
14494 * Returns true if this KeyMap is enabled
14495 * @return {Boolean}
14497 isEnabled : function(){
14498 return this.enabled;
14502 * Enables this KeyMap
14504 enable: function(){
14506 this.el.on(this.eventName, this.handleKeyDown, this);
14507 this.enabled = true;
14512 * Disable this KeyMap
14514 disable: function(){
14516 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14517 this.enabled = false;
14522 * Ext JS Library 1.1.1
14523 * Copyright(c) 2006-2007, Ext JS, LLC.
14525 * Originally Released Under LGPL - original licence link has changed is not relivant.
14528 * <script type="text/javascript">
14533 * @class Roo.util.TextMetrics
14534 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14535 * wide, in pixels, a given block of text will be.
14538 Roo.util.TextMetrics = function(){
14542 * Measures the size of the specified text
14543 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14544 * that can affect the size of the rendered text
14545 * @param {String} text The text to measure
14546 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14547 * in order to accurately measure the text height
14548 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14550 measure : function(el, text, fixedWidth){
14552 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14555 shared.setFixedWidth(fixedWidth || 'auto');
14556 return shared.getSize(text);
14560 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14561 * the overhead of multiple calls to initialize the style properties on each measurement.
14562 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14563 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14564 * in order to accurately measure the text height
14565 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14567 createInstance : function(el, fixedWidth){
14568 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14575 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14576 var ml = new Roo.Element(document.createElement('div'));
14577 document.body.appendChild(ml.dom);
14578 ml.position('absolute');
14579 ml.setLeftTop(-1000, -1000);
14583 ml.setWidth(fixedWidth);
14588 * Returns the size of the specified text based on the internal element's style and width properties
14589 * @memberOf Roo.util.TextMetrics.Instance#
14590 * @param {String} text The text to measure
14591 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14593 getSize : function(text){
14595 var s = ml.getSize();
14601 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14602 * that can affect the size of the rendered text
14603 * @memberOf Roo.util.TextMetrics.Instance#
14604 * @param {String/HTMLElement} el The element, dom node or id
14606 bind : function(el){
14608 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14613 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14614 * to set a fixed width in order to accurately measure the text height.
14615 * @memberOf Roo.util.TextMetrics.Instance#
14616 * @param {Number} width The width to set on the element
14618 setFixedWidth : function(width){
14619 ml.setWidth(width);
14623 * Returns the measured width of the specified text
14624 * @memberOf Roo.util.TextMetrics.Instance#
14625 * @param {String} text The text to measure
14626 * @return {Number} width The width in pixels
14628 getWidth : function(text){
14629 ml.dom.style.width = 'auto';
14630 return this.getSize(text).width;
14634 * Returns the measured height of the specified text. For multiline text, be sure to call
14635 * {@link #setFixedWidth} if necessary.
14636 * @memberOf Roo.util.TextMetrics.Instance#
14637 * @param {String} text The text to measure
14638 * @return {Number} height The height in pixels
14640 getHeight : function(text){
14641 return this.getSize(text).height;
14645 instance.bind(bindTo);
14650 // backwards compat
14651 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14653 * Ext JS Library 1.1.1
14654 * Copyright(c) 2006-2007, Ext JS, LLC.
14656 * Originally Released Under LGPL - original licence link has changed is not relivant.
14659 * <script type="text/javascript">
14663 * @class Roo.state.Provider
14664 * Abstract base class for state provider implementations. This class provides methods
14665 * for encoding and decoding <b>typed</b> variables including dates and defines the
14666 * Provider interface.
14668 Roo.state.Provider = function(){
14670 * @event statechange
14671 * Fires when a state change occurs.
14672 * @param {Provider} this This state provider
14673 * @param {String} key The state key which was changed
14674 * @param {String} value The encoded value for the state
14677 "statechange": true
14680 Roo.state.Provider.superclass.constructor.call(this);
14682 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14684 * Returns the current value for a key
14685 * @param {String} name The key name
14686 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14687 * @return {Mixed} The state data
14689 get : function(name, defaultValue){
14690 return typeof this.state[name] == "undefined" ?
14691 defaultValue : this.state[name];
14695 * Clears a value from the state
14696 * @param {String} name The key name
14698 clear : function(name){
14699 delete this.state[name];
14700 this.fireEvent("statechange", this, name, null);
14704 * Sets the value for a key
14705 * @param {String} name The key name
14706 * @param {Mixed} value The value to set
14708 set : function(name, value){
14709 this.state[name] = value;
14710 this.fireEvent("statechange", this, name, value);
14714 * Decodes a string previously encoded with {@link #encodeValue}.
14715 * @param {String} value The value to decode
14716 * @return {Mixed} The decoded value
14718 decodeValue : function(cookie){
14719 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14720 var matches = re.exec(unescape(cookie));
14721 if(!matches || !matches[1]) return; // non state cookie
14722 var type = matches[1];
14723 var v = matches[2];
14726 return parseFloat(v);
14728 return new Date(Date.parse(v));
14733 var values = v.split("^");
14734 for(var i = 0, len = values.length; i < len; i++){
14735 all.push(this.decodeValue(values[i]));
14740 var values = v.split("^");
14741 for(var i = 0, len = values.length; i < len; i++){
14742 var kv = values[i].split("=");
14743 all[kv[0]] = this.decodeValue(kv[1]);
14752 * Encodes a value including type information. Decode with {@link #decodeValue}.
14753 * @param {Mixed} value The value to encode
14754 * @return {String} The encoded value
14756 encodeValue : function(v){
14758 if(typeof v == "number"){
14760 }else if(typeof v == "boolean"){
14761 enc = "b:" + (v ? "1" : "0");
14762 }else if(v instanceof Date){
14763 enc = "d:" + v.toGMTString();
14764 }else if(v instanceof Array){
14766 for(var i = 0, len = v.length; i < len; i++){
14767 flat += this.encodeValue(v[i]);
14768 if(i != len-1) flat += "^";
14771 }else if(typeof v == "object"){
14774 if(typeof v[key] != "function"){
14775 flat += key + "=" + this.encodeValue(v[key]) + "^";
14778 enc = "o:" + flat.substring(0, flat.length-1);
14782 return escape(enc);
14788 * Ext JS Library 1.1.1
14789 * Copyright(c) 2006-2007, Ext JS, LLC.
14791 * Originally Released Under LGPL - original licence link has changed is not relivant.
14794 * <script type="text/javascript">
14797 * @class Roo.state.Manager
14798 * This is the global state manager. By default all components that are "state aware" check this class
14799 * for state information if you don't pass them a custom state provider. In order for this class
14800 * to be useful, it must be initialized with a provider when your application initializes.
14802 // in your initialization function
14804 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14806 // supposed you have a {@link Roo.BorderLayout}
14807 var layout = new Roo.BorderLayout(...);
14808 layout.restoreState();
14809 // or a {Roo.BasicDialog}
14810 var dialog = new Roo.BasicDialog(...);
14811 dialog.restoreState();
14815 Roo.state.Manager = function(){
14816 var provider = new Roo.state.Provider();
14820 * Configures the default state provider for your application
14821 * @param {Provider} stateProvider The state provider to set
14823 setProvider : function(stateProvider){
14824 provider = stateProvider;
14828 * Returns the current value for a key
14829 * @param {String} name The key name
14830 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14831 * @return {Mixed} The state data
14833 get : function(key, defaultValue){
14834 return provider.get(key, defaultValue);
14838 * Sets the value for a key
14839 * @param {String} name The key name
14840 * @param {Mixed} value The state data
14842 set : function(key, value){
14843 provider.set(key, value);
14847 * Clears a value from the state
14848 * @param {String} name The key name
14850 clear : function(key){
14851 provider.clear(key);
14855 * Gets the currently configured state provider
14856 * @return {Provider} The state provider
14858 getProvider : function(){
14865 * Ext JS Library 1.1.1
14866 * Copyright(c) 2006-2007, Ext JS, LLC.
14868 * Originally Released Under LGPL - original licence link has changed is not relivant.
14871 * <script type="text/javascript">
14874 * @class Roo.state.CookieProvider
14875 * @extends Roo.state.Provider
14876 * The default Provider implementation which saves state via cookies.
14879 var cp = new Roo.state.CookieProvider({
14881 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14882 domain: "roojs.com"
14884 Roo.state.Manager.setProvider(cp);
14886 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14887 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14888 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14889 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14890 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14891 * domain the page is running on including the 'www' like 'www.roojs.com')
14892 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14894 * Create a new CookieProvider
14895 * @param {Object} config The configuration object
14897 Roo.state.CookieProvider = function(config){
14898 Roo.state.CookieProvider.superclass.constructor.call(this);
14900 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14901 this.domain = null;
14902 this.secure = false;
14903 Roo.apply(this, config);
14904 this.state = this.readCookies();
14907 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14909 set : function(name, value){
14910 if(typeof value == "undefined" || value === null){
14914 this.setCookie(name, value);
14915 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14919 clear : function(name){
14920 this.clearCookie(name);
14921 Roo.state.CookieProvider.superclass.clear.call(this, name);
14925 readCookies : function(){
14927 var c = document.cookie + ";";
14928 var re = /\s?(.*?)=(.*?);/g;
14930 while((matches = re.exec(c)) != null){
14931 var name = matches[1];
14932 var value = matches[2];
14933 if(name && name.substring(0,3) == "ys-"){
14934 cookies[name.substr(3)] = this.decodeValue(value);
14941 setCookie : function(name, value){
14942 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14943 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14944 ((this.path == null) ? "" : ("; path=" + this.path)) +
14945 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14946 ((this.secure == true) ? "; secure" : "");
14950 clearCookie : function(name){
14951 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14952 ((this.path == null) ? "" : ("; path=" + this.path)) +
14953 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14954 ((this.secure == true) ? "; secure" : "");
14958 * Ext JS Library 1.1.1
14959 * Copyright(c) 2006-2007, Ext JS, LLC.
14961 * Originally Released Under LGPL - original licence link has changed is not relivant.
14964 * <script type="text/javascript">
14970 * These classes are derivatives of the similarly named classes in the YUI Library.
14971 * The original license:
14972 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14973 * Code licensed under the BSD License:
14974 * http://developer.yahoo.net/yui/license.txt
14979 var Event=Roo.EventManager;
14980 var Dom=Roo.lib.Dom;
14983 * @class Roo.dd.DragDrop
14984 * @extends Roo.util.Observable
14985 * Defines the interface and base operation of items that that can be
14986 * dragged or can be drop targets. It was designed to be extended, overriding
14987 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14988 * Up to three html elements can be associated with a DragDrop instance:
14990 * <li>linked element: the element that is passed into the constructor.
14991 * This is the element which defines the boundaries for interaction with
14992 * other DragDrop objects.</li>
14993 * <li>handle element(s): The drag operation only occurs if the element that
14994 * was clicked matches a handle element. By default this is the linked
14995 * element, but there are times that you will want only a portion of the
14996 * linked element to initiate the drag operation, and the setHandleElId()
14997 * method provides a way to define this.</li>
14998 * <li>drag element: this represents the element that would be moved along
14999 * with the cursor during a drag operation. By default, this is the linked
15000 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
15001 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
15004 * This class should not be instantiated until the onload event to ensure that
15005 * the associated elements are available.
15006 * The following would define a DragDrop obj that would interact with any
15007 * other DragDrop obj in the "group1" group:
15009 * dd = new Roo.dd.DragDrop("div1", "group1");
15011 * Since none of the event handlers have been implemented, nothing would
15012 * actually happen if you were to run the code above. Normally you would
15013 * override this class or one of the default implementations, but you can
15014 * also override the methods you want on an instance of the class...
15016 * dd.onDragDrop = function(e, id) {
15017 * alert("dd was dropped on " + id);
15021 * @param {String} id of the element that is linked to this instance
15022 * @param {String} sGroup the group of related DragDrop objects
15023 * @param {object} config an object containing configurable attributes
15024 * Valid properties for DragDrop:
15025 * padding, isTarget, maintainOffset, primaryButtonOnly
15027 Roo.dd.DragDrop = function(id, sGroup, config) {
15029 this.init(id, sGroup, config);
15034 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
15037 * The id of the element associated with this object. This is what we
15038 * refer to as the "linked element" because the size and position of
15039 * this element is used to determine when the drag and drop objects have
15047 * Configuration attributes passed into the constructor
15054 * The id of the element that will be dragged. By default this is same
15055 * as the linked element , but could be changed to another element. Ex:
15057 * @property dragElId
15064 * the id of the element that initiates the drag operation. By default
15065 * this is the linked element, but could be changed to be a child of this
15066 * element. This lets us do things like only starting the drag when the
15067 * header element within the linked html element is clicked.
15068 * @property handleElId
15075 * An associative array of HTML tags that will be ignored if clicked.
15076 * @property invalidHandleTypes
15077 * @type {string: string}
15079 invalidHandleTypes: null,
15082 * An associative array of ids for elements that will be ignored if clicked
15083 * @property invalidHandleIds
15084 * @type {string: string}
15086 invalidHandleIds: null,
15089 * An indexted array of css class names for elements that will be ignored
15091 * @property invalidHandleClasses
15094 invalidHandleClasses: null,
15097 * The linked element's absolute X position at the time the drag was
15099 * @property startPageX
15106 * The linked element's absolute X position at the time the drag was
15108 * @property startPageY
15115 * The group defines a logical collection of DragDrop objects that are
15116 * related. Instances only get events when interacting with other
15117 * DragDrop object in the same group. This lets us define multiple
15118 * groups using a single DragDrop subclass if we want.
15120 * @type {string: string}
15125 * Individual drag/drop instances can be locked. This will prevent
15126 * onmousedown start drag.
15134 * Lock this instance
15137 lock: function() { this.locked = true; },
15140 * Unlock this instace
15143 unlock: function() { this.locked = false; },
15146 * By default, all insances can be a drop target. This can be disabled by
15147 * setting isTarget to false.
15154 * The padding configured for this drag and drop object for calculating
15155 * the drop zone intersection with this object.
15162 * Cached reference to the linked element
15163 * @property _domRef
15169 * Internal typeof flag
15170 * @property __ygDragDrop
15173 __ygDragDrop: true,
15176 * Set to true when horizontal contraints are applied
15177 * @property constrainX
15184 * Set to true when vertical contraints are applied
15185 * @property constrainY
15192 * The left constraint
15200 * The right constraint
15208 * The up constraint
15217 * The down constraint
15225 * Maintain offsets when we resetconstraints. Set to true when you want
15226 * the position of the element relative to its parent to stay the same
15227 * when the page changes
15229 * @property maintainOffset
15232 maintainOffset: false,
15235 * Array of pixel locations the element will snap to if we specified a
15236 * horizontal graduation/interval. This array is generated automatically
15237 * when you define a tick interval.
15244 * Array of pixel locations the element will snap to if we specified a
15245 * vertical graduation/interval. This array is generated automatically
15246 * when you define a tick interval.
15253 * By default the drag and drop instance will only respond to the primary
15254 * button click (left button for a right-handed mouse). Set to true to
15255 * allow drag and drop to start with any mouse click that is propogated
15257 * @property primaryButtonOnly
15260 primaryButtonOnly: true,
15263 * The availabe property is false until the linked dom element is accessible.
15264 * @property available
15270 * By default, drags can only be initiated if the mousedown occurs in the
15271 * region the linked element is. This is done in part to work around a
15272 * bug in some browsers that mis-report the mousedown if the previous
15273 * mouseup happened outside of the window. This property is set to true
15274 * if outer handles are defined.
15276 * @property hasOuterHandles
15280 hasOuterHandles: false,
15283 * Code that executes immediately before the startDrag event
15284 * @method b4StartDrag
15287 b4StartDrag: function(x, y) { },
15290 * Abstract method called after a drag/drop object is clicked
15291 * and the drag or mousedown time thresholds have beeen met.
15292 * @method startDrag
15293 * @param {int} X click location
15294 * @param {int} Y click location
15296 startDrag: function(x, y) { /* override this */ },
15299 * Code that executes immediately before the onDrag event
15303 b4Drag: function(e) { },
15306 * Abstract method called during the onMouseMove event while dragging an
15309 * @param {Event} e the mousemove event
15311 onDrag: function(e) { /* override this */ },
15314 * Abstract method called when this element fist begins hovering over
15315 * another DragDrop obj
15316 * @method onDragEnter
15317 * @param {Event} e the mousemove event
15318 * @param {String|DragDrop[]} id In POINT mode, the element
15319 * id this is hovering over. In INTERSECT mode, an array of one or more
15320 * dragdrop items being hovered over.
15322 onDragEnter: function(e, id) { /* override this */ },
15325 * Code that executes immediately before the onDragOver event
15326 * @method b4DragOver
15329 b4DragOver: function(e) { },
15332 * Abstract method called when this element is hovering over another
15334 * @method onDragOver
15335 * @param {Event} e the mousemove event
15336 * @param {String|DragDrop[]} id In POINT mode, the element
15337 * id this is hovering over. In INTERSECT mode, an array of dd items
15338 * being hovered over.
15340 onDragOver: function(e, id) { /* override this */ },
15343 * Code that executes immediately before the onDragOut event
15344 * @method b4DragOut
15347 b4DragOut: function(e) { },
15350 * Abstract method called when we are no longer hovering over an element
15351 * @method onDragOut
15352 * @param {Event} e the mousemove event
15353 * @param {String|DragDrop[]} id In POINT mode, the element
15354 * id this was hovering over. In INTERSECT mode, an array of dd items
15355 * that the mouse is no longer over.
15357 onDragOut: function(e, id) { /* override this */ },
15360 * Code that executes immediately before the onDragDrop event
15361 * @method b4DragDrop
15364 b4DragDrop: function(e) { },
15367 * Abstract method called when this item is dropped on another DragDrop
15369 * @method onDragDrop
15370 * @param {Event} e the mouseup event
15371 * @param {String|DragDrop[]} id In POINT mode, the element
15372 * id this was dropped on. In INTERSECT mode, an array of dd items this
15375 onDragDrop: function(e, id) { /* override this */ },
15378 * Abstract method called when this item is dropped on an area with no
15380 * @method onInvalidDrop
15381 * @param {Event} e the mouseup event
15383 onInvalidDrop: function(e) { /* override this */ },
15386 * Code that executes immediately before the endDrag event
15387 * @method b4EndDrag
15390 b4EndDrag: function(e) { },
15393 * Fired when we are done dragging the object
15395 * @param {Event} e the mouseup event
15397 endDrag: function(e) { /* override this */ },
15400 * Code executed immediately before the onMouseDown event
15401 * @method b4MouseDown
15402 * @param {Event} e the mousedown event
15405 b4MouseDown: function(e) { },
15408 * Event handler that fires when a drag/drop obj gets a mousedown
15409 * @method onMouseDown
15410 * @param {Event} e the mousedown event
15412 onMouseDown: function(e) { /* override this */ },
15415 * Event handler that fires when a drag/drop obj gets a mouseup
15416 * @method onMouseUp
15417 * @param {Event} e the mouseup event
15419 onMouseUp: function(e) { /* override this */ },
15422 * Override the onAvailable method to do what is needed after the initial
15423 * position was determined.
15424 * @method onAvailable
15426 onAvailable: function () {
15430 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
15433 defaultPadding : {left:0, right:0, top:0, bottom:0},
15436 * Initializes the drag drop object's constraints to restrict movement to a certain element.
15440 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
15441 { dragElId: "existingProxyDiv" });
15442 dd.startDrag = function(){
15443 this.constrainTo("parent-id");
15446 * Or you can initalize it using the {@link Roo.Element} object:
15448 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
15449 startDrag : function(){
15450 this.constrainTo("parent-id");
15454 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
15455 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
15456 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
15457 * an object containing the sides to pad. For example: {right:10, bottom:10}
15458 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
15460 constrainTo : function(constrainTo, pad, inContent){
15461 if(typeof pad == "number"){
15462 pad = {left: pad, right:pad, top:pad, bottom:pad};
15464 pad = pad || this.defaultPadding;
15465 var b = Roo.get(this.getEl()).getBox();
15466 var ce = Roo.get(constrainTo);
15467 var s = ce.getScroll();
15468 var c, cd = ce.dom;
15469 if(cd == document.body){
15470 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
15473 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
15477 var topSpace = b.y - c.y;
15478 var leftSpace = b.x - c.x;
15480 this.resetConstraints();
15481 this.setXConstraint(leftSpace - (pad.left||0), // left
15482 c.width - leftSpace - b.width - (pad.right||0) //right
15484 this.setYConstraint(topSpace - (pad.top||0), //top
15485 c.height - topSpace - b.height - (pad.bottom||0) //bottom
15490 * Returns a reference to the linked element
15492 * @return {HTMLElement} the html element
15494 getEl: function() {
15495 if (!this._domRef) {
15496 this._domRef = Roo.getDom(this.id);
15499 return this._domRef;
15503 * Returns a reference to the actual element to drag. By default this is
15504 * the same as the html element, but it can be assigned to another
15505 * element. An example of this can be found in Roo.dd.DDProxy
15506 * @method getDragEl
15507 * @return {HTMLElement} the html element
15509 getDragEl: function() {
15510 return Roo.getDom(this.dragElId);
15514 * Sets up the DragDrop object. Must be called in the constructor of any
15515 * Roo.dd.DragDrop subclass
15517 * @param id the id of the linked element
15518 * @param {String} sGroup the group of related items
15519 * @param {object} config configuration attributes
15521 init: function(id, sGroup, config) {
15522 this.initTarget(id, sGroup, config);
15523 if (!Roo.isTouch) {
15524 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15526 Event.on(this.id, "touchstart", this.handleMouseDown, this);
15527 // Event.on(this.id, "selectstart", Event.preventDefault);
15531 * Initializes Targeting functionality only... the object does not
15532 * get a mousedown handler.
15533 * @method initTarget
15534 * @param id the id of the linked element
15535 * @param {String} sGroup the group of related items
15536 * @param {object} config configuration attributes
15538 initTarget: function(id, sGroup, config) {
15540 // configuration attributes
15541 this.config = config || {};
15543 // create a local reference to the drag and drop manager
15544 this.DDM = Roo.dd.DDM;
15545 // initialize the groups array
15548 // assume that we have an element reference instead of an id if the
15549 // parameter is not a string
15550 if (typeof id !== "string") {
15557 // add to an interaction group
15558 this.addToGroup((sGroup) ? sGroup : "default");
15560 // We don't want to register this as the handle with the manager
15561 // so we just set the id rather than calling the setter.
15562 this.handleElId = id;
15564 // the linked element is the element that gets dragged by default
15565 this.setDragElId(id);
15567 // by default, clicked anchors will not start drag operations.
15568 this.invalidHandleTypes = { A: "A" };
15569 this.invalidHandleIds = {};
15570 this.invalidHandleClasses = [];
15572 this.applyConfig();
15574 this.handleOnAvailable();
15578 * Applies the configuration parameters that were passed into the constructor.
15579 * This is supposed to happen at each level through the inheritance chain. So
15580 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15581 * DragDrop in order to get all of the parameters that are available in
15583 * @method applyConfig
15585 applyConfig: function() {
15587 // configurable properties:
15588 // padding, isTarget, maintainOffset, primaryButtonOnly
15589 this.padding = this.config.padding || [0, 0, 0, 0];
15590 this.isTarget = (this.config.isTarget !== false);
15591 this.maintainOffset = (this.config.maintainOffset);
15592 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15597 * Executed when the linked element is available
15598 * @method handleOnAvailable
15601 handleOnAvailable: function() {
15602 this.available = true;
15603 this.resetConstraints();
15604 this.onAvailable();
15608 * Configures the padding for the target zone in px. Effectively expands
15609 * (or reduces) the virtual object size for targeting calculations.
15610 * Supports css-style shorthand; if only one parameter is passed, all sides
15611 * will have that padding, and if only two are passed, the top and bottom
15612 * will have the first param, the left and right the second.
15613 * @method setPadding
15614 * @param {int} iTop Top pad
15615 * @param {int} iRight Right pad
15616 * @param {int} iBot Bot pad
15617 * @param {int} iLeft Left pad
15619 setPadding: function(iTop, iRight, iBot, iLeft) {
15620 // this.padding = [iLeft, iRight, iTop, iBot];
15621 if (!iRight && 0 !== iRight) {
15622 this.padding = [iTop, iTop, iTop, iTop];
15623 } else if (!iBot && 0 !== iBot) {
15624 this.padding = [iTop, iRight, iTop, iRight];
15626 this.padding = [iTop, iRight, iBot, iLeft];
15631 * Stores the initial placement of the linked element.
15632 * @method setInitialPosition
15633 * @param {int} diffX the X offset, default 0
15634 * @param {int} diffY the Y offset, default 0
15636 setInitPosition: function(diffX, diffY) {
15637 var el = this.getEl();
15639 if (!this.DDM.verifyEl(el)) {
15643 var dx = diffX || 0;
15644 var dy = diffY || 0;
15646 var p = Dom.getXY( el );
15648 this.initPageX = p[0] - dx;
15649 this.initPageY = p[1] - dy;
15651 this.lastPageX = p[0];
15652 this.lastPageY = p[1];
15655 this.setStartPosition(p);
15659 * Sets the start position of the element. This is set when the obj
15660 * is initialized, the reset when a drag is started.
15661 * @method setStartPosition
15662 * @param pos current position (from previous lookup)
15665 setStartPosition: function(pos) {
15666 var p = pos || Dom.getXY( this.getEl() );
15667 this.deltaSetXY = null;
15669 this.startPageX = p[0];
15670 this.startPageY = p[1];
15674 * Add this instance to a group of related drag/drop objects. All
15675 * instances belong to at least one group, and can belong to as many
15676 * groups as needed.
15677 * @method addToGroup
15678 * @param sGroup {string} the name of the group
15680 addToGroup: function(sGroup) {
15681 this.groups[sGroup] = true;
15682 this.DDM.regDragDrop(this, sGroup);
15686 * Remove's this instance from the supplied interaction group
15687 * @method removeFromGroup
15688 * @param {string} sGroup The group to drop
15690 removeFromGroup: function(sGroup) {
15691 if (this.groups[sGroup]) {
15692 delete this.groups[sGroup];
15695 this.DDM.removeDDFromGroup(this, sGroup);
15699 * Allows you to specify that an element other than the linked element
15700 * will be moved with the cursor during a drag
15701 * @method setDragElId
15702 * @param id {string} the id of the element that will be used to initiate the drag
15704 setDragElId: function(id) {
15705 this.dragElId = id;
15709 * Allows you to specify a child of the linked element that should be
15710 * used to initiate the drag operation. An example of this would be if
15711 * you have a content div with text and links. Clicking anywhere in the
15712 * content area would normally start the drag operation. Use this method
15713 * to specify that an element inside of the content div is the element
15714 * that starts the drag operation.
15715 * @method setHandleElId
15716 * @param id {string} the id of the element that will be used to
15717 * initiate the drag.
15719 setHandleElId: function(id) {
15720 if (typeof id !== "string") {
15723 this.handleElId = id;
15724 this.DDM.regHandle(this.id, id);
15728 * Allows you to set an element outside of the linked element as a drag
15730 * @method setOuterHandleElId
15731 * @param id the id of the element that will be used to initiate the drag
15733 setOuterHandleElId: function(id) {
15734 if (typeof id !== "string") {
15737 Event.on(id, "mousedown",
15738 this.handleMouseDown, this);
15739 this.setHandleElId(id);
15741 this.hasOuterHandles = true;
15745 * Remove all drag and drop hooks for this element
15748 unreg: function() {
15749 Event.un(this.id, "mousedown",
15750 this.handleMouseDown);
15751 Event.un(this.id, "touchstart",
15752 this.handleMouseDown);
15753 this._domRef = null;
15754 this.DDM._remove(this);
15757 destroy : function(){
15762 * Returns true if this instance is locked, or the drag drop mgr is locked
15763 * (meaning that all drag/drop is disabled on the page.)
15765 * @return {boolean} true if this obj or all drag/drop is locked, else
15768 isLocked: function() {
15769 return (this.DDM.isLocked() || this.locked);
15773 * Fired when this object is clicked
15774 * @method handleMouseDown
15776 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15779 handleMouseDown: function(e, oDD){
15781 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
15782 //Roo.log('not touch/ button !=0');
15785 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
15786 return; // double touch..
15790 if (this.isLocked()) {
15791 //Roo.log('locked');
15795 this.DDM.refreshCache(this.groups);
15796 Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
15797 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15798 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15799 //Roo.log('no outer handes or not over target');
15802 Roo.log('check validator');
15803 if (this.clickValidator(e)) {
15804 Roo.log('validate success');
15805 // set the initial element position
15806 this.setStartPosition();
15809 this.b4MouseDown(e);
15810 this.onMouseDown(e);
15812 this.DDM.handleMouseDown(e, this);
15814 this.DDM.stopEvent(e);
15822 clickValidator: function(e) {
15823 var target = e.getTarget();
15824 return ( this.isValidHandleChild(target) &&
15825 (this.id == this.handleElId ||
15826 this.DDM.handleWasClicked(target, this.id)) );
15830 * Allows you to specify a tag name that should not start a drag operation
15831 * when clicked. This is designed to facilitate embedding links within a
15832 * drag handle that do something other than start the drag.
15833 * @method addInvalidHandleType
15834 * @param {string} tagName the type of element to exclude
15836 addInvalidHandleType: function(tagName) {
15837 var type = tagName.toUpperCase();
15838 this.invalidHandleTypes[type] = type;
15842 * Lets you to specify an element id for a child of a drag handle
15843 * that should not initiate a drag
15844 * @method addInvalidHandleId
15845 * @param {string} id the element id of the element you wish to ignore
15847 addInvalidHandleId: function(id) {
15848 if (typeof id !== "string") {
15851 this.invalidHandleIds[id] = id;
15855 * Lets you specify a css class of elements that will not initiate a drag
15856 * @method addInvalidHandleClass
15857 * @param {string} cssClass the class of the elements you wish to ignore
15859 addInvalidHandleClass: function(cssClass) {
15860 this.invalidHandleClasses.push(cssClass);
15864 * Unsets an excluded tag name set by addInvalidHandleType
15865 * @method removeInvalidHandleType
15866 * @param {string} tagName the type of element to unexclude
15868 removeInvalidHandleType: function(tagName) {
15869 var type = tagName.toUpperCase();
15870 // this.invalidHandleTypes[type] = null;
15871 delete this.invalidHandleTypes[type];
15875 * Unsets an invalid handle id
15876 * @method removeInvalidHandleId
15877 * @param {string} id the id of the element to re-enable
15879 removeInvalidHandleId: function(id) {
15880 if (typeof id !== "string") {
15883 delete this.invalidHandleIds[id];
15887 * Unsets an invalid css class
15888 * @method removeInvalidHandleClass
15889 * @param {string} cssClass the class of the element(s) you wish to
15892 removeInvalidHandleClass: function(cssClass) {
15893 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15894 if (this.invalidHandleClasses[i] == cssClass) {
15895 delete this.invalidHandleClasses[i];
15901 * Checks the tag exclusion list to see if this click should be ignored
15902 * @method isValidHandleChild
15903 * @param {HTMLElement} node the HTMLElement to evaluate
15904 * @return {boolean} true if this is a valid tag type, false if not
15906 isValidHandleChild: function(node) {
15909 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15912 nodeName = node.nodeName.toUpperCase();
15914 nodeName = node.nodeName;
15916 valid = valid && !this.invalidHandleTypes[nodeName];
15917 valid = valid && !this.invalidHandleIds[node.id];
15919 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15920 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15929 * Create the array of horizontal tick marks if an interval was specified
15930 * in setXConstraint().
15931 * @method setXTicks
15934 setXTicks: function(iStartX, iTickSize) {
15936 this.xTickSize = iTickSize;
15940 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15942 this.xTicks[this.xTicks.length] = i;
15947 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15949 this.xTicks[this.xTicks.length] = i;
15954 this.xTicks.sort(this.DDM.numericSort) ;
15958 * Create the array of vertical tick marks if an interval was specified in
15959 * setYConstraint().
15960 * @method setYTicks
15963 setYTicks: function(iStartY, iTickSize) {
15965 this.yTickSize = iTickSize;
15969 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15971 this.yTicks[this.yTicks.length] = i;
15976 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15978 this.yTicks[this.yTicks.length] = i;
15983 this.yTicks.sort(this.DDM.numericSort) ;
15987 * By default, the element can be dragged any place on the screen. Use
15988 * this method to limit the horizontal travel of the element. Pass in
15989 * 0,0 for the parameters if you want to lock the drag to the y axis.
15990 * @method setXConstraint
15991 * @param {int} iLeft the number of pixels the element can move to the left
15992 * @param {int} iRight the number of pixels the element can move to the
15994 * @param {int} iTickSize optional parameter for specifying that the
15996 * should move iTickSize pixels at a time.
15998 setXConstraint: function(iLeft, iRight, iTickSize) {
15999 this.leftConstraint = iLeft;
16000 this.rightConstraint = iRight;
16002 this.minX = this.initPageX - iLeft;
16003 this.maxX = this.initPageX + iRight;
16004 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
16006 this.constrainX = true;
16010 * Clears any constraints applied to this instance. Also clears ticks
16011 * since they can't exist independent of a constraint at this time.
16012 * @method clearConstraints
16014 clearConstraints: function() {
16015 this.constrainX = false;
16016 this.constrainY = false;
16021 * Clears any tick interval defined for this instance
16022 * @method clearTicks
16024 clearTicks: function() {
16025 this.xTicks = null;
16026 this.yTicks = null;
16027 this.xTickSize = 0;
16028 this.yTickSize = 0;
16032 * By default, the element can be dragged any place on the screen. Set
16033 * this to limit the vertical travel of the element. Pass in 0,0 for the
16034 * parameters if you want to lock the drag to the x axis.
16035 * @method setYConstraint
16036 * @param {int} iUp the number of pixels the element can move up
16037 * @param {int} iDown the number of pixels the element can move down
16038 * @param {int} iTickSize optional parameter for specifying that the
16039 * element should move iTickSize pixels at a time.
16041 setYConstraint: function(iUp, iDown, iTickSize) {
16042 this.topConstraint = iUp;
16043 this.bottomConstraint = iDown;
16045 this.minY = this.initPageY - iUp;
16046 this.maxY = this.initPageY + iDown;
16047 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
16049 this.constrainY = true;
16054 * resetConstraints must be called if you manually reposition a dd element.
16055 * @method resetConstraints
16056 * @param {boolean} maintainOffset
16058 resetConstraints: function() {
16061 // Maintain offsets if necessary
16062 if (this.initPageX || this.initPageX === 0) {
16063 // figure out how much this thing has moved
16064 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
16065 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
16067 this.setInitPosition(dx, dy);
16069 // This is the first time we have detected the element's position
16071 this.setInitPosition();
16074 if (this.constrainX) {
16075 this.setXConstraint( this.leftConstraint,
16076 this.rightConstraint,
16080 if (this.constrainY) {
16081 this.setYConstraint( this.topConstraint,
16082 this.bottomConstraint,
16088 * Normally the drag element is moved pixel by pixel, but we can specify
16089 * that it move a number of pixels at a time. This method resolves the
16090 * location when we have it set up like this.
16092 * @param {int} val where we want to place the object
16093 * @param {int[]} tickArray sorted array of valid points
16094 * @return {int} the closest tick
16097 getTick: function(val, tickArray) {
16100 // If tick interval is not defined, it is effectively 1 pixel,
16101 // so we return the value passed to us.
16103 } else if (tickArray[0] >= val) {
16104 // The value is lower than the first tick, so we return the first
16106 return tickArray[0];
16108 for (var i=0, len=tickArray.length; i<len; ++i) {
16110 if (tickArray[next] && tickArray[next] >= val) {
16111 var diff1 = val - tickArray[i];
16112 var diff2 = tickArray[next] - val;
16113 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
16117 // The value is larger than the last tick, so we return the last
16119 return tickArray[tickArray.length - 1];
16126 * @return {string} string representation of the dd obj
16128 toString: function() {
16129 return ("DragDrop " + this.id);
16137 * Ext JS Library 1.1.1
16138 * Copyright(c) 2006-2007, Ext JS, LLC.
16140 * Originally Released Under LGPL - original licence link has changed is not relivant.
16143 * <script type="text/javascript">
16148 * The drag and drop utility provides a framework for building drag and drop
16149 * applications. In addition to enabling drag and drop for specific elements,
16150 * the drag and drop elements are tracked by the manager class, and the
16151 * interactions between the various elements are tracked during the drag and
16152 * the implementing code is notified about these important moments.
16155 // Only load the library once. Rewriting the manager class would orphan
16156 // existing drag and drop instances.
16157 if (!Roo.dd.DragDropMgr) {
16160 * @class Roo.dd.DragDropMgr
16161 * DragDropMgr is a singleton that tracks the element interaction for
16162 * all DragDrop items in the window. Generally, you will not call
16163 * this class directly, but it does have helper methods that could
16164 * be useful in your DragDrop implementations.
16167 Roo.dd.DragDropMgr = function() {
16169 var Event = Roo.EventManager;
16174 * Two dimensional Array of registered DragDrop objects. The first
16175 * dimension is the DragDrop item group, the second the DragDrop
16178 * @type {string: string}
16185 * Array of element ids defined as drag handles. Used to determine
16186 * if the element that generated the mousedown event is actually the
16187 * handle and not the html element itself.
16188 * @property handleIds
16189 * @type {string: string}
16196 * the DragDrop object that is currently being dragged
16197 * @property dragCurrent
16205 * the DragDrop object(s) that are being hovered over
16206 * @property dragOvers
16214 * the X distance between the cursor and the object being dragged
16223 * the Y distance between the cursor and the object being dragged
16232 * Flag to determine if we should prevent the default behavior of the
16233 * events we define. By default this is true, but this can be set to
16234 * false if you need the default behavior (not recommended)
16235 * @property preventDefault
16239 preventDefault: true,
16242 * Flag to determine if we should stop the propagation of the events
16243 * we generate. This is true by default but you may want to set it to
16244 * false if the html element contains other features that require the
16246 * @property stopPropagation
16250 stopPropagation: true,
16253 * Internal flag that is set to true when drag and drop has been
16255 * @property initialized
16262 * All drag and drop can be disabled.
16270 * Called the first time an element is registered.
16276 this.initialized = true;
16280 * In point mode, drag and drop interaction is defined by the
16281 * location of the cursor during the drag/drop
16289 * In intersect mode, drag and drop interactio nis defined by the
16290 * overlap of two or more drag and drop objects.
16291 * @property INTERSECT
16298 * The current drag and drop mode. Default: POINT
16306 * Runs method on all drag and drop objects
16307 * @method _execOnAll
16311 _execOnAll: function(sMethod, args) {
16312 for (var i in this.ids) {
16313 for (var j in this.ids[i]) {
16314 var oDD = this.ids[i][j];
16315 if (! this.isTypeOfDD(oDD)) {
16318 oDD[sMethod].apply(oDD, args);
16324 * Drag and drop initialization. Sets up the global event handlers
16329 _onLoad: function() {
16333 if (!Roo.isTouch) {
16334 Event.on(document, "mouseup", this.handleMouseUp, this, true);
16335 Event.on(document, "mousemove", this.handleMouseMove, this, true);
16337 Event.on(document, "touchend", this.handleMouseUp, this, true);
16338 Event.on(document, "touchmove", this.handleMouseMove, this, true);
16340 Event.on(window, "unload", this._onUnload, this, true);
16341 Event.on(window, "resize", this._onResize, this, true);
16342 // Event.on(window, "mouseout", this._test);
16347 * Reset constraints on all drag and drop objs
16348 * @method _onResize
16352 _onResize: function(e) {
16353 this._execOnAll("resetConstraints", []);
16357 * Lock all drag and drop functionality
16361 lock: function() { this.locked = true; },
16364 * Unlock all drag and drop functionality
16368 unlock: function() { this.locked = false; },
16371 * Is drag and drop locked?
16373 * @return {boolean} True if drag and drop is locked, false otherwise.
16376 isLocked: function() { return this.locked; },
16379 * Location cache that is set for all drag drop objects when a drag is
16380 * initiated, cleared when the drag is finished.
16381 * @property locationCache
16388 * Set useCache to false if you want to force object the lookup of each
16389 * drag and drop linked element constantly during a drag.
16390 * @property useCache
16397 * The number of pixels that the mouse needs to move after the
16398 * mousedown before the drag is initiated. Default=3;
16399 * @property clickPixelThresh
16403 clickPixelThresh: 3,
16406 * The number of milliseconds after the mousedown event to initiate the
16407 * drag if we don't get a mouseup event. Default=1000
16408 * @property clickTimeThresh
16412 clickTimeThresh: 350,
16415 * Flag that indicates that either the drag pixel threshold or the
16416 * mousdown time threshold has been met
16417 * @property dragThreshMet
16422 dragThreshMet: false,
16425 * Timeout used for the click time threshold
16426 * @property clickTimeout
16431 clickTimeout: null,
16434 * The X position of the mousedown event stored for later use when a
16435 * drag threshold is met.
16444 * The Y position of the mousedown event stored for later use when a
16445 * drag threshold is met.
16454 * Each DragDrop instance must be registered with the DragDropMgr.
16455 * This is executed in DragDrop.init()
16456 * @method regDragDrop
16457 * @param {DragDrop} oDD the DragDrop object to register
16458 * @param {String} sGroup the name of the group this element belongs to
16461 regDragDrop: function(oDD, sGroup) {
16462 if (!this.initialized) { this.init(); }
16464 if (!this.ids[sGroup]) {
16465 this.ids[sGroup] = {};
16467 this.ids[sGroup][oDD.id] = oDD;
16471 * Removes the supplied dd instance from the supplied group. Executed
16472 * by DragDrop.removeFromGroup, so don't call this function directly.
16473 * @method removeDDFromGroup
16477 removeDDFromGroup: function(oDD, sGroup) {
16478 if (!this.ids[sGroup]) {
16479 this.ids[sGroup] = {};
16482 var obj = this.ids[sGroup];
16483 if (obj && obj[oDD.id]) {
16484 delete obj[oDD.id];
16489 * Unregisters a drag and drop item. This is executed in
16490 * DragDrop.unreg, use that method instead of calling this directly.
16495 _remove: function(oDD) {
16496 for (var g in oDD.groups) {
16497 if (g && this.ids[g][oDD.id]) {
16498 delete this.ids[g][oDD.id];
16501 delete this.handleIds[oDD.id];
16505 * Each DragDrop handle element must be registered. This is done
16506 * automatically when executing DragDrop.setHandleElId()
16507 * @method regHandle
16508 * @param {String} sDDId the DragDrop id this element is a handle for
16509 * @param {String} sHandleId the id of the element that is the drag
16513 regHandle: function(sDDId, sHandleId) {
16514 if (!this.handleIds[sDDId]) {
16515 this.handleIds[sDDId] = {};
16517 this.handleIds[sDDId][sHandleId] = sHandleId;
16521 * Utility function to determine if a given element has been
16522 * registered as a drag drop item.
16523 * @method isDragDrop
16524 * @param {String} id the element id to check
16525 * @return {boolean} true if this element is a DragDrop item,
16529 isDragDrop: function(id) {
16530 return ( this.getDDById(id) ) ? true : false;
16534 * Returns the drag and drop instances that are in all groups the
16535 * passed in instance belongs to.
16536 * @method getRelated
16537 * @param {DragDrop} p_oDD the obj to get related data for
16538 * @param {boolean} bTargetsOnly if true, only return targetable objs
16539 * @return {DragDrop[]} the related instances
16542 getRelated: function(p_oDD, bTargetsOnly) {
16544 for (var i in p_oDD.groups) {
16545 for (j in this.ids[i]) {
16546 var dd = this.ids[i][j];
16547 if (! this.isTypeOfDD(dd)) {
16550 if (!bTargetsOnly || dd.isTarget) {
16551 oDDs[oDDs.length] = dd;
16560 * Returns true if the specified dd target is a legal target for
16561 * the specifice drag obj
16562 * @method isLegalTarget
16563 * @param {DragDrop} the drag obj
16564 * @param {DragDrop} the target
16565 * @return {boolean} true if the target is a legal target for the
16569 isLegalTarget: function (oDD, oTargetDD) {
16570 var targets = this.getRelated(oDD, true);
16571 for (var i=0, len=targets.length;i<len;++i) {
16572 if (targets[i].id == oTargetDD.id) {
16581 * My goal is to be able to transparently determine if an object is
16582 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16583 * returns "object", oDD.constructor.toString() always returns
16584 * "DragDrop" and not the name of the subclass. So for now it just
16585 * evaluates a well-known variable in DragDrop.
16586 * @method isTypeOfDD
16587 * @param {Object} the object to evaluate
16588 * @return {boolean} true if typeof oDD = DragDrop
16591 isTypeOfDD: function (oDD) {
16592 return (oDD && oDD.__ygDragDrop);
16596 * Utility function to determine if a given element has been
16597 * registered as a drag drop handle for the given Drag Drop object.
16599 * @param {String} id the element id to check
16600 * @return {boolean} true if this element is a DragDrop handle, false
16604 isHandle: function(sDDId, sHandleId) {
16605 return ( this.handleIds[sDDId] &&
16606 this.handleIds[sDDId][sHandleId] );
16610 * Returns the DragDrop instance for a given id
16611 * @method getDDById
16612 * @param {String} id the id of the DragDrop object
16613 * @return {DragDrop} the drag drop object, null if it is not found
16616 getDDById: function(id) {
16617 for (var i in this.ids) {
16618 if (this.ids[i][id]) {
16619 return this.ids[i][id];
16626 * Fired after a registered DragDrop object gets the mousedown event.
16627 * Sets up the events required to track the object being dragged
16628 * @method handleMouseDown
16629 * @param {Event} e the event
16630 * @param oDD the DragDrop object being dragged
16634 handleMouseDown: function(e, oDD) {
16636 Roo.QuickTips.disable();
16638 this.currentTarget = e.getTarget();
16640 this.dragCurrent = oDD;
16642 var el = oDD.getEl();
16644 // track start position
16645 this.startX = e.getPageX();
16646 this.startY = e.getPageY();
16648 this.deltaX = this.startX - el.offsetLeft;
16649 this.deltaY = this.startY - el.offsetTop;
16651 this.dragThreshMet = false;
16653 this.clickTimeout = setTimeout(
16655 var DDM = Roo.dd.DDM;
16656 DDM.startDrag(DDM.startX, DDM.startY);
16658 this.clickTimeThresh );
16662 * Fired when either the drag pixel threshol or the mousedown hold
16663 * time threshold has been met.
16664 * @method startDrag
16665 * @param x {int} the X position of the original mousedown
16666 * @param y {int} the Y position of the original mousedown
16669 startDrag: function(x, y) {
16670 clearTimeout(this.clickTimeout);
16671 if (this.dragCurrent) {
16672 this.dragCurrent.b4StartDrag(x, y);
16673 this.dragCurrent.startDrag(x, y);
16675 this.dragThreshMet = true;
16679 * Internal function to handle the mouseup event. Will be invoked
16680 * from the context of the document.
16681 * @method handleMouseUp
16682 * @param {Event} e the event
16686 handleMouseUp: function(e) {
16689 Roo.QuickTips.enable();
16691 if (! this.dragCurrent) {
16695 clearTimeout(this.clickTimeout);
16697 if (this.dragThreshMet) {
16698 this.fireEvents(e, true);
16708 * Utility to stop event propagation and event default, if these
16709 * features are turned on.
16710 * @method stopEvent
16711 * @param {Event} e the event as returned by this.getEvent()
16714 stopEvent: function(e){
16715 if(this.stopPropagation) {
16716 e.stopPropagation();
16719 if (this.preventDefault) {
16720 e.preventDefault();
16725 * Internal function to clean up event handlers after the drag
16726 * operation is complete
16728 * @param {Event} e the event
16732 stopDrag: function(e) {
16733 // Fire the drag end event for the item that was dragged
16734 if (this.dragCurrent) {
16735 if (this.dragThreshMet) {
16736 this.dragCurrent.b4EndDrag(e);
16737 this.dragCurrent.endDrag(e);
16740 this.dragCurrent.onMouseUp(e);
16743 this.dragCurrent = null;
16744 this.dragOvers = {};
16748 * Internal function to handle the mousemove event. Will be invoked
16749 * from the context of the html element.
16751 * @TODO figure out what we can do about mouse events lost when the
16752 * user drags objects beyond the window boundary. Currently we can
16753 * detect this in internet explorer by verifying that the mouse is
16754 * down during the mousemove event. Firefox doesn't give us the
16755 * button state on the mousemove event.
16756 * @method handleMouseMove
16757 * @param {Event} e the event
16761 handleMouseMove: function(e) {
16762 if (! this.dragCurrent) {
16766 // var button = e.which || e.button;
16768 // check for IE mouseup outside of page boundary
16769 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16771 return this.handleMouseUp(e);
16774 if (!this.dragThreshMet) {
16775 var diffX = Math.abs(this.startX - e.getPageX());
16776 var diffY = Math.abs(this.startY - e.getPageY());
16777 if (diffX > this.clickPixelThresh ||
16778 diffY > this.clickPixelThresh) {
16779 this.startDrag(this.startX, this.startY);
16783 if (this.dragThreshMet) {
16784 this.dragCurrent.b4Drag(e);
16785 this.dragCurrent.onDrag(e);
16786 if(!this.dragCurrent.moveOnly){
16787 this.fireEvents(e, false);
16797 * Iterates over all of the DragDrop elements to find ones we are
16798 * hovering over or dropping on
16799 * @method fireEvents
16800 * @param {Event} e the event
16801 * @param {boolean} isDrop is this a drop op or a mouseover op?
16805 fireEvents: function(e, isDrop) {
16806 var dc = this.dragCurrent;
16808 // If the user did the mouse up outside of the window, we could
16809 // get here even though we have ended the drag.
16810 if (!dc || dc.isLocked()) {
16814 var pt = e.getPoint();
16816 // cache the previous dragOver array
16822 var enterEvts = [];
16824 // Check to see if the object(s) we were hovering over is no longer
16825 // being hovered over so we can fire the onDragOut event
16826 for (var i in this.dragOvers) {
16828 var ddo = this.dragOvers[i];
16830 if (! this.isTypeOfDD(ddo)) {
16834 if (! this.isOverTarget(pt, ddo, this.mode)) {
16835 outEvts.push( ddo );
16838 oldOvers[i] = true;
16839 delete this.dragOvers[i];
16842 for (var sGroup in dc.groups) {
16844 if ("string" != typeof sGroup) {
16848 for (i in this.ids[sGroup]) {
16849 var oDD = this.ids[sGroup][i];
16850 if (! this.isTypeOfDD(oDD)) {
16854 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16855 if (this.isOverTarget(pt, oDD, this.mode)) {
16856 // look for drop interactions
16858 dropEvts.push( oDD );
16859 // look for drag enter and drag over interactions
16862 // initial drag over: dragEnter fires
16863 if (!oldOvers[oDD.id]) {
16864 enterEvts.push( oDD );
16865 // subsequent drag overs: dragOver fires
16867 overEvts.push( oDD );
16870 this.dragOvers[oDD.id] = oDD;
16878 if (outEvts.length) {
16879 dc.b4DragOut(e, outEvts);
16880 dc.onDragOut(e, outEvts);
16883 if (enterEvts.length) {
16884 dc.onDragEnter(e, enterEvts);
16887 if (overEvts.length) {
16888 dc.b4DragOver(e, overEvts);
16889 dc.onDragOver(e, overEvts);
16892 if (dropEvts.length) {
16893 dc.b4DragDrop(e, dropEvts);
16894 dc.onDragDrop(e, dropEvts);
16898 // fire dragout events
16900 for (i=0, len=outEvts.length; i<len; ++i) {
16901 dc.b4DragOut(e, outEvts[i].id);
16902 dc.onDragOut(e, outEvts[i].id);
16905 // fire enter events
16906 for (i=0,len=enterEvts.length; i<len; ++i) {
16907 // dc.b4DragEnter(e, oDD.id);
16908 dc.onDragEnter(e, enterEvts[i].id);
16911 // fire over events
16912 for (i=0,len=overEvts.length; i<len; ++i) {
16913 dc.b4DragOver(e, overEvts[i].id);
16914 dc.onDragOver(e, overEvts[i].id);
16917 // fire drop events
16918 for (i=0, len=dropEvts.length; i<len; ++i) {
16919 dc.b4DragDrop(e, dropEvts[i].id);
16920 dc.onDragDrop(e, dropEvts[i].id);
16925 // notify about a drop that did not find a target
16926 if (isDrop && !dropEvts.length) {
16927 dc.onInvalidDrop(e);
16933 * Helper function for getting the best match from the list of drag
16934 * and drop objects returned by the drag and drop events when we are
16935 * in INTERSECT mode. It returns either the first object that the
16936 * cursor is over, or the object that has the greatest overlap with
16937 * the dragged element.
16938 * @method getBestMatch
16939 * @param {DragDrop[]} dds The array of drag and drop objects
16941 * @return {DragDrop} The best single match
16944 getBestMatch: function(dds) {
16946 // Return null if the input is not what we expect
16947 //if (!dds || !dds.length || dds.length == 0) {
16949 // If there is only one item, it wins
16950 //} else if (dds.length == 1) {
16952 var len = dds.length;
16957 // Loop through the targeted items
16958 for (var i=0; i<len; ++i) {
16960 // If the cursor is over the object, it wins. If the
16961 // cursor is over multiple matches, the first one we come
16963 if (dd.cursorIsOver) {
16966 // Otherwise the object with the most overlap wins
16969 winner.overlap.getArea() < dd.overlap.getArea()) {
16980 * Refreshes the cache of the top-left and bottom-right points of the
16981 * drag and drop objects in the specified group(s). This is in the
16982 * format that is stored in the drag and drop instance, so typical
16985 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16989 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16991 * @TODO this really should be an indexed array. Alternatively this
16992 * method could accept both.
16993 * @method refreshCache
16994 * @param {Object} groups an associative array of groups to refresh
16997 refreshCache: function(groups) {
16998 for (var sGroup in groups) {
16999 if ("string" != typeof sGroup) {
17002 for (var i in this.ids[sGroup]) {
17003 var oDD = this.ids[sGroup][i];
17005 if (this.isTypeOfDD(oDD)) {
17006 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
17007 var loc = this.getLocation(oDD);
17009 this.locationCache[oDD.id] = loc;
17011 delete this.locationCache[oDD.id];
17012 // this will unregister the drag and drop object if
17013 // the element is not in a usable state
17022 * This checks to make sure an element exists and is in the DOM. The
17023 * main purpose is to handle cases where innerHTML is used to remove
17024 * drag and drop objects from the DOM. IE provides an 'unspecified
17025 * error' when trying to access the offsetParent of such an element
17027 * @param {HTMLElement} el the element to check
17028 * @return {boolean} true if the element looks usable
17031 verifyEl: function(el) {
17036 parent = el.offsetParent;
17039 parent = el.offsetParent;
17050 * Returns a Region object containing the drag and drop element's position
17051 * and size, including the padding configured for it
17052 * @method getLocation
17053 * @param {DragDrop} oDD the drag and drop object to get the
17055 * @return {Roo.lib.Region} a Region object representing the total area
17056 * the element occupies, including any padding
17057 * the instance is configured for.
17060 getLocation: function(oDD) {
17061 if (! this.isTypeOfDD(oDD)) {
17065 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
17068 pos= Roo.lib.Dom.getXY(el);
17076 x2 = x1 + el.offsetWidth;
17078 y2 = y1 + el.offsetHeight;
17080 t = y1 - oDD.padding[0];
17081 r = x2 + oDD.padding[1];
17082 b = y2 + oDD.padding[2];
17083 l = x1 - oDD.padding[3];
17085 return new Roo.lib.Region( t, r, b, l );
17089 * Checks the cursor location to see if it over the target
17090 * @method isOverTarget
17091 * @param {Roo.lib.Point} pt The point to evaluate
17092 * @param {DragDrop} oTarget the DragDrop object we are inspecting
17093 * @return {boolean} true if the mouse is over the target
17097 isOverTarget: function(pt, oTarget, intersect) {
17098 // use cache if available
17099 var loc = this.locationCache[oTarget.id];
17100 if (!loc || !this.useCache) {
17101 loc = this.getLocation(oTarget);
17102 this.locationCache[oTarget.id] = loc;
17110 oTarget.cursorIsOver = loc.contains( pt );
17112 // DragDrop is using this as a sanity check for the initial mousedown
17113 // in this case we are done. In POINT mode, if the drag obj has no
17114 // contraints, we are also done. Otherwise we need to evaluate the
17115 // location of the target as related to the actual location of the
17116 // dragged element.
17117 var dc = this.dragCurrent;
17118 if (!dc || !dc.getTargetCoord ||
17119 (!intersect && !dc.constrainX && !dc.constrainY)) {
17120 return oTarget.cursorIsOver;
17123 oTarget.overlap = null;
17125 // Get the current location of the drag element, this is the
17126 // location of the mouse event less the delta that represents
17127 // where the original mousedown happened on the element. We
17128 // need to consider constraints and ticks as well.
17129 var pos = dc.getTargetCoord(pt.x, pt.y);
17131 var el = dc.getDragEl();
17132 var curRegion = new Roo.lib.Region( pos.y,
17133 pos.x + el.offsetWidth,
17134 pos.y + el.offsetHeight,
17137 var overlap = curRegion.intersect(loc);
17140 oTarget.overlap = overlap;
17141 return (intersect) ? true : oTarget.cursorIsOver;
17148 * unload event handler
17149 * @method _onUnload
17153 _onUnload: function(e, me) {
17154 Roo.dd.DragDropMgr.unregAll();
17158 * Cleans up the drag and drop events and objects.
17163 unregAll: function() {
17165 if (this.dragCurrent) {
17167 this.dragCurrent = null;
17170 this._execOnAll("unreg", []);
17172 for (i in this.elementCache) {
17173 delete this.elementCache[i];
17176 this.elementCache = {};
17181 * A cache of DOM elements
17182 * @property elementCache
17189 * Get the wrapper for the DOM element specified
17190 * @method getElWrapper
17191 * @param {String} id the id of the element to get
17192 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
17194 * @deprecated This wrapper isn't that useful
17197 getElWrapper: function(id) {
17198 var oWrapper = this.elementCache[id];
17199 if (!oWrapper || !oWrapper.el) {
17200 oWrapper = this.elementCache[id] =
17201 new this.ElementWrapper(Roo.getDom(id));
17207 * Returns the actual DOM element
17208 * @method getElement
17209 * @param {String} id the id of the elment to get
17210 * @return {Object} The element
17211 * @deprecated use Roo.getDom instead
17214 getElement: function(id) {
17215 return Roo.getDom(id);
17219 * Returns the style property for the DOM element (i.e.,
17220 * document.getElById(id).style)
17222 * @param {String} id the id of the elment to get
17223 * @return {Object} The style property of the element
17224 * @deprecated use Roo.getDom instead
17227 getCss: function(id) {
17228 var el = Roo.getDom(id);
17229 return (el) ? el.style : null;
17233 * Inner class for cached elements
17234 * @class DragDropMgr.ElementWrapper
17239 ElementWrapper: function(el) {
17244 this.el = el || null;
17249 this.id = this.el && el.id;
17251 * A reference to the style property
17254 this.css = this.el && el.style;
17258 * Returns the X position of an html element
17260 * @param el the element for which to get the position
17261 * @return {int} the X coordinate
17263 * @deprecated use Roo.lib.Dom.getX instead
17266 getPosX: function(el) {
17267 return Roo.lib.Dom.getX(el);
17271 * Returns the Y position of an html element
17273 * @param el the element for which to get the position
17274 * @return {int} the Y coordinate
17275 * @deprecated use Roo.lib.Dom.getY instead
17278 getPosY: function(el) {
17279 return Roo.lib.Dom.getY(el);
17283 * Swap two nodes. In IE, we use the native method, for others we
17284 * emulate the IE behavior
17286 * @param n1 the first node to swap
17287 * @param n2 the other node to swap
17290 swapNode: function(n1, n2) {
17294 var p = n2.parentNode;
17295 var s = n2.nextSibling;
17298 p.insertBefore(n1, n2);
17299 } else if (n2 == n1.nextSibling) {
17300 p.insertBefore(n2, n1);
17302 n1.parentNode.replaceChild(n2, n1);
17303 p.insertBefore(n1, s);
17309 * Returns the current scroll position
17310 * @method getScroll
17314 getScroll: function () {
17315 var t, l, dde=document.documentElement, db=document.body;
17316 if (dde && (dde.scrollTop || dde.scrollLeft)) {
17318 l = dde.scrollLeft;
17325 return { top: t, left: l };
17329 * Returns the specified element style property
17331 * @param {HTMLElement} el the element
17332 * @param {string} styleProp the style property
17333 * @return {string} The value of the style property
17334 * @deprecated use Roo.lib.Dom.getStyle
17337 getStyle: function(el, styleProp) {
17338 return Roo.fly(el).getStyle(styleProp);
17342 * Gets the scrollTop
17343 * @method getScrollTop
17344 * @return {int} the document's scrollTop
17347 getScrollTop: function () { return this.getScroll().top; },
17350 * Gets the scrollLeft
17351 * @method getScrollLeft
17352 * @return {int} the document's scrollTop
17355 getScrollLeft: function () { return this.getScroll().left; },
17358 * Sets the x/y position of an element to the location of the
17361 * @param {HTMLElement} moveEl The element to move
17362 * @param {HTMLElement} targetEl The position reference element
17365 moveToEl: function (moveEl, targetEl) {
17366 var aCoord = Roo.lib.Dom.getXY(targetEl);
17367 Roo.lib.Dom.setXY(moveEl, aCoord);
17371 * Numeric array sort function
17372 * @method numericSort
17375 numericSort: function(a, b) { return (a - b); },
17379 * @property _timeoutCount
17386 * Trying to make the load order less important. Without this we get
17387 * an error if this file is loaded before the Event Utility.
17388 * @method _addListeners
17392 _addListeners: function() {
17393 var DDM = Roo.dd.DDM;
17394 if ( Roo.lib.Event && document ) {
17397 if (DDM._timeoutCount > 2000) {
17399 setTimeout(DDM._addListeners, 10);
17400 if (document && document.body) {
17401 DDM._timeoutCount += 1;
17408 * Recursively searches the immediate parent and all child nodes for
17409 * the handle element in order to determine wheter or not it was
17411 * @method handleWasClicked
17412 * @param node the html element to inspect
17415 handleWasClicked: function(node, id) {
17416 if (this.isHandle(id, node.id)) {
17419 // check to see if this is a text node child of the one we want
17420 var p = node.parentNode;
17423 if (this.isHandle(id, p.id)) {
17438 // shorter alias, save a few bytes
17439 Roo.dd.DDM = Roo.dd.DragDropMgr;
17440 Roo.dd.DDM._addListeners();
17444 * Ext JS Library 1.1.1
17445 * Copyright(c) 2006-2007, Ext JS, LLC.
17447 * Originally Released Under LGPL - original licence link has changed is not relivant.
17450 * <script type="text/javascript">
17455 * A DragDrop implementation where the linked element follows the
17456 * mouse cursor during a drag.
17457 * @extends Roo.dd.DragDrop
17459 * @param {String} id the id of the linked element
17460 * @param {String} sGroup the group of related DragDrop items
17461 * @param {object} config an object containing configurable attributes
17462 * Valid properties for DD:
17465 Roo.dd.DD = function(id, sGroup, config) {
17467 this.init(id, sGroup, config);
17471 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
17474 * When set to true, the utility automatically tries to scroll the browser
17475 * window wehn a drag and drop element is dragged near the viewport boundary.
17476 * Defaults to true.
17483 * Sets the pointer offset to the distance between the linked element's top
17484 * left corner and the location the element was clicked
17485 * @method autoOffset
17486 * @param {int} iPageX the X coordinate of the click
17487 * @param {int} iPageY the Y coordinate of the click
17489 autoOffset: function(iPageX, iPageY) {
17490 var x = iPageX - this.startPageX;
17491 var y = iPageY - this.startPageY;
17492 this.setDelta(x, y);
17496 * Sets the pointer offset. You can call this directly to force the
17497 * offset to be in a particular location (e.g., pass in 0,0 to set it
17498 * to the center of the object)
17500 * @param {int} iDeltaX the distance from the left
17501 * @param {int} iDeltaY the distance from the top
17503 setDelta: function(iDeltaX, iDeltaY) {
17504 this.deltaX = iDeltaX;
17505 this.deltaY = iDeltaY;
17509 * Sets the drag element to the location of the mousedown or click event,
17510 * maintaining the cursor location relative to the location on the element
17511 * that was clicked. Override this if you want to place the element in a
17512 * location other than where the cursor is.
17513 * @method setDragElPos
17514 * @param {int} iPageX the X coordinate of the mousedown or drag event
17515 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17517 setDragElPos: function(iPageX, iPageY) {
17518 // the first time we do this, we are going to check to make sure
17519 // the element has css positioning
17521 var el = this.getDragEl();
17522 this.alignElWithMouse(el, iPageX, iPageY);
17526 * Sets the element to the location of the mousedown or click event,
17527 * maintaining the cursor location relative to the location on the element
17528 * that was clicked. Override this if you want to place the element in a
17529 * location other than where the cursor is.
17530 * @method alignElWithMouse
17531 * @param {HTMLElement} el the element to move
17532 * @param {int} iPageX the X coordinate of the mousedown or drag event
17533 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17535 alignElWithMouse: function(el, iPageX, iPageY) {
17536 var oCoord = this.getTargetCoord(iPageX, iPageY);
17537 var fly = el.dom ? el : Roo.fly(el);
17538 if (!this.deltaSetXY) {
17539 var aCoord = [oCoord.x, oCoord.y];
17541 var newLeft = fly.getLeft(true);
17542 var newTop = fly.getTop(true);
17543 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17545 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17548 this.cachePosition(oCoord.x, oCoord.y);
17549 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17554 * Saves the most recent position so that we can reset the constraints and
17555 * tick marks on-demand. We need to know this so that we can calculate the
17556 * number of pixels the element is offset from its original position.
17557 * @method cachePosition
17558 * @param iPageX the current x position (optional, this just makes it so we
17559 * don't have to look it up again)
17560 * @param iPageY the current y position (optional, this just makes it so we
17561 * don't have to look it up again)
17563 cachePosition: function(iPageX, iPageY) {
17565 this.lastPageX = iPageX;
17566 this.lastPageY = iPageY;
17568 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17569 this.lastPageX = aCoord[0];
17570 this.lastPageY = aCoord[1];
17575 * Auto-scroll the window if the dragged object has been moved beyond the
17576 * visible window boundary.
17577 * @method autoScroll
17578 * @param {int} x the drag element's x position
17579 * @param {int} y the drag element's y position
17580 * @param {int} h the height of the drag element
17581 * @param {int} w the width of the drag element
17584 autoScroll: function(x, y, h, w) {
17587 // The client height
17588 var clientH = Roo.lib.Dom.getViewWidth();
17590 // The client width
17591 var clientW = Roo.lib.Dom.getViewHeight();
17593 // The amt scrolled down
17594 var st = this.DDM.getScrollTop();
17596 // The amt scrolled right
17597 var sl = this.DDM.getScrollLeft();
17599 // Location of the bottom of the element
17602 // Location of the right of the element
17605 // The distance from the cursor to the bottom of the visible area,
17606 // adjusted so that we don't scroll if the cursor is beyond the
17607 // element drag constraints
17608 var toBot = (clientH + st - y - this.deltaY);
17610 // The distance from the cursor to the right of the visible area
17611 var toRight = (clientW + sl - x - this.deltaX);
17614 // How close to the edge the cursor must be before we scroll
17615 // var thresh = (document.all) ? 100 : 40;
17618 // How many pixels to scroll per autoscroll op. This helps to reduce
17619 // clunky scrolling. IE is more sensitive about this ... it needs this
17620 // value to be higher.
17621 var scrAmt = (document.all) ? 80 : 30;
17623 // Scroll down if we are near the bottom of the visible page and the
17624 // obj extends below the crease
17625 if ( bot > clientH && toBot < thresh ) {
17626 window.scrollTo(sl, st + scrAmt);
17629 // Scroll up if the window is scrolled down and the top of the object
17630 // goes above the top border
17631 if ( y < st && st > 0 && y - st < thresh ) {
17632 window.scrollTo(sl, st - scrAmt);
17635 // Scroll right if the obj is beyond the right border and the cursor is
17636 // near the border.
17637 if ( right > clientW && toRight < thresh ) {
17638 window.scrollTo(sl + scrAmt, st);
17641 // Scroll left if the window has been scrolled to the right and the obj
17642 // extends past the left border
17643 if ( x < sl && sl > 0 && x - sl < thresh ) {
17644 window.scrollTo(sl - scrAmt, st);
17650 * Finds the location the element should be placed if we want to move
17651 * it to where the mouse location less the click offset would place us.
17652 * @method getTargetCoord
17653 * @param {int} iPageX the X coordinate of the click
17654 * @param {int} iPageY the Y coordinate of the click
17655 * @return an object that contains the coordinates (Object.x and Object.y)
17658 getTargetCoord: function(iPageX, iPageY) {
17661 var x = iPageX - this.deltaX;
17662 var y = iPageY - this.deltaY;
17664 if (this.constrainX) {
17665 if (x < this.minX) { x = this.minX; }
17666 if (x > this.maxX) { x = this.maxX; }
17669 if (this.constrainY) {
17670 if (y < this.minY) { y = this.minY; }
17671 if (y > this.maxY) { y = this.maxY; }
17674 x = this.getTick(x, this.xTicks);
17675 y = this.getTick(y, this.yTicks);
17682 * Sets up config options specific to this class. Overrides
17683 * Roo.dd.DragDrop, but all versions of this method through the
17684 * inheritance chain are called
17686 applyConfig: function() {
17687 Roo.dd.DD.superclass.applyConfig.call(this);
17688 this.scroll = (this.config.scroll !== false);
17692 * Event that fires prior to the onMouseDown event. Overrides
17695 b4MouseDown: function(e) {
17696 // this.resetConstraints();
17697 this.autoOffset(e.getPageX(),
17702 * Event that fires prior to the onDrag event. Overrides
17705 b4Drag: function(e) {
17706 this.setDragElPos(e.getPageX(),
17710 toString: function() {
17711 return ("DD " + this.id);
17714 //////////////////////////////////////////////////////////////////////////
17715 // Debugging ygDragDrop events that can be overridden
17716 //////////////////////////////////////////////////////////////////////////
17718 startDrag: function(x, y) {
17721 onDrag: function(e) {
17724 onDragEnter: function(e, id) {
17727 onDragOver: function(e, id) {
17730 onDragOut: function(e, id) {
17733 onDragDrop: function(e, id) {
17736 endDrag: function(e) {
17743 * Ext JS Library 1.1.1
17744 * Copyright(c) 2006-2007, Ext JS, LLC.
17746 * Originally Released Under LGPL - original licence link has changed is not relivant.
17749 * <script type="text/javascript">
17753 * @class Roo.dd.DDProxy
17754 * A DragDrop implementation that inserts an empty, bordered div into
17755 * the document that follows the cursor during drag operations. At the time of
17756 * the click, the frame div is resized to the dimensions of the linked html
17757 * element, and moved to the exact location of the linked element.
17759 * References to the "frame" element refer to the single proxy element that
17760 * was created to be dragged in place of all DDProxy elements on the
17763 * @extends Roo.dd.DD
17765 * @param {String} id the id of the linked html element
17766 * @param {String} sGroup the group of related DragDrop objects
17767 * @param {object} config an object containing configurable attributes
17768 * Valid properties for DDProxy in addition to those in DragDrop:
17769 * resizeFrame, centerFrame, dragElId
17771 Roo.dd.DDProxy = function(id, sGroup, config) {
17773 this.init(id, sGroup, config);
17779 * The default drag frame div id
17780 * @property Roo.dd.DDProxy.dragElId
17784 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17786 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17789 * By default we resize the drag frame to be the same size as the element
17790 * we want to drag (this is to get the frame effect). We can turn it off
17791 * if we want a different behavior.
17792 * @property resizeFrame
17798 * By default the frame is positioned exactly where the drag element is, so
17799 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17800 * you do not have constraints on the obj is to have the drag frame centered
17801 * around the cursor. Set centerFrame to true for this effect.
17802 * @property centerFrame
17805 centerFrame: false,
17808 * Creates the proxy element if it does not yet exist
17809 * @method createFrame
17811 createFrame: function() {
17813 var body = document.body;
17815 if (!body || !body.firstChild) {
17816 setTimeout( function() { self.createFrame(); }, 50 );
17820 var div = this.getDragEl();
17823 div = document.createElement("div");
17824 div.id = this.dragElId;
17827 s.position = "absolute";
17828 s.visibility = "hidden";
17830 s.border = "2px solid #aaa";
17833 // appendChild can blow up IE if invoked prior to the window load event
17834 // while rendering a table. It is possible there are other scenarios
17835 // that would cause this to happen as well.
17836 body.insertBefore(div, body.firstChild);
17841 * Initialization for the drag frame element. Must be called in the
17842 * constructor of all subclasses
17843 * @method initFrame
17845 initFrame: function() {
17846 this.createFrame();
17849 applyConfig: function() {
17850 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17852 this.resizeFrame = (this.config.resizeFrame !== false);
17853 this.centerFrame = (this.config.centerFrame);
17854 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17858 * Resizes the drag frame to the dimensions of the clicked object, positions
17859 * it over the object, and finally displays it
17860 * @method showFrame
17861 * @param {int} iPageX X click position
17862 * @param {int} iPageY Y click position
17865 showFrame: function(iPageX, iPageY) {
17866 var el = this.getEl();
17867 var dragEl = this.getDragEl();
17868 var s = dragEl.style;
17870 this._resizeProxy();
17872 if (this.centerFrame) {
17873 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17874 Math.round(parseInt(s.height, 10)/2) );
17877 this.setDragElPos(iPageX, iPageY);
17879 Roo.fly(dragEl).show();
17883 * The proxy is automatically resized to the dimensions of the linked
17884 * element when a drag is initiated, unless resizeFrame is set to false
17885 * @method _resizeProxy
17888 _resizeProxy: function() {
17889 if (this.resizeFrame) {
17890 var el = this.getEl();
17891 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17895 // overrides Roo.dd.DragDrop
17896 b4MouseDown: function(e) {
17897 var x = e.getPageX();
17898 var y = e.getPageY();
17899 this.autoOffset(x, y);
17900 this.setDragElPos(x, y);
17903 // overrides Roo.dd.DragDrop
17904 b4StartDrag: function(x, y) {
17905 // show the drag frame
17906 this.showFrame(x, y);
17909 // overrides Roo.dd.DragDrop
17910 b4EndDrag: function(e) {
17911 Roo.fly(this.getDragEl()).hide();
17914 // overrides Roo.dd.DragDrop
17915 // By default we try to move the element to the last location of the frame.
17916 // This is so that the default behavior mirrors that of Roo.dd.DD.
17917 endDrag: function(e) {
17919 var lel = this.getEl();
17920 var del = this.getDragEl();
17922 // Show the drag frame briefly so we can get its position
17923 del.style.visibility = "";
17926 // Hide the linked element before the move to get around a Safari
17928 lel.style.visibility = "hidden";
17929 Roo.dd.DDM.moveToEl(lel, del);
17930 del.style.visibility = "hidden";
17931 lel.style.visibility = "";
17936 beforeMove : function(){
17940 afterDrag : function(){
17944 toString: function() {
17945 return ("DDProxy " + this.id);
17951 * Ext JS Library 1.1.1
17952 * Copyright(c) 2006-2007, Ext JS, LLC.
17954 * Originally Released Under LGPL - original licence link has changed is not relivant.
17957 * <script type="text/javascript">
17961 * @class Roo.dd.DDTarget
17962 * A DragDrop implementation that does not move, but can be a drop
17963 * target. You would get the same result by simply omitting implementation
17964 * for the event callbacks, but this way we reduce the processing cost of the
17965 * event listener and the callbacks.
17966 * @extends Roo.dd.DragDrop
17968 * @param {String} id the id of the element that is a drop target
17969 * @param {String} sGroup the group of related DragDrop objects
17970 * @param {object} config an object containing configurable attributes
17971 * Valid properties for DDTarget in addition to those in
17975 Roo.dd.DDTarget = function(id, sGroup, config) {
17977 this.initTarget(id, sGroup, config);
17979 if (config.listeners || config.events) {
17980 Roo.dd.DragDrop.superclass.constructor.call(this, {
17981 listeners : config.listeners || {},
17982 events : config.events || {}
17987 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17988 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17989 toString: function() {
17990 return ("DDTarget " + this.id);
17995 * Ext JS Library 1.1.1
17996 * Copyright(c) 2006-2007, Ext JS, LLC.
17998 * Originally Released Under LGPL - original licence link has changed is not relivant.
18001 * <script type="text/javascript">
18006 * @class Roo.dd.ScrollManager
18007 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
18008 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
18011 Roo.dd.ScrollManager = function(){
18012 var ddm = Roo.dd.DragDropMgr;
18019 var onStop = function(e){
18024 var triggerRefresh = function(){
18025 if(ddm.dragCurrent){
18026 ddm.refreshCache(ddm.dragCurrent.groups);
18030 var doScroll = function(){
18031 if(ddm.dragCurrent){
18032 var dds = Roo.dd.ScrollManager;
18034 if(proc.el.scroll(proc.dir, dds.increment)){
18038 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
18043 var clearProc = function(){
18045 clearInterval(proc.id);
18052 var startProc = function(el, dir){
18053 Roo.log('scroll startproc');
18057 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
18060 var onFire = function(e, isDrop){
18062 if(isDrop || !ddm.dragCurrent){ return; }
18063 var dds = Roo.dd.ScrollManager;
18064 if(!dragEl || dragEl != ddm.dragCurrent){
18065 dragEl = ddm.dragCurrent;
18066 // refresh regions on drag start
18067 dds.refreshCache();
18070 var xy = Roo.lib.Event.getXY(e);
18071 var pt = new Roo.lib.Point(xy[0], xy[1]);
18072 for(var id in els){
18073 var el = els[id], r = el._region;
18074 if(r && r.contains(pt) && el.isScrollable()){
18075 if(r.bottom - pt.y <= dds.thresh){
18077 startProc(el, "down");
18080 }else if(r.right - pt.x <= dds.thresh){
18082 startProc(el, "left");
18085 }else if(pt.y - r.top <= dds.thresh){
18087 startProc(el, "up");
18090 }else if(pt.x - r.left <= dds.thresh){
18092 startProc(el, "right");
18101 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
18102 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
18106 * Registers new overflow element(s) to auto scroll
18107 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
18109 register : function(el){
18110 if(el instanceof Array){
18111 for(var i = 0, len = el.length; i < len; i++) {
18112 this.register(el[i]);
18118 Roo.dd.ScrollManager.els = els;
18122 * Unregisters overflow element(s) so they are no longer scrolled
18123 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
18125 unregister : function(el){
18126 if(el instanceof Array){
18127 for(var i = 0, len = el.length; i < len; i++) {
18128 this.unregister(el[i]);
18137 * The number of pixels from the edge of a container the pointer needs to be to
18138 * trigger scrolling (defaults to 25)
18144 * The number of pixels to scroll in each scroll increment (defaults to 50)
18150 * The frequency of scrolls in milliseconds (defaults to 500)
18156 * True to animate the scroll (defaults to true)
18162 * The animation duration in seconds -
18163 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
18169 * Manually trigger a cache refresh.
18171 refreshCache : function(){
18172 for(var id in els){
18173 if(typeof els[id] == 'object'){ // for people extending the object prototype
18174 els[id]._region = els[id].getRegion();
18181 * Ext JS Library 1.1.1
18182 * Copyright(c) 2006-2007, Ext JS, LLC.
18184 * Originally Released Under LGPL - original licence link has changed is not relivant.
18187 * <script type="text/javascript">
18192 * @class Roo.dd.Registry
18193 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
18194 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
18197 Roo.dd.Registry = function(){
18200 var autoIdSeed = 0;
18202 var getId = function(el, autogen){
18203 if(typeof el == "string"){
18207 if(!id && autogen !== false){
18208 id = "roodd-" + (++autoIdSeed);
18216 * Register a drag drop element
18217 * @param {String|HTMLElement} element The id or DOM node to register
18218 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
18219 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
18220 * knows how to interpret, plus there are some specific properties known to the Registry that should be
18221 * populated in the data object (if applicable):
18223 Value Description<br />
18224 --------- ------------------------------------------<br />
18225 handles Array of DOM nodes that trigger dragging<br />
18226 for the element being registered<br />
18227 isHandle True if the element passed in triggers<br />
18228 dragging itself, else false
18231 register : function(el, data){
18233 if(typeof el == "string"){
18234 el = document.getElementById(el);
18237 elements[getId(el)] = data;
18238 if(data.isHandle !== false){
18239 handles[data.ddel.id] = data;
18242 var hs = data.handles;
18243 for(var i = 0, len = hs.length; i < len; i++){
18244 handles[getId(hs[i])] = data;
18250 * Unregister a drag drop element
18251 * @param {String|HTMLElement} element The id or DOM node to unregister
18253 unregister : function(el){
18254 var id = getId(el, false);
18255 var data = elements[id];
18257 delete elements[id];
18259 var hs = data.handles;
18260 for(var i = 0, len = hs.length; i < len; i++){
18261 delete handles[getId(hs[i], false)];
18268 * Returns the handle registered for a DOM Node by id
18269 * @param {String|HTMLElement} id The DOM node or id to look up
18270 * @return {Object} handle The custom handle data
18272 getHandle : function(id){
18273 if(typeof id != "string"){ // must be element?
18276 return handles[id];
18280 * Returns the handle that is registered for the DOM node that is the target of the event
18281 * @param {Event} e The event
18282 * @return {Object} handle The custom handle data
18284 getHandleFromEvent : function(e){
18285 var t = Roo.lib.Event.getTarget(e);
18286 return t ? handles[t.id] : null;
18290 * Returns a custom data object that is registered for a DOM node by id
18291 * @param {String|HTMLElement} id The DOM node or id to look up
18292 * @return {Object} data The custom data
18294 getTarget : function(id){
18295 if(typeof id != "string"){ // must be element?
18298 return elements[id];
18302 * Returns a custom data object that is registered for the DOM node that is the target of the event
18303 * @param {Event} e The event
18304 * @return {Object} data The custom data
18306 getTargetFromEvent : function(e){
18307 var t = Roo.lib.Event.getTarget(e);
18308 return t ? elements[t.id] || handles[t.id] : null;
18313 * Ext JS Library 1.1.1
18314 * Copyright(c) 2006-2007, Ext JS, LLC.
18316 * Originally Released Under LGPL - original licence link has changed is not relivant.
18319 * <script type="text/javascript">
18324 * @class Roo.dd.StatusProxy
18325 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
18326 * default drag proxy used by all Roo.dd components.
18328 * @param {Object} config
18330 Roo.dd.StatusProxy = function(config){
18331 Roo.apply(this, config);
18332 this.id = this.id || Roo.id();
18333 this.el = new Roo.Layer({
18335 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
18336 {tag: "div", cls: "x-dd-drop-icon"},
18337 {tag: "div", cls: "x-dd-drag-ghost"}
18340 shadow: !config || config.shadow !== false
18342 this.ghost = Roo.get(this.el.dom.childNodes[1]);
18343 this.dropStatus = this.dropNotAllowed;
18346 Roo.dd.StatusProxy.prototype = {
18348 * @cfg {String} dropAllowed
18349 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
18351 dropAllowed : "x-dd-drop-ok",
18353 * @cfg {String} dropNotAllowed
18354 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
18356 dropNotAllowed : "x-dd-drop-nodrop",
18359 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
18360 * over the current target element.
18361 * @param {String} cssClass The css class for the new drop status indicator image
18363 setStatus : function(cssClass){
18364 cssClass = cssClass || this.dropNotAllowed;
18365 if(this.dropStatus != cssClass){
18366 this.el.replaceClass(this.dropStatus, cssClass);
18367 this.dropStatus = cssClass;
18372 * Resets the status indicator to the default dropNotAllowed value
18373 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
18375 reset : function(clearGhost){
18376 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
18377 this.dropStatus = this.dropNotAllowed;
18379 this.ghost.update("");
18384 * Updates the contents of the ghost element
18385 * @param {String} html The html that will replace the current innerHTML of the ghost element
18387 update : function(html){
18388 if(typeof html == "string"){
18389 this.ghost.update(html);
18391 this.ghost.update("");
18392 html.style.margin = "0";
18393 this.ghost.dom.appendChild(html);
18395 // ensure float = none set?? cant remember why though.
18396 var el = this.ghost.dom.firstChild;
18398 Roo.fly(el).setStyle('float', 'none');
18403 * Returns the underlying proxy {@link Roo.Layer}
18404 * @return {Roo.Layer} el
18406 getEl : function(){
18411 * Returns the ghost element
18412 * @return {Roo.Element} el
18414 getGhost : function(){
18420 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
18422 hide : function(clear){
18430 * Stops the repair animation if it's currently running
18433 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
18439 * Displays this proxy
18446 * Force the Layer to sync its shadow and shim positions to the element
18453 * Causes the proxy to return to its position of origin via an animation. Should be called after an
18454 * invalid drop operation by the item being dragged.
18455 * @param {Array} xy The XY position of the element ([x, y])
18456 * @param {Function} callback The function to call after the repair is complete
18457 * @param {Object} scope The scope in which to execute the callback
18459 repair : function(xy, callback, scope){
18460 this.callback = callback;
18461 this.scope = scope;
18462 if(xy && this.animRepair !== false){
18463 this.el.addClass("x-dd-drag-repair");
18464 this.el.hideUnders(true);
18465 this.anim = this.el.shift({
18466 duration: this.repairDuration || .5,
18470 callback: this.afterRepair,
18474 this.afterRepair();
18479 afterRepair : function(){
18481 if(typeof this.callback == "function"){
18482 this.callback.call(this.scope || this);
18484 this.callback = null;
18489 * Ext JS Library 1.1.1
18490 * Copyright(c) 2006-2007, Ext JS, LLC.
18492 * Originally Released Under LGPL - original licence link has changed is not relivant.
18495 * <script type="text/javascript">
18499 * @class Roo.dd.DragSource
18500 * @extends Roo.dd.DDProxy
18501 * A simple class that provides the basic implementation needed to make any element draggable.
18503 * @param {String/HTMLElement/Element} el The container element
18504 * @param {Object} config
18506 Roo.dd.DragSource = function(el, config){
18507 this.el = Roo.get(el);
18508 this.dragData = {};
18510 Roo.apply(this, config);
18513 this.proxy = new Roo.dd.StatusProxy();
18516 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18517 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
18519 this.dragging = false;
18522 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
18524 * @cfg {String} dropAllowed
18525 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18527 dropAllowed : "x-dd-drop-ok",
18529 * @cfg {String} dropNotAllowed
18530 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18532 dropNotAllowed : "x-dd-drop-nodrop",
18535 * Returns the data object associated with this drag source
18536 * @return {Object} data An object containing arbitrary data
18538 getDragData : function(e){
18539 return this.dragData;
18543 onDragEnter : function(e, id){
18544 var target = Roo.dd.DragDropMgr.getDDById(id);
18545 this.cachedTarget = target;
18546 if(this.beforeDragEnter(target, e, id) !== false){
18547 if(target.isNotifyTarget){
18548 var status = target.notifyEnter(this, e, this.dragData);
18549 this.proxy.setStatus(status);
18551 this.proxy.setStatus(this.dropAllowed);
18554 if(this.afterDragEnter){
18556 * An empty function by default, but provided so that you can perform a custom action
18557 * when the dragged item enters the drop target by providing an implementation.
18558 * @param {Roo.dd.DragDrop} target The drop target
18559 * @param {Event} e The event object
18560 * @param {String} id The id of the dragged element
18561 * @method afterDragEnter
18563 this.afterDragEnter(target, e, id);
18569 * An empty function by default, but provided so that you can perform a custom action
18570 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
18571 * @param {Roo.dd.DragDrop} target The drop target
18572 * @param {Event} e The event object
18573 * @param {String} id The id of the dragged element
18574 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18576 beforeDragEnter : function(target, e, id){
18581 alignElWithMouse: function() {
18582 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18587 onDragOver : function(e, id){
18588 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18589 if(this.beforeDragOver(target, e, id) !== false){
18590 if(target.isNotifyTarget){
18591 var status = target.notifyOver(this, e, this.dragData);
18592 this.proxy.setStatus(status);
18595 if(this.afterDragOver){
18597 * An empty function by default, but provided so that you can perform a custom action
18598 * while the dragged item is over the drop target by providing an implementation.
18599 * @param {Roo.dd.DragDrop} target The drop target
18600 * @param {Event} e The event object
18601 * @param {String} id The id of the dragged element
18602 * @method afterDragOver
18604 this.afterDragOver(target, e, id);
18610 * An empty function by default, but provided so that you can perform a custom action
18611 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18612 * @param {Roo.dd.DragDrop} target The drop target
18613 * @param {Event} e The event object
18614 * @param {String} id The id of the dragged element
18615 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18617 beforeDragOver : function(target, e, id){
18622 onDragOut : function(e, id){
18623 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18624 if(this.beforeDragOut(target, e, id) !== false){
18625 if(target.isNotifyTarget){
18626 target.notifyOut(this, e, this.dragData);
18628 this.proxy.reset();
18629 if(this.afterDragOut){
18631 * An empty function by default, but provided so that you can perform a custom action
18632 * after the dragged item is dragged out of the target without dropping.
18633 * @param {Roo.dd.DragDrop} target The drop target
18634 * @param {Event} e The event object
18635 * @param {String} id The id of the dragged element
18636 * @method afterDragOut
18638 this.afterDragOut(target, e, id);
18641 this.cachedTarget = null;
18645 * An empty function by default, but provided so that you can perform a custom action before the dragged
18646 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18647 * @param {Roo.dd.DragDrop} target The drop target
18648 * @param {Event} e The event object
18649 * @param {String} id The id of the dragged element
18650 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18652 beforeDragOut : function(target, e, id){
18657 onDragDrop : function(e, id){
18658 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18659 if(this.beforeDragDrop(target, e, id) !== false){
18660 if(target.isNotifyTarget){
18661 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18662 this.onValidDrop(target, e, id);
18664 this.onInvalidDrop(target, e, id);
18667 this.onValidDrop(target, e, id);
18670 if(this.afterDragDrop){
18672 * An empty function by default, but provided so that you can perform a custom action
18673 * after a valid drag drop has occurred by providing an implementation.
18674 * @param {Roo.dd.DragDrop} target The drop target
18675 * @param {Event} e The event object
18676 * @param {String} id The id of the dropped element
18677 * @method afterDragDrop
18679 this.afterDragDrop(target, e, id);
18682 delete this.cachedTarget;
18686 * An empty function by default, but provided so that you can perform a custom action before the dragged
18687 * item is dropped onto the target and optionally cancel the onDragDrop.
18688 * @param {Roo.dd.DragDrop} target The drop target
18689 * @param {Event} e The event object
18690 * @param {String} id The id of the dragged element
18691 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18693 beforeDragDrop : function(target, e, id){
18698 onValidDrop : function(target, e, id){
18700 if(this.afterValidDrop){
18702 * An empty function by default, but provided so that you can perform a custom action
18703 * after a valid drop has occurred by providing an implementation.
18704 * @param {Object} target The target DD
18705 * @param {Event} e The event object
18706 * @param {String} id The id of the dropped element
18707 * @method afterInvalidDrop
18709 this.afterValidDrop(target, e, id);
18714 getRepairXY : function(e, data){
18715 return this.el.getXY();
18719 onInvalidDrop : function(target, e, id){
18720 this.beforeInvalidDrop(target, e, id);
18721 if(this.cachedTarget){
18722 if(this.cachedTarget.isNotifyTarget){
18723 this.cachedTarget.notifyOut(this, e, this.dragData);
18725 this.cacheTarget = null;
18727 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18729 if(this.afterInvalidDrop){
18731 * An empty function by default, but provided so that you can perform a custom action
18732 * after an invalid drop has occurred by providing an implementation.
18733 * @param {Event} e The event object
18734 * @param {String} id The id of the dropped element
18735 * @method afterInvalidDrop
18737 this.afterInvalidDrop(e, id);
18742 afterRepair : function(){
18744 this.el.highlight(this.hlColor || "c3daf9");
18746 this.dragging = false;
18750 * An empty function by default, but provided so that you can perform a custom action after an invalid
18751 * drop has occurred.
18752 * @param {Roo.dd.DragDrop} target The drop target
18753 * @param {Event} e The event object
18754 * @param {String} id The id of the dragged element
18755 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18757 beforeInvalidDrop : function(target, e, id){
18762 handleMouseDown : function(e){
18763 if(this.dragging) {
18766 var data = this.getDragData(e);
18767 if(data && this.onBeforeDrag(data, e) !== false){
18768 this.dragData = data;
18770 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18775 * An empty function by default, but provided so that you can perform a custom action before the initial
18776 * drag event begins and optionally cancel it.
18777 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18778 * @param {Event} e The event object
18779 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18781 onBeforeDrag : function(data, e){
18786 * An empty function by default, but provided so that you can perform a custom action once the initial
18787 * drag event has begun. The drag cannot be canceled from this function.
18788 * @param {Number} x The x position of the click on the dragged object
18789 * @param {Number} y The y position of the click on the dragged object
18791 onStartDrag : Roo.emptyFn,
18793 // private - YUI override
18794 startDrag : function(x, y){
18795 this.proxy.reset();
18796 this.dragging = true;
18797 this.proxy.update("");
18798 this.onInitDrag(x, y);
18803 onInitDrag : function(x, y){
18804 var clone = this.el.dom.cloneNode(true);
18805 clone.id = Roo.id(); // prevent duplicate ids
18806 this.proxy.update(clone);
18807 this.onStartDrag(x, y);
18812 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18813 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18815 getProxy : function(){
18820 * Hides the drag source's {@link Roo.dd.StatusProxy}
18822 hideProxy : function(){
18824 this.proxy.reset(true);
18825 this.dragging = false;
18829 triggerCacheRefresh : function(){
18830 Roo.dd.DDM.refreshCache(this.groups);
18833 // private - override to prevent hiding
18834 b4EndDrag: function(e) {
18837 // private - override to prevent moving
18838 endDrag : function(e){
18839 this.onEndDrag(this.dragData, e);
18843 onEndDrag : function(data, e){
18846 // private - pin to cursor
18847 autoOffset : function(x, y) {
18848 this.setDelta(-12, -20);
18852 * Ext JS Library 1.1.1
18853 * Copyright(c) 2006-2007, Ext JS, LLC.
18855 * Originally Released Under LGPL - original licence link has changed is not relivant.
18858 * <script type="text/javascript">
18863 * @class Roo.dd.DropTarget
18864 * @extends Roo.dd.DDTarget
18865 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18866 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18868 * @param {String/HTMLElement/Element} el The container element
18869 * @param {Object} config
18871 Roo.dd.DropTarget = function(el, config){
18872 this.el = Roo.get(el);
18874 var listeners = false; ;
18875 if (config && config.listeners) {
18876 listeners= config.listeners;
18877 delete config.listeners;
18879 Roo.apply(this, config);
18881 if(this.containerScroll){
18882 Roo.dd.ScrollManager.register(this.el);
18886 * @scope Roo.dd.DropTarget
18891 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18892 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18893 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18895 * IMPORTANT : it should set this.overClass and this.dropAllowed
18897 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18898 * @param {Event} e The event
18899 * @param {Object} data An object containing arbitrary data supplied by the drag source
18905 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18906 * This method will be called on every mouse movement while the drag source is over the drop target.
18907 * This default implementation simply returns the dropAllowed config value.
18909 * IMPORTANT : it should set this.dropAllowed
18911 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18912 * @param {Event} e The event
18913 * @param {Object} data An object containing arbitrary data supplied by the drag source
18919 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18920 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18921 * overClass (if any) from the drop element.
18923 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18924 * @param {Event} e The event
18925 * @param {Object} data An object containing arbitrary data supplied by the drag source
18931 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18932 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18933 * implementation that does something to process the drop event and returns true so that the drag source's
18934 * repair action does not run.
18936 * IMPORTANT : it should set this.success
18938 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18939 * @param {Event} e The event
18940 * @param {Object} data An object containing arbitrary data supplied by the drag source
18946 Roo.dd.DropTarget.superclass.constructor.call( this,
18948 this.ddGroup || this.group,
18951 listeners : listeners || {}
18959 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18961 * @cfg {String} overClass
18962 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18965 * @cfg {String} ddGroup
18966 * The drag drop group to handle drop events for
18970 * @cfg {String} dropAllowed
18971 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18973 dropAllowed : "x-dd-drop-ok",
18975 * @cfg {String} dropNotAllowed
18976 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18978 dropNotAllowed : "x-dd-drop-nodrop",
18980 * @cfg {boolean} success
18981 * set this after drop listener..
18985 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
18986 * if the drop point is valid for over/enter..
18993 isNotifyTarget : true,
18998 notifyEnter : function(dd, e, data)
19001 this.fireEvent('enter', dd, e, data);
19002 if(this.overClass){
19003 this.el.addClass(this.overClass);
19005 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
19006 this.valid ? this.dropAllowed : this.dropNotAllowed
19013 notifyOver : function(dd, e, data)
19016 this.fireEvent('over', dd, e, data);
19017 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
19018 this.valid ? this.dropAllowed : this.dropNotAllowed
19025 notifyOut : function(dd, e, data)
19027 this.fireEvent('out', dd, e, data);
19028 if(this.overClass){
19029 this.el.removeClass(this.overClass);
19036 notifyDrop : function(dd, e, data)
19038 this.success = false;
19039 this.fireEvent('drop', dd, e, data);
19040 return this.success;
19044 * Ext JS Library 1.1.1
19045 * Copyright(c) 2006-2007, Ext JS, LLC.
19047 * Originally Released Under LGPL - original licence link has changed is not relivant.
19050 * <script type="text/javascript">
19055 * @class Roo.dd.DragZone
19056 * @extends Roo.dd.DragSource
19057 * This class provides a container DD instance that proxies for multiple child node sources.<br />
19058 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
19060 * @param {String/HTMLElement/Element} el The container element
19061 * @param {Object} config
19063 Roo.dd.DragZone = function(el, config){
19064 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
19065 if(this.containerScroll){
19066 Roo.dd.ScrollManager.register(this.el);
19070 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
19072 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
19073 * for auto scrolling during drag operations.
19076 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
19077 * method after a failed drop (defaults to "c3daf9" - light blue)
19081 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
19082 * for a valid target to drag based on the mouse down. Override this method
19083 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
19084 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
19085 * @param {EventObject} e The mouse down event
19086 * @return {Object} The dragData
19088 getDragData : function(e){
19089 return Roo.dd.Registry.getHandleFromEvent(e);
19093 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
19094 * this.dragData.ddel
19095 * @param {Number} x The x position of the click on the dragged object
19096 * @param {Number} y The y position of the click on the dragged object
19097 * @return {Boolean} true to continue the drag, false to cancel
19099 onInitDrag : function(x, y){
19100 this.proxy.update(this.dragData.ddel.cloneNode(true));
19101 this.onStartDrag(x, y);
19106 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
19108 afterRepair : function(){
19110 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
19112 this.dragging = false;
19116 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
19117 * the XY of this.dragData.ddel
19118 * @param {EventObject} e The mouse up event
19119 * @return {Array} The xy location (e.g. [100, 200])
19121 getRepairXY : function(e){
19122 return Roo.Element.fly(this.dragData.ddel).getXY();
19126 * Ext JS Library 1.1.1
19127 * Copyright(c) 2006-2007, Ext JS, LLC.
19129 * Originally Released Under LGPL - original licence link has changed is not relivant.
19132 * <script type="text/javascript">
19135 * @class Roo.dd.DropZone
19136 * @extends Roo.dd.DropTarget
19137 * This class provides a container DD instance that proxies for multiple child node targets.<br />
19138 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
19140 * @param {String/HTMLElement/Element} el The container element
19141 * @param {Object} config
19143 Roo.dd.DropZone = function(el, config){
19144 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
19147 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
19149 * Returns a custom data object associated with the DOM node that is the target of the event. By default
19150 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
19151 * provide your own custom lookup.
19152 * @param {Event} e The event
19153 * @return {Object} data The custom data
19155 getTargetFromEvent : function(e){
19156 return Roo.dd.Registry.getTargetFromEvent(e);
19160 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
19161 * that it has registered. This method has no default implementation and should be overridden to provide
19162 * node-specific processing if necessary.
19163 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19164 * {@link #getTargetFromEvent} for this node)
19165 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19166 * @param {Event} e The event
19167 * @param {Object} data An object containing arbitrary data supplied by the drag source
19169 onNodeEnter : function(n, dd, e, data){
19174 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
19175 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
19176 * overridden to provide the proper feedback.
19177 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19178 * {@link #getTargetFromEvent} for this node)
19179 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19180 * @param {Event} e The event
19181 * @param {Object} data An object containing arbitrary data supplied by the drag source
19182 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19183 * underlying {@link Roo.dd.StatusProxy} can be updated
19185 onNodeOver : function(n, dd, e, data){
19186 return this.dropAllowed;
19190 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
19191 * the drop node without dropping. This method has no default implementation and should be overridden to provide
19192 * node-specific processing if necessary.
19193 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19194 * {@link #getTargetFromEvent} for this node)
19195 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19196 * @param {Event} e The event
19197 * @param {Object} data An object containing arbitrary data supplied by the drag source
19199 onNodeOut : function(n, dd, e, data){
19204 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
19205 * the drop node. The default implementation returns false, so it should be overridden to provide the
19206 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
19207 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19208 * {@link #getTargetFromEvent} for this node)
19209 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19210 * @param {Event} e The event
19211 * @param {Object} data An object containing arbitrary data supplied by the drag source
19212 * @return {Boolean} True if the drop was valid, else false
19214 onNodeDrop : function(n, dd, e, data){
19219 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
19220 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
19221 * it should be overridden to provide the proper feedback if necessary.
19222 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19223 * @param {Event} e The event
19224 * @param {Object} data An object containing arbitrary data supplied by the drag source
19225 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19226 * underlying {@link Roo.dd.StatusProxy} can be updated
19228 onContainerOver : function(dd, e, data){
19229 return this.dropNotAllowed;
19233 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
19234 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
19235 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
19236 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
19237 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19238 * @param {Event} e The event
19239 * @param {Object} data An object containing arbitrary data supplied by the drag source
19240 * @return {Boolean} True if the drop was valid, else false
19242 onContainerDrop : function(dd, e, data){
19247 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
19248 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
19249 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
19250 * you should override this method and provide a custom implementation.
19251 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19252 * @param {Event} e The event
19253 * @param {Object} data An object containing arbitrary data supplied by the drag source
19254 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19255 * underlying {@link Roo.dd.StatusProxy} can be updated
19257 notifyEnter : function(dd, e, data){
19258 return this.dropNotAllowed;
19262 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
19263 * This method will be called on every mouse movement while the drag source is over the drop zone.
19264 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
19265 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
19266 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
19267 * registered node, it will call {@link #onContainerOver}.
19268 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19269 * @param {Event} e The event
19270 * @param {Object} data An object containing arbitrary data supplied by the drag source
19271 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19272 * underlying {@link Roo.dd.StatusProxy} can be updated
19274 notifyOver : function(dd, e, data){
19275 var n = this.getTargetFromEvent(e);
19276 if(!n){ // not over valid drop target
19277 if(this.lastOverNode){
19278 this.onNodeOut(this.lastOverNode, dd, e, data);
19279 this.lastOverNode = null;
19281 return this.onContainerOver(dd, e, data);
19283 if(this.lastOverNode != n){
19284 if(this.lastOverNode){
19285 this.onNodeOut(this.lastOverNode, dd, e, data);
19287 this.onNodeEnter(n, dd, e, data);
19288 this.lastOverNode = n;
19290 return this.onNodeOver(n, dd, e, data);
19294 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
19295 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
19296 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
19297 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
19298 * @param {Event} e The event
19299 * @param {Object} data An object containing arbitrary data supplied by the drag zone
19301 notifyOut : function(dd, e, data){
19302 if(this.lastOverNode){
19303 this.onNodeOut(this.lastOverNode, dd, e, data);
19304 this.lastOverNode = null;
19309 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
19310 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
19311 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
19312 * otherwise it will call {@link #onContainerDrop}.
19313 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19314 * @param {Event} e The event
19315 * @param {Object} data An object containing arbitrary data supplied by the drag source
19316 * @return {Boolean} True if the drop was valid, else false
19318 notifyDrop : function(dd, e, data){
19319 if(this.lastOverNode){
19320 this.onNodeOut(this.lastOverNode, dd, e, data);
19321 this.lastOverNode = null;
19323 var n = this.getTargetFromEvent(e);
19325 this.onNodeDrop(n, dd, e, data) :
19326 this.onContainerDrop(dd, e, data);
19330 triggerCacheRefresh : function(){
19331 Roo.dd.DDM.refreshCache(this.groups);
19335 * Ext JS Library 1.1.1
19336 * Copyright(c) 2006-2007, Ext JS, LLC.
19338 * Originally Released Under LGPL - original licence link has changed is not relivant.
19341 * <script type="text/javascript">
19346 * @class Roo.data.SortTypes
19348 * Defines the default sorting (casting?) comparison functions used when sorting data.
19350 Roo.data.SortTypes = {
19352 * Default sort that does nothing
19353 * @param {Mixed} s The value being converted
19354 * @return {Mixed} The comparison value
19356 none : function(s){
19361 * The regular expression used to strip tags
19365 stripTagsRE : /<\/?[^>]+>/gi,
19368 * Strips all HTML tags to sort on text only
19369 * @param {Mixed} s The value being converted
19370 * @return {String} The comparison value
19372 asText : function(s){
19373 return String(s).replace(this.stripTagsRE, "");
19377 * Strips all HTML tags to sort on text only - Case insensitive
19378 * @param {Mixed} s The value being converted
19379 * @return {String} The comparison value
19381 asUCText : function(s){
19382 return String(s).toUpperCase().replace(this.stripTagsRE, "");
19386 * Case insensitive string
19387 * @param {Mixed} s The value being converted
19388 * @return {String} The comparison value
19390 asUCString : function(s) {
19391 return String(s).toUpperCase();
19396 * @param {Mixed} s The value being converted
19397 * @return {Number} The comparison value
19399 asDate : function(s) {
19403 if(s instanceof Date){
19404 return s.getTime();
19406 return Date.parse(String(s));
19411 * @param {Mixed} s The value being converted
19412 * @return {Float} The comparison value
19414 asFloat : function(s) {
19415 var val = parseFloat(String(s).replace(/,/g, ""));
19416 if(isNaN(val)) val = 0;
19422 * @param {Mixed} s The value being converted
19423 * @return {Number} The comparison value
19425 asInt : function(s) {
19426 var val = parseInt(String(s).replace(/,/g, ""));
19427 if(isNaN(val)) val = 0;
19432 * Ext JS Library 1.1.1
19433 * Copyright(c) 2006-2007, Ext JS, LLC.
19435 * Originally Released Under LGPL - original licence link has changed is not relivant.
19438 * <script type="text/javascript">
19442 * @class Roo.data.Record
19443 * Instances of this class encapsulate both record <em>definition</em> information, and record
19444 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
19445 * to access Records cached in an {@link Roo.data.Store} object.<br>
19447 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
19448 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
19451 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
19453 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
19454 * {@link #create}. The parameters are the same.
19455 * @param {Array} data An associative Array of data values keyed by the field name.
19456 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
19457 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
19458 * not specified an integer id is generated.
19460 Roo.data.Record = function(data, id){
19461 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
19466 * Generate a constructor for a specific record layout.
19467 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
19468 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
19469 * Each field definition object may contain the following properties: <ul>
19470 * <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,
19471 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
19472 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
19473 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
19474 * is being used, then this is a string containing the javascript expression to reference the data relative to
19475 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
19476 * to the data item relative to the record element. If the mapping expression is the same as the field name,
19477 * this may be omitted.</p></li>
19478 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
19479 * <ul><li>auto (Default, implies no conversion)</li>
19484 * <li>date</li></ul></p></li>
19485 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
19486 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
19487 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
19488 * by the Reader into an object that will be stored in the Record. It is passed the
19489 * following parameters:<ul>
19490 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
19492 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
19494 * <br>usage:<br><pre><code>
19495 var TopicRecord = Roo.data.Record.create(
19496 {name: 'title', mapping: 'topic_title'},
19497 {name: 'author', mapping: 'username'},
19498 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
19499 {name: 'lastPost', mapping: 'post_time', type: 'date'},
19500 {name: 'lastPoster', mapping: 'user2'},
19501 {name: 'excerpt', mapping: 'post_text'}
19504 var myNewRecord = new TopicRecord({
19505 title: 'Do my job please',
19508 lastPost: new Date(),
19509 lastPoster: 'Animal',
19510 excerpt: 'No way dude!'
19512 myStore.add(myNewRecord);
19517 Roo.data.Record.create = function(o){
19518 var f = function(){
19519 f.superclass.constructor.apply(this, arguments);
19521 Roo.extend(f, Roo.data.Record);
19522 var p = f.prototype;
19523 p.fields = new Roo.util.MixedCollection(false, function(field){
19526 for(var i = 0, len = o.length; i < len; i++){
19527 p.fields.add(new Roo.data.Field(o[i]));
19529 f.getField = function(name){
19530 return p.fields.get(name);
19535 Roo.data.Record.AUTO_ID = 1000;
19536 Roo.data.Record.EDIT = 'edit';
19537 Roo.data.Record.REJECT = 'reject';
19538 Roo.data.Record.COMMIT = 'commit';
19540 Roo.data.Record.prototype = {
19542 * Readonly flag - true if this record has been modified.
19551 join : function(store){
19552 this.store = store;
19556 * Set the named field to the specified value.
19557 * @param {String} name The name of the field to set.
19558 * @param {Object} value The value to set the field to.
19560 set : function(name, value){
19561 if(this.data[name] == value){
19565 if(!this.modified){
19566 this.modified = {};
19568 if(typeof this.modified[name] == 'undefined'){
19569 this.modified[name] = this.data[name];
19571 this.data[name] = value;
19572 if(!this.editing && this.store){
19573 this.store.afterEdit(this);
19578 * Get the value of the named field.
19579 * @param {String} name The name of the field to get the value of.
19580 * @return {Object} The value of the field.
19582 get : function(name){
19583 return this.data[name];
19587 beginEdit : function(){
19588 this.editing = true;
19589 this.modified = {};
19593 cancelEdit : function(){
19594 this.editing = false;
19595 delete this.modified;
19599 endEdit : function(){
19600 this.editing = false;
19601 if(this.dirty && this.store){
19602 this.store.afterEdit(this);
19607 * Usually called by the {@link Roo.data.Store} which owns the Record.
19608 * Rejects all changes made to the Record since either creation, or the last commit operation.
19609 * Modified fields are reverted to their original values.
19611 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19612 * of reject operations.
19614 reject : function(){
19615 var m = this.modified;
19617 if(typeof m[n] != "function"){
19618 this.data[n] = m[n];
19621 this.dirty = false;
19622 delete this.modified;
19623 this.editing = false;
19625 this.store.afterReject(this);
19630 * Usually called by the {@link Roo.data.Store} which owns the Record.
19631 * Commits all changes made to the Record since either creation, or the last commit operation.
19633 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19634 * of commit operations.
19636 commit : function(){
19637 this.dirty = false;
19638 delete this.modified;
19639 this.editing = false;
19641 this.store.afterCommit(this);
19646 hasError : function(){
19647 return this.error != null;
19651 clearError : function(){
19656 * Creates a copy of this record.
19657 * @param {String} id (optional) A new record id if you don't want to use this record's id
19660 copy : function(newId) {
19661 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19665 * Ext JS Library 1.1.1
19666 * Copyright(c) 2006-2007, Ext JS, LLC.
19668 * Originally Released Under LGPL - original licence link has changed is not relivant.
19671 * <script type="text/javascript">
19677 * @class Roo.data.Store
19678 * @extends Roo.util.Observable
19679 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19680 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19682 * 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
19683 * has no knowledge of the format of the data returned by the Proxy.<br>
19685 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19686 * instances from the data object. These records are cached and made available through accessor functions.
19688 * Creates a new Store.
19689 * @param {Object} config A config object containing the objects needed for the Store to access data,
19690 * and read the data into Records.
19692 Roo.data.Store = function(config){
19693 this.data = new Roo.util.MixedCollection(false);
19694 this.data.getKey = function(o){
19697 this.baseParams = {};
19699 this.paramNames = {
19704 "multisort" : "_multisort"
19707 if(config && config.data){
19708 this.inlineData = config.data;
19709 delete config.data;
19712 Roo.apply(this, config);
19714 if(this.reader){ // reader passed
19715 this.reader = Roo.factory(this.reader, Roo.data);
19716 this.reader.xmodule = this.xmodule || false;
19717 if(!this.recordType){
19718 this.recordType = this.reader.recordType;
19720 if(this.reader.onMetaChange){
19721 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19725 if(this.recordType){
19726 this.fields = this.recordType.prototype.fields;
19728 this.modified = [];
19732 * @event datachanged
19733 * Fires when the data cache has changed, and a widget which is using this Store
19734 * as a Record cache should refresh its view.
19735 * @param {Store} this
19737 datachanged : true,
19739 * @event metachange
19740 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19741 * @param {Store} this
19742 * @param {Object} meta The JSON metadata
19747 * Fires when Records have been added to the Store
19748 * @param {Store} this
19749 * @param {Roo.data.Record[]} records The array of Records added
19750 * @param {Number} index The index at which the record(s) were added
19755 * Fires when a Record has been removed from the Store
19756 * @param {Store} this
19757 * @param {Roo.data.Record} record The Record that was removed
19758 * @param {Number} index The index at which the record was removed
19763 * Fires when a Record has been updated
19764 * @param {Store} this
19765 * @param {Roo.data.Record} record The Record that was updated
19766 * @param {String} operation The update operation being performed. Value may be one of:
19768 Roo.data.Record.EDIT
19769 Roo.data.Record.REJECT
19770 Roo.data.Record.COMMIT
19776 * Fires when the data cache has been cleared.
19777 * @param {Store} this
19781 * @event beforeload
19782 * Fires before a request is made for a new data object. If the beforeload handler returns false
19783 * the load action will be canceled.
19784 * @param {Store} this
19785 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19789 * @event beforeloadadd
19790 * Fires after a new set of Records has been loaded.
19791 * @param {Store} this
19792 * @param {Roo.data.Record[]} records The Records that were loaded
19793 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19795 beforeloadadd : true,
19798 * Fires after a new set of Records has been loaded, before they are added to the store.
19799 * @param {Store} this
19800 * @param {Roo.data.Record[]} records The Records that were loaded
19801 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19802 * @params {Object} return from reader
19806 * @event loadexception
19807 * Fires if an exception occurs in the Proxy during loading.
19808 * Called with the signature of the Proxy's "loadexception" event.
19809 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19812 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19813 * @param {Object} load options
19814 * @param {Object} jsonData from your request (normally this contains the Exception)
19816 loadexception : true
19820 this.proxy = Roo.factory(this.proxy, Roo.data);
19821 this.proxy.xmodule = this.xmodule || false;
19822 this.relayEvents(this.proxy, ["loadexception"]);
19824 this.sortToggle = {};
19825 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19827 Roo.data.Store.superclass.constructor.call(this);
19829 if(this.inlineData){
19830 this.loadData(this.inlineData);
19831 delete this.inlineData;
19835 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19837 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19838 * without a remote query - used by combo/forms at present.
19842 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19845 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19848 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19849 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19852 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19853 * on any HTTP request
19856 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19859 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19863 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19864 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19866 remoteSort : false,
19869 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19870 * loaded or when a record is removed. (defaults to false).
19872 pruneModifiedRecords : false,
19875 lastOptions : null,
19878 * Add Records to the Store and fires the add event.
19879 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19881 add : function(records){
19882 records = [].concat(records);
19883 for(var i = 0, len = records.length; i < len; i++){
19884 records[i].join(this);
19886 var index = this.data.length;
19887 this.data.addAll(records);
19888 this.fireEvent("add", this, records, index);
19892 * Remove a Record from the Store and fires the remove event.
19893 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19895 remove : function(record){
19896 var index = this.data.indexOf(record);
19897 this.data.removeAt(index);
19898 if(this.pruneModifiedRecords){
19899 this.modified.remove(record);
19901 this.fireEvent("remove", this, record, index);
19905 * Remove all Records from the Store and fires the clear event.
19907 removeAll : function(){
19909 if(this.pruneModifiedRecords){
19910 this.modified = [];
19912 this.fireEvent("clear", this);
19916 * Inserts Records to the Store at the given index and fires the add event.
19917 * @param {Number} index The start index at which to insert the passed Records.
19918 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19920 insert : function(index, records){
19921 records = [].concat(records);
19922 for(var i = 0, len = records.length; i < len; i++){
19923 this.data.insert(index, records[i]);
19924 records[i].join(this);
19926 this.fireEvent("add", this, records, index);
19930 * Get the index within the cache of the passed Record.
19931 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19932 * @return {Number} The index of the passed Record. Returns -1 if not found.
19934 indexOf : function(record){
19935 return this.data.indexOf(record);
19939 * Get the index within the cache of the Record with the passed id.
19940 * @param {String} id The id of the Record to find.
19941 * @return {Number} The index of the Record. Returns -1 if not found.
19943 indexOfId : function(id){
19944 return this.data.indexOfKey(id);
19948 * Get the Record with the specified id.
19949 * @param {String} id The id of the Record to find.
19950 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19952 getById : function(id){
19953 return this.data.key(id);
19957 * Get the Record at the specified index.
19958 * @param {Number} index The index of the Record to find.
19959 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19961 getAt : function(index){
19962 return this.data.itemAt(index);
19966 * Returns a range of Records between specified indices.
19967 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19968 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19969 * @return {Roo.data.Record[]} An array of Records
19971 getRange : function(start, end){
19972 return this.data.getRange(start, end);
19976 storeOptions : function(o){
19977 o = Roo.apply({}, o);
19980 this.lastOptions = o;
19984 * Loads the Record cache from the configured Proxy using the configured Reader.
19986 * If using remote paging, then the first load call must specify the <em>start</em>
19987 * and <em>limit</em> properties in the options.params property to establish the initial
19988 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19990 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19991 * and this call will return before the new data has been loaded. Perform any post-processing
19992 * in a callback function, or in a "load" event handler.</strong>
19994 * @param {Object} options An object containing properties which control loading options:<ul>
19995 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19996 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19997 * passed the following arguments:<ul>
19998 * <li>r : Roo.data.Record[]</li>
19999 * <li>options: Options object from the load call</li>
20000 * <li>success: Boolean success indicator</li></ul></li>
20001 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
20002 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
20005 load : function(options){
20006 options = options || {};
20007 if(this.fireEvent("beforeload", this, options) !== false){
20008 this.storeOptions(options);
20009 var p = Roo.apply(options.params || {}, this.baseParams);
20010 // if meta was not loaded from remote source.. try requesting it.
20011 if (!this.reader.metaFromRemote) {
20012 p._requestMeta = 1;
20014 if(this.sortInfo && this.remoteSort){
20015 var pn = this.paramNames;
20016 p[pn["sort"]] = this.sortInfo.field;
20017 p[pn["dir"]] = this.sortInfo.direction;
20019 if (this.multiSort) {
20020 var pn = this.paramNames;
20021 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
20024 this.proxy.load(p, this.reader, this.loadRecords, this, options);
20029 * Reloads the Record cache from the configured Proxy using the configured Reader and
20030 * the options from the last load operation performed.
20031 * @param {Object} options (optional) An object containing properties which may override the options
20032 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
20033 * the most recently used options are reused).
20035 reload : function(options){
20036 this.load(Roo.applyIf(options||{}, this.lastOptions));
20040 // Called as a callback by the Reader during a load operation.
20041 loadRecords : function(o, options, success){
20042 if(!o || success === false){
20043 if(success !== false){
20044 this.fireEvent("load", this, [], options, o);
20046 if(options.callback){
20047 options.callback.call(options.scope || this, [], options, false);
20051 // if data returned failure - throw an exception.
20052 if (o.success === false) {
20053 // show a message if no listener is registered.
20054 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
20055 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
20057 // loadmask wil be hooked into this..
20058 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
20061 var r = o.records, t = o.totalRecords || r.length;
20063 this.fireEvent("beforeloadadd", this, r, options, o);
20065 if(!options || options.add !== true){
20066 if(this.pruneModifiedRecords){
20067 this.modified = [];
20069 for(var i = 0, len = r.length; i < len; i++){
20073 this.data = this.snapshot;
20074 delete this.snapshot;
20077 this.data.addAll(r);
20078 this.totalLength = t;
20080 this.fireEvent("datachanged", this);
20082 this.totalLength = Math.max(t, this.data.length+r.length);
20085 this.fireEvent("load", this, r, options, o);
20086 if(options.callback){
20087 options.callback.call(options.scope || this, r, options, true);
20093 * Loads data from a passed data block. A Reader which understands the format of the data
20094 * must have been configured in the constructor.
20095 * @param {Object} data The data block from which to read the Records. The format of the data expected
20096 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
20097 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
20099 loadData : function(o, append){
20100 var r = this.reader.readRecords(o);
20101 this.loadRecords(r, {add: append}, true);
20105 * Gets the number of cached records.
20107 * <em>If using paging, this may not be the total size of the dataset. If the data object
20108 * used by the Reader contains the dataset size, then the getTotalCount() function returns
20109 * the data set size</em>
20111 getCount : function(){
20112 return this.data.length || 0;
20116 * Gets the total number of records in the dataset as returned by the server.
20118 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
20119 * the dataset size</em>
20121 getTotalCount : function(){
20122 return this.totalLength || 0;
20126 * Returns the sort state of the Store as an object with two properties:
20128 field {String} The name of the field by which the Records are sorted
20129 direction {String} The sort order, "ASC" or "DESC"
20132 getSortState : function(){
20133 return this.sortInfo;
20137 applySort : function(){
20138 if(this.sortInfo && !this.remoteSort){
20139 var s = this.sortInfo, f = s.field;
20140 var st = this.fields.get(f).sortType;
20141 var fn = function(r1, r2){
20142 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
20143 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
20145 this.data.sort(s.direction, fn);
20146 if(this.snapshot && this.snapshot != this.data){
20147 this.snapshot.sort(s.direction, fn);
20153 * Sets the default sort column and order to be used by the next load operation.
20154 * @param {String} fieldName The name of the field to sort by.
20155 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
20157 setDefaultSort : function(field, dir){
20158 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
20162 * Sort the Records.
20163 * If remote sorting is used, the sort is performed on the server, and the cache is
20164 * reloaded. If local sorting is used, the cache is sorted internally.
20165 * @param {String} fieldName The name of the field to sort by.
20166 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
20168 sort : function(fieldName, dir){
20169 var f = this.fields.get(fieldName);
20171 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
20173 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
20174 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
20179 this.sortToggle[f.name] = dir;
20180 this.sortInfo = {field: f.name, direction: dir};
20181 if(!this.remoteSort){
20183 this.fireEvent("datachanged", this);
20185 this.load(this.lastOptions);
20190 * Calls the specified function for each of the Records in the cache.
20191 * @param {Function} fn The function to call. The Record is passed as the first parameter.
20192 * Returning <em>false</em> aborts and exits the iteration.
20193 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
20195 each : function(fn, scope){
20196 this.data.each(fn, scope);
20200 * Gets all records modified since the last commit. Modified records are persisted across load operations
20201 * (e.g., during paging).
20202 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
20204 getModifiedRecords : function(){
20205 return this.modified;
20209 createFilterFn : function(property, value, anyMatch){
20210 if(!value.exec){ // not a regex
20211 value = String(value);
20212 if(value.length == 0){
20215 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
20217 return function(r){
20218 return value.test(r.data[property]);
20223 * Sums the value of <i>property</i> for each record between start and end and returns the result.
20224 * @param {String} property A field on your records
20225 * @param {Number} start The record index to start at (defaults to 0)
20226 * @param {Number} end The last record index to include (defaults to length - 1)
20227 * @return {Number} The sum
20229 sum : function(property, start, end){
20230 var rs = this.data.items, v = 0;
20231 start = start || 0;
20232 end = (end || end === 0) ? end : rs.length-1;
20234 for(var i = start; i <= end; i++){
20235 v += (rs[i].data[property] || 0);
20241 * Filter the records by a specified property.
20242 * @param {String} field A field on your records
20243 * @param {String/RegExp} value Either a string that the field
20244 * should start with or a RegExp to test against the field
20245 * @param {Boolean} anyMatch True to match any part not just the beginning
20247 filter : function(property, value, anyMatch){
20248 var fn = this.createFilterFn(property, value, anyMatch);
20249 return fn ? this.filterBy(fn) : this.clearFilter();
20253 * Filter by a function. The specified function will be called with each
20254 * record in this data source. If the function returns true the record is included,
20255 * otherwise it is filtered.
20256 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
20257 * @param {Object} scope (optional) The scope of the function (defaults to this)
20259 filterBy : function(fn, scope){
20260 this.snapshot = this.snapshot || this.data;
20261 this.data = this.queryBy(fn, scope||this);
20262 this.fireEvent("datachanged", this);
20266 * Query the records by a specified property.
20267 * @param {String} field A field on your records
20268 * @param {String/RegExp} value Either a string that the field
20269 * should start with or a RegExp to test against the field
20270 * @param {Boolean} anyMatch True to match any part not just the beginning
20271 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
20273 query : function(property, value, anyMatch){
20274 var fn = this.createFilterFn(property, value, anyMatch);
20275 return fn ? this.queryBy(fn) : this.data.clone();
20279 * Query by a function. The specified function will be called with each
20280 * record in this data source. If the function returns true the record is included
20282 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
20283 * @param {Object} scope (optional) The scope of the function (defaults to this)
20284 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
20286 queryBy : function(fn, scope){
20287 var data = this.snapshot || this.data;
20288 return data.filterBy(fn, scope||this);
20292 * Collects unique values for a particular dataIndex from this store.
20293 * @param {String} dataIndex The property to collect
20294 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
20295 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
20296 * @return {Array} An array of the unique values
20298 collect : function(dataIndex, allowNull, bypassFilter){
20299 var d = (bypassFilter === true && this.snapshot) ?
20300 this.snapshot.items : this.data.items;
20301 var v, sv, r = [], l = {};
20302 for(var i = 0, len = d.length; i < len; i++){
20303 v = d[i].data[dataIndex];
20305 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
20314 * Revert to a view of the Record cache with no filtering applied.
20315 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
20317 clearFilter : function(suppressEvent){
20318 if(this.snapshot && this.snapshot != this.data){
20319 this.data = this.snapshot;
20320 delete this.snapshot;
20321 if(suppressEvent !== true){
20322 this.fireEvent("datachanged", this);
20328 afterEdit : function(record){
20329 if(this.modified.indexOf(record) == -1){
20330 this.modified.push(record);
20332 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
20336 afterReject : function(record){
20337 this.modified.remove(record);
20338 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
20342 afterCommit : function(record){
20343 this.modified.remove(record);
20344 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
20348 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
20349 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
20351 commitChanges : function(){
20352 var m = this.modified.slice(0);
20353 this.modified = [];
20354 for(var i = 0, len = m.length; i < len; i++){
20360 * Cancel outstanding changes on all changed records.
20362 rejectChanges : function(){
20363 var m = this.modified.slice(0);
20364 this.modified = [];
20365 for(var i = 0, len = m.length; i < len; i++){
20370 onMetaChange : function(meta, rtype, o){
20371 this.recordType = rtype;
20372 this.fields = rtype.prototype.fields;
20373 delete this.snapshot;
20374 this.sortInfo = meta.sortInfo || this.sortInfo;
20375 this.modified = [];
20376 this.fireEvent('metachange', this, this.reader.meta);
20380 * Ext JS Library 1.1.1
20381 * Copyright(c) 2006-2007, Ext JS, LLC.
20383 * Originally Released Under LGPL - original licence link has changed is not relivant.
20386 * <script type="text/javascript">
20390 * @class Roo.data.SimpleStore
20391 * @extends Roo.data.Store
20392 * Small helper class to make creating Stores from Array data easier.
20393 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
20394 * @cfg {Array} fields An array of field definition objects, or field name strings.
20395 * @cfg {Array} data The multi-dimensional array of data
20397 * @param {Object} config
20399 Roo.data.SimpleStore = function(config){
20400 Roo.data.SimpleStore.superclass.constructor.call(this, {
20402 reader: new Roo.data.ArrayReader({
20405 Roo.data.Record.create(config.fields)
20407 proxy : new Roo.data.MemoryProxy(config.data)
20411 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
20413 * Ext JS Library 1.1.1
20414 * Copyright(c) 2006-2007, Ext JS, LLC.
20416 * Originally Released Under LGPL - original licence link has changed is not relivant.
20419 * <script type="text/javascript">
20424 * @extends Roo.data.Store
20425 * @class Roo.data.JsonStore
20426 * Small helper class to make creating Stores for JSON data easier. <br/>
20428 var store = new Roo.data.JsonStore({
20429 url: 'get-images.php',
20431 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
20434 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
20435 * JsonReader and HttpProxy (unless inline data is provided).</b>
20436 * @cfg {Array} fields An array of field definition objects, or field name strings.
20438 * @param {Object} config
20440 Roo.data.JsonStore = function(c){
20441 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
20442 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
20443 reader: new Roo.data.JsonReader(c, c.fields)
20446 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
20448 * Ext JS Library 1.1.1
20449 * Copyright(c) 2006-2007, Ext JS, LLC.
20451 * Originally Released Under LGPL - original licence link has changed is not relivant.
20454 * <script type="text/javascript">
20458 Roo.data.Field = function(config){
20459 if(typeof config == "string"){
20460 config = {name: config};
20462 Roo.apply(this, config);
20465 this.type = "auto";
20468 var st = Roo.data.SortTypes;
20469 // named sortTypes are supported, here we look them up
20470 if(typeof this.sortType == "string"){
20471 this.sortType = st[this.sortType];
20474 // set default sortType for strings and dates
20475 if(!this.sortType){
20478 this.sortType = st.asUCString;
20481 this.sortType = st.asDate;
20484 this.sortType = st.none;
20489 var stripRe = /[\$,%]/g;
20491 // prebuilt conversion function for this field, instead of
20492 // switching every time we're reading a value
20494 var cv, dateFormat = this.dateFormat;
20499 cv = function(v){ return v; };
20502 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
20506 return v !== undefined && v !== null && v !== '' ?
20507 parseInt(String(v).replace(stripRe, ""), 10) : '';
20512 return v !== undefined && v !== null && v !== '' ?
20513 parseFloat(String(v).replace(stripRe, ""), 10) : '';
20518 cv = function(v){ return v === true || v === "true" || v == 1; };
20525 if(v instanceof Date){
20529 if(dateFormat == "timestamp"){
20530 return new Date(v*1000);
20532 return Date.parseDate(v, dateFormat);
20534 var parsed = Date.parse(v);
20535 return parsed ? new Date(parsed) : null;
20544 Roo.data.Field.prototype = {
20552 * Ext JS Library 1.1.1
20553 * Copyright(c) 2006-2007, Ext JS, LLC.
20555 * Originally Released Under LGPL - original licence link has changed is not relivant.
20558 * <script type="text/javascript">
20561 // Base class for reading structured data from a data source. This class is intended to be
20562 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20565 * @class Roo.data.DataReader
20566 * Base class for reading structured data from a data source. This class is intended to be
20567 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20570 Roo.data.DataReader = function(meta, recordType){
20574 this.recordType = recordType instanceof Array ?
20575 Roo.data.Record.create(recordType) : recordType;
20578 Roo.data.DataReader.prototype = {
20580 * Create an empty record
20581 * @param {Object} data (optional) - overlay some values
20582 * @return {Roo.data.Record} record created.
20584 newRow : function(d) {
20586 this.recordType.prototype.fields.each(function(c) {
20588 case 'int' : da[c.name] = 0; break;
20589 case 'date' : da[c.name] = new Date(); break;
20590 case 'float' : da[c.name] = 0.0; break;
20591 case 'boolean' : da[c.name] = false; break;
20592 default : da[c.name] = ""; break;
20596 return new this.recordType(Roo.apply(da, d));
20601 * Ext JS Library 1.1.1
20602 * Copyright(c) 2006-2007, Ext JS, LLC.
20604 * Originally Released Under LGPL - original licence link has changed is not relivant.
20607 * <script type="text/javascript">
20611 * @class Roo.data.DataProxy
20612 * @extends Roo.data.Observable
20613 * This class is an abstract base class for implementations which provide retrieval of
20614 * unformatted data objects.<br>
20616 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20617 * (of the appropriate type which knows how to parse the data object) to provide a block of
20618 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20620 * Custom implementations must implement the load method as described in
20621 * {@link Roo.data.HttpProxy#load}.
20623 Roo.data.DataProxy = function(){
20626 * @event beforeload
20627 * Fires before a network request is made to retrieve a data object.
20628 * @param {Object} This DataProxy object.
20629 * @param {Object} params The params parameter to the load function.
20634 * Fires before the load method's callback is called.
20635 * @param {Object} This DataProxy object.
20636 * @param {Object} o The data object.
20637 * @param {Object} arg The callback argument object passed to the load function.
20641 * @event loadexception
20642 * Fires if an Exception occurs during data retrieval.
20643 * @param {Object} This DataProxy object.
20644 * @param {Object} o The data object.
20645 * @param {Object} arg The callback argument object passed to the load function.
20646 * @param {Object} e The Exception.
20648 loadexception : true
20650 Roo.data.DataProxy.superclass.constructor.call(this);
20653 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20656 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20660 * Ext JS Library 1.1.1
20661 * Copyright(c) 2006-2007, Ext JS, LLC.
20663 * Originally Released Under LGPL - original licence link has changed is not relivant.
20666 * <script type="text/javascript">
20669 * @class Roo.data.MemoryProxy
20670 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20671 * to the Reader when its load method is called.
20673 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20675 Roo.data.MemoryProxy = function(data){
20679 Roo.data.MemoryProxy.superclass.constructor.call(this);
20683 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20685 * Load data from the requested source (in this case an in-memory
20686 * data object passed to the constructor), read the data object into
20687 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20688 * process that block using the passed callback.
20689 * @param {Object} params This parameter is not used by the MemoryProxy class.
20690 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20691 * object into a block of Roo.data.Records.
20692 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20693 * The function must be passed <ul>
20694 * <li>The Record block object</li>
20695 * <li>The "arg" argument from the load function</li>
20696 * <li>A boolean success indicator</li>
20698 * @param {Object} scope The scope in which to call the callback
20699 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20701 load : function(params, reader, callback, scope, arg){
20702 params = params || {};
20705 result = reader.readRecords(this.data);
20707 this.fireEvent("loadexception", this, arg, null, e);
20708 callback.call(scope, null, arg, false);
20711 callback.call(scope, result, arg, true);
20715 update : function(params, records){
20720 * Ext JS Library 1.1.1
20721 * Copyright(c) 2006-2007, Ext JS, LLC.
20723 * Originally Released Under LGPL - original licence link has changed is not relivant.
20726 * <script type="text/javascript">
20729 * @class Roo.data.HttpProxy
20730 * @extends Roo.data.DataProxy
20731 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20732 * configured to reference a certain URL.<br><br>
20734 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20735 * from which the running page was served.<br><br>
20737 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20739 * Be aware that to enable the browser to parse an XML document, the server must set
20740 * the Content-Type header in the HTTP response to "text/xml".
20742 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20743 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20744 * will be used to make the request.
20746 Roo.data.HttpProxy = function(conn){
20747 Roo.data.HttpProxy.superclass.constructor.call(this);
20748 // is conn a conn config or a real conn?
20750 this.useAjax = !conn || !conn.events;
20754 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20755 // thse are take from connection...
20758 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20761 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20762 * extra parameters to each request made by this object. (defaults to undefined)
20765 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20766 * to each request made by this object. (defaults to undefined)
20769 * @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)
20772 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20775 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20781 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20785 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20786 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20787 * a finer-grained basis than the DataProxy events.
20789 getConnection : function(){
20790 return this.useAjax ? Roo.Ajax : this.conn;
20794 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20795 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20796 * process that block using the passed callback.
20797 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20798 * for the request to the remote server.
20799 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20800 * object into a block of Roo.data.Records.
20801 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20802 * The function must be passed <ul>
20803 * <li>The Record block object</li>
20804 * <li>The "arg" argument from the load function</li>
20805 * <li>A boolean success indicator</li>
20807 * @param {Object} scope The scope in which to call the callback
20808 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20810 load : function(params, reader, callback, scope, arg){
20811 if(this.fireEvent("beforeload", this, params) !== false){
20813 params : params || {},
20815 callback : callback,
20820 callback : this.loadResponse,
20824 Roo.applyIf(o, this.conn);
20825 if(this.activeRequest){
20826 Roo.Ajax.abort(this.activeRequest);
20828 this.activeRequest = Roo.Ajax.request(o);
20830 this.conn.request(o);
20833 callback.call(scope||this, null, arg, false);
20838 loadResponse : function(o, success, response){
20839 delete this.activeRequest;
20841 this.fireEvent("loadexception", this, o, response);
20842 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20847 result = o.reader.read(response);
20849 this.fireEvent("loadexception", this, o, response, e);
20850 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20854 this.fireEvent("load", this, o, o.request.arg);
20855 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20859 update : function(dataSet){
20864 updateResponse : function(dataSet){
20869 * Ext JS Library 1.1.1
20870 * Copyright(c) 2006-2007, Ext JS, LLC.
20872 * Originally Released Under LGPL - original licence link has changed is not relivant.
20875 * <script type="text/javascript">
20879 * @class Roo.data.ScriptTagProxy
20880 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20881 * other than the originating domain of the running page.<br><br>
20883 * <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
20884 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20886 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20887 * source code that is used as the source inside a <script> tag.<br><br>
20889 * In order for the browser to process the returned data, the server must wrap the data object
20890 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20891 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20892 * depending on whether the callback name was passed:
20895 boolean scriptTag = false;
20896 String cb = request.getParameter("callback");
20899 response.setContentType("text/javascript");
20901 response.setContentType("application/x-json");
20903 Writer out = response.getWriter();
20905 out.write(cb + "(");
20907 out.print(dataBlock.toJsonString());
20914 * @param {Object} config A configuration object.
20916 Roo.data.ScriptTagProxy = function(config){
20917 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20918 Roo.apply(this, config);
20919 this.head = document.getElementsByTagName("head")[0];
20922 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20924 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20926 * @cfg {String} url The URL from which to request the data object.
20929 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20933 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20934 * the server the name of the callback function set up by the load call to process the returned data object.
20935 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20936 * javascript output which calls this named function passing the data object as its only parameter.
20938 callbackParam : "callback",
20940 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20941 * name to the request.
20946 * Load data from the configured URL, read the data object into
20947 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20948 * process that block using the passed callback.
20949 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20950 * for the request to the remote server.
20951 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20952 * object into a block of Roo.data.Records.
20953 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20954 * The function must be passed <ul>
20955 * <li>The Record block object</li>
20956 * <li>The "arg" argument from the load function</li>
20957 * <li>A boolean success indicator</li>
20959 * @param {Object} scope The scope in which to call the callback
20960 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20962 load : function(params, reader, callback, scope, arg){
20963 if(this.fireEvent("beforeload", this, params) !== false){
20965 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20967 var url = this.url;
20968 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20970 url += "&_dc=" + (new Date().getTime());
20972 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20975 cb : "stcCallback"+transId,
20976 scriptId : "stcScript"+transId,
20980 callback : callback,
20986 window[trans.cb] = function(o){
20987 conn.handleResponse(o, trans);
20990 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20992 if(this.autoAbort !== false){
20996 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20998 var script = document.createElement("script");
20999 script.setAttribute("src", url);
21000 script.setAttribute("type", "text/javascript");
21001 script.setAttribute("id", trans.scriptId);
21002 this.head.appendChild(script);
21004 this.trans = trans;
21006 callback.call(scope||this, null, arg, false);
21011 isLoading : function(){
21012 return this.trans ? true : false;
21016 * Abort the current server request.
21018 abort : function(){
21019 if(this.isLoading()){
21020 this.destroyTrans(this.trans);
21025 destroyTrans : function(trans, isLoaded){
21026 this.head.removeChild(document.getElementById(trans.scriptId));
21027 clearTimeout(trans.timeoutId);
21029 window[trans.cb] = undefined;
21031 delete window[trans.cb];
21034 // if hasn't been loaded, wait for load to remove it to prevent script error
21035 window[trans.cb] = function(){
21036 window[trans.cb] = undefined;
21038 delete window[trans.cb];
21045 handleResponse : function(o, trans){
21046 this.trans = false;
21047 this.destroyTrans(trans, true);
21050 result = trans.reader.readRecords(o);
21052 this.fireEvent("loadexception", this, o, trans.arg, e);
21053 trans.callback.call(trans.scope||window, null, trans.arg, false);
21056 this.fireEvent("load", this, o, trans.arg);
21057 trans.callback.call(trans.scope||window, result, trans.arg, true);
21061 handleFailure : function(trans){
21062 this.trans = false;
21063 this.destroyTrans(trans, false);
21064 this.fireEvent("loadexception", this, null, trans.arg);
21065 trans.callback.call(trans.scope||window, null, trans.arg, false);
21069 * Ext JS Library 1.1.1
21070 * Copyright(c) 2006-2007, Ext JS, LLC.
21072 * Originally Released Under LGPL - original licence link has changed is not relivant.
21075 * <script type="text/javascript">
21079 * @class Roo.data.JsonReader
21080 * @extends Roo.data.DataReader
21081 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
21082 * based on mappings in a provided Roo.data.Record constructor.
21084 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
21085 * in the reply previously.
21090 var RecordDef = Roo.data.Record.create([
21091 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
21092 {name: 'occupation'} // This field will use "occupation" as the mapping.
21094 var myReader = new Roo.data.JsonReader({
21095 totalProperty: "results", // The property which contains the total dataset size (optional)
21096 root: "rows", // The property which contains an Array of row objects
21097 id: "id" // The property within each row object that provides an ID for the record (optional)
21101 * This would consume a JSON file like this:
21103 { 'results': 2, 'rows': [
21104 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
21105 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
21108 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
21109 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
21110 * paged from the remote server.
21111 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
21112 * @cfg {String} root name of the property which contains the Array of row objects.
21113 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
21115 * Create a new JsonReader
21116 * @param {Object} meta Metadata configuration options
21117 * @param {Object} recordType Either an Array of field definition objects,
21118 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
21120 Roo.data.JsonReader = function(meta, recordType){
21123 // set some defaults:
21124 Roo.applyIf(meta, {
21125 totalProperty: 'total',
21126 successProperty : 'success',
21131 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
21133 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
21136 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
21137 * Used by Store query builder to append _requestMeta to params.
21140 metaFromRemote : false,
21142 * This method is only used by a DataProxy which has retrieved data from a remote server.
21143 * @param {Object} response The XHR object which contains the JSON data in its responseText.
21144 * @return {Object} data A data block which is used by an Roo.data.Store object as
21145 * a cache of Roo.data.Records.
21147 read : function(response){
21148 var json = response.responseText;
21150 var o = /* eval:var:o */ eval("("+json+")");
21152 throw {message: "JsonReader.read: Json object not found"};
21158 this.metaFromRemote = true;
21159 this.meta = o.metaData;
21160 this.recordType = Roo.data.Record.create(o.metaData.fields);
21161 this.onMetaChange(this.meta, this.recordType, o);
21163 return this.readRecords(o);
21166 // private function a store will implement
21167 onMetaChange : function(meta, recordType, o){
21174 simpleAccess: function(obj, subsc) {
21181 getJsonAccessor: function(){
21183 return function(expr) {
21185 return(re.test(expr))
21186 ? new Function("obj", "return obj." + expr)
21191 return Roo.emptyFn;
21196 * Create a data block containing Roo.data.Records from an XML document.
21197 * @param {Object} o An object which contains an Array of row objects in the property specified
21198 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
21199 * which contains the total size of the dataset.
21200 * @return {Object} data A data block which is used by an Roo.data.Store object as
21201 * a cache of Roo.data.Records.
21203 readRecords : function(o){
21205 * After any data loads, the raw JSON data is available for further custom processing.
21209 var s = this.meta, Record = this.recordType,
21210 f = Record.prototype.fields, fi = f.items, fl = f.length;
21212 // Generate extraction functions for the totalProperty, the root, the id, and for each field
21214 if(s.totalProperty) {
21215 this.getTotal = this.getJsonAccessor(s.totalProperty);
21217 if(s.successProperty) {
21218 this.getSuccess = this.getJsonAccessor(s.successProperty);
21220 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
21222 var g = this.getJsonAccessor(s.id);
21223 this.getId = function(rec) {
21225 return (r === undefined || r === "") ? null : r;
21228 this.getId = function(){return null;};
21231 for(var jj = 0; jj < fl; jj++){
21233 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
21234 this.ef[jj] = this.getJsonAccessor(map);
21238 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
21239 if(s.totalProperty){
21240 var vt = parseInt(this.getTotal(o), 10);
21245 if(s.successProperty){
21246 var vs = this.getSuccess(o);
21247 if(vs === false || vs === 'false'){
21252 for(var i = 0; i < c; i++){
21255 var id = this.getId(n);
21256 for(var j = 0; j < fl; j++){
21258 var v = this.ef[j](n);
21260 Roo.log('missing convert for ' + f.name);
21264 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
21266 var record = new Record(values, id);
21268 records[i] = record;
21274 totalRecords : totalRecords
21279 * Ext JS Library 1.1.1
21280 * Copyright(c) 2006-2007, Ext JS, LLC.
21282 * Originally Released Under LGPL - original licence link has changed is not relivant.
21285 * <script type="text/javascript">
21289 * @class Roo.data.XmlReader
21290 * @extends Roo.data.DataReader
21291 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
21292 * based on mappings in a provided Roo.data.Record constructor.<br><br>
21294 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
21295 * header in the HTTP response must be set to "text/xml".</em>
21299 var RecordDef = Roo.data.Record.create([
21300 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
21301 {name: 'occupation'} // This field will use "occupation" as the mapping.
21303 var myReader = new Roo.data.XmlReader({
21304 totalRecords: "results", // The element which contains the total dataset size (optional)
21305 record: "row", // The repeated element which contains row information
21306 id: "id" // The element within the row that provides an ID for the record (optional)
21310 * This would consume an XML file like this:
21314 <results>2</results>
21317 <name>Bill</name>
21318 <occupation>Gardener</occupation>
21322 <name>Ben</name>
21323 <occupation>Horticulturalist</occupation>
21327 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
21328 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
21329 * paged from the remote server.
21330 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
21331 * @cfg {String} success The DomQuery path to the success attribute used by forms.
21332 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
21333 * a record identifier value.
21335 * Create a new XmlReader
21336 * @param {Object} meta Metadata configuration options
21337 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
21338 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
21339 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
21341 Roo.data.XmlReader = function(meta, recordType){
21343 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
21345 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
21347 * This method is only used by a DataProxy which has retrieved data from a remote server.
21348 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
21349 * to contain a method called 'responseXML' that returns an XML document object.
21350 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
21351 * a cache of Roo.data.Records.
21353 read : function(response){
21354 var doc = response.responseXML;
21356 throw {message: "XmlReader.read: XML Document not available"};
21358 return this.readRecords(doc);
21362 * Create a data block containing Roo.data.Records from an XML document.
21363 * @param {Object} doc A parsed XML document.
21364 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
21365 * a cache of Roo.data.Records.
21367 readRecords : function(doc){
21369 * After any data loads/reads, the raw XML Document is available for further custom processing.
21370 * @type XMLDocument
21372 this.xmlData = doc;
21373 var root = doc.documentElement || doc;
21374 var q = Roo.DomQuery;
21375 var recordType = this.recordType, fields = recordType.prototype.fields;
21376 var sid = this.meta.id;
21377 var totalRecords = 0, success = true;
21378 if(this.meta.totalRecords){
21379 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
21382 if(this.meta.success){
21383 var sv = q.selectValue(this.meta.success, root, true);
21384 success = sv !== false && sv !== 'false';
21387 var ns = q.select(this.meta.record, root);
21388 for(var i = 0, len = ns.length; i < len; i++) {
21391 var id = sid ? q.selectValue(sid, n) : undefined;
21392 for(var j = 0, jlen = fields.length; j < jlen; j++){
21393 var f = fields.items[j];
21394 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
21396 values[f.name] = v;
21398 var record = new recordType(values, id);
21400 records[records.length] = record;
21406 totalRecords : totalRecords || records.length
21411 * Ext JS Library 1.1.1
21412 * Copyright(c) 2006-2007, Ext JS, LLC.
21414 * Originally Released Under LGPL - original licence link has changed is not relivant.
21417 * <script type="text/javascript">
21421 * @class Roo.data.ArrayReader
21422 * @extends Roo.data.DataReader
21423 * Data reader class to create an Array of Roo.data.Record objects from an Array.
21424 * Each element of that Array represents a row of data fields. The
21425 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
21426 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
21430 var RecordDef = Roo.data.Record.create([
21431 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
21432 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
21434 var myReader = new Roo.data.ArrayReader({
21435 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
21439 * This would consume an Array like this:
21441 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
21443 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
21445 * Create a new JsonReader
21446 * @param {Object} meta Metadata configuration options.
21447 * @param {Object} recordType Either an Array of field definition objects
21448 * as specified to {@link Roo.data.Record#create},
21449 * or an {@link Roo.data.Record} object
21450 * created using {@link Roo.data.Record#create}.
21452 Roo.data.ArrayReader = function(meta, recordType){
21453 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
21456 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
21458 * Create a data block containing Roo.data.Records from an XML document.
21459 * @param {Object} o An Array of row objects which represents the dataset.
21460 * @return {Object} data A data block which is used by an Roo.data.Store object as
21461 * a cache of Roo.data.Records.
21463 readRecords : function(o){
21464 var sid = this.meta ? this.meta.id : null;
21465 var recordType = this.recordType, fields = recordType.prototype.fields;
21468 for(var i = 0; i < root.length; i++){
21471 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
21472 for(var j = 0, jlen = fields.length; j < jlen; j++){
21473 var f = fields.items[j];
21474 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
21475 var v = n[k] !== undefined ? n[k] : f.defaultValue;
21477 values[f.name] = v;
21479 var record = new recordType(values, id);
21481 records[records.length] = record;
21485 totalRecords : records.length
21490 * Ext JS Library 1.1.1
21491 * Copyright(c) 2006-2007, Ext JS, LLC.
21493 * Originally Released Under LGPL - original licence link has changed is not relivant.
21496 * <script type="text/javascript">
21501 * @class Roo.data.Tree
21502 * @extends Roo.util.Observable
21503 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
21504 * in the tree have most standard DOM functionality.
21506 * @param {Node} root (optional) The root node
21508 Roo.data.Tree = function(root){
21509 this.nodeHash = {};
21511 * The root node for this tree
21516 this.setRootNode(root);
21521 * Fires when a new child node is appended to a node in this tree.
21522 * @param {Tree} tree The owner tree
21523 * @param {Node} parent The parent node
21524 * @param {Node} node The newly appended node
21525 * @param {Number} index The index of the newly appended node
21530 * Fires when a child node is removed from a node in this tree.
21531 * @param {Tree} tree The owner tree
21532 * @param {Node} parent The parent node
21533 * @param {Node} node The child node removed
21538 * Fires when a node is moved to a new location in the tree
21539 * @param {Tree} tree The owner tree
21540 * @param {Node} node The node moved
21541 * @param {Node} oldParent The old parent of this node
21542 * @param {Node} newParent The new parent of this node
21543 * @param {Number} index The index it was moved to
21548 * Fires when a new child node is inserted in a node in this tree.
21549 * @param {Tree} tree The owner tree
21550 * @param {Node} parent The parent node
21551 * @param {Node} node The child node inserted
21552 * @param {Node} refNode The child node the node was inserted before
21556 * @event beforeappend
21557 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21558 * @param {Tree} tree The owner tree
21559 * @param {Node} parent The parent node
21560 * @param {Node} node The child node to be appended
21562 "beforeappend" : true,
21564 * @event beforeremove
21565 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21566 * @param {Tree} tree The owner tree
21567 * @param {Node} parent The parent node
21568 * @param {Node} node The child node to be removed
21570 "beforeremove" : true,
21572 * @event beforemove
21573 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21574 * @param {Tree} tree The owner tree
21575 * @param {Node} node The node being moved
21576 * @param {Node} oldParent The parent of the node
21577 * @param {Node} newParent The new parent the node is moving to
21578 * @param {Number} index The index it is being moved to
21580 "beforemove" : true,
21582 * @event beforeinsert
21583 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21584 * @param {Tree} tree The owner tree
21585 * @param {Node} parent The parent node
21586 * @param {Node} node The child node to be inserted
21587 * @param {Node} refNode The child node the node is being inserted before
21589 "beforeinsert" : true
21592 Roo.data.Tree.superclass.constructor.call(this);
21595 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21596 pathSeparator: "/",
21598 proxyNodeEvent : function(){
21599 return this.fireEvent.apply(this, arguments);
21603 * Returns the root node for this tree.
21606 getRootNode : function(){
21611 * Sets the root node for this tree.
21612 * @param {Node} node
21615 setRootNode : function(node){
21617 node.ownerTree = this;
21618 node.isRoot = true;
21619 this.registerNode(node);
21624 * Gets a node in this tree by its id.
21625 * @param {String} id
21628 getNodeById : function(id){
21629 return this.nodeHash[id];
21632 registerNode : function(node){
21633 this.nodeHash[node.id] = node;
21636 unregisterNode : function(node){
21637 delete this.nodeHash[node.id];
21640 toString : function(){
21641 return "[Tree"+(this.id?" "+this.id:"")+"]";
21646 * @class Roo.data.Node
21647 * @extends Roo.util.Observable
21648 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21649 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21651 * @param {Object} attributes The attributes/config for the node
21653 Roo.data.Node = function(attributes){
21655 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21658 this.attributes = attributes || {};
21659 this.leaf = this.attributes.leaf;
21661 * The node id. @type String
21663 this.id = this.attributes.id;
21665 this.id = Roo.id(null, "ynode-");
21666 this.attributes.id = this.id;
21671 * All child nodes of this node. @type Array
21673 this.childNodes = [];
21674 if(!this.childNodes.indexOf){ // indexOf is a must
21675 this.childNodes.indexOf = function(o){
21676 for(var i = 0, len = this.length; i < len; i++){
21685 * The parent node for this node. @type Node
21687 this.parentNode = null;
21689 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21691 this.firstChild = null;
21693 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21695 this.lastChild = null;
21697 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21699 this.previousSibling = null;
21701 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21703 this.nextSibling = null;
21708 * Fires when a new child node is appended
21709 * @param {Tree} tree The owner tree
21710 * @param {Node} this This node
21711 * @param {Node} node The newly appended node
21712 * @param {Number} index The index of the newly appended node
21717 * Fires when a child node is removed
21718 * @param {Tree} tree The owner tree
21719 * @param {Node} this This node
21720 * @param {Node} node The removed node
21725 * Fires when this node is moved to a new location in the tree
21726 * @param {Tree} tree The owner tree
21727 * @param {Node} this This node
21728 * @param {Node} oldParent The old parent of this node
21729 * @param {Node} newParent The new parent of this node
21730 * @param {Number} index The index it was moved to
21735 * Fires when a new child node is inserted.
21736 * @param {Tree} tree The owner tree
21737 * @param {Node} this This node
21738 * @param {Node} node The child node inserted
21739 * @param {Node} refNode The child node the node was inserted before
21743 * @event beforeappend
21744 * Fires before a new child is appended, return false to cancel the append.
21745 * @param {Tree} tree The owner tree
21746 * @param {Node} this This node
21747 * @param {Node} node The child node to be appended
21749 "beforeappend" : true,
21751 * @event beforeremove
21752 * Fires before a child is removed, return false to cancel the remove.
21753 * @param {Tree} tree The owner tree
21754 * @param {Node} this This node
21755 * @param {Node} node The child node to be removed
21757 "beforeremove" : true,
21759 * @event beforemove
21760 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21761 * @param {Tree} tree The owner tree
21762 * @param {Node} this This node
21763 * @param {Node} oldParent The parent of this node
21764 * @param {Node} newParent The new parent this node is moving to
21765 * @param {Number} index The index it is being moved to
21767 "beforemove" : true,
21769 * @event beforeinsert
21770 * Fires before a new child is inserted, return false to cancel the insert.
21771 * @param {Tree} tree The owner tree
21772 * @param {Node} this This node
21773 * @param {Node} node The child node to be inserted
21774 * @param {Node} refNode The child node the node is being inserted before
21776 "beforeinsert" : true
21778 this.listeners = this.attributes.listeners;
21779 Roo.data.Node.superclass.constructor.call(this);
21782 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21783 fireEvent : function(evtName){
21784 // first do standard event for this node
21785 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21788 // then bubble it up to the tree if the event wasn't cancelled
21789 var ot = this.getOwnerTree();
21791 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21799 * Returns true if this node is a leaf
21800 * @return {Boolean}
21802 isLeaf : function(){
21803 return this.leaf === true;
21807 setFirstChild : function(node){
21808 this.firstChild = node;
21812 setLastChild : function(node){
21813 this.lastChild = node;
21818 * Returns true if this node is the last child of its parent
21819 * @return {Boolean}
21821 isLast : function(){
21822 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21826 * Returns true if this node is the first child of its parent
21827 * @return {Boolean}
21829 isFirst : function(){
21830 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21833 hasChildNodes : function(){
21834 return !this.isLeaf() && this.childNodes.length > 0;
21838 * Insert node(s) as the last child node of this node.
21839 * @param {Node/Array} node The node or Array of nodes to append
21840 * @return {Node} The appended node if single append, or null if an array was passed
21842 appendChild : function(node){
21844 if(node instanceof Array){
21846 }else if(arguments.length > 1){
21849 // if passed an array or multiple args do them one by one
21851 for(var i = 0, len = multi.length; i < len; i++) {
21852 this.appendChild(multi[i]);
21855 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21858 var index = this.childNodes.length;
21859 var oldParent = node.parentNode;
21860 // it's a move, make sure we move it cleanly
21862 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21865 oldParent.removeChild(node);
21867 index = this.childNodes.length;
21869 this.setFirstChild(node);
21871 this.childNodes.push(node);
21872 node.parentNode = this;
21873 var ps = this.childNodes[index-1];
21875 node.previousSibling = ps;
21876 ps.nextSibling = node;
21878 node.previousSibling = null;
21880 node.nextSibling = null;
21881 this.setLastChild(node);
21882 node.setOwnerTree(this.getOwnerTree());
21883 this.fireEvent("append", this.ownerTree, this, node, index);
21885 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21892 * Removes a child node from this node.
21893 * @param {Node} node The node to remove
21894 * @return {Node} The removed node
21896 removeChild : function(node){
21897 var index = this.childNodes.indexOf(node);
21901 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21905 // remove it from childNodes collection
21906 this.childNodes.splice(index, 1);
21909 if(node.previousSibling){
21910 node.previousSibling.nextSibling = node.nextSibling;
21912 if(node.nextSibling){
21913 node.nextSibling.previousSibling = node.previousSibling;
21916 // update child refs
21917 if(this.firstChild == node){
21918 this.setFirstChild(node.nextSibling);
21920 if(this.lastChild == node){
21921 this.setLastChild(node.previousSibling);
21924 node.setOwnerTree(null);
21925 // clear any references from the node
21926 node.parentNode = null;
21927 node.previousSibling = null;
21928 node.nextSibling = null;
21929 this.fireEvent("remove", this.ownerTree, this, node);
21934 * Inserts the first node before the second node in this nodes childNodes collection.
21935 * @param {Node} node The node to insert
21936 * @param {Node} refNode The node to insert before (if null the node is appended)
21937 * @return {Node} The inserted node
21939 insertBefore : function(node, refNode){
21940 if(!refNode){ // like standard Dom, refNode can be null for append
21941 return this.appendChild(node);
21944 if(node == refNode){
21948 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21951 var index = this.childNodes.indexOf(refNode);
21952 var oldParent = node.parentNode;
21953 var refIndex = index;
21955 // when moving internally, indexes will change after remove
21956 if(oldParent == this && this.childNodes.indexOf(node) < index){
21960 // it's a move, make sure we move it cleanly
21962 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21965 oldParent.removeChild(node);
21968 this.setFirstChild(node);
21970 this.childNodes.splice(refIndex, 0, node);
21971 node.parentNode = this;
21972 var ps = this.childNodes[refIndex-1];
21974 node.previousSibling = ps;
21975 ps.nextSibling = node;
21977 node.previousSibling = null;
21979 node.nextSibling = refNode;
21980 refNode.previousSibling = node;
21981 node.setOwnerTree(this.getOwnerTree());
21982 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21984 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21990 * Returns the child node at the specified index.
21991 * @param {Number} index
21994 item : function(index){
21995 return this.childNodes[index];
21999 * Replaces one child node in this node with another.
22000 * @param {Node} newChild The replacement node
22001 * @param {Node} oldChild The node to replace
22002 * @return {Node} The replaced node
22004 replaceChild : function(newChild, oldChild){
22005 this.insertBefore(newChild, oldChild);
22006 this.removeChild(oldChild);
22011 * Returns the index of a child node
22012 * @param {Node} node
22013 * @return {Number} The index of the node or -1 if it was not found
22015 indexOf : function(child){
22016 return this.childNodes.indexOf(child);
22020 * Returns the tree this node is in.
22023 getOwnerTree : function(){
22024 // if it doesn't have one, look for one
22025 if(!this.ownerTree){
22029 this.ownerTree = p.ownerTree;
22035 return this.ownerTree;
22039 * Returns depth of this node (the root node has a depth of 0)
22042 getDepth : function(){
22045 while(p.parentNode){
22053 setOwnerTree : function(tree){
22054 // if it's move, we need to update everyone
22055 if(tree != this.ownerTree){
22056 if(this.ownerTree){
22057 this.ownerTree.unregisterNode(this);
22059 this.ownerTree = tree;
22060 var cs = this.childNodes;
22061 for(var i = 0, len = cs.length; i < len; i++) {
22062 cs[i].setOwnerTree(tree);
22065 tree.registerNode(this);
22071 * Returns the path for this node. The path can be used to expand or select this node programmatically.
22072 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
22073 * @return {String} The path
22075 getPath : function(attr){
22076 attr = attr || "id";
22077 var p = this.parentNode;
22078 var b = [this.attributes[attr]];
22080 b.unshift(p.attributes[attr]);
22083 var sep = this.getOwnerTree().pathSeparator;
22084 return sep + b.join(sep);
22088 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
22089 * function call will be the scope provided or the current node. The arguments to the function
22090 * will be the args provided or the current node. If the function returns false at any point,
22091 * the bubble is stopped.
22092 * @param {Function} fn The function to call
22093 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22094 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22096 bubble : function(fn, scope, args){
22099 if(fn.call(scope || p, args || p) === false){
22107 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
22108 * function call will be the scope provided or the current node. The arguments to the function
22109 * will be the args provided or the current node. If the function returns false at any point,
22110 * the cascade is stopped on that branch.
22111 * @param {Function} fn The function to call
22112 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22113 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22115 cascade : function(fn, scope, args){
22116 if(fn.call(scope || this, args || this) !== false){
22117 var cs = this.childNodes;
22118 for(var i = 0, len = cs.length; i < len; i++) {
22119 cs[i].cascade(fn, scope, args);
22125 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
22126 * function call will be the scope provided or the current node. The arguments to the function
22127 * will be the args provided or the current node. If the function returns false at any point,
22128 * the iteration stops.
22129 * @param {Function} fn The function to call
22130 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22131 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22133 eachChild : function(fn, scope, args){
22134 var cs = this.childNodes;
22135 for(var i = 0, len = cs.length; i < len; i++) {
22136 if(fn.call(scope || this, args || cs[i]) === false){
22143 * Finds the first child that has the attribute with the specified value.
22144 * @param {String} attribute The attribute name
22145 * @param {Mixed} value The value to search for
22146 * @return {Node} The found child or null if none was found
22148 findChild : function(attribute, value){
22149 var cs = this.childNodes;
22150 for(var i = 0, len = cs.length; i < len; i++) {
22151 if(cs[i].attributes[attribute] == value){
22159 * Finds the first child by a custom function. The child matches if the function passed
22161 * @param {Function} fn
22162 * @param {Object} scope (optional)
22163 * @return {Node} The found child or null if none was found
22165 findChildBy : function(fn, scope){
22166 var cs = this.childNodes;
22167 for(var i = 0, len = cs.length; i < len; i++) {
22168 if(fn.call(scope||cs[i], cs[i]) === true){
22176 * Sorts this nodes children using the supplied sort function
22177 * @param {Function} fn
22178 * @param {Object} scope (optional)
22180 sort : function(fn, scope){
22181 var cs = this.childNodes;
22182 var len = cs.length;
22184 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
22186 for(var i = 0; i < len; i++){
22188 n.previousSibling = cs[i-1];
22189 n.nextSibling = cs[i+1];
22191 this.setFirstChild(n);
22194 this.setLastChild(n);
22201 * Returns true if this node is an ancestor (at any point) of the passed node.
22202 * @param {Node} node
22203 * @return {Boolean}
22205 contains : function(node){
22206 return node.isAncestor(this);
22210 * Returns true if the passed node is an ancestor (at any point) of this node.
22211 * @param {Node} node
22212 * @return {Boolean}
22214 isAncestor : function(node){
22215 var p = this.parentNode;
22225 toString : function(){
22226 return "[Node"+(this.id?" "+this.id:"")+"]";
22230 * Ext JS Library 1.1.1
22231 * Copyright(c) 2006-2007, Ext JS, LLC.
22233 * Originally Released Under LGPL - original licence link has changed is not relivant.
22236 * <script type="text/javascript">
22241 * @class Roo.ComponentMgr
22242 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
22245 Roo.ComponentMgr = function(){
22246 var all = new Roo.util.MixedCollection();
22250 * Registers a component.
22251 * @param {Roo.Component} c The component
22253 register : function(c){
22258 * Unregisters a component.
22259 * @param {Roo.Component} c The component
22261 unregister : function(c){
22266 * Returns a component by id
22267 * @param {String} id The component id
22269 get : function(id){
22270 return all.get(id);
22274 * Registers a function that will be called when a specified component is added to ComponentMgr
22275 * @param {String} id The component id
22276 * @param {Funtction} fn The callback function
22277 * @param {Object} scope The scope of the callback
22279 onAvailable : function(id, fn, scope){
22280 all.on("add", function(index, o){
22282 fn.call(scope || o, o);
22283 all.un("add", fn, scope);
22290 * Ext JS Library 1.1.1
22291 * Copyright(c) 2006-2007, Ext JS, LLC.
22293 * Originally Released Under LGPL - original licence link has changed is not relivant.
22296 * <script type="text/javascript">
22300 * @class Roo.Component
22301 * @extends Roo.util.Observable
22302 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
22303 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
22304 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
22305 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
22306 * All visual components (widgets) that require rendering into a layout should subclass Component.
22308 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
22309 * 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
22310 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
22312 Roo.Component = function(config){
22313 config = config || {};
22314 if(config.tagName || config.dom || typeof config == "string"){ // element object
22315 config = {el: config, id: config.id || config};
22317 this.initialConfig = config;
22319 Roo.apply(this, config);
22323 * Fires after the component is disabled.
22324 * @param {Roo.Component} this
22329 * Fires after the component is enabled.
22330 * @param {Roo.Component} this
22334 * @event beforeshow
22335 * Fires before the component is shown. Return false to stop the show.
22336 * @param {Roo.Component} this
22341 * Fires after the component is shown.
22342 * @param {Roo.Component} this
22346 * @event beforehide
22347 * Fires before the component is hidden. Return false to stop the hide.
22348 * @param {Roo.Component} this
22353 * Fires after the component is hidden.
22354 * @param {Roo.Component} this
22358 * @event beforerender
22359 * Fires before the component is rendered. Return false to stop the render.
22360 * @param {Roo.Component} this
22362 beforerender : true,
22365 * Fires after the component is rendered.
22366 * @param {Roo.Component} this
22370 * @event beforedestroy
22371 * Fires before the component is destroyed. Return false to stop the destroy.
22372 * @param {Roo.Component} this
22374 beforedestroy : true,
22377 * Fires after the component is destroyed.
22378 * @param {Roo.Component} this
22383 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
22385 Roo.ComponentMgr.register(this);
22386 Roo.Component.superclass.constructor.call(this);
22387 this.initComponent();
22388 if(this.renderTo){ // not supported by all components yet. use at your own risk!
22389 this.render(this.renderTo);
22390 delete this.renderTo;
22395 Roo.Component.AUTO_ID = 1000;
22397 Roo.extend(Roo.Component, Roo.util.Observable, {
22399 * @scope Roo.Component.prototype
22401 * true if this component is hidden. Read-only.
22406 * true if this component is disabled. Read-only.
22411 * true if this component has been rendered. Read-only.
22415 /** @cfg {String} disableClass
22416 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
22418 disabledClass : "x-item-disabled",
22419 /** @cfg {Boolean} allowDomMove
22420 * Whether the component can move the Dom node when rendering (defaults to true).
22422 allowDomMove : true,
22423 /** @cfg {String} hideMode
22424 * How this component should hidden. Supported values are
22425 * "visibility" (css visibility), "offsets" (negative offset position) and
22426 * "display" (css display) - defaults to "display".
22428 hideMode: 'display',
22431 ctype : "Roo.Component",
22434 * @cfg {String} actionMode
22435 * which property holds the element that used for hide() / show() / disable() / enable()
22441 getActionEl : function(){
22442 return this[this.actionMode];
22445 initComponent : Roo.emptyFn,
22447 * If this is a lazy rendering component, render it to its container element.
22448 * @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.
22450 render : function(container, position){
22451 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
22452 if(!container && this.el){
22453 this.el = Roo.get(this.el);
22454 container = this.el.dom.parentNode;
22455 this.allowDomMove = false;
22457 this.container = Roo.get(container);
22458 this.rendered = true;
22459 if(position !== undefined){
22460 if(typeof position == 'number'){
22461 position = this.container.dom.childNodes[position];
22463 position = Roo.getDom(position);
22466 this.onRender(this.container, position || null);
22468 this.el.addClass(this.cls);
22472 this.el.applyStyles(this.style);
22475 this.fireEvent("render", this);
22476 this.afterRender(this.container);
22488 // default function is not really useful
22489 onRender : function(ct, position){
22491 this.el = Roo.get(this.el);
22492 if(this.allowDomMove !== false){
22493 ct.dom.insertBefore(this.el.dom, position);
22499 getAutoCreate : function(){
22500 var cfg = typeof this.autoCreate == "object" ?
22501 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
22502 if(this.id && !cfg.id){
22509 afterRender : Roo.emptyFn,
22512 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
22513 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
22515 destroy : function(){
22516 if(this.fireEvent("beforedestroy", this) !== false){
22517 this.purgeListeners();
22518 this.beforeDestroy();
22520 this.el.removeAllListeners();
22522 if(this.actionMode == "container"){
22523 this.container.remove();
22527 Roo.ComponentMgr.unregister(this);
22528 this.fireEvent("destroy", this);
22533 beforeDestroy : function(){
22538 onDestroy : function(){
22543 * Returns the underlying {@link Roo.Element}.
22544 * @return {Roo.Element} The element
22546 getEl : function(){
22551 * Returns the id of this component.
22554 getId : function(){
22559 * Try to focus this component.
22560 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22561 * @return {Roo.Component} this
22563 focus : function(selectText){
22566 if(selectText === true){
22567 this.el.dom.select();
22582 * Disable this component.
22583 * @return {Roo.Component} this
22585 disable : function(){
22589 this.disabled = true;
22590 this.fireEvent("disable", this);
22595 onDisable : function(){
22596 this.getActionEl().addClass(this.disabledClass);
22597 this.el.dom.disabled = true;
22601 * Enable this component.
22602 * @return {Roo.Component} this
22604 enable : function(){
22608 this.disabled = false;
22609 this.fireEvent("enable", this);
22614 onEnable : function(){
22615 this.getActionEl().removeClass(this.disabledClass);
22616 this.el.dom.disabled = false;
22620 * Convenience function for setting disabled/enabled by boolean.
22621 * @param {Boolean} disabled
22623 setDisabled : function(disabled){
22624 this[disabled ? "disable" : "enable"]();
22628 * Show this component.
22629 * @return {Roo.Component} this
22632 if(this.fireEvent("beforeshow", this) !== false){
22633 this.hidden = false;
22637 this.fireEvent("show", this);
22643 onShow : function(){
22644 var ae = this.getActionEl();
22645 if(this.hideMode == 'visibility'){
22646 ae.dom.style.visibility = "visible";
22647 }else if(this.hideMode == 'offsets'){
22648 ae.removeClass('x-hidden');
22650 ae.dom.style.display = "";
22655 * Hide this component.
22656 * @return {Roo.Component} this
22659 if(this.fireEvent("beforehide", this) !== false){
22660 this.hidden = true;
22664 this.fireEvent("hide", this);
22670 onHide : function(){
22671 var ae = this.getActionEl();
22672 if(this.hideMode == 'visibility'){
22673 ae.dom.style.visibility = "hidden";
22674 }else if(this.hideMode == 'offsets'){
22675 ae.addClass('x-hidden');
22677 ae.dom.style.display = "none";
22682 * Convenience function to hide or show this component by boolean.
22683 * @param {Boolean} visible True to show, false to hide
22684 * @return {Roo.Component} this
22686 setVisible: function(visible){
22696 * Returns true if this component is visible.
22698 isVisible : function(){
22699 return this.getActionEl().isVisible();
22702 cloneConfig : function(overrides){
22703 overrides = overrides || {};
22704 var id = overrides.id || Roo.id();
22705 var cfg = Roo.applyIf(overrides, this.initialConfig);
22706 cfg.id = id; // prevent dup id
22707 return new this.constructor(cfg);
22711 * Ext JS Library 1.1.1
22712 * Copyright(c) 2006-2007, Ext JS, LLC.
22714 * Originally Released Under LGPL - original licence link has changed is not relivant.
22717 * <script type="text/javascript">
22722 * @extends Roo.Element
22723 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22724 * automatic maintaining of shadow/shim positions.
22725 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22726 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22727 * you can pass a string with a CSS class name. False turns off the shadow.
22728 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22729 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22730 * @cfg {String} cls CSS class to add to the element
22731 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22732 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22734 * @param {Object} config An object with config options.
22735 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22738 Roo.Layer = function(config, existingEl){
22739 config = config || {};
22740 var dh = Roo.DomHelper;
22741 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22743 this.dom = Roo.getDom(existingEl);
22746 var o = config.dh || {tag: "div", cls: "x-layer"};
22747 this.dom = dh.append(pel, o);
22750 this.addClass(config.cls);
22752 this.constrain = config.constrain !== false;
22753 this.visibilityMode = Roo.Element.VISIBILITY;
22755 this.id = this.dom.id = config.id;
22757 this.id = Roo.id(this.dom);
22759 this.zindex = config.zindex || this.getZIndex();
22760 this.position("absolute", this.zindex);
22762 this.shadowOffset = config.shadowOffset || 4;
22763 this.shadow = new Roo.Shadow({
22764 offset : this.shadowOffset,
22765 mode : config.shadow
22768 this.shadowOffset = 0;
22770 this.useShim = config.shim !== false && Roo.useShims;
22771 this.useDisplay = config.useDisplay;
22775 var supr = Roo.Element.prototype;
22777 // shims are shared among layer to keep from having 100 iframes
22780 Roo.extend(Roo.Layer, Roo.Element, {
22782 getZIndex : function(){
22783 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22786 getShim : function(){
22793 var shim = shims.shift();
22795 shim = this.createShim();
22796 shim.enableDisplayMode('block');
22797 shim.dom.style.display = 'none';
22798 shim.dom.style.visibility = 'visible';
22800 var pn = this.dom.parentNode;
22801 if(shim.dom.parentNode != pn){
22802 pn.insertBefore(shim.dom, this.dom);
22804 shim.setStyle('z-index', this.getZIndex()-2);
22809 hideShim : function(){
22811 this.shim.setDisplayed(false);
22812 shims.push(this.shim);
22817 disableShadow : function(){
22819 this.shadowDisabled = true;
22820 this.shadow.hide();
22821 this.lastShadowOffset = this.shadowOffset;
22822 this.shadowOffset = 0;
22826 enableShadow : function(show){
22828 this.shadowDisabled = false;
22829 this.shadowOffset = this.lastShadowOffset;
22830 delete this.lastShadowOffset;
22838 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22839 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22840 sync : function(doShow){
22841 var sw = this.shadow;
22842 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22843 var sh = this.getShim();
22845 var w = this.getWidth(),
22846 h = this.getHeight();
22848 var l = this.getLeft(true),
22849 t = this.getTop(true);
22851 if(sw && !this.shadowDisabled){
22852 if(doShow && !sw.isVisible()){
22855 sw.realign(l, t, w, h);
22861 // fit the shim behind the shadow, so it is shimmed too
22862 var a = sw.adjusts, s = sh.dom.style;
22863 s.left = (Math.min(l, l+a.l))+"px";
22864 s.top = (Math.min(t, t+a.t))+"px";
22865 s.width = (w+a.w)+"px";
22866 s.height = (h+a.h)+"px";
22873 sh.setLeftTop(l, t);
22880 destroy : function(){
22883 this.shadow.hide();
22885 this.removeAllListeners();
22886 var pn = this.dom.parentNode;
22888 pn.removeChild(this.dom);
22890 Roo.Element.uncache(this.id);
22893 remove : function(){
22898 beginUpdate : function(){
22899 this.updating = true;
22903 endUpdate : function(){
22904 this.updating = false;
22909 hideUnders : function(negOffset){
22911 this.shadow.hide();
22917 constrainXY : function(){
22918 if(this.constrain){
22919 var vw = Roo.lib.Dom.getViewWidth(),
22920 vh = Roo.lib.Dom.getViewHeight();
22921 var s = Roo.get(document).getScroll();
22923 var xy = this.getXY();
22924 var x = xy[0], y = xy[1];
22925 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22926 // only move it if it needs it
22928 // first validate right/bottom
22929 if((x + w) > vw+s.left){
22930 x = vw - w - this.shadowOffset;
22933 if((y + h) > vh+s.top){
22934 y = vh - h - this.shadowOffset;
22937 // then make sure top/left isn't negative
22948 var ay = this.avoidY;
22949 if(y <= ay && (y+h) >= ay){
22955 supr.setXY.call(this, xy);
22961 isVisible : function(){
22962 return this.visible;
22966 showAction : function(){
22967 this.visible = true; // track visibility to prevent getStyle calls
22968 if(this.useDisplay === true){
22969 this.setDisplayed("");
22970 }else if(this.lastXY){
22971 supr.setXY.call(this, this.lastXY);
22972 }else if(this.lastLT){
22973 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22978 hideAction : function(){
22979 this.visible = false;
22980 if(this.useDisplay === true){
22981 this.setDisplayed(false);
22983 this.setLeftTop(-10000,-10000);
22987 // overridden Element method
22988 setVisible : function(v, a, d, c, e){
22993 var cb = function(){
22998 }.createDelegate(this);
22999 supr.setVisible.call(this, true, true, d, cb, e);
23002 this.hideUnders(true);
23011 }.createDelegate(this);
23013 supr.setVisible.call(this, v, a, d, cb, e);
23022 storeXY : function(xy){
23023 delete this.lastLT;
23027 storeLeftTop : function(left, top){
23028 delete this.lastXY;
23029 this.lastLT = [left, top];
23033 beforeFx : function(){
23034 this.beforeAction();
23035 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23039 afterFx : function(){
23040 Roo.Layer.superclass.afterFx.apply(this, arguments);
23041 this.sync(this.isVisible());
23045 beforeAction : function(){
23046 if(!this.updating && this.shadow){
23047 this.shadow.hide();
23051 // overridden Element method
23052 setLeft : function(left){
23053 this.storeLeftTop(left, this.getTop(true));
23054 supr.setLeft.apply(this, arguments);
23058 setTop : function(top){
23059 this.storeLeftTop(this.getLeft(true), top);
23060 supr.setTop.apply(this, arguments);
23064 setLeftTop : function(left, top){
23065 this.storeLeftTop(left, top);
23066 supr.setLeftTop.apply(this, arguments);
23070 setXY : function(xy, a, d, c, e){
23072 this.beforeAction();
23074 var cb = this.createCB(c);
23075 supr.setXY.call(this, xy, a, d, cb, e);
23082 createCB : function(c){
23093 // overridden Element method
23094 setX : function(x, a, d, c, e){
23095 this.setXY([x, this.getY()], a, d, c, e);
23098 // overridden Element method
23099 setY : function(y, a, d, c, e){
23100 this.setXY([this.getX(), y], a, d, c, e);
23103 // overridden Element method
23104 setSize : function(w, h, a, d, c, e){
23105 this.beforeAction();
23106 var cb = this.createCB(c);
23107 supr.setSize.call(this, w, h, a, d, cb, e);
23113 // overridden Element method
23114 setWidth : function(w, a, d, c, e){
23115 this.beforeAction();
23116 var cb = this.createCB(c);
23117 supr.setWidth.call(this, w, a, d, cb, e);
23123 // overridden Element method
23124 setHeight : function(h, a, d, c, e){
23125 this.beforeAction();
23126 var cb = this.createCB(c);
23127 supr.setHeight.call(this, h, a, d, cb, e);
23133 // overridden Element method
23134 setBounds : function(x, y, w, h, a, d, c, e){
23135 this.beforeAction();
23136 var cb = this.createCB(c);
23138 this.storeXY([x, y]);
23139 supr.setXY.call(this, [x, y]);
23140 supr.setSize.call(this, w, h, a, d, cb, e);
23143 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
23149 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
23150 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
23151 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
23152 * @param {Number} zindex The new z-index to set
23153 * @return {this} The Layer
23155 setZIndex : function(zindex){
23156 this.zindex = zindex;
23157 this.setStyle("z-index", zindex + 2);
23159 this.shadow.setZIndex(zindex + 1);
23162 this.shim.setStyle("z-index", zindex);
23168 * Ext JS Library 1.1.1
23169 * Copyright(c) 2006-2007, Ext JS, LLC.
23171 * Originally Released Under LGPL - original licence link has changed is not relivant.
23174 * <script type="text/javascript">
23179 * @class Roo.Shadow
23180 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
23181 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
23182 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
23184 * Create a new Shadow
23185 * @param {Object} config The config object
23187 Roo.Shadow = function(config){
23188 Roo.apply(this, config);
23189 if(typeof this.mode != "string"){
23190 this.mode = this.defaultMode;
23192 var o = this.offset, a = {h: 0};
23193 var rad = Math.floor(this.offset/2);
23194 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
23200 a.l -= this.offset + rad;
23201 a.t -= this.offset + rad;
23212 a.l -= (this.offset - rad);
23213 a.t -= this.offset + rad;
23215 a.w -= (this.offset - rad)*2;
23226 a.l -= (this.offset - rad);
23227 a.t -= (this.offset - rad);
23229 a.w -= (this.offset + rad + 1);
23230 a.h -= (this.offset + rad);
23239 Roo.Shadow.prototype = {
23241 * @cfg {String} mode
23242 * The shadow display mode. Supports the following options:<br />
23243 * sides: Shadow displays on both sides and bottom only<br />
23244 * frame: Shadow displays equally on all four sides<br />
23245 * drop: Traditional bottom-right drop shadow (default)
23248 * @cfg {String} offset
23249 * The number of pixels to offset the shadow from the element (defaults to 4)
23254 defaultMode: "drop",
23257 * Displays the shadow under the target element
23258 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
23260 show : function(target){
23261 target = Roo.get(target);
23263 this.el = Roo.Shadow.Pool.pull();
23264 if(this.el.dom.nextSibling != target.dom){
23265 this.el.insertBefore(target);
23268 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
23270 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
23273 target.getLeft(true),
23274 target.getTop(true),
23278 this.el.dom.style.display = "block";
23282 * Returns true if the shadow is visible, else false
23284 isVisible : function(){
23285 return this.el ? true : false;
23289 * Direct alignment when values are already available. Show must be called at least once before
23290 * calling this method to ensure it is initialized.
23291 * @param {Number} left The target element left position
23292 * @param {Number} top The target element top position
23293 * @param {Number} width The target element width
23294 * @param {Number} height The target element height
23296 realign : function(l, t, w, h){
23300 var a = this.adjusts, d = this.el.dom, s = d.style;
23302 s.left = (l+a.l)+"px";
23303 s.top = (t+a.t)+"px";
23304 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
23306 if(s.width != sws || s.height != shs){
23310 var cn = d.childNodes;
23311 var sww = Math.max(0, (sw-12))+"px";
23312 cn[0].childNodes[1].style.width = sww;
23313 cn[1].childNodes[1].style.width = sww;
23314 cn[2].childNodes[1].style.width = sww;
23315 cn[1].style.height = Math.max(0, (sh-12))+"px";
23321 * Hides this shadow
23325 this.el.dom.style.display = "none";
23326 Roo.Shadow.Pool.push(this.el);
23332 * Adjust the z-index of this shadow
23333 * @param {Number} zindex The new z-index
23335 setZIndex : function(z){
23338 this.el.setStyle("z-index", z);
23343 // Private utility class that manages the internal Shadow cache
23344 Roo.Shadow.Pool = function(){
23346 var markup = Roo.isIE ?
23347 '<div class="x-ie-shadow"></div>' :
23348 '<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>';
23351 var sh = p.shift();
23353 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
23354 sh.autoBoxAdjust = false;
23359 push : function(sh){
23365 * Ext JS Library 1.1.1
23366 * Copyright(c) 2006-2007, Ext JS, LLC.
23368 * Originally Released Under LGPL - original licence link has changed is not relivant.
23371 * <script type="text/javascript">
23375 * @class Roo.BoxComponent
23376 * @extends Roo.Component
23377 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
23378 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
23379 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
23380 * layout containers.
23382 * @param {Roo.Element/String/Object} config The configuration options.
23384 Roo.BoxComponent = function(config){
23385 Roo.Component.call(this, config);
23389 * Fires after the component is resized.
23390 * @param {Roo.Component} this
23391 * @param {Number} adjWidth The box-adjusted width that was set
23392 * @param {Number} adjHeight The box-adjusted height that was set
23393 * @param {Number} rawWidth The width that was originally specified
23394 * @param {Number} rawHeight The height that was originally specified
23399 * Fires after the component is moved.
23400 * @param {Roo.Component} this
23401 * @param {Number} x The new x position
23402 * @param {Number} y The new y position
23408 Roo.extend(Roo.BoxComponent, Roo.Component, {
23409 // private, set in afterRender to signify that the component has been rendered
23411 // private, used to defer height settings to subclasses
23412 deferHeight: false,
23413 /** @cfg {Number} width
23414 * width (optional) size of component
23416 /** @cfg {Number} height
23417 * height (optional) size of component
23421 * Sets the width and height of the component. This method fires the resize event. This method can accept
23422 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
23423 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
23424 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
23425 * @return {Roo.BoxComponent} this
23427 setSize : function(w, h){
23428 // support for standard size objects
23429 if(typeof w == 'object'){
23434 if(!this.boxReady){
23440 // prevent recalcs when not needed
23441 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
23444 this.lastSize = {width: w, height: h};
23446 var adj = this.adjustSize(w, h);
23447 var aw = adj.width, ah = adj.height;
23448 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
23449 var rz = this.getResizeEl();
23450 if(!this.deferHeight && aw !== undefined && ah !== undefined){
23451 rz.setSize(aw, ah);
23452 }else if(!this.deferHeight && ah !== undefined){
23454 }else if(aw !== undefined){
23457 this.onResize(aw, ah, w, h);
23458 this.fireEvent('resize', this, aw, ah, w, h);
23464 * Gets the current size of the component's underlying element.
23465 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
23467 getSize : function(){
23468 return this.el.getSize();
23472 * Gets the current XY position of the component's underlying element.
23473 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23474 * @return {Array} The XY position of the element (e.g., [100, 200])
23476 getPosition : function(local){
23477 if(local === true){
23478 return [this.el.getLeft(true), this.el.getTop(true)];
23480 return this.xy || this.el.getXY();
23484 * Gets the current box measurements of the component's underlying element.
23485 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23486 * @returns {Object} box An object in the format {x, y, width, height}
23488 getBox : function(local){
23489 var s = this.el.getSize();
23491 s.x = this.el.getLeft(true);
23492 s.y = this.el.getTop(true);
23494 var xy = this.xy || this.el.getXY();
23502 * Sets the current box measurements of the component's underlying element.
23503 * @param {Object} box An object in the format {x, y, width, height}
23504 * @returns {Roo.BoxComponent} this
23506 updateBox : function(box){
23507 this.setSize(box.width, box.height);
23508 this.setPagePosition(box.x, box.y);
23513 getResizeEl : function(){
23514 return this.resizeEl || this.el;
23518 getPositionEl : function(){
23519 return this.positionEl || this.el;
23523 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
23524 * This method fires the move event.
23525 * @param {Number} left The new left
23526 * @param {Number} top The new top
23527 * @returns {Roo.BoxComponent} this
23529 setPosition : function(x, y){
23532 if(!this.boxReady){
23535 var adj = this.adjustPosition(x, y);
23536 var ax = adj.x, ay = adj.y;
23538 var el = this.getPositionEl();
23539 if(ax !== undefined || ay !== undefined){
23540 if(ax !== undefined && ay !== undefined){
23541 el.setLeftTop(ax, ay);
23542 }else if(ax !== undefined){
23544 }else if(ay !== undefined){
23547 this.onPosition(ax, ay);
23548 this.fireEvent('move', this, ax, ay);
23554 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
23555 * This method fires the move event.
23556 * @param {Number} x The new x position
23557 * @param {Number} y The new y position
23558 * @returns {Roo.BoxComponent} this
23560 setPagePosition : function(x, y){
23563 if(!this.boxReady){
23566 if(x === undefined || y === undefined){ // cannot translate undefined points
23569 var p = this.el.translatePoints(x, y);
23570 this.setPosition(p.left, p.top);
23575 onRender : function(ct, position){
23576 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23578 this.resizeEl = Roo.get(this.resizeEl);
23580 if(this.positionEl){
23581 this.positionEl = Roo.get(this.positionEl);
23586 afterRender : function(){
23587 Roo.BoxComponent.superclass.afterRender.call(this);
23588 this.boxReady = true;
23589 this.setSize(this.width, this.height);
23590 if(this.x || this.y){
23591 this.setPosition(this.x, this.y);
23593 if(this.pageX || this.pageY){
23594 this.setPagePosition(this.pageX, this.pageY);
23599 * Force the component's size to recalculate based on the underlying element's current height and width.
23600 * @returns {Roo.BoxComponent} this
23602 syncSize : function(){
23603 delete this.lastSize;
23604 this.setSize(this.el.getWidth(), this.el.getHeight());
23609 * Called after the component is resized, this method is empty by default but can be implemented by any
23610 * subclass that needs to perform custom logic after a resize occurs.
23611 * @param {Number} adjWidth The box-adjusted width that was set
23612 * @param {Number} adjHeight The box-adjusted height that was set
23613 * @param {Number} rawWidth The width that was originally specified
23614 * @param {Number} rawHeight The height that was originally specified
23616 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23621 * Called after the component is moved, this method is empty by default but can be implemented by any
23622 * subclass that needs to perform custom logic after a move occurs.
23623 * @param {Number} x The new x position
23624 * @param {Number} y The new y position
23626 onPosition : function(x, y){
23631 adjustSize : function(w, h){
23632 if(this.autoWidth){
23635 if(this.autoHeight){
23638 return {width : w, height: h};
23642 adjustPosition : function(x, y){
23643 return {x : x, y: y};
23647 * Ext JS Library 1.1.1
23648 * Copyright(c) 2006-2007, Ext JS, LLC.
23650 * Originally Released Under LGPL - original licence link has changed is not relivant.
23653 * <script type="text/javascript">
23658 * @class Roo.SplitBar
23659 * @extends Roo.util.Observable
23660 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23664 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23665 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23666 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23667 split.minSize = 100;
23668 split.maxSize = 600;
23669 split.animate = true;
23670 split.on('moved', splitterMoved);
23673 * Create a new SplitBar
23674 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23675 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23676 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23677 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23678 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23679 position of the SplitBar).
23681 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23684 this.el = Roo.get(dragElement, true);
23685 this.el.dom.unselectable = "on";
23687 this.resizingEl = Roo.get(resizingElement, true);
23691 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23692 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23695 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23698 * The minimum size of the resizing element. (Defaults to 0)
23704 * The maximum size of the resizing element. (Defaults to 2000)
23707 this.maxSize = 2000;
23710 * Whether to animate the transition to the new size
23713 this.animate = false;
23716 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23719 this.useShim = false;
23724 if(!existingProxy){
23726 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23728 this.proxy = Roo.get(existingProxy).dom;
23731 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23734 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23737 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23740 this.dragSpecs = {};
23743 * @private The adapter to use to positon and resize elements
23745 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23746 this.adapter.init(this);
23748 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23750 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23751 this.el.addClass("x-splitbar-h");
23754 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23755 this.el.addClass("x-splitbar-v");
23761 * Fires when the splitter is moved (alias for {@link #event-moved})
23762 * @param {Roo.SplitBar} this
23763 * @param {Number} newSize the new width or height
23768 * Fires when the splitter is moved
23769 * @param {Roo.SplitBar} this
23770 * @param {Number} newSize the new width or height
23774 * @event beforeresize
23775 * Fires before the splitter is dragged
23776 * @param {Roo.SplitBar} this
23778 "beforeresize" : true,
23780 "beforeapply" : true
23783 Roo.util.Observable.call(this);
23786 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23787 onStartProxyDrag : function(x, y){
23788 this.fireEvent("beforeresize", this);
23790 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23792 o.enableDisplayMode("block");
23793 // all splitbars share the same overlay
23794 Roo.SplitBar.prototype.overlay = o;
23796 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23797 this.overlay.show();
23798 Roo.get(this.proxy).setDisplayed("block");
23799 var size = this.adapter.getElementSize(this);
23800 this.activeMinSize = this.getMinimumSize();;
23801 this.activeMaxSize = this.getMaximumSize();;
23802 var c1 = size - this.activeMinSize;
23803 var c2 = Math.max(this.activeMaxSize - size, 0);
23804 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23805 this.dd.resetConstraints();
23806 this.dd.setXConstraint(
23807 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23808 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23810 this.dd.setYConstraint(0, 0);
23812 this.dd.resetConstraints();
23813 this.dd.setXConstraint(0, 0);
23814 this.dd.setYConstraint(
23815 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23816 this.placement == Roo.SplitBar.TOP ? c2 : c1
23819 this.dragSpecs.startSize = size;
23820 this.dragSpecs.startPoint = [x, y];
23821 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23825 * @private Called after the drag operation by the DDProxy
23827 onEndProxyDrag : function(e){
23828 Roo.get(this.proxy).setDisplayed(false);
23829 var endPoint = Roo.lib.Event.getXY(e);
23831 this.overlay.hide();
23834 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23835 newSize = this.dragSpecs.startSize +
23836 (this.placement == Roo.SplitBar.LEFT ?
23837 endPoint[0] - this.dragSpecs.startPoint[0] :
23838 this.dragSpecs.startPoint[0] - endPoint[0]
23841 newSize = this.dragSpecs.startSize +
23842 (this.placement == Roo.SplitBar.TOP ?
23843 endPoint[1] - this.dragSpecs.startPoint[1] :
23844 this.dragSpecs.startPoint[1] - endPoint[1]
23847 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23848 if(newSize != this.dragSpecs.startSize){
23849 if(this.fireEvent('beforeapply', this, newSize) !== false){
23850 this.adapter.setElementSize(this, newSize);
23851 this.fireEvent("moved", this, newSize);
23852 this.fireEvent("resize", this, newSize);
23858 * Get the adapter this SplitBar uses
23859 * @return The adapter object
23861 getAdapter : function(){
23862 return this.adapter;
23866 * Set the adapter this SplitBar uses
23867 * @param {Object} adapter A SplitBar adapter object
23869 setAdapter : function(adapter){
23870 this.adapter = adapter;
23871 this.adapter.init(this);
23875 * Gets the minimum size for the resizing element
23876 * @return {Number} The minimum size
23878 getMinimumSize : function(){
23879 return this.minSize;
23883 * Sets the minimum size for the resizing element
23884 * @param {Number} minSize The minimum size
23886 setMinimumSize : function(minSize){
23887 this.minSize = minSize;
23891 * Gets the maximum size for the resizing element
23892 * @return {Number} The maximum size
23894 getMaximumSize : function(){
23895 return this.maxSize;
23899 * Sets the maximum size for the resizing element
23900 * @param {Number} maxSize The maximum size
23902 setMaximumSize : function(maxSize){
23903 this.maxSize = maxSize;
23907 * Sets the initialize size for the resizing element
23908 * @param {Number} size The initial size
23910 setCurrentSize : function(size){
23911 var oldAnimate = this.animate;
23912 this.animate = false;
23913 this.adapter.setElementSize(this, size);
23914 this.animate = oldAnimate;
23918 * Destroy this splitbar.
23919 * @param {Boolean} removeEl True to remove the element
23921 destroy : function(removeEl){
23923 this.shim.remove();
23926 this.proxy.parentNode.removeChild(this.proxy);
23934 * @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.
23936 Roo.SplitBar.createProxy = function(dir){
23937 var proxy = new Roo.Element(document.createElement("div"));
23938 proxy.unselectable();
23939 var cls = 'x-splitbar-proxy';
23940 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23941 document.body.appendChild(proxy.dom);
23946 * @class Roo.SplitBar.BasicLayoutAdapter
23947 * Default Adapter. It assumes the splitter and resizing element are not positioned
23948 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23950 Roo.SplitBar.BasicLayoutAdapter = function(){
23953 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23954 // do nothing for now
23955 init : function(s){
23959 * Called before drag operations to get the current size of the resizing element.
23960 * @param {Roo.SplitBar} s The SplitBar using this adapter
23962 getElementSize : function(s){
23963 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23964 return s.resizingEl.getWidth();
23966 return s.resizingEl.getHeight();
23971 * Called after drag operations to set the size of the resizing element.
23972 * @param {Roo.SplitBar} s The SplitBar using this adapter
23973 * @param {Number} newSize The new size to set
23974 * @param {Function} onComplete A function to be invoked when resizing is complete
23976 setElementSize : function(s, newSize, onComplete){
23977 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23979 s.resizingEl.setWidth(newSize);
23981 onComplete(s, newSize);
23984 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23989 s.resizingEl.setHeight(newSize);
23991 onComplete(s, newSize);
23994 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24001 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24002 * @extends Roo.SplitBar.BasicLayoutAdapter
24003 * Adapter that moves the splitter element to align with the resized sizing element.
24004 * Used with an absolute positioned SplitBar.
24005 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24006 * document.body, make sure you assign an id to the body element.
24008 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24009 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24010 this.container = Roo.get(container);
24013 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24014 init : function(s){
24015 this.basic.init(s);
24018 getElementSize : function(s){
24019 return this.basic.getElementSize(s);
24022 setElementSize : function(s, newSize, onComplete){
24023 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24026 moveSplitter : function(s){
24027 var yes = Roo.SplitBar;
24028 switch(s.placement){
24030 s.el.setX(s.resizingEl.getRight());
24033 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24036 s.el.setY(s.resizingEl.getBottom());
24039 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24046 * Orientation constant - Create a vertical SplitBar
24050 Roo.SplitBar.VERTICAL = 1;
24053 * Orientation constant - Create a horizontal SplitBar
24057 Roo.SplitBar.HORIZONTAL = 2;
24060 * Placement constant - The resizing element is to the left of the splitter element
24064 Roo.SplitBar.LEFT = 1;
24067 * Placement constant - The resizing element is to the right of the splitter element
24071 Roo.SplitBar.RIGHT = 2;
24074 * Placement constant - The resizing element is positioned above the splitter element
24078 Roo.SplitBar.TOP = 3;
24081 * Placement constant - The resizing element is positioned under splitter element
24085 Roo.SplitBar.BOTTOM = 4;
24088 * Ext JS Library 1.1.1
24089 * Copyright(c) 2006-2007, Ext JS, LLC.
24091 * Originally Released Under LGPL - original licence link has changed is not relivant.
24094 * <script type="text/javascript">
24099 * @extends Roo.util.Observable
24100 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24101 * This class also supports single and multi selection modes. <br>
24102 * Create a data model bound view:
24104 var store = new Roo.data.Store(...);
24106 var view = new Roo.View({
24108 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24110 singleSelect: true,
24111 selectedClass: "ydataview-selected",
24115 // listen for node click?
24116 view.on("click", function(vw, index, node, e){
24117 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24121 dataModel.load("foobar.xml");
24123 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24125 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24126 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24128 * Note: old style constructor is still suported (container, template, config)
24131 * Create a new View
24132 * @param {Object} config The config object
24135 Roo.View = function(config, depreciated_tpl, depreciated_config){
24137 if (typeof(depreciated_tpl) == 'undefined') {
24138 // new way.. - universal constructor.
24139 Roo.apply(this, config);
24140 this.el = Roo.get(this.el);
24143 this.el = Roo.get(config);
24144 this.tpl = depreciated_tpl;
24145 Roo.apply(this, depreciated_config);
24147 this.wrapEl = this.el.wrap().wrap();
24148 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24151 if(typeof(this.tpl) == "string"){
24152 this.tpl = new Roo.Template(this.tpl);
24154 // support xtype ctors..
24155 this.tpl = new Roo.factory(this.tpl, Roo);
24159 this.tpl.compile();
24167 * @event beforeclick
24168 * Fires before a click is processed. Returns false to cancel the default action.
24169 * @param {Roo.View} this
24170 * @param {Number} index The index of the target node
24171 * @param {HTMLElement} node The target node
24172 * @param {Roo.EventObject} e The raw event object
24174 "beforeclick" : true,
24177 * Fires when a template node is clicked.
24178 * @param {Roo.View} this
24179 * @param {Number} index The index of the target node
24180 * @param {HTMLElement} node The target node
24181 * @param {Roo.EventObject} e The raw event object
24186 * Fires when a template node is double clicked.
24187 * @param {Roo.View} this
24188 * @param {Number} index The index of the target node
24189 * @param {HTMLElement} node The target node
24190 * @param {Roo.EventObject} e The raw event object
24194 * @event contextmenu
24195 * Fires when a template node is right clicked.
24196 * @param {Roo.View} this
24197 * @param {Number} index The index of the target node
24198 * @param {HTMLElement} node The target node
24199 * @param {Roo.EventObject} e The raw event object
24201 "contextmenu" : true,
24203 * @event selectionchange
24204 * Fires when the selected nodes change.
24205 * @param {Roo.View} this
24206 * @param {Array} selections Array of the selected nodes
24208 "selectionchange" : true,
24211 * @event beforeselect
24212 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24213 * @param {Roo.View} this
24214 * @param {HTMLElement} node The node to be selected
24215 * @param {Array} selections Array of currently selected nodes
24217 "beforeselect" : true,
24219 * @event preparedata
24220 * Fires on every row to render, to allow you to change the data.
24221 * @param {Roo.View} this
24222 * @param {Object} data to be rendered (change this)
24224 "preparedata" : true
24232 "click": this.onClick,
24233 "dblclick": this.onDblClick,
24234 "contextmenu": this.onContextMenu,
24238 this.selections = [];
24240 this.cmp = new Roo.CompositeElementLite([]);
24242 this.store = Roo.factory(this.store, Roo.data);
24243 this.setStore(this.store, true);
24246 if ( this.footer && this.footer.xtype) {
24248 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24250 this.footer.dataSource = this.store
24251 this.footer.container = fctr;
24252 this.footer = Roo.factory(this.footer, Roo);
24253 fctr.insertFirst(this.el);
24255 // this is a bit insane - as the paging toolbar seems to detach the el..
24256 // dom.parentNode.parentNode.parentNode
24257 // they get detached?
24261 Roo.View.superclass.constructor.call(this);
24266 Roo.extend(Roo.View, Roo.util.Observable, {
24269 * @cfg {Roo.data.Store} store Data store to load data from.
24274 * @cfg {String|Roo.Element} el The container element.
24279 * @cfg {String|Roo.Template} tpl The template used by this View
24283 * @cfg {String} dataName the named area of the template to use as the data area
24284 * Works with domtemplates roo-name="name"
24288 * @cfg {String} selectedClass The css class to add to selected nodes
24290 selectedClass : "x-view-selected",
24292 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24297 * @cfg {String} text to display on mask (default Loading)
24301 * @cfg {Boolean} multiSelect Allow multiple selection
24303 multiSelect : false,
24305 * @cfg {Boolean} singleSelect Allow single selection
24307 singleSelect: false,
24310 * @cfg {Boolean} toggleSelect - selecting
24312 toggleSelect : false,
24315 * Returns the element this view is bound to.
24316 * @return {Roo.Element}
24318 getEl : function(){
24319 return this.wrapEl;
24325 * Refreshes the view. - called by datachanged on the store. - do not call directly.
24327 refresh : function(){
24330 // if we are using something like 'domtemplate', then
24331 // the what gets used is:
24332 // t.applySubtemplate(NAME, data, wrapping data..)
24333 // the outer template then get' applied with
24334 // the store 'extra data'
24335 // and the body get's added to the
24336 // roo-name="data" node?
24337 // <span class='roo-tpl-{name}'></span> ?????
24341 this.clearSelections();
24342 this.el.update("");
24344 var records = this.store.getRange();
24345 if(records.length < 1) {
24347 // is this valid?? = should it render a template??
24349 this.el.update(this.emptyText);
24353 if (this.dataName) {
24354 this.el.update(t.apply(this.store.meta)); //????
24355 el = this.el.child('.roo-tpl-' + this.dataName);
24358 for(var i = 0, len = records.length; i < len; i++){
24359 var data = this.prepareData(records[i].data, i, records[i]);
24360 this.fireEvent("preparedata", this, data, i, records[i]);
24361 html[html.length] = Roo.util.Format.trim(
24363 t.applySubtemplate(this.dataName, data, this.store.meta) :
24370 el.update(html.join(""));
24371 this.nodes = el.dom.childNodes;
24372 this.updateIndexes(0);
24376 * Function to override to reformat the data that is sent to
24377 * the template for each node.
24378 * DEPRICATED - use the preparedata event handler.
24379 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
24380 * a JSON object for an UpdateManager bound view).
24382 prepareData : function(data, index, record)
24384 this.fireEvent("preparedata", this, data, index, record);
24388 onUpdate : function(ds, record){
24389 this.clearSelections();
24390 var index = this.store.indexOf(record);
24391 var n = this.nodes[index];
24392 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
24393 n.parentNode.removeChild(n);
24394 this.updateIndexes(index, index);
24400 onAdd : function(ds, records, index)
24402 this.clearSelections();
24403 if(this.nodes.length == 0){
24407 var n = this.nodes[index];
24408 for(var i = 0, len = records.length; i < len; i++){
24409 var d = this.prepareData(records[i].data, i, records[i]);
24411 this.tpl.insertBefore(n, d);
24414 this.tpl.append(this.el, d);
24417 this.updateIndexes(index);
24420 onRemove : function(ds, record, index){
24421 this.clearSelections();
24422 var el = this.dataName ?
24423 this.el.child('.roo-tpl-' + this.dataName) :
24425 el.dom.removeChild(this.nodes[index]);
24426 this.updateIndexes(index);
24430 * Refresh an individual node.
24431 * @param {Number} index
24433 refreshNode : function(index){
24434 this.onUpdate(this.store, this.store.getAt(index));
24437 updateIndexes : function(startIndex, endIndex){
24438 var ns = this.nodes;
24439 startIndex = startIndex || 0;
24440 endIndex = endIndex || ns.length - 1;
24441 for(var i = startIndex; i <= endIndex; i++){
24442 ns[i].nodeIndex = i;
24447 * Changes the data store this view uses and refresh the view.
24448 * @param {Store} store
24450 setStore : function(store, initial){
24451 if(!initial && this.store){
24452 this.store.un("datachanged", this.refresh);
24453 this.store.un("add", this.onAdd);
24454 this.store.un("remove", this.onRemove);
24455 this.store.un("update", this.onUpdate);
24456 this.store.un("clear", this.refresh);
24457 this.store.un("beforeload", this.onBeforeLoad);
24458 this.store.un("load", this.onLoad);
24459 this.store.un("loadexception", this.onLoad);
24463 store.on("datachanged", this.refresh, this);
24464 store.on("add", this.onAdd, this);
24465 store.on("remove", this.onRemove, this);
24466 store.on("update", this.onUpdate, this);
24467 store.on("clear", this.refresh, this);
24468 store.on("beforeload", this.onBeforeLoad, this);
24469 store.on("load", this.onLoad, this);
24470 store.on("loadexception", this.onLoad, this);
24478 * onbeforeLoad - masks the loading area.
24481 onBeforeLoad : function()
24483 this.el.update("");
24484 this.el.mask(this.mask ? this.mask : "Loading" );
24486 onLoad : function ()
24493 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
24494 * @param {HTMLElement} node
24495 * @return {HTMLElement} The template node
24497 findItemFromChild : function(node){
24498 var el = this.dataName ?
24499 this.el.child('.roo-tpl-' + this.dataName,true) :
24502 if(!node || node.parentNode == el){
24505 var p = node.parentNode;
24506 while(p && p != el){
24507 if(p.parentNode == el){
24516 onClick : function(e){
24517 var item = this.findItemFromChild(e.getTarget());
24519 var index = this.indexOf(item);
24520 if(this.onItemClick(item, index, e) !== false){
24521 this.fireEvent("click", this, index, item, e);
24524 this.clearSelections();
24529 onContextMenu : function(e){
24530 var item = this.findItemFromChild(e.getTarget());
24532 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
24537 onDblClick : function(e){
24538 var item = this.findItemFromChild(e.getTarget());
24540 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
24544 onItemClick : function(item, index, e)
24546 if(this.fireEvent("beforeclick", this, index, item, e) === false){
24549 if (this.toggleSelect) {
24550 var m = this.isSelected(item) ? 'unselect' : 'select';
24553 _t[m](item, true, false);
24556 if(this.multiSelect || this.singleSelect){
24557 if(this.multiSelect && e.shiftKey && this.lastSelection){
24558 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
24560 this.select(item, this.multiSelect && e.ctrlKey);
24561 this.lastSelection = item;
24563 e.preventDefault();
24569 * Get the number of selected nodes.
24572 getSelectionCount : function(){
24573 return this.selections.length;
24577 * Get the currently selected nodes.
24578 * @return {Array} An array of HTMLElements
24580 getSelectedNodes : function(){
24581 return this.selections;
24585 * Get the indexes of the selected nodes.
24588 getSelectedIndexes : function(){
24589 var indexes = [], s = this.selections;
24590 for(var i = 0, len = s.length; i < len; i++){
24591 indexes.push(s[i].nodeIndex);
24597 * Clear all selections
24598 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
24600 clearSelections : function(suppressEvent){
24601 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
24602 this.cmp.elements = this.selections;
24603 this.cmp.removeClass(this.selectedClass);
24604 this.selections = [];
24605 if(!suppressEvent){
24606 this.fireEvent("selectionchange", this, this.selections);
24612 * Returns true if the passed node is selected
24613 * @param {HTMLElement/Number} node The node or node index
24614 * @return {Boolean}
24616 isSelected : function(node){
24617 var s = this.selections;
24621 node = this.getNode(node);
24622 return s.indexOf(node) !== -1;
24627 * @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
24628 * @param {Boolean} keepExisting (optional) true to keep existing selections
24629 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24631 select : function(nodeInfo, keepExisting, suppressEvent){
24632 if(nodeInfo instanceof Array){
24634 this.clearSelections(true);
24636 for(var i = 0, len = nodeInfo.length; i < len; i++){
24637 this.select(nodeInfo[i], true, true);
24641 var node = this.getNode(nodeInfo);
24642 if(!node || this.isSelected(node)){
24643 return; // already selected.
24646 this.clearSelections(true);
24648 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
24649 Roo.fly(node).addClass(this.selectedClass);
24650 this.selections.push(node);
24651 if(!suppressEvent){
24652 this.fireEvent("selectionchange", this, this.selections);
24660 * @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
24661 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
24662 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24664 unselect : function(nodeInfo, keepExisting, suppressEvent)
24666 if(nodeInfo instanceof Array){
24667 Roo.each(this.selections, function(s) {
24668 this.unselect(s, nodeInfo);
24672 var node = this.getNode(nodeInfo);
24673 if(!node || !this.isSelected(node)){
24674 Roo.log("not selected");
24675 return; // not selected.
24679 Roo.each(this.selections, function(s) {
24681 Roo.fly(node).removeClass(this.selectedClass);
24688 this.selections= ns;
24689 this.fireEvent("selectionchange", this, this.selections);
24693 * Gets a template node.
24694 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24695 * @return {HTMLElement} The node or null if it wasn't found
24697 getNode : function(nodeInfo){
24698 if(typeof nodeInfo == "string"){
24699 return document.getElementById(nodeInfo);
24700 }else if(typeof nodeInfo == "number"){
24701 return this.nodes[nodeInfo];
24707 * Gets a range template nodes.
24708 * @param {Number} startIndex
24709 * @param {Number} endIndex
24710 * @return {Array} An array of nodes
24712 getNodes : function(start, end){
24713 var ns = this.nodes;
24714 start = start || 0;
24715 end = typeof end == "undefined" ? ns.length - 1 : end;
24718 for(var i = start; i <= end; i++){
24722 for(var i = start; i >= end; i--){
24730 * Finds the index of the passed node
24731 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24732 * @return {Number} The index of the node or -1
24734 indexOf : function(node){
24735 node = this.getNode(node);
24736 if(typeof node.nodeIndex == "number"){
24737 return node.nodeIndex;
24739 var ns = this.nodes;
24740 for(var i = 0, len = ns.length; i < len; i++){
24750 * Ext JS Library 1.1.1
24751 * Copyright(c) 2006-2007, Ext JS, LLC.
24753 * Originally Released Under LGPL - original licence link has changed is not relivant.
24756 * <script type="text/javascript">
24760 * @class Roo.JsonView
24761 * @extends Roo.View
24762 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24764 var view = new Roo.JsonView({
24765 container: "my-element",
24766 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24771 // listen for node click?
24772 view.on("click", function(vw, index, node, e){
24773 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24776 // direct load of JSON data
24777 view.load("foobar.php");
24779 // Example from my blog list
24780 var tpl = new Roo.Template(
24781 '<div class="entry">' +
24782 '<a class="entry-title" href="{link}">{title}</a>' +
24783 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24784 "</div><hr />"
24787 var moreView = new Roo.JsonView({
24788 container : "entry-list",
24792 moreView.on("beforerender", this.sortEntries, this);
24794 url: "/blog/get-posts.php",
24795 params: "allposts=true",
24796 text: "Loading Blog Entries..."
24800 * Note: old code is supported with arguments : (container, template, config)
24804 * Create a new JsonView
24806 * @param {Object} config The config object
24809 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24812 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24814 var um = this.el.getUpdateManager();
24815 um.setRenderer(this);
24816 um.on("update", this.onLoad, this);
24817 um.on("failure", this.onLoadException, this);
24820 * @event beforerender
24821 * Fires before rendering of the downloaded JSON data.
24822 * @param {Roo.JsonView} this
24823 * @param {Object} data The JSON data loaded
24827 * Fires when data is loaded.
24828 * @param {Roo.JsonView} this
24829 * @param {Object} data The JSON data loaded
24830 * @param {Object} response The raw Connect response object
24833 * @event loadexception
24834 * Fires when loading fails.
24835 * @param {Roo.JsonView} this
24836 * @param {Object} response The raw Connect response object
24839 'beforerender' : true,
24841 'loadexception' : true
24844 Roo.extend(Roo.JsonView, Roo.View, {
24846 * @type {String} The root property in the loaded JSON object that contains the data
24851 * Refreshes the view.
24853 refresh : function(){
24854 this.clearSelections();
24855 this.el.update("");
24857 var o = this.jsonData;
24858 if(o && o.length > 0){
24859 for(var i = 0, len = o.length; i < len; i++){
24860 var data = this.prepareData(o[i], i, o);
24861 html[html.length] = this.tpl.apply(data);
24864 html.push(this.emptyText);
24866 this.el.update(html.join(""));
24867 this.nodes = this.el.dom.childNodes;
24868 this.updateIndexes(0);
24872 * 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.
24873 * @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:
24876 url: "your-url.php",
24877 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24878 callback: yourFunction,
24879 scope: yourObject, //(optional scope)
24882 text: "Loading...",
24887 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24888 * 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.
24889 * @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}
24890 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24891 * @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.
24894 var um = this.el.getUpdateManager();
24895 um.update.apply(um, arguments);
24898 render : function(el, response){
24899 this.clearSelections();
24900 this.el.update("");
24903 o = Roo.util.JSON.decode(response.responseText);
24906 o = o[this.jsonRoot];
24911 * The current JSON data or null
24914 this.beforeRender();
24919 * Get the number of records in the current JSON dataset
24922 getCount : function(){
24923 return this.jsonData ? this.jsonData.length : 0;
24927 * Returns the JSON object for the specified node(s)
24928 * @param {HTMLElement/Array} node The node or an array of nodes
24929 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24930 * you get the JSON object for the node
24932 getNodeData : function(node){
24933 if(node instanceof Array){
24935 for(var i = 0, len = node.length; i < len; i++){
24936 data.push(this.getNodeData(node[i]));
24940 return this.jsonData[this.indexOf(node)] || null;
24943 beforeRender : function(){
24944 this.snapshot = this.jsonData;
24946 this.sort.apply(this, this.sortInfo);
24948 this.fireEvent("beforerender", this, this.jsonData);
24951 onLoad : function(el, o){
24952 this.fireEvent("load", this, this.jsonData, o);
24955 onLoadException : function(el, o){
24956 this.fireEvent("loadexception", this, o);
24960 * Filter the data by a specific property.
24961 * @param {String} property A property on your JSON objects
24962 * @param {String/RegExp} value Either string that the property values
24963 * should start with, or a RegExp to test against the property
24965 filter : function(property, value){
24968 var ss = this.snapshot;
24969 if(typeof value == "string"){
24970 var vlen = value.length;
24972 this.clearFilter();
24975 value = value.toLowerCase();
24976 for(var i = 0, len = ss.length; i < len; i++){
24978 if(o[property].substr(0, vlen).toLowerCase() == value){
24982 } else if(value.exec){ // regex?
24983 for(var i = 0, len = ss.length; i < len; i++){
24985 if(value.test(o[property])){
24992 this.jsonData = data;
24998 * Filter by a function. The passed function will be called with each
24999 * object in the current dataset. If the function returns true the value is kept,
25000 * otherwise it is filtered.
25001 * @param {Function} fn
25002 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25004 filterBy : function(fn, scope){
25007 var ss = this.snapshot;
25008 for(var i = 0, len = ss.length; i < len; i++){
25010 if(fn.call(scope || this, o)){
25014 this.jsonData = data;
25020 * Clears the current filter.
25022 clearFilter : function(){
25023 if(this.snapshot && this.jsonData != this.snapshot){
25024 this.jsonData = this.snapshot;
25031 * Sorts the data for this view and refreshes it.
25032 * @param {String} property A property on your JSON objects to sort on
25033 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25034 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25036 sort : function(property, dir, sortType){
25037 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25040 var dsc = dir && dir.toLowerCase() == "desc";
25041 var f = function(o1, o2){
25042 var v1 = sortType ? sortType(o1[p]) : o1[p];
25043 var v2 = sortType ? sortType(o2[p]) : o2[p];
25046 return dsc ? +1 : -1;
25047 } else if(v1 > v2){
25048 return dsc ? -1 : +1;
25053 this.jsonData.sort(f);
25055 if(this.jsonData != this.snapshot){
25056 this.snapshot.sort(f);
25062 * Ext JS Library 1.1.1
25063 * Copyright(c) 2006-2007, Ext JS, LLC.
25065 * Originally Released Under LGPL - original licence link has changed is not relivant.
25068 * <script type="text/javascript">
25073 * @class Roo.ColorPalette
25074 * @extends Roo.Component
25075 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25076 * Here's an example of typical usage:
25078 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25079 cp.render('my-div');
25081 cp.on('select', function(palette, selColor){
25082 // do something with selColor
25086 * Create a new ColorPalette
25087 * @param {Object} config The config object
25089 Roo.ColorPalette = function(config){
25090 Roo.ColorPalette.superclass.constructor.call(this, config);
25094 * Fires when a color is selected
25095 * @param {ColorPalette} this
25096 * @param {String} color The 6-digit color hex code (without the # symbol)
25102 this.on("select", this.handler, this.scope, true);
25105 Roo.extend(Roo.ColorPalette, Roo.Component, {
25107 * @cfg {String} itemCls
25108 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25110 itemCls : "x-color-palette",
25112 * @cfg {String} value
25113 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25114 * the hex codes are case-sensitive.
25117 clickEvent:'click',
25119 ctype: "Roo.ColorPalette",
25122 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25124 allowReselect : false,
25127 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25128 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25129 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25130 * of colors with the width setting until the box is symmetrical.</p>
25131 * <p>You can override individual colors if needed:</p>
25133 var cp = new Roo.ColorPalette();
25134 cp.colors[0] = "FF0000"; // change the first box to red
25137 Or you can provide a custom array of your own for complete control:
25139 var cp = new Roo.ColorPalette();
25140 cp.colors = ["000000", "993300", "333300"];
25145 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25146 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25147 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25148 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25149 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25153 onRender : function(container, position){
25154 var t = new Roo.MasterTemplate(
25155 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25157 var c = this.colors;
25158 for(var i = 0, len = c.length; i < len; i++){
25161 var el = document.createElement("div");
25162 el.className = this.itemCls;
25164 container.dom.insertBefore(el, position);
25165 this.el = Roo.get(el);
25166 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25167 if(this.clickEvent != 'click'){
25168 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25173 afterRender : function(){
25174 Roo.ColorPalette.superclass.afterRender.call(this);
25176 var s = this.value;
25183 handleClick : function(e, t){
25184 e.preventDefault();
25185 if(!this.disabled){
25186 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25187 this.select(c.toUpperCase());
25192 * Selects the specified color in the palette (fires the select event)
25193 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25195 select : function(color){
25196 color = color.replace("#", "");
25197 if(color != this.value || this.allowReselect){
25200 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25202 el.child("a.color-"+color).addClass("x-color-palette-sel");
25203 this.value = color;
25204 this.fireEvent("select", this, color);
25209 * Ext JS Library 1.1.1
25210 * Copyright(c) 2006-2007, Ext JS, LLC.
25212 * Originally Released Under LGPL - original licence link has changed is not relivant.
25215 * <script type="text/javascript">
25219 * @class Roo.DatePicker
25220 * @extends Roo.Component
25221 * Simple date picker class.
25223 * Create a new DatePicker
25224 * @param {Object} config The config object
25226 Roo.DatePicker = function(config){
25227 Roo.DatePicker.superclass.constructor.call(this, config);
25229 this.value = config && config.value ?
25230 config.value.clearTime() : new Date().clearTime();
25235 * Fires when a date is selected
25236 * @param {DatePicker} this
25237 * @param {Date} date The selected date
25241 * @event monthchange
25242 * Fires when the displayed month changes
25243 * @param {DatePicker} this
25244 * @param {Date} date The selected month
25246 'monthchange': true
25250 this.on("select", this.handler, this.scope || this);
25252 // build the disabledDatesRE
25253 if(!this.disabledDatesRE && this.disabledDates){
25254 var dd = this.disabledDates;
25256 for(var i = 0; i < dd.length; i++){
25258 if(i != dd.length-1) re += "|";
25260 this.disabledDatesRE = new RegExp(re + ")");
25264 Roo.extend(Roo.DatePicker, Roo.Component, {
25266 * @cfg {String} todayText
25267 * The text to display on the button that selects the current date (defaults to "Today")
25269 todayText : "Today",
25271 * @cfg {String} okText
25272 * The text to display on the ok button
25274 okText : " OK ", //   to give the user extra clicking room
25276 * @cfg {String} cancelText
25277 * The text to display on the cancel button
25279 cancelText : "Cancel",
25281 * @cfg {String} todayTip
25282 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25284 todayTip : "{0} (Spacebar)",
25286 * @cfg {Date} minDate
25287 * Minimum allowable date (JavaScript date object, defaults to null)
25291 * @cfg {Date} maxDate
25292 * Maximum allowable date (JavaScript date object, defaults to null)
25296 * @cfg {String} minText
25297 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25299 minText : "This date is before the minimum date",
25301 * @cfg {String} maxText
25302 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25304 maxText : "This date is after the maximum date",
25306 * @cfg {String} format
25307 * The default date format string which can be overriden for localization support. The format must be
25308 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25312 * @cfg {Array} disabledDays
25313 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25315 disabledDays : null,
25317 * @cfg {String} disabledDaysText
25318 * The tooltip to display when the date falls on a disabled day (defaults to "")
25320 disabledDaysText : "",
25322 * @cfg {RegExp} disabledDatesRE
25323 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25325 disabledDatesRE : null,
25327 * @cfg {String} disabledDatesText
25328 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25330 disabledDatesText : "",
25332 * @cfg {Boolean} constrainToViewport
25333 * True to constrain the date picker to the viewport (defaults to true)
25335 constrainToViewport : true,
25337 * @cfg {Array} monthNames
25338 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25340 monthNames : Date.monthNames,
25342 * @cfg {Array} dayNames
25343 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25345 dayNames : Date.dayNames,
25347 * @cfg {String} nextText
25348 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25350 nextText: 'Next Month (Control+Right)',
25352 * @cfg {String} prevText
25353 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25355 prevText: 'Previous Month (Control+Left)',
25357 * @cfg {String} monthYearText
25358 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25360 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25362 * @cfg {Number} startDay
25363 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25367 * @cfg {Bool} showClear
25368 * Show a clear button (usefull for date form elements that can be blank.)
25374 * Sets the value of the date field
25375 * @param {Date} value The date to set
25377 setValue : function(value){
25378 var old = this.value;
25380 if (typeof(value) == 'string') {
25382 value = Date.parseDate(value, this.format);
25385 value = new Date();
25388 this.value = value.clearTime(true);
25390 this.update(this.value);
25395 * Gets the current selected value of the date field
25396 * @return {Date} The selected date
25398 getValue : function(){
25403 focus : function(){
25405 this.update(this.activeDate);
25410 onRender : function(container, position){
25413 '<table cellspacing="0">',
25414 '<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>',
25415 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
25416 var dn = this.dayNames;
25417 for(var i = 0; i < 7; i++){
25418 var d = this.startDay+i;
25422 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
25424 m[m.length] = "</tr></thead><tbody><tr>";
25425 for(var i = 0; i < 42; i++) {
25426 if(i % 7 == 0 && i != 0){
25427 m[m.length] = "</tr><tr>";
25429 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
25431 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
25432 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
25434 var el = document.createElement("div");
25435 el.className = "x-date-picker";
25436 el.innerHTML = m.join("");
25438 container.dom.insertBefore(el, position);
25440 this.el = Roo.get(el);
25441 this.eventEl = Roo.get(el.firstChild);
25443 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
25444 handler: this.showPrevMonth,
25446 preventDefault:true,
25450 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
25451 handler: this.showNextMonth,
25453 preventDefault:true,
25457 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
25459 this.monthPicker = this.el.down('div.x-date-mp');
25460 this.monthPicker.enableDisplayMode('block');
25462 var kn = new Roo.KeyNav(this.eventEl, {
25463 "left" : function(e){
25465 this.showPrevMonth() :
25466 this.update(this.activeDate.add("d", -1));
25469 "right" : function(e){
25471 this.showNextMonth() :
25472 this.update(this.activeDate.add("d", 1));
25475 "up" : function(e){
25477 this.showNextYear() :
25478 this.update(this.activeDate.add("d", -7));
25481 "down" : function(e){
25483 this.showPrevYear() :
25484 this.update(this.activeDate.add("d", 7));
25487 "pageUp" : function(e){
25488 this.showNextMonth();
25491 "pageDown" : function(e){
25492 this.showPrevMonth();
25495 "enter" : function(e){
25496 e.stopPropagation();
25503 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
25505 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
25507 this.el.unselectable();
25509 this.cells = this.el.select("table.x-date-inner tbody td");
25510 this.textNodes = this.el.query("table.x-date-inner tbody span");
25512 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
25514 tooltip: this.monthYearText
25517 this.mbtn.on('click', this.showMonthPicker, this);
25518 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
25521 var today = (new Date()).dateFormat(this.format);
25523 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
25524 if (this.showClear) {
25525 baseTb.add( new Roo.Toolbar.Fill());
25528 text: String.format(this.todayText, today),
25529 tooltip: String.format(this.todayTip, today),
25530 handler: this.selectToday,
25534 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
25537 if (this.showClear) {
25539 baseTb.add( new Roo.Toolbar.Fill());
25542 cls: 'x-btn-icon x-btn-clear',
25543 handler: function() {
25545 this.fireEvent("select", this, '');
25555 this.update(this.value);
25558 createMonthPicker : function(){
25559 if(!this.monthPicker.dom.firstChild){
25560 var buf = ['<table border="0" cellspacing="0">'];
25561 for(var i = 0; i < 6; i++){
25563 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
25564 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
25566 '<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>' :
25567 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
25571 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
25573 '</button><button type="button" class="x-date-mp-cancel">',
25575 '</button></td></tr>',
25578 this.monthPicker.update(buf.join(''));
25579 this.monthPicker.on('click', this.onMonthClick, this);
25580 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
25582 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
25583 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
25585 this.mpMonths.each(function(m, a, i){
25588 m.dom.xmonth = 5 + Math.round(i * .5);
25590 m.dom.xmonth = Math.round((i-1) * .5);
25596 showMonthPicker : function(){
25597 this.createMonthPicker();
25598 var size = this.el.getSize();
25599 this.monthPicker.setSize(size);
25600 this.monthPicker.child('table').setSize(size);
25602 this.mpSelMonth = (this.activeDate || this.value).getMonth();
25603 this.updateMPMonth(this.mpSelMonth);
25604 this.mpSelYear = (this.activeDate || this.value).getFullYear();
25605 this.updateMPYear(this.mpSelYear);
25607 this.monthPicker.slideIn('t', {duration:.2});
25610 updateMPYear : function(y){
25612 var ys = this.mpYears.elements;
25613 for(var i = 1; i <= 10; i++){
25614 var td = ys[i-1], y2;
25616 y2 = y + Math.round(i * .5);
25617 td.firstChild.innerHTML = y2;
25620 y2 = y - (5-Math.round(i * .5));
25621 td.firstChild.innerHTML = y2;
25624 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
25628 updateMPMonth : function(sm){
25629 this.mpMonths.each(function(m, a, i){
25630 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
25634 selectMPMonth: function(m){
25638 onMonthClick : function(e, t){
25640 var el = new Roo.Element(t), pn;
25641 if(el.is('button.x-date-mp-cancel')){
25642 this.hideMonthPicker();
25644 else if(el.is('button.x-date-mp-ok')){
25645 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25646 this.hideMonthPicker();
25648 else if(pn = el.up('td.x-date-mp-month', 2)){
25649 this.mpMonths.removeClass('x-date-mp-sel');
25650 pn.addClass('x-date-mp-sel');
25651 this.mpSelMonth = pn.dom.xmonth;
25653 else if(pn = el.up('td.x-date-mp-year', 2)){
25654 this.mpYears.removeClass('x-date-mp-sel');
25655 pn.addClass('x-date-mp-sel');
25656 this.mpSelYear = pn.dom.xyear;
25658 else if(el.is('a.x-date-mp-prev')){
25659 this.updateMPYear(this.mpyear-10);
25661 else if(el.is('a.x-date-mp-next')){
25662 this.updateMPYear(this.mpyear+10);
25666 onMonthDblClick : function(e, t){
25668 var el = new Roo.Element(t), pn;
25669 if(pn = el.up('td.x-date-mp-month', 2)){
25670 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
25671 this.hideMonthPicker();
25673 else if(pn = el.up('td.x-date-mp-year', 2)){
25674 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25675 this.hideMonthPicker();
25679 hideMonthPicker : function(disableAnim){
25680 if(this.monthPicker){
25681 if(disableAnim === true){
25682 this.monthPicker.hide();
25684 this.monthPicker.slideOut('t', {duration:.2});
25690 showPrevMonth : function(e){
25691 this.update(this.activeDate.add("mo", -1));
25695 showNextMonth : function(e){
25696 this.update(this.activeDate.add("mo", 1));
25700 showPrevYear : function(){
25701 this.update(this.activeDate.add("y", -1));
25705 showNextYear : function(){
25706 this.update(this.activeDate.add("y", 1));
25710 handleMouseWheel : function(e){
25711 var delta = e.getWheelDelta();
25713 this.showPrevMonth();
25715 } else if(delta < 0){
25716 this.showNextMonth();
25722 handleDateClick : function(e, t){
25724 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25725 this.setValue(new Date(t.dateValue));
25726 this.fireEvent("select", this, this.value);
25731 selectToday : function(){
25732 this.setValue(new Date().clearTime());
25733 this.fireEvent("select", this, this.value);
25737 update : function(date)
25739 var vd = this.activeDate;
25740 this.activeDate = date;
25742 var t = date.getTime();
25743 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25744 this.cells.removeClass("x-date-selected");
25745 this.cells.each(function(c){
25746 if(c.dom.firstChild.dateValue == t){
25747 c.addClass("x-date-selected");
25748 setTimeout(function(){
25749 try{c.dom.firstChild.focus();}catch(e){}
25758 var days = date.getDaysInMonth();
25759 var firstOfMonth = date.getFirstDateOfMonth();
25760 var startingPos = firstOfMonth.getDay()-this.startDay;
25762 if(startingPos <= this.startDay){
25766 var pm = date.add("mo", -1);
25767 var prevStart = pm.getDaysInMonth()-startingPos;
25769 var cells = this.cells.elements;
25770 var textEls = this.textNodes;
25771 days += startingPos;
25773 // convert everything to numbers so it's fast
25774 var day = 86400000;
25775 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25776 var today = new Date().clearTime().getTime();
25777 var sel = date.clearTime().getTime();
25778 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25779 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25780 var ddMatch = this.disabledDatesRE;
25781 var ddText = this.disabledDatesText;
25782 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25783 var ddaysText = this.disabledDaysText;
25784 var format = this.format;
25786 var setCellClass = function(cal, cell){
25788 var t = d.getTime();
25789 cell.firstChild.dateValue = t;
25791 cell.className += " x-date-today";
25792 cell.title = cal.todayText;
25795 cell.className += " x-date-selected";
25796 setTimeout(function(){
25797 try{cell.firstChild.focus();}catch(e){}
25802 cell.className = " x-date-disabled";
25803 cell.title = cal.minText;
25807 cell.className = " x-date-disabled";
25808 cell.title = cal.maxText;
25812 if(ddays.indexOf(d.getDay()) != -1){
25813 cell.title = ddaysText;
25814 cell.className = " x-date-disabled";
25817 if(ddMatch && format){
25818 var fvalue = d.dateFormat(format);
25819 if(ddMatch.test(fvalue)){
25820 cell.title = ddText.replace("%0", fvalue);
25821 cell.className = " x-date-disabled";
25827 for(; i < startingPos; i++) {
25828 textEls[i].innerHTML = (++prevStart);
25829 d.setDate(d.getDate()+1);
25830 cells[i].className = "x-date-prevday";
25831 setCellClass(this, cells[i]);
25833 for(; i < days; i++){
25834 intDay = i - startingPos + 1;
25835 textEls[i].innerHTML = (intDay);
25836 d.setDate(d.getDate()+1);
25837 cells[i].className = "x-date-active";
25838 setCellClass(this, cells[i]);
25841 for(; i < 42; i++) {
25842 textEls[i].innerHTML = (++extraDays);
25843 d.setDate(d.getDate()+1);
25844 cells[i].className = "x-date-nextday";
25845 setCellClass(this, cells[i]);
25848 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25849 this.fireEvent('monthchange', this, date);
25851 if(!this.internalRender){
25852 var main = this.el.dom.firstChild;
25853 var w = main.offsetWidth;
25854 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25855 Roo.fly(main).setWidth(w);
25856 this.internalRender = true;
25857 // opera does not respect the auto grow header center column
25858 // then, after it gets a width opera refuses to recalculate
25859 // without a second pass
25860 if(Roo.isOpera && !this.secondPass){
25861 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25862 this.secondPass = true;
25863 this.update.defer(10, this, [date]);
25871 * Ext JS Library 1.1.1
25872 * Copyright(c) 2006-2007, Ext JS, LLC.
25874 * Originally Released Under LGPL - original licence link has changed is not relivant.
25877 * <script type="text/javascript">
25880 * @class Roo.TabPanel
25881 * @extends Roo.util.Observable
25882 * A lightweight tab container.
25886 // basic tabs 1, built from existing content
25887 var tabs = new Roo.TabPanel("tabs1");
25888 tabs.addTab("script", "View Script");
25889 tabs.addTab("markup", "View Markup");
25890 tabs.activate("script");
25892 // more advanced tabs, built from javascript
25893 var jtabs = new Roo.TabPanel("jtabs");
25894 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25896 // set up the UpdateManager
25897 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25898 var updater = tab2.getUpdateManager();
25899 updater.setDefaultUrl("ajax1.htm");
25900 tab2.on('activate', updater.refresh, updater, true);
25902 // Use setUrl for Ajax loading
25903 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25904 tab3.setUrl("ajax2.htm", null, true);
25907 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25910 jtabs.activate("jtabs-1");
25913 * Create a new TabPanel.
25914 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25915 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25917 Roo.TabPanel = function(container, config){
25919 * The container element for this TabPanel.
25920 * @type Roo.Element
25922 this.el = Roo.get(container, true);
25924 if(typeof config == "boolean"){
25925 this.tabPosition = config ? "bottom" : "top";
25927 Roo.apply(this, config);
25930 if(this.tabPosition == "bottom"){
25931 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25932 this.el.addClass("x-tabs-bottom");
25934 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25935 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25936 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25938 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25940 if(this.tabPosition != "bottom"){
25941 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
25942 * @type Roo.Element
25944 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25945 this.el.addClass("x-tabs-top");
25949 this.bodyEl.setStyle("position", "relative");
25951 this.active = null;
25952 this.activateDelegate = this.activate.createDelegate(this);
25957 * Fires when the active tab changes
25958 * @param {Roo.TabPanel} this
25959 * @param {Roo.TabPanelItem} activePanel The new active tab
25963 * @event beforetabchange
25964 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25965 * @param {Roo.TabPanel} this
25966 * @param {Object} e Set cancel to true on this object to cancel the tab change
25967 * @param {Roo.TabPanelItem} tab The tab being changed to
25969 "beforetabchange" : true
25972 Roo.EventManager.onWindowResize(this.onResize, this);
25973 this.cpad = this.el.getPadding("lr");
25974 this.hiddenCount = 0;
25977 // toolbar on the tabbar support...
25978 if (this.toolbar) {
25979 var tcfg = this.toolbar;
25980 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
25981 this.toolbar = new Roo.Toolbar(tcfg);
25982 if (Roo.isSafari) {
25983 var tbl = tcfg.container.child('table', true);
25984 tbl.setAttribute('width', '100%');
25991 Roo.TabPanel.superclass.constructor.call(this);
25994 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25996 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25998 tabPosition : "top",
26000 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26002 currentTabWidth : 0,
26004 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26008 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26012 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26014 preferredTabWidth : 175,
26016 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26018 resizeTabs : false,
26020 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26022 monitorResize : true,
26024 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26029 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26030 * @param {String} id The id of the div to use <b>or create</b>
26031 * @param {String} text The text for the tab
26032 * @param {String} content (optional) Content to put in the TabPanelItem body
26033 * @param {Boolean} closable (optional) True to create a close icon on the tab
26034 * @return {Roo.TabPanelItem} The created TabPanelItem
26036 addTab : function(id, text, content, closable){
26037 var item = new Roo.TabPanelItem(this, id, text, closable);
26038 this.addTabItem(item);
26040 item.setContent(content);
26046 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26047 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26048 * @return {Roo.TabPanelItem}
26050 getTab : function(id){
26051 return this.items[id];
26055 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26056 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26058 hideTab : function(id){
26059 var t = this.items[id];
26062 this.hiddenCount++;
26063 this.autoSizeTabs();
26068 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26069 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26071 unhideTab : function(id){
26072 var t = this.items[id];
26074 t.setHidden(false);
26075 this.hiddenCount--;
26076 this.autoSizeTabs();
26081 * Adds an existing {@link Roo.TabPanelItem}.
26082 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26084 addTabItem : function(item){
26085 this.items[item.id] = item;
26086 this.items.push(item);
26087 if(this.resizeTabs){
26088 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26089 this.autoSizeTabs();
26096 * Removes a {@link Roo.TabPanelItem}.
26097 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26099 removeTab : function(id){
26100 var items = this.items;
26101 var tab = items[id];
26102 if(!tab) { return; }
26103 var index = items.indexOf(tab);
26104 if(this.active == tab && items.length > 1){
26105 var newTab = this.getNextAvailable(index);
26110 this.stripEl.dom.removeChild(tab.pnode.dom);
26111 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26112 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26114 items.splice(index, 1);
26115 delete this.items[tab.id];
26116 tab.fireEvent("close", tab);
26117 tab.purgeListeners();
26118 this.autoSizeTabs();
26121 getNextAvailable : function(start){
26122 var items = this.items;
26124 // look for a next tab that will slide over to
26125 // replace the one being removed
26126 while(index < items.length){
26127 var item = items[++index];
26128 if(item && !item.isHidden()){
26132 // if one isn't found select the previous tab (on the left)
26135 var item = items[--index];
26136 if(item && !item.isHidden()){
26144 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26145 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26147 disableTab : function(id){
26148 var tab = this.items[id];
26149 if(tab && this.active != tab){
26155 * Enables a {@link Roo.TabPanelItem} that is disabled.
26156 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26158 enableTab : function(id){
26159 var tab = this.items[id];
26164 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26165 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26166 * @return {Roo.TabPanelItem} The TabPanelItem.
26168 activate : function(id){
26169 var tab = this.items[id];
26173 if(tab == this.active || tab.disabled){
26177 this.fireEvent("beforetabchange", this, e, tab);
26178 if(e.cancel !== true && !tab.disabled){
26180 this.active.hide();
26182 this.active = this.items[id];
26183 this.active.show();
26184 this.fireEvent("tabchange", this, this.active);
26190 * Gets the active {@link Roo.TabPanelItem}.
26191 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26193 getActiveTab : function(){
26194 return this.active;
26198 * Updates the tab body element to fit the height of the container element
26199 * for overflow scrolling
26200 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26202 syncHeight : function(targetHeight){
26203 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26204 var bm = this.bodyEl.getMargins();
26205 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26206 this.bodyEl.setHeight(newHeight);
26210 onResize : function(){
26211 if(this.monitorResize){
26212 this.autoSizeTabs();
26217 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26219 beginUpdate : function(){
26220 this.updating = true;
26224 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26226 endUpdate : function(){
26227 this.updating = false;
26228 this.autoSizeTabs();
26232 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26234 autoSizeTabs : function(){
26235 var count = this.items.length;
26236 var vcount = count - this.hiddenCount;
26237 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26238 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26239 var availWidth = Math.floor(w / vcount);
26240 var b = this.stripBody;
26241 if(b.getWidth() > w){
26242 var tabs = this.items;
26243 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26244 if(availWidth < this.minTabWidth){
26245 /*if(!this.sleft){ // incomplete scrolling code
26246 this.createScrollButtons();
26249 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26252 if(this.currentTabWidth < this.preferredTabWidth){
26253 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26259 * Returns the number of tabs in this TabPanel.
26262 getCount : function(){
26263 return this.items.length;
26267 * Resizes all the tabs to the passed width
26268 * @param {Number} The new width
26270 setTabWidth : function(width){
26271 this.currentTabWidth = width;
26272 for(var i = 0, len = this.items.length; i < len; i++) {
26273 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26278 * Destroys this TabPanel
26279 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26281 destroy : function(removeEl){
26282 Roo.EventManager.removeResizeListener(this.onResize, this);
26283 for(var i = 0, len = this.items.length; i < len; i++){
26284 this.items[i].purgeListeners();
26286 if(removeEl === true){
26287 this.el.update("");
26294 * @class Roo.TabPanelItem
26295 * @extends Roo.util.Observable
26296 * Represents an individual item (tab plus body) in a TabPanel.
26297 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26298 * @param {String} id The id of this TabPanelItem
26299 * @param {String} text The text for the tab of this TabPanelItem
26300 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26302 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26304 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26305 * @type Roo.TabPanel
26307 this.tabPanel = tabPanel;
26309 * The id for this TabPanelItem
26314 this.disabled = false;
26318 this.loaded = false;
26319 this.closable = closable;
26322 * The body element for this TabPanelItem.
26323 * @type Roo.Element
26325 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26326 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26327 this.bodyEl.setStyle("display", "block");
26328 this.bodyEl.setStyle("zoom", "1");
26331 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26333 this.el = Roo.get(els.el, true);
26334 this.inner = Roo.get(els.inner, true);
26335 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26336 this.pnode = Roo.get(els.el.parentNode, true);
26337 this.el.on("mousedown", this.onTabMouseDown, this);
26338 this.el.on("click", this.onTabClick, this);
26341 var c = Roo.get(els.close, true);
26342 c.dom.title = this.closeText;
26343 c.addClassOnOver("close-over");
26344 c.on("click", this.closeClick, this);
26350 * Fires when this tab becomes the active tab.
26351 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26352 * @param {Roo.TabPanelItem} this
26356 * @event beforeclose
26357 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26358 * @param {Roo.TabPanelItem} this
26359 * @param {Object} e Set cancel to true on this object to cancel the close.
26361 "beforeclose": true,
26364 * Fires when this tab is closed.
26365 * @param {Roo.TabPanelItem} this
26369 * @event deactivate
26370 * Fires when this tab is no longer the active tab.
26371 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26372 * @param {Roo.TabPanelItem} this
26374 "deactivate" : true
26376 this.hidden = false;
26378 Roo.TabPanelItem.superclass.constructor.call(this);
26381 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
26382 purgeListeners : function(){
26383 Roo.util.Observable.prototype.purgeListeners.call(this);
26384 this.el.removeAllListeners();
26387 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
26390 this.pnode.addClass("on");
26393 this.tabPanel.stripWrap.repaint();
26395 this.fireEvent("activate", this.tabPanel, this);
26399 * Returns true if this tab is the active tab.
26400 * @return {Boolean}
26402 isActive : function(){
26403 return this.tabPanel.getActiveTab() == this;
26407 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
26410 this.pnode.removeClass("on");
26412 this.fireEvent("deactivate", this.tabPanel, this);
26415 hideAction : function(){
26416 this.bodyEl.hide();
26417 this.bodyEl.setStyle("position", "absolute");
26418 this.bodyEl.setLeft("-20000px");
26419 this.bodyEl.setTop("-20000px");
26422 showAction : function(){
26423 this.bodyEl.setStyle("position", "relative");
26424 this.bodyEl.setTop("");
26425 this.bodyEl.setLeft("");
26426 this.bodyEl.show();
26430 * Set the tooltip for the tab.
26431 * @param {String} tooltip The tab's tooltip
26433 setTooltip : function(text){
26434 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
26435 this.textEl.dom.qtip = text;
26436 this.textEl.dom.removeAttribute('title');
26438 this.textEl.dom.title = text;
26442 onTabClick : function(e){
26443 e.preventDefault();
26444 this.tabPanel.activate(this.id);
26447 onTabMouseDown : function(e){
26448 e.preventDefault();
26449 this.tabPanel.activate(this.id);
26452 getWidth : function(){
26453 return this.inner.getWidth();
26456 setWidth : function(width){
26457 var iwidth = width - this.pnode.getPadding("lr");
26458 this.inner.setWidth(iwidth);
26459 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
26460 this.pnode.setWidth(width);
26464 * Show or hide the tab
26465 * @param {Boolean} hidden True to hide or false to show.
26467 setHidden : function(hidden){
26468 this.hidden = hidden;
26469 this.pnode.setStyle("display", hidden ? "none" : "");
26473 * Returns true if this tab is "hidden"
26474 * @return {Boolean}
26476 isHidden : function(){
26477 return this.hidden;
26481 * Returns the text for this tab
26484 getText : function(){
26488 autoSize : function(){
26489 //this.el.beginMeasure();
26490 this.textEl.setWidth(1);
26491 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
26492 //this.el.endMeasure();
26496 * Sets the text for the tab (Note: this also sets the tooltip text)
26497 * @param {String} text The tab's text and tooltip
26499 setText : function(text){
26501 this.textEl.update(text);
26502 this.setTooltip(text);
26503 if(!this.tabPanel.resizeTabs){
26508 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
26510 activate : function(){
26511 this.tabPanel.activate(this.id);
26515 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
26517 disable : function(){
26518 if(this.tabPanel.active != this){
26519 this.disabled = true;
26520 this.pnode.addClass("disabled");
26525 * Enables this TabPanelItem if it was previously disabled.
26527 enable : function(){
26528 this.disabled = false;
26529 this.pnode.removeClass("disabled");
26533 * Sets the content for this TabPanelItem.
26534 * @param {String} content The content
26535 * @param {Boolean} loadScripts true to look for and load scripts
26537 setContent : function(content, loadScripts){
26538 this.bodyEl.update(content, loadScripts);
26542 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
26543 * @return {Roo.UpdateManager} The UpdateManager
26545 getUpdateManager : function(){
26546 return this.bodyEl.getUpdateManager();
26550 * Set a URL to be used to load the content for this TabPanelItem.
26551 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
26552 * @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)
26553 * @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)
26554 * @return {Roo.UpdateManager} The UpdateManager
26556 setUrl : function(url, params, loadOnce){
26557 if(this.refreshDelegate){
26558 this.un('activate', this.refreshDelegate);
26560 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
26561 this.on("activate", this.refreshDelegate);
26562 return this.bodyEl.getUpdateManager();
26566 _handleRefresh : function(url, params, loadOnce){
26567 if(!loadOnce || !this.loaded){
26568 var updater = this.bodyEl.getUpdateManager();
26569 updater.update(url, params, this._setLoaded.createDelegate(this));
26574 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
26575 * Will fail silently if the setUrl method has not been called.
26576 * This does not activate the panel, just updates its content.
26578 refresh : function(){
26579 if(this.refreshDelegate){
26580 this.loaded = false;
26581 this.refreshDelegate();
26586 _setLoaded : function(){
26587 this.loaded = true;
26591 closeClick : function(e){
26594 this.fireEvent("beforeclose", this, o);
26595 if(o.cancel !== true){
26596 this.tabPanel.removeTab(this.id);
26600 * The text displayed in the tooltip for the close icon.
26603 closeText : "Close this tab"
26607 Roo.TabPanel.prototype.createStrip = function(container){
26608 var strip = document.createElement("div");
26609 strip.className = "x-tabs-wrap";
26610 container.appendChild(strip);
26614 Roo.TabPanel.prototype.createStripList = function(strip){
26615 // div wrapper for retard IE
26616 // returns the "tr" element.
26617 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
26618 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
26619 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
26620 return strip.firstChild.firstChild.firstChild.firstChild;
26623 Roo.TabPanel.prototype.createBody = function(container){
26624 var body = document.createElement("div");
26625 Roo.id(body, "tab-body");
26626 Roo.fly(body).addClass("x-tabs-body");
26627 container.appendChild(body);
26631 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
26632 var body = Roo.getDom(id);
26634 body = document.createElement("div");
26637 Roo.fly(body).addClass("x-tabs-item-body");
26638 bodyEl.insertBefore(body, bodyEl.firstChild);
26642 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
26643 var td = document.createElement("td");
26644 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
26645 //stripEl.appendChild(td);
26647 td.className = "x-tabs-closable";
26648 if(!this.closeTpl){
26649 this.closeTpl = new Roo.Template(
26650 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26651 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
26652 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
26655 var el = this.closeTpl.overwrite(td, {"text": text});
26656 var close = el.getElementsByTagName("div")[0];
26657 var inner = el.getElementsByTagName("em")[0];
26658 return {"el": el, "close": close, "inner": inner};
26661 this.tabTpl = new Roo.Template(
26662 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26663 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
26666 var el = this.tabTpl.overwrite(td, {"text": text});
26667 var inner = el.getElementsByTagName("em")[0];
26668 return {"el": el, "inner": inner};
26672 * Ext JS Library 1.1.1
26673 * Copyright(c) 2006-2007, Ext JS, LLC.
26675 * Originally Released Under LGPL - original licence link has changed is not relivant.
26678 * <script type="text/javascript">
26682 * @class Roo.Button
26683 * @extends Roo.util.Observable
26684 * Simple Button class
26685 * @cfg {String} text The button text
26686 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
26687 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
26688 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
26689 * @cfg {Object} scope The scope of the handler
26690 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
26691 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
26692 * @cfg {Boolean} hidden True to start hidden (defaults to false)
26693 * @cfg {Boolean} disabled True to start disabled (defaults to false)
26694 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
26695 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
26696 applies if enableToggle = true)
26697 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
26698 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
26699 an {@link Roo.util.ClickRepeater} config object (defaults to false).
26701 * Create a new button
26702 * @param {Object} config The config object
26704 Roo.Button = function(renderTo, config)
26708 renderTo = config.renderTo || false;
26711 Roo.apply(this, config);
26715 * Fires when this button is clicked
26716 * @param {Button} this
26717 * @param {EventObject} e The click event
26722 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26723 * @param {Button} this
26724 * @param {Boolean} pressed
26729 * Fires when the mouse hovers over the button
26730 * @param {Button} this
26731 * @param {Event} e The event object
26733 'mouseover' : true,
26736 * Fires when the mouse exits the button
26737 * @param {Button} this
26738 * @param {Event} e The event object
26743 * Fires when the button is rendered
26744 * @param {Button} this
26749 this.menu = Roo.menu.MenuMgr.get(this.menu);
26751 // register listeners first!! - so render can be captured..
26752 Roo.util.Observable.call(this);
26754 this.render(renderTo);
26760 Roo.extend(Roo.Button, Roo.util.Observable, {
26766 * Read-only. True if this button is hidden
26771 * Read-only. True if this button is disabled
26776 * Read-only. True if this button is pressed (only if enableToggle = true)
26782 * @cfg {Number} tabIndex
26783 * The DOM tabIndex for this button (defaults to undefined)
26785 tabIndex : undefined,
26788 * @cfg {Boolean} enableToggle
26789 * True to enable pressed/not pressed toggling (defaults to false)
26791 enableToggle: false,
26793 * @cfg {Mixed} menu
26794 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26798 * @cfg {String} menuAlign
26799 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26801 menuAlign : "tl-bl?",
26804 * @cfg {String} iconCls
26805 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26807 iconCls : undefined,
26809 * @cfg {String} type
26810 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26815 menuClassTarget: 'tr',
26818 * @cfg {String} clickEvent
26819 * The type of event to map to the button's event handler (defaults to 'click')
26821 clickEvent : 'click',
26824 * @cfg {Boolean} handleMouseEvents
26825 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26827 handleMouseEvents : true,
26830 * @cfg {String} tooltipType
26831 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26833 tooltipType : 'qtip',
26836 * @cfg {String} cls
26837 * A CSS class to apply to the button's main element.
26841 * @cfg {Roo.Template} template (Optional)
26842 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26843 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26844 * require code modifications if required elements (e.g. a button) aren't present.
26848 render : function(renderTo){
26850 if(this.hideParent){
26851 this.parentEl = Roo.get(renderTo);
26853 if(!this.dhconfig){
26854 if(!this.template){
26855 if(!Roo.Button.buttonTemplate){
26856 // hideous table template
26857 Roo.Button.buttonTemplate = new Roo.Template(
26858 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26859 '<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>',
26860 "</tr></tbody></table>");
26862 this.template = Roo.Button.buttonTemplate;
26864 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26865 var btnEl = btn.child("button:first");
26866 btnEl.on('focus', this.onFocus, this);
26867 btnEl.on('blur', this.onBlur, this);
26869 btn.addClass(this.cls);
26872 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26875 btnEl.addClass(this.iconCls);
26877 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26880 if(this.tabIndex !== undefined){
26881 btnEl.dom.tabIndex = this.tabIndex;
26884 if(typeof this.tooltip == 'object'){
26885 Roo.QuickTips.tips(Roo.apply({
26889 btnEl.dom[this.tooltipType] = this.tooltip;
26893 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26897 this.el.dom.id = this.el.id = this.id;
26900 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26901 this.menu.on("show", this.onMenuShow, this);
26902 this.menu.on("hide", this.onMenuHide, this);
26904 btn.addClass("x-btn");
26905 if(Roo.isIE && !Roo.isIE7){
26906 this.autoWidth.defer(1, this);
26910 if(this.handleMouseEvents){
26911 btn.on("mouseover", this.onMouseOver, this);
26912 btn.on("mouseout", this.onMouseOut, this);
26913 btn.on("mousedown", this.onMouseDown, this);
26915 btn.on(this.clickEvent, this.onClick, this);
26916 //btn.on("mouseup", this.onMouseUp, this);
26923 Roo.ButtonToggleMgr.register(this);
26925 this.el.addClass("x-btn-pressed");
26928 var repeater = new Roo.util.ClickRepeater(btn,
26929 typeof this.repeat == "object" ? this.repeat : {}
26931 repeater.on("click", this.onClick, this);
26934 this.fireEvent('render', this);
26938 * Returns the button's underlying element
26939 * @return {Roo.Element} The element
26941 getEl : function(){
26946 * Destroys this Button and removes any listeners.
26948 destroy : function(){
26949 Roo.ButtonToggleMgr.unregister(this);
26950 this.el.removeAllListeners();
26951 this.purgeListeners();
26956 autoWidth : function(){
26958 this.el.setWidth("auto");
26959 if(Roo.isIE7 && Roo.isStrict){
26960 var ib = this.el.child('button');
26961 if(ib && ib.getWidth() > 20){
26963 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26968 this.el.beginMeasure();
26970 if(this.el.getWidth() < this.minWidth){
26971 this.el.setWidth(this.minWidth);
26974 this.el.endMeasure();
26981 * Assigns this button's click handler
26982 * @param {Function} handler The function to call when the button is clicked
26983 * @param {Object} scope (optional) Scope for the function passed in
26985 setHandler : function(handler, scope){
26986 this.handler = handler;
26987 this.scope = scope;
26991 * Sets this button's text
26992 * @param {String} text The button text
26994 setText : function(text){
26997 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27003 * Gets the text for this button
27004 * @return {String} The button text
27006 getText : function(){
27014 this.hidden = false;
27016 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27024 this.hidden = true;
27026 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27031 * Convenience function for boolean show/hide
27032 * @param {Boolean} visible True to show, false to hide
27034 setVisible: function(visible){
27043 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27044 * @param {Boolean} state (optional) Force a particular state
27046 toggle : function(state){
27047 state = state === undefined ? !this.pressed : state;
27048 if(state != this.pressed){
27050 this.el.addClass("x-btn-pressed");
27051 this.pressed = true;
27052 this.fireEvent("toggle", this, true);
27054 this.el.removeClass("x-btn-pressed");
27055 this.pressed = false;
27056 this.fireEvent("toggle", this, false);
27058 if(this.toggleHandler){
27059 this.toggleHandler.call(this.scope || this, this, state);
27067 focus : function(){
27068 this.el.child('button:first').focus();
27072 * Disable this button
27074 disable : function(){
27076 this.el.addClass("x-btn-disabled");
27078 this.disabled = true;
27082 * Enable this button
27084 enable : function(){
27086 this.el.removeClass("x-btn-disabled");
27088 this.disabled = false;
27092 * Convenience function for boolean enable/disable
27093 * @param {Boolean} enabled True to enable, false to disable
27095 setDisabled : function(v){
27096 this[v !== true ? "enable" : "disable"]();
27100 onClick : function(e){
27102 e.preventDefault();
27107 if(!this.disabled){
27108 if(this.enableToggle){
27111 if(this.menu && !this.menu.isVisible()){
27112 this.menu.show(this.el, this.menuAlign);
27114 this.fireEvent("click", this, e);
27116 this.el.removeClass("x-btn-over");
27117 this.handler.call(this.scope || this, this, e);
27122 onMouseOver : function(e){
27123 if(!this.disabled){
27124 this.el.addClass("x-btn-over");
27125 this.fireEvent('mouseover', this, e);
27129 onMouseOut : function(e){
27130 if(!e.within(this.el, true)){
27131 this.el.removeClass("x-btn-over");
27132 this.fireEvent('mouseout', this, e);
27136 onFocus : function(e){
27137 if(!this.disabled){
27138 this.el.addClass("x-btn-focus");
27142 onBlur : function(e){
27143 this.el.removeClass("x-btn-focus");
27146 onMouseDown : function(e){
27147 if(!this.disabled && e.button == 0){
27148 this.el.addClass("x-btn-click");
27149 Roo.get(document).on('mouseup', this.onMouseUp, this);
27153 onMouseUp : function(e){
27155 this.el.removeClass("x-btn-click");
27156 Roo.get(document).un('mouseup', this.onMouseUp, this);
27160 onMenuShow : function(e){
27161 this.el.addClass("x-btn-menu-active");
27164 onMenuHide : function(e){
27165 this.el.removeClass("x-btn-menu-active");
27169 // Private utility class used by Button
27170 Roo.ButtonToggleMgr = function(){
27173 function toggleGroup(btn, state){
27175 var g = groups[btn.toggleGroup];
27176 for(var i = 0, l = g.length; i < l; i++){
27178 g[i].toggle(false);
27185 register : function(btn){
27186 if(!btn.toggleGroup){
27189 var g = groups[btn.toggleGroup];
27191 g = groups[btn.toggleGroup] = [];
27194 btn.on("toggle", toggleGroup);
27197 unregister : function(btn){
27198 if(!btn.toggleGroup){
27201 var g = groups[btn.toggleGroup];
27204 btn.un("toggle", toggleGroup);
27210 * Ext JS Library 1.1.1
27211 * Copyright(c) 2006-2007, Ext JS, LLC.
27213 * Originally Released Under LGPL - original licence link has changed is not relivant.
27216 * <script type="text/javascript">
27220 * @class Roo.SplitButton
27221 * @extends Roo.Button
27222 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27223 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27224 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27225 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27226 * @cfg {String} arrowTooltip The title attribute of the arrow
27228 * Create a new menu button
27229 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27230 * @param {Object} config The config object
27232 Roo.SplitButton = function(renderTo, config){
27233 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27235 * @event arrowclick
27236 * Fires when this button's arrow is clicked
27237 * @param {SplitButton} this
27238 * @param {EventObject} e The click event
27240 this.addEvents({"arrowclick":true});
27243 Roo.extend(Roo.SplitButton, Roo.Button, {
27244 render : function(renderTo){
27245 // this is one sweet looking template!
27246 var tpl = new Roo.Template(
27247 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27248 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27249 '<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>',
27250 "</tbody></table></td><td>",
27251 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27252 '<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>',
27253 "</tbody></table></td></tr></table>"
27255 var btn = tpl.append(renderTo, [this.text, this.type], true);
27256 var btnEl = btn.child("button");
27258 btn.addClass(this.cls);
27261 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27264 btnEl.addClass(this.iconCls);
27266 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27270 if(this.handleMouseEvents){
27271 btn.on("mouseover", this.onMouseOver, this);
27272 btn.on("mouseout", this.onMouseOut, this);
27273 btn.on("mousedown", this.onMouseDown, this);
27274 btn.on("mouseup", this.onMouseUp, this);
27276 btn.on(this.clickEvent, this.onClick, this);
27278 if(typeof this.tooltip == 'object'){
27279 Roo.QuickTips.tips(Roo.apply({
27283 btnEl.dom[this.tooltipType] = this.tooltip;
27286 if(this.arrowTooltip){
27287 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27296 this.el.addClass("x-btn-pressed");
27298 if(Roo.isIE && !Roo.isIE7){
27299 this.autoWidth.defer(1, this);
27304 this.menu.on("show", this.onMenuShow, this);
27305 this.menu.on("hide", this.onMenuHide, this);
27307 this.fireEvent('render', this);
27311 autoWidth : function(){
27313 var tbl = this.el.child("table:first");
27314 var tbl2 = this.el.child("table:last");
27315 this.el.setWidth("auto");
27316 tbl.setWidth("auto");
27317 if(Roo.isIE7 && Roo.isStrict){
27318 var ib = this.el.child('button:first');
27319 if(ib && ib.getWidth() > 20){
27321 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27326 this.el.beginMeasure();
27328 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27329 tbl.setWidth(this.minWidth-tbl2.getWidth());
27332 this.el.endMeasure();
27335 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27339 * Sets this button's click handler
27340 * @param {Function} handler The function to call when the button is clicked
27341 * @param {Object} scope (optional) Scope for the function passed above
27343 setHandler : function(handler, scope){
27344 this.handler = handler;
27345 this.scope = scope;
27349 * Sets this button's arrow click handler
27350 * @param {Function} handler The function to call when the arrow is clicked
27351 * @param {Object} scope (optional) Scope for the function passed above
27353 setArrowHandler : function(handler, scope){
27354 this.arrowHandler = handler;
27355 this.scope = scope;
27361 focus : function(){
27363 this.el.child("button:first").focus();
27368 onClick : function(e){
27369 e.preventDefault();
27370 if(!this.disabled){
27371 if(e.getTarget(".x-btn-menu-arrow-wrap")){
27372 if(this.menu && !this.menu.isVisible()){
27373 this.menu.show(this.el, this.menuAlign);
27375 this.fireEvent("arrowclick", this, e);
27376 if(this.arrowHandler){
27377 this.arrowHandler.call(this.scope || this, this, e);
27380 this.fireEvent("click", this, e);
27382 this.handler.call(this.scope || this, this, e);
27388 onMouseDown : function(e){
27389 if(!this.disabled){
27390 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
27394 onMouseUp : function(e){
27395 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
27400 // backwards compat
27401 Roo.MenuButton = Roo.SplitButton;/*
27403 * Ext JS Library 1.1.1
27404 * Copyright(c) 2006-2007, Ext JS, LLC.
27406 * Originally Released Under LGPL - original licence link has changed is not relivant.
27409 * <script type="text/javascript">
27413 * @class Roo.Toolbar
27414 * Basic Toolbar class.
27416 * Creates a new Toolbar
27417 * @param {Object} container The config object
27419 Roo.Toolbar = function(container, buttons, config)
27421 /// old consturctor format still supported..
27422 if(container instanceof Array){ // omit the container for later rendering
27423 buttons = container;
27427 if (typeof(container) == 'object' && container.xtype) {
27428 config = container;
27429 container = config.container;
27430 buttons = config.buttons || []; // not really - use items!!
27433 if (config && config.items) {
27434 xitems = config.items;
27435 delete config.items;
27437 Roo.apply(this, config);
27438 this.buttons = buttons;
27441 this.render(container);
27443 this.xitems = xitems;
27444 Roo.each(xitems, function(b) {
27450 Roo.Toolbar.prototype = {
27452 * @cfg {Array} items
27453 * array of button configs or elements to add (will be converted to a MixedCollection)
27457 * @cfg {String/HTMLElement/Element} container
27458 * The id or element that will contain the toolbar
27461 render : function(ct){
27462 this.el = Roo.get(ct);
27464 this.el.addClass(this.cls);
27466 // using a table allows for vertical alignment
27467 // 100% width is needed by Safari...
27468 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
27469 this.tr = this.el.child("tr", true);
27471 this.items = new Roo.util.MixedCollection(false, function(o){
27472 return o.id || ("item" + (++autoId));
27475 this.add.apply(this, this.buttons);
27476 delete this.buttons;
27481 * Adds element(s) to the toolbar -- this function takes a variable number of
27482 * arguments of mixed type and adds them to the toolbar.
27483 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
27485 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
27486 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
27487 * <li>Field: Any form field (equivalent to {@link #addField})</li>
27488 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
27489 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
27490 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
27491 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
27492 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
27493 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
27495 * @param {Mixed} arg2
27496 * @param {Mixed} etc.
27499 var a = arguments, l = a.length;
27500 for(var i = 0; i < l; i++){
27505 _add : function(el) {
27508 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
27511 if (el.applyTo){ // some kind of form field
27512 return this.addField(el);
27514 if (el.render){ // some kind of Toolbar.Item
27515 return this.addItem(el);
27517 if (typeof el == "string"){ // string
27518 if(el == "separator" || el == "-"){
27519 return this.addSeparator();
27522 return this.addSpacer();
27525 return this.addFill();
27527 return this.addText(el);
27530 if(el.tagName){ // element
27531 return this.addElement(el);
27533 if(typeof el == "object"){ // must be button config?
27534 return this.addButton(el);
27536 // and now what?!?!
27542 * Add an Xtype element
27543 * @param {Object} xtype Xtype Object
27544 * @return {Object} created Object
27546 addxtype : function(e){
27547 return this.add(e);
27551 * Returns the Element for this toolbar.
27552 * @return {Roo.Element}
27554 getEl : function(){
27560 * @return {Roo.Toolbar.Item} The separator item
27562 addSeparator : function(){
27563 return this.addItem(new Roo.Toolbar.Separator());
27567 * Adds a spacer element
27568 * @return {Roo.Toolbar.Spacer} The spacer item
27570 addSpacer : function(){
27571 return this.addItem(new Roo.Toolbar.Spacer());
27575 * Adds a fill element that forces subsequent additions to the right side of the toolbar
27576 * @return {Roo.Toolbar.Fill} The fill item
27578 addFill : function(){
27579 return this.addItem(new Roo.Toolbar.Fill());
27583 * Adds any standard HTML element to the toolbar
27584 * @param {String/HTMLElement/Element} el The element or id of the element to add
27585 * @return {Roo.Toolbar.Item} The element's item
27587 addElement : function(el){
27588 return this.addItem(new Roo.Toolbar.Item(el));
27591 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
27592 * @type Roo.util.MixedCollection
27597 * Adds any Toolbar.Item or subclass
27598 * @param {Roo.Toolbar.Item} item
27599 * @return {Roo.Toolbar.Item} The item
27601 addItem : function(item){
27602 var td = this.nextBlock();
27604 this.items.add(item);
27609 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
27610 * @param {Object/Array} config A button config or array of configs
27611 * @return {Roo.Toolbar.Button/Array}
27613 addButton : function(config){
27614 if(config instanceof Array){
27616 for(var i = 0, len = config.length; i < len; i++) {
27617 buttons.push(this.addButton(config[i]));
27622 if(!(config instanceof Roo.Toolbar.Button)){
27624 new Roo.Toolbar.SplitButton(config) :
27625 new Roo.Toolbar.Button(config);
27627 var td = this.nextBlock();
27634 * Adds text to the toolbar
27635 * @param {String} text The text to add
27636 * @return {Roo.Toolbar.Item} The element's item
27638 addText : function(text){
27639 return this.addItem(new Roo.Toolbar.TextItem(text));
27643 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
27644 * @param {Number} index The index where the item is to be inserted
27645 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
27646 * @return {Roo.Toolbar.Button/Item}
27648 insertButton : function(index, item){
27649 if(item instanceof Array){
27651 for(var i = 0, len = item.length; i < len; i++) {
27652 buttons.push(this.insertButton(index + i, item[i]));
27656 if (!(item instanceof Roo.Toolbar.Button)){
27657 item = new Roo.Toolbar.Button(item);
27659 var td = document.createElement("td");
27660 this.tr.insertBefore(td, this.tr.childNodes[index]);
27662 this.items.insert(index, item);
27667 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
27668 * @param {Object} config
27669 * @return {Roo.Toolbar.Item} The element's item
27671 addDom : function(config, returnEl){
27672 var td = this.nextBlock();
27673 Roo.DomHelper.overwrite(td, config);
27674 var ti = new Roo.Toolbar.Item(td.firstChild);
27676 this.items.add(ti);
27681 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
27682 * @type Roo.util.MixedCollection
27687 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
27688 * Note: the field should not have been rendered yet. For a field that has already been
27689 * rendered, use {@link #addElement}.
27690 * @param {Roo.form.Field} field
27691 * @return {Roo.ToolbarItem}
27695 addField : function(field) {
27696 if (!this.fields) {
27698 this.fields = new Roo.util.MixedCollection(false, function(o){
27699 return o.id || ("item" + (++autoId));
27704 var td = this.nextBlock();
27706 var ti = new Roo.Toolbar.Item(td.firstChild);
27708 this.items.add(ti);
27709 this.fields.add(field);
27720 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27721 this.el.child('div').hide();
27729 this.el.child('div').show();
27733 nextBlock : function(){
27734 var td = document.createElement("td");
27735 this.tr.appendChild(td);
27740 destroy : function(){
27741 if(this.items){ // rendered?
27742 Roo.destroy.apply(Roo, this.items.items);
27744 if(this.fields){ // rendered?
27745 Roo.destroy.apply(Roo, this.fields.items);
27747 Roo.Element.uncache(this.el, this.tr);
27752 * @class Roo.Toolbar.Item
27753 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27755 * Creates a new Item
27756 * @param {HTMLElement} el
27758 Roo.Toolbar.Item = function(el){
27759 this.el = Roo.getDom(el);
27760 this.id = Roo.id(this.el);
27761 this.hidden = false;
27764 Roo.Toolbar.Item.prototype = {
27767 * Get this item's HTML Element
27768 * @return {HTMLElement}
27770 getEl : function(){
27775 render : function(td){
27777 td.appendChild(this.el);
27781 * Removes and destroys this item.
27783 destroy : function(){
27784 this.td.parentNode.removeChild(this.td);
27791 this.hidden = false;
27792 this.td.style.display = "";
27799 this.hidden = true;
27800 this.td.style.display = "none";
27804 * Convenience function for boolean show/hide.
27805 * @param {Boolean} visible true to show/false to hide
27807 setVisible: function(visible){
27816 * Try to focus this item.
27818 focus : function(){
27819 Roo.fly(this.el).focus();
27823 * Disables this item.
27825 disable : function(){
27826 Roo.fly(this.td).addClass("x-item-disabled");
27827 this.disabled = true;
27828 this.el.disabled = true;
27832 * Enables this item.
27834 enable : function(){
27835 Roo.fly(this.td).removeClass("x-item-disabled");
27836 this.disabled = false;
27837 this.el.disabled = false;
27843 * @class Roo.Toolbar.Separator
27844 * @extends Roo.Toolbar.Item
27845 * A simple toolbar separator class
27847 * Creates a new Separator
27849 Roo.Toolbar.Separator = function(){
27850 var s = document.createElement("span");
27851 s.className = "ytb-sep";
27852 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27854 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27855 enable:Roo.emptyFn,
27856 disable:Roo.emptyFn,
27861 * @class Roo.Toolbar.Spacer
27862 * @extends Roo.Toolbar.Item
27863 * A simple element that adds extra horizontal space to a toolbar.
27865 * Creates a new Spacer
27867 Roo.Toolbar.Spacer = function(){
27868 var s = document.createElement("div");
27869 s.className = "ytb-spacer";
27870 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27872 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27873 enable:Roo.emptyFn,
27874 disable:Roo.emptyFn,
27879 * @class Roo.Toolbar.Fill
27880 * @extends Roo.Toolbar.Spacer
27881 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27883 * Creates a new Spacer
27885 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27887 render : function(td){
27888 td.style.width = '100%';
27889 Roo.Toolbar.Fill.superclass.render.call(this, td);
27894 * @class Roo.Toolbar.TextItem
27895 * @extends Roo.Toolbar.Item
27896 * A simple class that renders text directly into a toolbar.
27898 * Creates a new TextItem
27899 * @param {String} text
27901 Roo.Toolbar.TextItem = function(text){
27902 if (typeof(text) == 'object') {
27905 var s = document.createElement("span");
27906 s.className = "ytb-text";
27907 s.innerHTML = text;
27908 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27910 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27911 enable:Roo.emptyFn,
27912 disable:Roo.emptyFn,
27917 * @class Roo.Toolbar.Button
27918 * @extends Roo.Button
27919 * A button that renders into a toolbar.
27921 * Creates a new Button
27922 * @param {Object} config A standard {@link Roo.Button} config object
27924 Roo.Toolbar.Button = function(config){
27925 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27927 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27928 render : function(td){
27930 Roo.Toolbar.Button.superclass.render.call(this, td);
27934 * Removes and destroys this button
27936 destroy : function(){
27937 Roo.Toolbar.Button.superclass.destroy.call(this);
27938 this.td.parentNode.removeChild(this.td);
27942 * Shows this button
27945 this.hidden = false;
27946 this.td.style.display = "";
27950 * Hides this button
27953 this.hidden = true;
27954 this.td.style.display = "none";
27958 * Disables this item
27960 disable : function(){
27961 Roo.fly(this.td).addClass("x-item-disabled");
27962 this.disabled = true;
27966 * Enables this item
27968 enable : function(){
27969 Roo.fly(this.td).removeClass("x-item-disabled");
27970 this.disabled = false;
27973 // backwards compat
27974 Roo.ToolbarButton = Roo.Toolbar.Button;
27977 * @class Roo.Toolbar.SplitButton
27978 * @extends Roo.SplitButton
27979 * A menu button that renders into a toolbar.
27981 * Creates a new SplitButton
27982 * @param {Object} config A standard {@link Roo.SplitButton} config object
27984 Roo.Toolbar.SplitButton = function(config){
27985 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27987 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27988 render : function(td){
27990 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27994 * Removes and destroys this button
27996 destroy : function(){
27997 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27998 this.td.parentNode.removeChild(this.td);
28002 * Shows this button
28005 this.hidden = false;
28006 this.td.style.display = "";
28010 * Hides this button
28013 this.hidden = true;
28014 this.td.style.display = "none";
28018 // backwards compat
28019 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28021 * Ext JS Library 1.1.1
28022 * Copyright(c) 2006-2007, Ext JS, LLC.
28024 * Originally Released Under LGPL - original licence link has changed is not relivant.
28027 * <script type="text/javascript">
28031 * @class Roo.PagingToolbar
28032 * @extends Roo.Toolbar
28033 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28035 * Create a new PagingToolbar
28036 * @param {Object} config The config object
28038 Roo.PagingToolbar = function(el, ds, config)
28040 // old args format still supported... - xtype is prefered..
28041 if (typeof(el) == 'object' && el.xtype) {
28042 // created from xtype...
28044 ds = el.dataSource;
28045 el = config.container;
28048 if (config.items) {
28049 items = config.items;
28053 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28056 this.renderButtons(this.el);
28059 // supprot items array.
28061 Roo.each(items, function(e) {
28062 this.add(Roo.factory(e));
28067 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28069 * @cfg {Roo.data.Store} dataSource
28070 * The underlying data store providing the paged data
28073 * @cfg {String/HTMLElement/Element} container
28074 * container The id or element that will contain the toolbar
28077 * @cfg {Boolean} displayInfo
28078 * True to display the displayMsg (defaults to false)
28081 * @cfg {Number} pageSize
28082 * The number of records to display per page (defaults to 20)
28086 * @cfg {String} displayMsg
28087 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28089 displayMsg : 'Displaying {0} - {1} of {2}',
28091 * @cfg {String} emptyMsg
28092 * The message to display when no records are found (defaults to "No data to display")
28094 emptyMsg : 'No data to display',
28096 * Customizable piece of the default paging text (defaults to "Page")
28099 beforePageText : "Page",
28101 * Customizable piece of the default paging text (defaults to "of %0")
28104 afterPageText : "of {0}",
28106 * Customizable piece of the default paging text (defaults to "First Page")
28109 firstText : "First Page",
28111 * Customizable piece of the default paging text (defaults to "Previous Page")
28114 prevText : "Previous Page",
28116 * Customizable piece of the default paging text (defaults to "Next Page")
28119 nextText : "Next Page",
28121 * Customizable piece of the default paging text (defaults to "Last Page")
28124 lastText : "Last Page",
28126 * Customizable piece of the default paging text (defaults to "Refresh")
28129 refreshText : "Refresh",
28132 renderButtons : function(el){
28133 Roo.PagingToolbar.superclass.render.call(this, el);
28134 this.first = this.addButton({
28135 tooltip: this.firstText,
28136 cls: "x-btn-icon x-grid-page-first",
28138 handler: this.onClick.createDelegate(this, ["first"])
28140 this.prev = this.addButton({
28141 tooltip: this.prevText,
28142 cls: "x-btn-icon x-grid-page-prev",
28144 handler: this.onClick.createDelegate(this, ["prev"])
28146 //this.addSeparator();
28147 this.add(this.beforePageText);
28148 this.field = Roo.get(this.addDom({
28153 cls: "x-grid-page-number"
28155 this.field.on("keydown", this.onPagingKeydown, this);
28156 this.field.on("focus", function(){this.dom.select();});
28157 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28158 this.field.setHeight(18);
28159 //this.addSeparator();
28160 this.next = this.addButton({
28161 tooltip: this.nextText,
28162 cls: "x-btn-icon x-grid-page-next",
28164 handler: this.onClick.createDelegate(this, ["next"])
28166 this.last = this.addButton({
28167 tooltip: this.lastText,
28168 cls: "x-btn-icon x-grid-page-last",
28170 handler: this.onClick.createDelegate(this, ["last"])
28172 //this.addSeparator();
28173 this.loading = this.addButton({
28174 tooltip: this.refreshText,
28175 cls: "x-btn-icon x-grid-loading",
28176 handler: this.onClick.createDelegate(this, ["refresh"])
28179 if(this.displayInfo){
28180 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28185 updateInfo : function(){
28186 if(this.displayEl){
28187 var count = this.ds.getCount();
28188 var msg = count == 0 ?
28192 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28194 this.displayEl.update(msg);
28199 onLoad : function(ds, r, o){
28200 this.cursor = o.params ? o.params.start : 0;
28201 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28203 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28204 this.field.dom.value = ap;
28205 this.first.setDisabled(ap == 1);
28206 this.prev.setDisabled(ap == 1);
28207 this.next.setDisabled(ap == ps);
28208 this.last.setDisabled(ap == ps);
28209 this.loading.enable();
28214 getPageData : function(){
28215 var total = this.ds.getTotalCount();
28218 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28219 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28224 onLoadError : function(){
28225 this.loading.enable();
28229 onPagingKeydown : function(e){
28230 var k = e.getKey();
28231 var d = this.getPageData();
28233 var v = this.field.dom.value, pageNum;
28234 if(!v || isNaN(pageNum = parseInt(v, 10))){
28235 this.field.dom.value = d.activePage;
28238 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28239 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28242 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))
28244 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28245 this.field.dom.value = pageNum;
28246 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28249 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28251 var v = this.field.dom.value, pageNum;
28252 var increment = (e.shiftKey) ? 10 : 1;
28253 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28255 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28256 this.field.dom.value = d.activePage;
28259 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28261 this.field.dom.value = parseInt(v, 10) + increment;
28262 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28263 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28270 beforeLoad : function(){
28272 this.loading.disable();
28277 onClick : function(which){
28281 ds.load({params:{start: 0, limit: this.pageSize}});
28284 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28287 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28290 var total = ds.getTotalCount();
28291 var extra = total % this.pageSize;
28292 var lastStart = extra ? (total - extra) : total-this.pageSize;
28293 ds.load({params:{start: lastStart, limit: this.pageSize}});
28296 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28302 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28303 * @param {Roo.data.Store} store The data store to unbind
28305 unbind : function(ds){
28306 ds.un("beforeload", this.beforeLoad, this);
28307 ds.un("load", this.onLoad, this);
28308 ds.un("loadexception", this.onLoadError, this);
28309 ds.un("remove", this.updateInfo, this);
28310 ds.un("add", this.updateInfo, this);
28311 this.ds = undefined;
28315 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28316 * @param {Roo.data.Store} store The data store to bind
28318 bind : function(ds){
28319 ds.on("beforeload", this.beforeLoad, this);
28320 ds.on("load", this.onLoad, this);
28321 ds.on("loadexception", this.onLoadError, this);
28322 ds.on("remove", this.updateInfo, this);
28323 ds.on("add", this.updateInfo, this);
28328 * Ext JS Library 1.1.1
28329 * Copyright(c) 2006-2007, Ext JS, LLC.
28331 * Originally Released Under LGPL - original licence link has changed is not relivant.
28334 * <script type="text/javascript">
28338 * @class Roo.Resizable
28339 * @extends Roo.util.Observable
28340 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28341 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28342 * 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
28343 * the element will be wrapped for you automatically.</p>
28344 * <p>Here is the list of valid resize handles:</p>
28347 ------ -------------------
28356 'hd' horizontal drag
28359 * <p>Here's an example showing the creation of a typical Resizable:</p>
28361 var resizer = new Roo.Resizable("element-id", {
28369 resizer.on("resize", myHandler);
28371 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
28372 * resizer.east.setDisplayed(false);</p>
28373 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
28374 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
28375 * resize operation's new size (defaults to [0, 0])
28376 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
28377 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
28378 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
28379 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
28380 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
28381 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
28382 * @cfg {Number} width The width of the element in pixels (defaults to null)
28383 * @cfg {Number} height The height of the element in pixels (defaults to null)
28384 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
28385 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
28386 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
28387 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
28388 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
28389 * in favor of the handles config option (defaults to false)
28390 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
28391 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
28392 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
28393 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
28394 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
28395 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
28396 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
28397 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
28398 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
28399 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
28400 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
28402 * Create a new resizable component
28403 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
28404 * @param {Object} config configuration options
28406 Roo.Resizable = function(el, config)
28408 this.el = Roo.get(el);
28410 if(config && config.wrap){
28411 config.resizeChild = this.el;
28412 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
28413 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
28414 this.el.setStyle("overflow", "hidden");
28415 this.el.setPositioning(config.resizeChild.getPositioning());
28416 config.resizeChild.clearPositioning();
28417 if(!config.width || !config.height){
28418 var csize = config.resizeChild.getSize();
28419 this.el.setSize(csize.width, csize.height);
28421 if(config.pinned && !config.adjustments){
28422 config.adjustments = "auto";
28426 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
28427 this.proxy.unselectable();
28428 this.proxy.enableDisplayMode('block');
28430 Roo.apply(this, config);
28433 this.disableTrackOver = true;
28434 this.el.addClass("x-resizable-pinned");
28436 // if the element isn't positioned, make it relative
28437 var position = this.el.getStyle("position");
28438 if(position != "absolute" && position != "fixed"){
28439 this.el.setStyle("position", "relative");
28441 if(!this.handles){ // no handles passed, must be legacy style
28442 this.handles = 's,e,se';
28443 if(this.multiDirectional){
28444 this.handles += ',n,w';
28447 if(this.handles == "all"){
28448 this.handles = "n s e w ne nw se sw";
28450 var hs = this.handles.split(/\s*?[,;]\s*?| /);
28451 var ps = Roo.Resizable.positions;
28452 for(var i = 0, len = hs.length; i < len; i++){
28453 if(hs[i] && ps[hs[i]]){
28454 var pos = ps[hs[i]];
28455 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
28459 this.corner = this.southeast;
28461 // updateBox = the box can move..
28462 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
28463 this.updateBox = true;
28466 this.activeHandle = null;
28468 if(this.resizeChild){
28469 if(typeof this.resizeChild == "boolean"){
28470 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
28472 this.resizeChild = Roo.get(this.resizeChild, true);
28476 if(this.adjustments == "auto"){
28477 var rc = this.resizeChild;
28478 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
28479 if(rc && (hw || hn)){
28480 rc.position("relative");
28481 rc.setLeft(hw ? hw.el.getWidth() : 0);
28482 rc.setTop(hn ? hn.el.getHeight() : 0);
28484 this.adjustments = [
28485 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
28486 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
28490 if(this.draggable){
28491 this.dd = this.dynamic ?
28492 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
28493 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
28499 * @event beforeresize
28500 * Fired before resize is allowed. Set enabled to false to cancel resize.
28501 * @param {Roo.Resizable} this
28502 * @param {Roo.EventObject} e The mousedown event
28504 "beforeresize" : true,
28507 * Fired a resizing.
28508 * @param {Roo.Resizable} this
28509 * @param {Number} x The new x position
28510 * @param {Number} y The new y position
28511 * @param {Number} w The new w width
28512 * @param {Number} h The new h hight
28513 * @param {Roo.EventObject} e The mouseup event
28518 * Fired after a resize.
28519 * @param {Roo.Resizable} this
28520 * @param {Number} width The new width
28521 * @param {Number} height The new height
28522 * @param {Roo.EventObject} e The mouseup event
28527 if(this.width !== null && this.height !== null){
28528 this.resizeTo(this.width, this.height);
28530 this.updateChildSize();
28533 this.el.dom.style.zoom = 1;
28535 Roo.Resizable.superclass.constructor.call(this);
28538 Roo.extend(Roo.Resizable, Roo.util.Observable, {
28539 resizeChild : false,
28540 adjustments : [0, 0],
28550 multiDirectional : false,
28551 disableTrackOver : false,
28552 easing : 'easeOutStrong',
28553 widthIncrement : 0,
28554 heightIncrement : 0,
28558 preserveRatio : false,
28559 transparent: false,
28565 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
28567 constrainTo: undefined,
28569 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
28571 resizeRegion: undefined,
28575 * Perform a manual resize
28576 * @param {Number} width
28577 * @param {Number} height
28579 resizeTo : function(width, height){
28580 this.el.setSize(width, height);
28581 this.updateChildSize();
28582 this.fireEvent("resize", this, width, height, null);
28586 startSizing : function(e, handle){
28587 this.fireEvent("beforeresize", this, e);
28588 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
28591 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
28592 this.overlay.unselectable();
28593 this.overlay.enableDisplayMode("block");
28594 this.overlay.on("mousemove", this.onMouseMove, this);
28595 this.overlay.on("mouseup", this.onMouseUp, this);
28597 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
28599 this.resizing = true;
28600 this.startBox = this.el.getBox();
28601 this.startPoint = e.getXY();
28602 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
28603 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
28605 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28606 this.overlay.show();
28608 if(this.constrainTo) {
28609 var ct = Roo.get(this.constrainTo);
28610 this.resizeRegion = ct.getRegion().adjust(
28611 ct.getFrameWidth('t'),
28612 ct.getFrameWidth('l'),
28613 -ct.getFrameWidth('b'),
28614 -ct.getFrameWidth('r')
28618 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
28620 this.proxy.setBox(this.startBox);
28622 this.proxy.setStyle('visibility', 'visible');
28628 onMouseDown : function(handle, e){
28631 this.activeHandle = handle;
28632 this.startSizing(e, handle);
28637 onMouseUp : function(e){
28638 var size = this.resizeElement();
28639 this.resizing = false;
28641 this.overlay.hide();
28643 this.fireEvent("resize", this, size.width, size.height, e);
28647 updateChildSize : function(){
28649 if(this.resizeChild){
28651 var child = this.resizeChild;
28652 var adj = this.adjustments;
28653 if(el.dom.offsetWidth){
28654 var b = el.getSize(true);
28655 child.setSize(b.width+adj[0], b.height+adj[1]);
28657 // Second call here for IE
28658 // The first call enables instant resizing and
28659 // the second call corrects scroll bars if they
28662 setTimeout(function(){
28663 if(el.dom.offsetWidth){
28664 var b = el.getSize(true);
28665 child.setSize(b.width+adj[0], b.height+adj[1]);
28673 snap : function(value, inc, min){
28674 if(!inc || !value) return value;
28675 var newValue = value;
28676 var m = value % inc;
28679 newValue = value + (inc-m);
28681 newValue = value - m;
28684 return Math.max(min, newValue);
28688 resizeElement : function(){
28689 var box = this.proxy.getBox();
28690 if(this.updateBox){
28691 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
28693 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
28695 this.updateChildSize();
28703 constrain : function(v, diff, m, mx){
28706 }else if(v - diff > mx){
28713 onMouseMove : function(e){
28716 try{// try catch so if something goes wrong the user doesn't get hung
28718 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
28722 //var curXY = this.startPoint;
28723 var curSize = this.curSize || this.startBox;
28724 var x = this.startBox.x, y = this.startBox.y;
28725 var ox = x, oy = y;
28726 var w = curSize.width, h = curSize.height;
28727 var ow = w, oh = h;
28728 var mw = this.minWidth, mh = this.minHeight;
28729 var mxw = this.maxWidth, mxh = this.maxHeight;
28730 var wi = this.widthIncrement;
28731 var hi = this.heightIncrement;
28733 var eventXY = e.getXY();
28734 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28735 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28737 var pos = this.activeHandle.position;
28742 w = Math.min(Math.max(mw, w), mxw);
28747 h = Math.min(Math.max(mh, h), mxh);
28752 w = Math.min(Math.max(mw, w), mxw);
28753 h = Math.min(Math.max(mh, h), mxh);
28756 diffY = this.constrain(h, diffY, mh, mxh);
28763 var adiffX = Math.abs(diffX);
28764 var sub = (adiffX % wi); // how much
28765 if (sub > (wi/2)) { // far enough to snap
28766 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28768 // remove difference..
28769 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28773 x = Math.max(this.minX, x);
28776 diffX = this.constrain(w, diffX, mw, mxw);
28782 w = Math.min(Math.max(mw, w), mxw);
28783 diffY = this.constrain(h, diffY, mh, mxh);
28788 diffX = this.constrain(w, diffX, mw, mxw);
28789 diffY = this.constrain(h, diffY, mh, mxh);
28796 diffX = this.constrain(w, diffX, mw, mxw);
28798 h = Math.min(Math.max(mh, h), mxh);
28804 var sw = this.snap(w, wi, mw);
28805 var sh = this.snap(h, hi, mh);
28806 if(sw != w || sh != h){
28829 if(this.preserveRatio){
28834 h = Math.min(Math.max(mh, h), mxh);
28839 w = Math.min(Math.max(mw, w), mxw);
28844 w = Math.min(Math.max(mw, w), mxw);
28850 w = Math.min(Math.max(mw, w), mxw);
28856 h = Math.min(Math.max(mh, h), mxh);
28864 h = Math.min(Math.max(mh, h), mxh);
28874 h = Math.min(Math.max(mh, h), mxh);
28882 if (pos == 'hdrag') {
28885 this.proxy.setBounds(x, y, w, h);
28887 this.resizeElement();
28891 this.fireEvent("resizing", this, x, y, w, h, e);
28895 handleOver : function(){
28897 this.el.addClass("x-resizable-over");
28902 handleOut : function(){
28903 if(!this.resizing){
28904 this.el.removeClass("x-resizable-over");
28909 * Returns the element this component is bound to.
28910 * @return {Roo.Element}
28912 getEl : function(){
28917 * Returns the resizeChild element (or null).
28918 * @return {Roo.Element}
28920 getResizeChild : function(){
28921 return this.resizeChild;
28923 groupHandler : function()
28928 * Destroys this resizable. If the element was wrapped and
28929 * removeEl is not true then the element remains.
28930 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28932 destroy : function(removeEl){
28933 this.proxy.remove();
28935 this.overlay.removeAllListeners();
28936 this.overlay.remove();
28938 var ps = Roo.Resizable.positions;
28940 if(typeof ps[k] != "function" && this[ps[k]]){
28941 var h = this[ps[k]];
28942 h.el.removeAllListeners();
28947 this.el.update("");
28954 // hash to map config positions to true positions
28955 Roo.Resizable.positions = {
28956 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28961 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28963 // only initialize the template if resizable is used
28964 var tpl = Roo.DomHelper.createTemplate(
28965 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28968 Roo.Resizable.Handle.prototype.tpl = tpl;
28970 this.position = pos;
28972 // show north drag fro topdra
28973 var handlepos = pos == 'hdrag' ? 'north' : pos;
28975 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28976 if (pos == 'hdrag') {
28977 this.el.setStyle('cursor', 'pointer');
28979 this.el.unselectable();
28981 this.el.setOpacity(0);
28983 this.el.on("mousedown", this.onMouseDown, this);
28984 if(!disableTrackOver){
28985 this.el.on("mouseover", this.onMouseOver, this);
28986 this.el.on("mouseout", this.onMouseOut, this);
28991 Roo.Resizable.Handle.prototype = {
28992 afterResize : function(rz){
28996 onMouseDown : function(e){
28997 this.rz.onMouseDown(this, e);
29000 onMouseOver : function(e){
29001 this.rz.handleOver(this, e);
29004 onMouseOut : function(e){
29005 this.rz.handleOut(this, e);
29009 * Ext JS Library 1.1.1
29010 * Copyright(c) 2006-2007, Ext JS, LLC.
29012 * Originally Released Under LGPL - original licence link has changed is not relivant.
29015 * <script type="text/javascript">
29019 * @class Roo.Editor
29020 * @extends Roo.Component
29021 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29023 * Create a new Editor
29024 * @param {Roo.form.Field} field The Field object (or descendant)
29025 * @param {Object} config The config object
29027 Roo.Editor = function(field, config){
29028 Roo.Editor.superclass.constructor.call(this, config);
29029 this.field = field;
29032 * @event beforestartedit
29033 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29034 * false from the handler of this event.
29035 * @param {Editor} this
29036 * @param {Roo.Element} boundEl The underlying element bound to this editor
29037 * @param {Mixed} value The field value being set
29039 "beforestartedit" : true,
29042 * Fires when this editor is displayed
29043 * @param {Roo.Element} boundEl The underlying element bound to this editor
29044 * @param {Mixed} value The starting field value
29046 "startedit" : true,
29048 * @event beforecomplete
29049 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29050 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29051 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29052 * event will not fire since no edit actually occurred.
29053 * @param {Editor} this
29054 * @param {Mixed} value The current field value
29055 * @param {Mixed} startValue The original field value
29057 "beforecomplete" : true,
29060 * Fires after editing is complete and any changed value has been written to the underlying field.
29061 * @param {Editor} this
29062 * @param {Mixed} value The current field value
29063 * @param {Mixed} startValue The original field value
29067 * @event specialkey
29068 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29069 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29070 * @param {Roo.form.Field} this
29071 * @param {Roo.EventObject} e The event object
29073 "specialkey" : true
29077 Roo.extend(Roo.Editor, Roo.Component, {
29079 * @cfg {Boolean/String} autosize
29080 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29081 * or "height" to adopt the height only (defaults to false)
29084 * @cfg {Boolean} revertInvalid
29085 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29086 * validation fails (defaults to true)
29089 * @cfg {Boolean} ignoreNoChange
29090 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29091 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29092 * will never be ignored.
29095 * @cfg {Boolean} hideEl
29096 * False to keep the bound element visible while the editor is displayed (defaults to true)
29099 * @cfg {Mixed} value
29100 * The data value of the underlying field (defaults to "")
29104 * @cfg {String} alignment
29105 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29109 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29110 * for bottom-right shadow (defaults to "frame")
29114 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29118 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29120 completeOnEnter : false,
29122 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29124 cancelOnEsc : false,
29126 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29131 onRender : function(ct, position){
29132 this.el = new Roo.Layer({
29133 shadow: this.shadow,
29139 constrain: this.constrain
29141 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29142 if(this.field.msgTarget != 'title'){
29143 this.field.msgTarget = 'qtip';
29145 this.field.render(this.el);
29147 this.field.el.dom.setAttribute('autocomplete', 'off');
29149 this.field.on("specialkey", this.onSpecialKey, this);
29150 if(this.swallowKeys){
29151 this.field.el.swallowEvent(['keydown','keypress']);
29154 this.field.on("blur", this.onBlur, this);
29155 if(this.field.grow){
29156 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29160 onSpecialKey : function(field, e)
29162 //Roo.log('editor onSpecialKey');
29163 if(this.completeOnEnter && e.getKey() == e.ENTER){
29165 this.completeEdit();
29168 // do not fire special key otherwise it might hide close the editor...
29169 if(e.getKey() == e.ENTER){
29172 if(this.cancelOnEsc && e.getKey() == e.ESC){
29176 this.fireEvent('specialkey', field, e);
29181 * Starts the editing process and shows the editor.
29182 * @param {String/HTMLElement/Element} el The element to edit
29183 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29184 * to the innerHTML of el.
29186 startEdit : function(el, value){
29188 this.completeEdit();
29190 this.boundEl = Roo.get(el);
29191 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29192 if(!this.rendered){
29193 this.render(this.parentEl || document.body);
29195 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29198 this.startValue = v;
29199 this.field.setValue(v);
29201 var sz = this.boundEl.getSize();
29202 switch(this.autoSize){
29204 this.setSize(sz.width, "");
29207 this.setSize("", sz.height);
29210 this.setSize(sz.width, sz.height);
29213 this.el.alignTo(this.boundEl, this.alignment);
29214 this.editing = true;
29216 Roo.QuickTips.disable();
29222 * Sets the height and width of this editor.
29223 * @param {Number} width The new width
29224 * @param {Number} height The new height
29226 setSize : function(w, h){
29227 this.field.setSize(w, h);
29234 * Realigns the editor to the bound field based on the current alignment config value.
29236 realign : function(){
29237 this.el.alignTo(this.boundEl, this.alignment);
29241 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29242 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29244 completeEdit : function(remainVisible){
29248 var v = this.getValue();
29249 if(this.revertInvalid !== false && !this.field.isValid()){
29250 v = this.startValue;
29251 this.cancelEdit(true);
29253 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29254 this.editing = false;
29258 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29259 this.editing = false;
29260 if(this.updateEl && this.boundEl){
29261 this.boundEl.update(v);
29263 if(remainVisible !== true){
29266 this.fireEvent("complete", this, v, this.startValue);
29271 onShow : function(){
29273 if(this.hideEl !== false){
29274 this.boundEl.hide();
29277 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29278 this.fixIEFocus = true;
29279 this.deferredFocus.defer(50, this);
29281 this.field.focus();
29283 this.fireEvent("startedit", this.boundEl, this.startValue);
29286 deferredFocus : function(){
29288 this.field.focus();
29293 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29294 * reverted to the original starting value.
29295 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29296 * cancel (defaults to false)
29298 cancelEdit : function(remainVisible){
29300 this.setValue(this.startValue);
29301 if(remainVisible !== true){
29308 onBlur : function(){
29309 if(this.allowBlur !== true && this.editing){
29310 this.completeEdit();
29315 onHide : function(){
29317 this.completeEdit();
29321 if(this.field.collapse){
29322 this.field.collapse();
29325 if(this.hideEl !== false){
29326 this.boundEl.show();
29329 Roo.QuickTips.enable();
29334 * Sets the data value of the editor
29335 * @param {Mixed} value Any valid value supported by the underlying field
29337 setValue : function(v){
29338 this.field.setValue(v);
29342 * Gets the data value of the editor
29343 * @return {Mixed} The data value
29345 getValue : function(){
29346 return this.field.getValue();
29350 * Ext JS Library 1.1.1
29351 * Copyright(c) 2006-2007, Ext JS, LLC.
29353 * Originally Released Under LGPL - original licence link has changed is not relivant.
29356 * <script type="text/javascript">
29360 * @class Roo.BasicDialog
29361 * @extends Roo.util.Observable
29362 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29364 var dlg = new Roo.BasicDialog("my-dlg", {
29373 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
29374 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
29375 dlg.addButton('Cancel', dlg.hide, dlg);
29378 <b>A Dialog should always be a direct child of the body element.</b>
29379 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
29380 * @cfg {String} title Default text to display in the title bar (defaults to null)
29381 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29382 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29383 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
29384 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
29385 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
29386 * (defaults to null with no animation)
29387 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
29388 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
29389 * property for valid values (defaults to 'all')
29390 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
29391 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
29392 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
29393 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
29394 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
29395 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
29396 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
29397 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
29398 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
29399 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
29400 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
29401 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
29402 * draggable = true (defaults to false)
29403 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
29404 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
29405 * shadow (defaults to false)
29406 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
29407 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
29408 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
29409 * @cfg {Array} buttons Array of buttons
29410 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
29412 * Create a new BasicDialog.
29413 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
29414 * @param {Object} config Configuration options
29416 Roo.BasicDialog = function(el, config){
29417 this.el = Roo.get(el);
29418 var dh = Roo.DomHelper;
29419 if(!this.el && config && config.autoCreate){
29420 if(typeof config.autoCreate == "object"){
29421 if(!config.autoCreate.id){
29422 config.autoCreate.id = el;
29424 this.el = dh.append(document.body,
29425 config.autoCreate, true);
29427 this.el = dh.append(document.body,
29428 {tag: "div", id: el, style:'visibility:hidden;'}, true);
29432 el.setDisplayed(true);
29433 el.hide = this.hideAction;
29435 el.addClass("x-dlg");
29437 Roo.apply(this, config);
29439 this.proxy = el.createProxy("x-dlg-proxy");
29440 this.proxy.hide = this.hideAction;
29441 this.proxy.setOpacity(.5);
29445 el.setWidth(config.width);
29448 el.setHeight(config.height);
29450 this.size = el.getSize();
29451 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
29452 this.xy = [config.x,config.y];
29454 this.xy = el.getCenterXY(true);
29456 /** The header element @type Roo.Element */
29457 this.header = el.child("> .x-dlg-hd");
29458 /** The body element @type Roo.Element */
29459 this.body = el.child("> .x-dlg-bd");
29460 /** The footer element @type Roo.Element */
29461 this.footer = el.child("> .x-dlg-ft");
29464 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
29467 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
29470 this.header.unselectable();
29472 this.header.update(this.title);
29474 // this element allows the dialog to be focused for keyboard event
29475 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
29476 this.focusEl.swallowEvent("click", true);
29478 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
29480 // wrap the body and footer for special rendering
29481 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
29483 this.bwrap.dom.appendChild(this.footer.dom);
29486 this.bg = this.el.createChild({
29487 tag: "div", cls:"x-dlg-bg",
29488 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
29490 this.centerBg = this.bg.child("div.x-dlg-bg-center");
29493 if(this.autoScroll !== false && !this.autoTabs){
29494 this.body.setStyle("overflow", "auto");
29497 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
29499 if(this.closable !== false){
29500 this.el.addClass("x-dlg-closable");
29501 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
29502 this.close.on("click", this.closeClick, this);
29503 this.close.addClassOnOver("x-dlg-close-over");
29505 if(this.collapsible !== false){
29506 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
29507 this.collapseBtn.on("click", this.collapseClick, this);
29508 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
29509 this.header.on("dblclick", this.collapseClick, this);
29511 if(this.resizable !== false){
29512 this.el.addClass("x-dlg-resizable");
29513 this.resizer = new Roo.Resizable(el, {
29514 minWidth: this.minWidth || 80,
29515 minHeight:this.minHeight || 80,
29516 handles: this.resizeHandles || "all",
29519 this.resizer.on("beforeresize", this.beforeResize, this);
29520 this.resizer.on("resize", this.onResize, this);
29522 if(this.draggable !== false){
29523 el.addClass("x-dlg-draggable");
29524 if (!this.proxyDrag) {
29525 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
29528 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
29530 dd.setHandleElId(this.header.id);
29531 dd.endDrag = this.endMove.createDelegate(this);
29532 dd.startDrag = this.startMove.createDelegate(this);
29533 dd.onDrag = this.onDrag.createDelegate(this);
29538 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
29539 this.mask.enableDisplayMode("block");
29541 this.el.addClass("x-dlg-modal");
29544 this.shadow = new Roo.Shadow({
29545 mode : typeof this.shadow == "string" ? this.shadow : "sides",
29546 offset : this.shadowOffset
29549 this.shadowOffset = 0;
29551 if(Roo.useShims && this.shim !== false){
29552 this.shim = this.el.createShim();
29553 this.shim.hide = this.hideAction;
29561 if (this.buttons) {
29562 var bts= this.buttons;
29564 Roo.each(bts, function(b) {
29573 * Fires when a key is pressed
29574 * @param {Roo.BasicDialog} this
29575 * @param {Roo.EventObject} e
29580 * Fires when this dialog is moved by the user.
29581 * @param {Roo.BasicDialog} this
29582 * @param {Number} x The new page X
29583 * @param {Number} y The new page Y
29588 * Fires when this dialog is resized by the user.
29589 * @param {Roo.BasicDialog} this
29590 * @param {Number} width The new width
29591 * @param {Number} height The new height
29595 * @event beforehide
29596 * Fires before this dialog is hidden.
29597 * @param {Roo.BasicDialog} this
29599 "beforehide" : true,
29602 * Fires when this dialog is hidden.
29603 * @param {Roo.BasicDialog} this
29607 * @event beforeshow
29608 * Fires before this dialog is shown.
29609 * @param {Roo.BasicDialog} this
29611 "beforeshow" : true,
29614 * Fires when this dialog is shown.
29615 * @param {Roo.BasicDialog} this
29619 el.on("keydown", this.onKeyDown, this);
29620 el.on("mousedown", this.toFront, this);
29621 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
29623 Roo.DialogManager.register(this);
29624 Roo.BasicDialog.superclass.constructor.call(this);
29627 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
29628 shadowOffset: Roo.isIE ? 6 : 5,
29631 minButtonWidth: 75,
29632 defaultButton: null,
29633 buttonAlign: "right",
29638 * Sets the dialog title text
29639 * @param {String} text The title text to display
29640 * @return {Roo.BasicDialog} this
29642 setTitle : function(text){
29643 this.header.update(text);
29648 closeClick : function(){
29653 collapseClick : function(){
29654 this[this.collapsed ? "expand" : "collapse"]();
29658 * Collapses the dialog to its minimized state (only the title bar is visible).
29659 * Equivalent to the user clicking the collapse dialog button.
29661 collapse : function(){
29662 if(!this.collapsed){
29663 this.collapsed = true;
29664 this.el.addClass("x-dlg-collapsed");
29665 this.restoreHeight = this.el.getHeight();
29666 this.resizeTo(this.el.getWidth(), this.header.getHeight());
29671 * Expands a collapsed dialog back to its normal state. Equivalent to the user
29672 * clicking the expand dialog button.
29674 expand : function(){
29675 if(this.collapsed){
29676 this.collapsed = false;
29677 this.el.removeClass("x-dlg-collapsed");
29678 this.resizeTo(this.el.getWidth(), this.restoreHeight);
29683 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
29684 * @return {Roo.TabPanel} The tabs component
29686 initTabs : function(){
29687 var tabs = this.getTabs();
29688 while(tabs.getTab(0)){
29691 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
29693 tabs.addTab(Roo.id(dom), dom.title);
29701 beforeResize : function(){
29702 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
29706 onResize : function(){
29707 this.refreshSize();
29708 this.syncBodyHeight();
29709 this.adjustAssets();
29711 this.fireEvent("resize", this, this.size.width, this.size.height);
29715 onKeyDown : function(e){
29716 if(this.isVisible()){
29717 this.fireEvent("keydown", this, e);
29722 * Resizes the dialog.
29723 * @param {Number} width
29724 * @param {Number} height
29725 * @return {Roo.BasicDialog} this
29727 resizeTo : function(width, height){
29728 this.el.setSize(width, height);
29729 this.size = {width: width, height: height};
29730 this.syncBodyHeight();
29731 if(this.fixedcenter){
29734 if(this.isVisible()){
29735 this.constrainXY();
29736 this.adjustAssets();
29738 this.fireEvent("resize", this, width, height);
29744 * Resizes the dialog to fit the specified content size.
29745 * @param {Number} width
29746 * @param {Number} height
29747 * @return {Roo.BasicDialog} this
29749 setContentSize : function(w, h){
29750 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29751 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29752 //if(!this.el.isBorderBox()){
29753 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29754 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29757 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29758 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29760 this.resizeTo(w, h);
29765 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29766 * executed in response to a particular key being pressed while the dialog is active.
29767 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29768 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29769 * @param {Function} fn The function to call
29770 * @param {Object} scope (optional) The scope of the function
29771 * @return {Roo.BasicDialog} this
29773 addKeyListener : function(key, fn, scope){
29774 var keyCode, shift, ctrl, alt;
29775 if(typeof key == "object" && !(key instanceof Array)){
29776 keyCode = key["key"];
29777 shift = key["shift"];
29778 ctrl = key["ctrl"];
29783 var handler = function(dlg, e){
29784 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29785 var k = e.getKey();
29786 if(keyCode instanceof Array){
29787 for(var i = 0, len = keyCode.length; i < len; i++){
29788 if(keyCode[i] == k){
29789 fn.call(scope || window, dlg, k, e);
29795 fn.call(scope || window, dlg, k, e);
29800 this.on("keydown", handler);
29805 * Returns the TabPanel component (creates it if it doesn't exist).
29806 * Note: If you wish to simply check for the existence of tabs without creating them,
29807 * check for a null 'tabs' property.
29808 * @return {Roo.TabPanel} The tabs component
29810 getTabs : function(){
29812 this.el.addClass("x-dlg-auto-tabs");
29813 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29814 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29820 * Adds a button to the footer section of the dialog.
29821 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29822 * object or a valid Roo.DomHelper element config
29823 * @param {Function} handler The function called when the button is clicked
29824 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29825 * @return {Roo.Button} The new button
29827 addButton : function(config, handler, scope){
29828 var dh = Roo.DomHelper;
29830 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29832 if(!this.btnContainer){
29833 var tb = this.footer.createChild({
29835 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29836 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29838 this.btnContainer = tb.firstChild.firstChild.firstChild;
29843 minWidth: this.minButtonWidth,
29846 if(typeof config == "string"){
29847 bconfig.text = config;
29850 bconfig.dhconfig = config;
29852 Roo.apply(bconfig, config);
29856 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29857 bconfig.position = Math.max(0, bconfig.position);
29858 fc = this.btnContainer.childNodes[bconfig.position];
29861 var btn = new Roo.Button(
29863 this.btnContainer.insertBefore(document.createElement("td"),fc)
29864 : this.btnContainer.appendChild(document.createElement("td")),
29865 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29868 this.syncBodyHeight();
29871 * Array of all the buttons that have been added to this dialog via addButton
29876 this.buttons.push(btn);
29881 * Sets the default button to be focused when the dialog is displayed.
29882 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29883 * @return {Roo.BasicDialog} this
29885 setDefaultButton : function(btn){
29886 this.defaultButton = btn;
29891 getHeaderFooterHeight : function(safe){
29894 height += this.header.getHeight();
29897 var fm = this.footer.getMargins();
29898 height += (this.footer.getHeight()+fm.top+fm.bottom);
29900 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29901 height += this.centerBg.getPadding("tb");
29906 syncBodyHeight : function()
29908 var bd = this.body, // the text
29909 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
29911 var height = this.size.height - this.getHeaderFooterHeight(false);
29912 bd.setHeight(height-bd.getMargins("tb"));
29913 var hh = this.header.getHeight();
29914 var h = this.size.height-hh;
29917 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29918 bw.setHeight(h-cb.getPadding("tb"));
29920 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29921 bd.setWidth(bw.getWidth(true));
29923 this.tabs.syncHeight();
29925 this.tabs.el.repaint();
29931 * Restores the previous state of the dialog if Roo.state is configured.
29932 * @return {Roo.BasicDialog} this
29934 restoreState : function(){
29935 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29936 if(box && box.width){
29937 this.xy = [box.x, box.y];
29938 this.resizeTo(box.width, box.height);
29944 beforeShow : function(){
29946 if(this.fixedcenter){
29947 this.xy = this.el.getCenterXY(true);
29950 Roo.get(document.body).addClass("x-body-masked");
29951 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29954 this.constrainXY();
29958 animShow : function(){
29959 var b = Roo.get(this.animateTarget).getBox();
29960 this.proxy.setSize(b.width, b.height);
29961 this.proxy.setLocation(b.x, b.y);
29963 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29964 true, .35, this.showEl.createDelegate(this));
29968 * Shows the dialog.
29969 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29970 * @return {Roo.BasicDialog} this
29972 show : function(animateTarget){
29973 if (this.fireEvent("beforeshow", this) === false){
29976 if(this.syncHeightBeforeShow){
29977 this.syncBodyHeight();
29978 }else if(this.firstShow){
29979 this.firstShow = false;
29980 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29982 this.animateTarget = animateTarget || this.animateTarget;
29983 if(!this.el.isVisible()){
29985 if(this.animateTarget && Roo.get(this.animateTarget)){
29995 showEl : function(){
29997 this.el.setXY(this.xy);
29999 this.adjustAssets(true);
30002 // IE peekaboo bug - fix found by Dave Fenwick
30006 this.fireEvent("show", this);
30010 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30011 * dialog itself will receive focus.
30013 focus : function(){
30014 if(this.defaultButton){
30015 this.defaultButton.focus();
30017 this.focusEl.focus();
30022 constrainXY : function(){
30023 if(this.constraintoviewport !== false){
30024 if(!this.viewSize){
30025 if(this.container){
30026 var s = this.container.getSize();
30027 this.viewSize = [s.width, s.height];
30029 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30032 var s = Roo.get(this.container||document).getScroll();
30034 var x = this.xy[0], y = this.xy[1];
30035 var w = this.size.width, h = this.size.height;
30036 var vw = this.viewSize[0], vh = this.viewSize[1];
30037 // only move it if it needs it
30039 // first validate right/bottom
30040 if(x + w > vw+s.left){
30044 if(y + h > vh+s.top){
30048 // then make sure top/left isn't negative
30060 if(this.isVisible()){
30061 this.el.setLocation(x, y);
30062 this.adjustAssets();
30069 onDrag : function(){
30070 if(!this.proxyDrag){
30071 this.xy = this.el.getXY();
30072 this.adjustAssets();
30077 adjustAssets : function(doShow){
30078 var x = this.xy[0], y = this.xy[1];
30079 var w = this.size.width, h = this.size.height;
30080 if(doShow === true){
30082 this.shadow.show(this.el);
30088 if(this.shadow && this.shadow.isVisible()){
30089 this.shadow.show(this.el);
30091 if(this.shim && this.shim.isVisible()){
30092 this.shim.setBounds(x, y, w, h);
30097 adjustViewport : function(w, h){
30099 w = Roo.lib.Dom.getViewWidth();
30100 h = Roo.lib.Dom.getViewHeight();
30103 this.viewSize = [w, h];
30104 if(this.modal && this.mask.isVisible()){
30105 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30106 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30108 if(this.isVisible()){
30109 this.constrainXY();
30114 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30115 * shadow, proxy, mask, etc.) Also removes all event listeners.
30116 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30118 destroy : function(removeEl){
30119 if(this.isVisible()){
30120 this.animateTarget = null;
30123 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30125 this.tabs.destroy(removeEl);
30138 for(var i = 0, len = this.buttons.length; i < len; i++){
30139 this.buttons[i].destroy();
30142 this.el.removeAllListeners();
30143 if(removeEl === true){
30144 this.el.update("");
30147 Roo.DialogManager.unregister(this);
30151 startMove : function(){
30152 if(this.proxyDrag){
30155 if(this.constraintoviewport !== false){
30156 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30161 endMove : function(){
30162 if(!this.proxyDrag){
30163 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30165 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30168 this.refreshSize();
30169 this.adjustAssets();
30171 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30175 * Brings this dialog to the front of any other visible dialogs
30176 * @return {Roo.BasicDialog} this
30178 toFront : function(){
30179 Roo.DialogManager.bringToFront(this);
30184 * Sends this dialog to the back (under) of any other visible dialogs
30185 * @return {Roo.BasicDialog} this
30187 toBack : function(){
30188 Roo.DialogManager.sendToBack(this);
30193 * Centers this dialog in the viewport
30194 * @return {Roo.BasicDialog} this
30196 center : function(){
30197 var xy = this.el.getCenterXY(true);
30198 this.moveTo(xy[0], xy[1]);
30203 * Moves the dialog's top-left corner to the specified point
30204 * @param {Number} x
30205 * @param {Number} y
30206 * @return {Roo.BasicDialog} this
30208 moveTo : function(x, y){
30210 if(this.isVisible()){
30211 this.el.setXY(this.xy);
30212 this.adjustAssets();
30218 * Aligns the dialog to the specified element
30219 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30220 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30221 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30222 * @return {Roo.BasicDialog} this
30224 alignTo : function(element, position, offsets){
30225 this.xy = this.el.getAlignToXY(element, position, offsets);
30226 if(this.isVisible()){
30227 this.el.setXY(this.xy);
30228 this.adjustAssets();
30234 * Anchors an element to another element and realigns it when the window is resized.
30235 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30236 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30237 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30238 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30239 * is a number, it is used as the buffer delay (defaults to 50ms).
30240 * @return {Roo.BasicDialog} this
30242 anchorTo : function(el, alignment, offsets, monitorScroll){
30243 var action = function(){
30244 this.alignTo(el, alignment, offsets);
30246 Roo.EventManager.onWindowResize(action, this);
30247 var tm = typeof monitorScroll;
30248 if(tm != 'undefined'){
30249 Roo.EventManager.on(window, 'scroll', action, this,
30250 {buffer: tm == 'number' ? monitorScroll : 50});
30257 * Returns true if the dialog is visible
30258 * @return {Boolean}
30260 isVisible : function(){
30261 return this.el.isVisible();
30265 animHide : function(callback){
30266 var b = Roo.get(this.animateTarget).getBox();
30268 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30270 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30271 this.hideEl.createDelegate(this, [callback]));
30275 * Hides the dialog.
30276 * @param {Function} callback (optional) Function to call when the dialog is hidden
30277 * @return {Roo.BasicDialog} this
30279 hide : function(callback){
30280 if (this.fireEvent("beforehide", this) === false){
30284 this.shadow.hide();
30289 // sometimes animateTarget seems to get set.. causing problems...
30290 // this just double checks..
30291 if(this.animateTarget && Roo.get(this.animateTarget)) {
30292 this.animHide(callback);
30295 this.hideEl(callback);
30301 hideEl : function(callback){
30305 Roo.get(document.body).removeClass("x-body-masked");
30307 this.fireEvent("hide", this);
30308 if(typeof callback == "function"){
30314 hideAction : function(){
30315 this.setLeft("-10000px");
30316 this.setTop("-10000px");
30317 this.setStyle("visibility", "hidden");
30321 refreshSize : function(){
30322 this.size = this.el.getSize();
30323 this.xy = this.el.getXY();
30324 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30328 // z-index is managed by the DialogManager and may be overwritten at any time
30329 setZIndex : function(index){
30331 this.mask.setStyle("z-index", index);
30334 this.shim.setStyle("z-index", ++index);
30337 this.shadow.setZIndex(++index);
30339 this.el.setStyle("z-index", ++index);
30341 this.proxy.setStyle("z-index", ++index);
30344 this.resizer.proxy.setStyle("z-index", ++index);
30347 this.lastZIndex = index;
30351 * Returns the element for this dialog
30352 * @return {Roo.Element} The underlying dialog Element
30354 getEl : function(){
30360 * @class Roo.DialogManager
30361 * Provides global access to BasicDialogs that have been created and
30362 * support for z-indexing (layering) multiple open dialogs.
30364 Roo.DialogManager = function(){
30366 var accessList = [];
30370 var sortDialogs = function(d1, d2){
30371 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
30375 var orderDialogs = function(){
30376 accessList.sort(sortDialogs);
30377 var seed = Roo.DialogManager.zseed;
30378 for(var i = 0, len = accessList.length; i < len; i++){
30379 var dlg = accessList[i];
30381 dlg.setZIndex(seed + (i*10));
30388 * The starting z-index for BasicDialogs (defaults to 9000)
30389 * @type Number The z-index value
30394 register : function(dlg){
30395 list[dlg.id] = dlg;
30396 accessList.push(dlg);
30400 unregister : function(dlg){
30401 delete list[dlg.id];
30404 if(!accessList.indexOf){
30405 for( i = 0, len = accessList.length; i < len; i++){
30406 if(accessList[i] == dlg){
30407 accessList.splice(i, 1);
30412 i = accessList.indexOf(dlg);
30414 accessList.splice(i, 1);
30420 * Gets a registered dialog by id
30421 * @param {String/Object} id The id of the dialog or a dialog
30422 * @return {Roo.BasicDialog} this
30424 get : function(id){
30425 return typeof id == "object" ? id : list[id];
30429 * Brings the specified dialog to the front
30430 * @param {String/Object} dlg The id of the dialog or a dialog
30431 * @return {Roo.BasicDialog} this
30433 bringToFront : function(dlg){
30434 dlg = this.get(dlg);
30437 dlg._lastAccess = new Date().getTime();
30444 * Sends the specified dialog to the back
30445 * @param {String/Object} dlg The id of the dialog or a dialog
30446 * @return {Roo.BasicDialog} this
30448 sendToBack : function(dlg){
30449 dlg = this.get(dlg);
30450 dlg._lastAccess = -(new Date().getTime());
30456 * Hides all dialogs
30458 hideAll : function(){
30459 for(var id in list){
30460 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
30469 * @class Roo.LayoutDialog
30470 * @extends Roo.BasicDialog
30471 * Dialog which provides adjustments for working with a layout in a Dialog.
30472 * Add your necessary layout config options to the dialog's config.<br>
30473 * Example usage (including a nested layout):
30476 dialog = new Roo.LayoutDialog("download-dlg", {
30485 // layout config merges with the dialog config
30487 tabPosition: "top",
30488 alwaysShowTabs: true
30491 dialog.addKeyListener(27, dialog.hide, dialog);
30492 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
30493 dialog.addButton("Build It!", this.getDownload, this);
30495 // we can even add nested layouts
30496 var innerLayout = new Roo.BorderLayout("dl-inner", {
30506 innerLayout.beginUpdate();
30507 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
30508 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
30509 innerLayout.endUpdate(true);
30511 var layout = dialog.getLayout();
30512 layout.beginUpdate();
30513 layout.add("center", new Roo.ContentPanel("standard-panel",
30514 {title: "Download the Source", fitToFrame:true}));
30515 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
30516 {title: "Build your own roo.js"}));
30517 layout.getRegion("center").showPanel(sp);
30518 layout.endUpdate();
30522 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
30523 * @param {Object} config configuration options
30525 Roo.LayoutDialog = function(el, cfg){
30528 if (typeof(cfg) == 'undefined') {
30529 config = Roo.apply({}, el);
30530 // not sure why we use documentElement here.. - it should always be body.
30531 // IE7 borks horribly if we use documentElement.
30532 // webkit also does not like documentElement - it creates a body element...
30533 el = Roo.get( document.body || document.documentElement ).createChild();
30534 //config.autoCreate = true;
30538 config.autoTabs = false;
30539 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
30540 this.body.setStyle({overflow:"hidden", position:"relative"});
30541 this.layout = new Roo.BorderLayout(this.body.dom, config);
30542 this.layout.monitorWindowResize = false;
30543 this.el.addClass("x-dlg-auto-layout");
30544 // fix case when center region overwrites center function
30545 this.center = Roo.BasicDialog.prototype.center;
30546 this.on("show", this.layout.layout, this.layout, true);
30547 if (config.items) {
30548 var xitems = config.items;
30549 delete config.items;
30550 Roo.each(xitems, this.addxtype, this);
30555 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
30557 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
30560 endUpdate : function(){
30561 this.layout.endUpdate();
30565 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
30568 beginUpdate : function(){
30569 this.layout.beginUpdate();
30573 * Get the BorderLayout for this dialog
30574 * @return {Roo.BorderLayout}
30576 getLayout : function(){
30577 return this.layout;
30580 showEl : function(){
30581 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
30583 this.layout.layout();
30588 // Use the syncHeightBeforeShow config option to control this automatically
30589 syncBodyHeight : function(){
30590 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
30591 if(this.layout){this.layout.layout();}
30595 * Add an xtype element (actually adds to the layout.)
30596 * @return {Object} xdata xtype object data.
30599 addxtype : function(c) {
30600 return this.layout.addxtype(c);
30604 * Ext JS Library 1.1.1
30605 * Copyright(c) 2006-2007, Ext JS, LLC.
30607 * Originally Released Under LGPL - original licence link has changed is not relivant.
30610 * <script type="text/javascript">
30614 * @class Roo.MessageBox
30615 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
30619 Roo.Msg.alert('Status', 'Changes saved successfully.');
30621 // Prompt for user data:
30622 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
30624 // process text value...
30628 // Show a dialog using config options:
30630 title:'Save Changes?',
30631 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
30632 buttons: Roo.Msg.YESNOCANCEL,
30639 Roo.MessageBox = function(){
30640 var dlg, opt, mask, waitTimer;
30641 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
30642 var buttons, activeTextEl, bwidth;
30645 var handleButton = function(button){
30647 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
30651 var handleHide = function(){
30652 if(opt && opt.cls){
30653 dlg.el.removeClass(opt.cls);
30656 Roo.TaskMgr.stop(waitTimer);
30662 var updateButtons = function(b){
30665 buttons["ok"].hide();
30666 buttons["cancel"].hide();
30667 buttons["yes"].hide();
30668 buttons["no"].hide();
30669 dlg.footer.dom.style.display = 'none';
30672 dlg.footer.dom.style.display = '';
30673 for(var k in buttons){
30674 if(typeof buttons[k] != "function"){
30677 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
30678 width += buttons[k].el.getWidth()+15;
30688 var handleEsc = function(d, k, e){
30689 if(opt && opt.closable !== false){
30699 * Returns a reference to the underlying {@link Roo.BasicDialog} element
30700 * @return {Roo.BasicDialog} The BasicDialog element
30702 getDialog : function(){
30704 dlg = new Roo.BasicDialog("x-msg-box", {
30709 constraintoviewport:false,
30711 collapsible : false,
30714 width:400, height:100,
30715 buttonAlign:"center",
30716 closeClick : function(){
30717 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
30718 handleButton("no");
30720 handleButton("cancel");
30724 dlg.on("hide", handleHide);
30726 dlg.addKeyListener(27, handleEsc);
30728 var bt = this.buttonText;
30729 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
30730 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
30731 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
30732 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
30733 bodyEl = dlg.body.createChild({
30735 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>'
30737 msgEl = bodyEl.dom.firstChild;
30738 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
30739 textboxEl.enableDisplayMode();
30740 textboxEl.addKeyListener([10,13], function(){
30741 if(dlg.isVisible() && opt && opt.buttons){
30742 if(opt.buttons.ok){
30743 handleButton("ok");
30744 }else if(opt.buttons.yes){
30745 handleButton("yes");
30749 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30750 textareaEl.enableDisplayMode();
30751 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30752 progressEl.enableDisplayMode();
30753 var pf = progressEl.dom.firstChild;
30755 pp = Roo.get(pf.firstChild);
30756 pp.setHeight(pf.offsetHeight);
30764 * Updates the message box body text
30765 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30766 * the XHTML-compliant non-breaking space character '&#160;')
30767 * @return {Roo.MessageBox} This message box
30769 updateText : function(text){
30770 if(!dlg.isVisible() && !opt.width){
30771 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30773 msgEl.innerHTML = text || ' ';
30775 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
30776 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
30778 Math.min(opt.width || cw , this.maxWidth),
30779 Math.max(opt.minWidth || this.minWidth, bwidth)
30782 activeTextEl.setWidth(w);
30784 if(dlg.isVisible()){
30785 dlg.fixedcenter = false;
30787 // to big, make it scroll. = But as usual stupid IE does not support
30790 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
30791 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
30792 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
30794 bodyEl.dom.style.height = '';
30795 bodyEl.dom.style.overflowY = '';
30798 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
30800 bodyEl.dom.style.overflowX = '';
30803 dlg.setContentSize(w, bodyEl.getHeight());
30804 if(dlg.isVisible()){
30805 dlg.fixedcenter = true;
30811 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30812 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30813 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30814 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30815 * @return {Roo.MessageBox} This message box
30817 updateProgress : function(value, text){
30819 this.updateText(text);
30821 if (pp) { // weird bug on my firefox - for some reason this is not defined
30822 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30828 * Returns true if the message box is currently displayed
30829 * @return {Boolean} True if the message box is visible, else false
30831 isVisible : function(){
30832 return dlg && dlg.isVisible();
30836 * Hides the message box if it is displayed
30839 if(this.isVisible()){
30845 * Displays a new message box, or reinitializes an existing message box, based on the config options
30846 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30847 * The following config object properties are supported:
30849 Property Type Description
30850 ---------- --------------- ------------------------------------------------------------------------------------
30851 animEl String/Element An id or Element from which the message box should animate as it opens and
30852 closes (defaults to undefined)
30853 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30854 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30855 closable Boolean False to hide the top-right close button (defaults to true). Note that
30856 progress and wait dialogs will ignore this property and always hide the
30857 close button as they can only be closed programmatically.
30858 cls String A custom CSS class to apply to the message box element
30859 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30860 displayed (defaults to 75)
30861 fn Function A callback function to execute after closing the dialog. The arguments to the
30862 function will be btn (the name of the button that was clicked, if applicable,
30863 e.g. "ok"), and text (the value of the active text field, if applicable).
30864 Progress and wait dialogs will ignore this option since they do not respond to
30865 user actions and can only be closed programmatically, so any required function
30866 should be called by the same code after it closes the dialog.
30867 icon String A CSS class that provides a background image to be used as an icon for
30868 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30869 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30870 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30871 modal Boolean False to allow user interaction with the page while the message box is
30872 displayed (defaults to true)
30873 msg String A string that will replace the existing message box body text (defaults
30874 to the XHTML-compliant non-breaking space character ' ')
30875 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30876 progress Boolean True to display a progress bar (defaults to false)
30877 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30878 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30879 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30880 title String The title text
30881 value String The string value to set into the active textbox element if displayed
30882 wait Boolean True to display a progress bar (defaults to false)
30883 width Number The width of the dialog in pixels
30890 msg: 'Please enter your address:',
30892 buttons: Roo.MessageBox.OKCANCEL,
30895 animEl: 'addAddressBtn'
30898 * @param {Object} config Configuration options
30899 * @return {Roo.MessageBox} This message box
30901 show : function(options)
30904 // this causes nightmares if you show one dialog after another
30905 // especially on callbacks..
30907 if(this.isVisible()){
30910 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
30911 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
30912 Roo.log("New Dialog Message:" + options.msg )
30913 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
30914 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
30917 var d = this.getDialog();
30919 d.setTitle(opt.title || " ");
30920 d.close.setDisplayed(opt.closable !== false);
30921 activeTextEl = textboxEl;
30922 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30927 textareaEl.setHeight(typeof opt.multiline == "number" ?
30928 opt.multiline : this.defaultTextHeight);
30929 activeTextEl = textareaEl;
30938 progressEl.setDisplayed(opt.progress === true);
30939 this.updateProgress(0);
30940 activeTextEl.dom.value = opt.value || "";
30942 dlg.setDefaultButton(activeTextEl);
30944 var bs = opt.buttons;
30947 db = buttons["ok"];
30948 }else if(bs && bs.yes){
30949 db = buttons["yes"];
30951 dlg.setDefaultButton(db);
30953 bwidth = updateButtons(opt.buttons);
30954 this.updateText(opt.msg);
30956 d.el.addClass(opt.cls);
30958 d.proxyDrag = opt.proxyDrag === true;
30959 d.modal = opt.modal !== false;
30960 d.mask = opt.modal !== false ? mask : false;
30961 if(!d.isVisible()){
30962 // force it to the end of the z-index stack so it gets a cursor in FF
30963 document.body.appendChild(dlg.el.dom);
30964 d.animateTarget = null;
30965 d.show(options.animEl);
30971 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30972 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30973 * and closing the message box when the process is complete.
30974 * @param {String} title The title bar text
30975 * @param {String} msg The message box body text
30976 * @return {Roo.MessageBox} This message box
30978 progress : function(title, msg){
30985 minWidth: this.minProgressWidth,
30992 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30993 * If a callback function is passed it will be called after the user clicks the button, and the
30994 * id of the button that was clicked will be passed as the only parameter to the callback
30995 * (could also be the top-right close button).
30996 * @param {String} title The title bar text
30997 * @param {String} msg The message box body text
30998 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30999 * @param {Object} scope (optional) The scope of the callback function
31000 * @return {Roo.MessageBox} This message box
31002 alert : function(title, msg, fn, scope){
31015 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31016 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31017 * You are responsible for closing the message box when the process is complete.
31018 * @param {String} msg The message box body text
31019 * @param {String} title (optional) The title bar text
31020 * @return {Roo.MessageBox} This message box
31022 wait : function(msg, title){
31033 waitTimer = Roo.TaskMgr.start({
31035 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31043 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31044 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31045 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31046 * @param {String} title The title bar text
31047 * @param {String} msg The message box body text
31048 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31049 * @param {Object} scope (optional) The scope of the callback function
31050 * @return {Roo.MessageBox} This message box
31052 confirm : function(title, msg, fn, scope){
31056 buttons: this.YESNO,
31065 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31066 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31067 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31068 * (could also be the top-right close button) and the text that was entered will be passed as the two
31069 * parameters to the callback.
31070 * @param {String} title The title bar text
31071 * @param {String} msg The message box body text
31072 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31073 * @param {Object} scope (optional) The scope of the callback function
31074 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31075 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31076 * @return {Roo.MessageBox} This message box
31078 prompt : function(title, msg, fn, scope, multiline){
31082 buttons: this.OKCANCEL,
31087 multiline: multiline,
31094 * Button config that displays a single OK button
31099 * Button config that displays Yes and No buttons
31102 YESNO : {yes:true, no:true},
31104 * Button config that displays OK and Cancel buttons
31107 OKCANCEL : {ok:true, cancel:true},
31109 * Button config that displays Yes, No and Cancel buttons
31112 YESNOCANCEL : {yes:true, no:true, cancel:true},
31115 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31118 defaultTextHeight : 75,
31120 * The maximum width in pixels of the message box (defaults to 600)
31125 * The minimum width in pixels of the message box (defaults to 100)
31130 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31131 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31134 minProgressWidth : 250,
31136 * An object containing the default button text strings that can be overriden for localized language support.
31137 * Supported properties are: ok, cancel, yes and no.
31138 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31151 * Shorthand for {@link Roo.MessageBox}
31153 Roo.Msg = Roo.MessageBox;/*
31155 * Ext JS Library 1.1.1
31156 * Copyright(c) 2006-2007, Ext JS, LLC.
31158 * Originally Released Under LGPL - original licence link has changed is not relivant.
31161 * <script type="text/javascript">
31164 * @class Roo.QuickTips
31165 * Provides attractive and customizable tooltips for any element.
31168 Roo.QuickTips = function(){
31169 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31170 var ce, bd, xy, dd;
31171 var visible = false, disabled = true, inited = false;
31172 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31174 var onOver = function(e){
31178 var t = e.getTarget();
31179 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31182 if(ce && t == ce.el){
31183 clearTimeout(hideProc);
31186 if(t && tagEls[t.id]){
31187 tagEls[t.id].el = t;
31188 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31191 var ttp, et = Roo.fly(t);
31192 var ns = cfg.namespace;
31193 if(tm.interceptTitles && t.title){
31196 t.removeAttribute("title");
31197 e.preventDefault();
31199 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31202 showProc = show.defer(tm.showDelay, tm, [{
31205 width: et.getAttributeNS(ns, cfg.width),
31206 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31207 title: et.getAttributeNS(ns, cfg.title),
31208 cls: et.getAttributeNS(ns, cfg.cls)
31213 var onOut = function(e){
31214 clearTimeout(showProc);
31215 var t = e.getTarget();
31216 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31217 hideProc = setTimeout(hide, tm.hideDelay);
31221 var onMove = function(e){
31227 if(tm.trackMouse && ce){
31232 var onDown = function(e){
31233 clearTimeout(showProc);
31234 clearTimeout(hideProc);
31236 if(tm.hideOnClick){
31239 tm.enable.defer(100, tm);
31244 var getPad = function(){
31245 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31248 var show = function(o){
31252 clearTimeout(dismissProc);
31254 if(removeCls){ // in case manually hidden
31255 el.removeClass(removeCls);
31259 el.addClass(ce.cls);
31260 removeCls = ce.cls;
31263 tipTitle.update(ce.title);
31266 tipTitle.update('');
31269 el.dom.style.width = tm.maxWidth+'px';
31270 //tipBody.dom.style.width = '';
31271 tipBodyText.update(o.text);
31272 var p = getPad(), w = ce.width;
31274 var td = tipBodyText.dom;
31275 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31276 if(aw > tm.maxWidth){
31278 }else if(aw < tm.minWidth){
31284 //tipBody.setWidth(w);
31285 el.setWidth(parseInt(w, 10) + p);
31286 if(ce.autoHide === false){
31287 close.setDisplayed(true);
31292 close.setDisplayed(false);
31298 el.avoidY = xy[1]-18;
31303 el.setStyle("visibility", "visible");
31304 el.fadeIn({callback: afterShow});
31310 var afterShow = function(){
31314 if(tm.autoDismiss && ce.autoHide !== false){
31315 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31320 var hide = function(noanim){
31321 clearTimeout(dismissProc);
31322 clearTimeout(hideProc);
31324 if(el.isVisible()){
31326 if(noanim !== true && tm.animate){
31327 el.fadeOut({callback: afterHide});
31334 var afterHide = function(){
31337 el.removeClass(removeCls);
31344 * @cfg {Number} minWidth
31345 * The minimum width of the quick tip (defaults to 40)
31349 * @cfg {Number} maxWidth
31350 * The maximum width of the quick tip (defaults to 300)
31354 * @cfg {Boolean} interceptTitles
31355 * True to automatically use the element's DOM title value if available (defaults to false)
31357 interceptTitles : false,
31359 * @cfg {Boolean} trackMouse
31360 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31362 trackMouse : false,
31364 * @cfg {Boolean} hideOnClick
31365 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
31367 hideOnClick : true,
31369 * @cfg {Number} showDelay
31370 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
31374 * @cfg {Number} hideDelay
31375 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
31379 * @cfg {Boolean} autoHide
31380 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
31381 * Used in conjunction with hideDelay.
31386 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
31387 * (defaults to true). Used in conjunction with autoDismissDelay.
31389 autoDismiss : true,
31392 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
31394 autoDismissDelay : 5000,
31396 * @cfg {Boolean} animate
31397 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
31402 * @cfg {String} title
31403 * Title text to display (defaults to ''). This can be any valid HTML markup.
31407 * @cfg {String} text
31408 * Body text to display (defaults to ''). This can be any valid HTML markup.
31412 * @cfg {String} cls
31413 * A CSS class to apply to the base quick tip element (defaults to '').
31417 * @cfg {Number} width
31418 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
31419 * minWidth or maxWidth.
31424 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
31425 * or display QuickTips in a page.
31428 tm = Roo.QuickTips;
31429 cfg = tm.tagConfig;
31431 if(!Roo.isReady){ // allow calling of init() before onReady
31432 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
31435 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
31436 el.fxDefaults = {stopFx: true};
31437 // maximum custom styling
31438 //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>');
31439 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>');
31440 tipTitle = el.child('h3');
31441 tipTitle.enableDisplayMode("block");
31442 tipBody = el.child('div.x-tip-bd');
31443 tipBodyText = el.child('div.x-tip-bd-inner');
31444 //bdLeft = el.child('div.x-tip-bd-left');
31445 //bdRight = el.child('div.x-tip-bd-right');
31446 close = el.child('div.x-tip-close');
31447 close.enableDisplayMode("block");
31448 close.on("click", hide);
31449 var d = Roo.get(document);
31450 d.on("mousedown", onDown);
31451 d.on("mouseover", onOver);
31452 d.on("mouseout", onOut);
31453 d.on("mousemove", onMove);
31454 esc = d.addKeyListener(27, hide);
31457 dd = el.initDD("default", null, {
31458 onDrag : function(){
31462 dd.setHandleElId(tipTitle.id);
31471 * Configures a new quick tip instance and assigns it to a target element. The following config options
31474 Property Type Description
31475 ---------- --------------------- ------------------------------------------------------------------------
31476 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
31478 * @param {Object} config The config object
31480 register : function(config){
31481 var cs = config instanceof Array ? config : arguments;
31482 for(var i = 0, len = cs.length; i < len; i++) {
31484 var target = c.target;
31486 if(target instanceof Array){
31487 for(var j = 0, jlen = target.length; j < jlen; j++){
31488 tagEls[target[j]] = c;
31491 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
31498 * Removes this quick tip from its element and destroys it.
31499 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
31501 unregister : function(el){
31502 delete tagEls[Roo.id(el)];
31506 * Enable this quick tip.
31508 enable : function(){
31509 if(inited && disabled){
31511 if(locks.length < 1){
31518 * Disable this quick tip.
31520 disable : function(){
31522 clearTimeout(showProc);
31523 clearTimeout(hideProc);
31524 clearTimeout(dismissProc);
31532 * Returns true if the quick tip is enabled, else false.
31534 isEnabled : function(){
31541 attribute : "qtip",
31551 // backwards compat
31552 Roo.QuickTips.tips = Roo.QuickTips.register;/*
31554 * Ext JS Library 1.1.1
31555 * Copyright(c) 2006-2007, Ext JS, LLC.
31557 * Originally Released Under LGPL - original licence link has changed is not relivant.
31560 * <script type="text/javascript">
31565 * @class Roo.tree.TreePanel
31566 * @extends Roo.data.Tree
31568 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
31569 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
31570 * @cfg {Boolean} enableDD true to enable drag and drop
31571 * @cfg {Boolean} enableDrag true to enable just drag
31572 * @cfg {Boolean} enableDrop true to enable just drop
31573 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
31574 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
31575 * @cfg {String} ddGroup The DD group this TreePanel belongs to
31576 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
31577 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
31578 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
31579 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
31580 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
31581 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
31582 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
31583 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
31584 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
31585 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
31586 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
31587 * @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>
31588 * @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>
31591 * @param {String/HTMLElement/Element} el The container element
31592 * @param {Object} config
31594 Roo.tree.TreePanel = function(el, config){
31596 var loader = false;
31598 root = config.root;
31599 delete config.root;
31601 if (config.loader) {
31602 loader = config.loader;
31603 delete config.loader;
31606 Roo.apply(this, config);
31607 Roo.tree.TreePanel.superclass.constructor.call(this);
31608 this.el = Roo.get(el);
31609 this.el.addClass('x-tree');
31610 //console.log(root);
31612 this.setRootNode( Roo.factory(root, Roo.tree));
31615 this.loader = Roo.factory(loader, Roo.tree);
31618 * Read-only. The id of the container element becomes this TreePanel's id.
31620 this.id = this.el.id;
31623 * @event beforeload
31624 * Fires before a node is loaded, return false to cancel
31625 * @param {Node} node The node being loaded
31627 "beforeload" : true,
31630 * Fires when a node is loaded
31631 * @param {Node} node The node that was loaded
31635 * @event textchange
31636 * Fires when the text for a node is changed
31637 * @param {Node} node The node
31638 * @param {String} text The new text
31639 * @param {String} oldText The old text
31641 "textchange" : true,
31643 * @event beforeexpand
31644 * Fires before a node is expanded, return false to cancel.
31645 * @param {Node} node The node
31646 * @param {Boolean} deep
31647 * @param {Boolean} anim
31649 "beforeexpand" : true,
31651 * @event beforecollapse
31652 * Fires before a node is collapsed, return false to cancel.
31653 * @param {Node} node The node
31654 * @param {Boolean} deep
31655 * @param {Boolean} anim
31657 "beforecollapse" : true,
31660 * Fires when a node is expanded
31661 * @param {Node} node The node
31665 * @event disabledchange
31666 * Fires when the disabled status of a node changes
31667 * @param {Node} node The node
31668 * @param {Boolean} disabled
31670 "disabledchange" : true,
31673 * Fires when a node is collapsed
31674 * @param {Node} node The node
31678 * @event beforeclick
31679 * Fires before click processing on a node. Return false to cancel the default action.
31680 * @param {Node} node The node
31681 * @param {Roo.EventObject} e The event object
31683 "beforeclick":true,
31685 * @event checkchange
31686 * Fires when a node with a checkbox's checked property changes
31687 * @param {Node} this This node
31688 * @param {Boolean} checked
31690 "checkchange":true,
31693 * Fires when a node is clicked
31694 * @param {Node} node The node
31695 * @param {Roo.EventObject} e The event object
31700 * Fires when a node is double clicked
31701 * @param {Node} node The node
31702 * @param {Roo.EventObject} e The event object
31706 * @event contextmenu
31707 * Fires when a node is right clicked
31708 * @param {Node} node The node
31709 * @param {Roo.EventObject} e The event object
31711 "contextmenu":true,
31713 * @event beforechildrenrendered
31714 * Fires right before the child nodes for a node are rendered
31715 * @param {Node} node The node
31717 "beforechildrenrendered":true,
31720 * Fires when a node starts being dragged
31721 * @param {Roo.tree.TreePanel} this
31722 * @param {Roo.tree.TreeNode} node
31723 * @param {event} e The raw browser event
31725 "startdrag" : true,
31728 * Fires when a drag operation is complete
31729 * @param {Roo.tree.TreePanel} this
31730 * @param {Roo.tree.TreeNode} node
31731 * @param {event} e The raw browser event
31736 * Fires when a dragged node is dropped on a valid DD target
31737 * @param {Roo.tree.TreePanel} this
31738 * @param {Roo.tree.TreeNode} node
31739 * @param {DD} dd The dd it was dropped on
31740 * @param {event} e The raw browser event
31744 * @event beforenodedrop
31745 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
31746 * passed to handlers has the following properties:<br />
31747 * <ul style="padding:5px;padding-left:16px;">
31748 * <li>tree - The TreePanel</li>
31749 * <li>target - The node being targeted for the drop</li>
31750 * <li>data - The drag data from the drag source</li>
31751 * <li>point - The point of the drop - append, above or below</li>
31752 * <li>source - The drag source</li>
31753 * <li>rawEvent - Raw mouse event</li>
31754 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
31755 * to be inserted by setting them on this object.</li>
31756 * <li>cancel - Set this to true to cancel the drop.</li>
31758 * @param {Object} dropEvent
31760 "beforenodedrop" : true,
31763 * Fires after a DD object is dropped on a node in this tree. The dropEvent
31764 * passed to handlers has the following properties:<br />
31765 * <ul style="padding:5px;padding-left:16px;">
31766 * <li>tree - The TreePanel</li>
31767 * <li>target - The node being targeted for the drop</li>
31768 * <li>data - The drag data from the drag source</li>
31769 * <li>point - The point of the drop - append, above or below</li>
31770 * <li>source - The drag source</li>
31771 * <li>rawEvent - Raw mouse event</li>
31772 * <li>dropNode - Dropped node(s).</li>
31774 * @param {Object} dropEvent
31778 * @event nodedragover
31779 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31780 * passed to handlers has the following properties:<br />
31781 * <ul style="padding:5px;padding-left:16px;">
31782 * <li>tree - The TreePanel</li>
31783 * <li>target - The node being targeted for the drop</li>
31784 * <li>data - The drag data from the drag source</li>
31785 * <li>point - The point of the drop - append, above or below</li>
31786 * <li>source - The drag source</li>
31787 * <li>rawEvent - Raw mouse event</li>
31788 * <li>dropNode - Drop node(s) provided by the source.</li>
31789 * <li>cancel - Set this to true to signal drop not allowed.</li>
31791 * @param {Object} dragOverEvent
31793 "nodedragover" : true
31796 if(this.singleExpand){
31797 this.on("beforeexpand", this.restrictExpand, this);
31800 this.editor.tree = this;
31801 this.editor = Roo.factory(this.editor, Roo.tree);
31804 if (this.selModel) {
31805 this.selModel = Roo.factory(this.selModel, Roo.tree);
31809 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31810 rootVisible : true,
31811 animate: Roo.enableFx,
31814 hlDrop : Roo.enableFx,
31818 rendererTip: false,
31820 restrictExpand : function(node){
31821 var p = node.parentNode;
31823 if(p.expandedChild && p.expandedChild.parentNode == p){
31824 p.expandedChild.collapse();
31826 p.expandedChild = node;
31830 // private override
31831 setRootNode : function(node){
31832 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31833 if(!this.rootVisible){
31834 node.ui = new Roo.tree.RootTreeNodeUI(node);
31840 * Returns the container element for this TreePanel
31842 getEl : function(){
31847 * Returns the default TreeLoader for this TreePanel
31849 getLoader : function(){
31850 return this.loader;
31856 expandAll : function(){
31857 this.root.expand(true);
31861 * Collapse all nodes
31863 collapseAll : function(){
31864 this.root.collapse(true);
31868 * Returns the selection model used by this TreePanel
31870 getSelectionModel : function(){
31871 if(!this.selModel){
31872 this.selModel = new Roo.tree.DefaultSelectionModel();
31874 return this.selModel;
31878 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31879 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31880 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31883 getChecked : function(a, startNode){
31884 startNode = startNode || this.root;
31886 var f = function(){
31887 if(this.attributes.checked){
31888 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31891 startNode.cascade(f);
31896 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31897 * @param {String} path
31898 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31899 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31900 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31902 expandPath : function(path, attr, callback){
31903 attr = attr || "id";
31904 var keys = path.split(this.pathSeparator);
31905 var curNode = this.root;
31906 if(curNode.attributes[attr] != keys[1]){ // invalid root
31908 callback(false, null);
31913 var f = function(){
31914 if(++index == keys.length){
31916 callback(true, curNode);
31920 var c = curNode.findChild(attr, keys[index]);
31923 callback(false, curNode);
31928 c.expand(false, false, f);
31930 curNode.expand(false, false, f);
31934 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31935 * @param {String} path
31936 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31937 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31938 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31940 selectPath : function(path, attr, callback){
31941 attr = attr || "id";
31942 var keys = path.split(this.pathSeparator);
31943 var v = keys.pop();
31944 if(keys.length > 0){
31945 var f = function(success, node){
31946 if(success && node){
31947 var n = node.findChild(attr, v);
31953 }else if(callback){
31954 callback(false, n);
31958 callback(false, n);
31962 this.expandPath(keys.join(this.pathSeparator), attr, f);
31964 this.root.select();
31966 callback(true, this.root);
31971 getTreeEl : function(){
31976 * Trigger rendering of this TreePanel
31978 render : function(){
31979 if (this.innerCt) {
31980 return this; // stop it rendering more than once!!
31983 this.innerCt = this.el.createChild({tag:"ul",
31984 cls:"x-tree-root-ct " +
31985 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31987 if(this.containerScroll){
31988 Roo.dd.ScrollManager.register(this.el);
31990 if((this.enableDD || this.enableDrop) && !this.dropZone){
31992 * The dropZone used by this tree if drop is enabled
31993 * @type Roo.tree.TreeDropZone
31995 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31996 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31999 if((this.enableDD || this.enableDrag) && !this.dragZone){
32001 * The dragZone used by this tree if drag is enabled
32002 * @type Roo.tree.TreeDragZone
32004 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32005 ddGroup: this.ddGroup || "TreeDD",
32006 scroll: this.ddScroll
32009 this.getSelectionModel().init(this);
32011 Roo.log("ROOT not set in tree");
32014 this.root.render();
32015 if(!this.rootVisible){
32016 this.root.renderChildren();
32022 * Ext JS Library 1.1.1
32023 * Copyright(c) 2006-2007, Ext JS, LLC.
32025 * Originally Released Under LGPL - original licence link has changed is not relivant.
32028 * <script type="text/javascript">
32033 * @class Roo.tree.DefaultSelectionModel
32034 * @extends Roo.util.Observable
32035 * The default single selection for a TreePanel.
32036 * @param {Object} cfg Configuration
32038 Roo.tree.DefaultSelectionModel = function(cfg){
32039 this.selNode = null;
32045 * @event selectionchange
32046 * Fires when the selected node changes
32047 * @param {DefaultSelectionModel} this
32048 * @param {TreeNode} node the new selection
32050 "selectionchange" : true,
32053 * @event beforeselect
32054 * Fires before the selected node changes, return false to cancel the change
32055 * @param {DefaultSelectionModel} this
32056 * @param {TreeNode} node the new selection
32057 * @param {TreeNode} node the old selection
32059 "beforeselect" : true
32062 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32065 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32066 init : function(tree){
32068 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32069 tree.on("click", this.onNodeClick, this);
32072 onNodeClick : function(node, e){
32073 if (e.ctrlKey && this.selNode == node) {
32074 this.unselect(node);
32082 * @param {TreeNode} node The node to select
32083 * @return {TreeNode} The selected node
32085 select : function(node){
32086 var last = this.selNode;
32087 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32089 last.ui.onSelectedChange(false);
32091 this.selNode = node;
32092 node.ui.onSelectedChange(true);
32093 this.fireEvent("selectionchange", this, node, last);
32100 * @param {TreeNode} node The node to unselect
32102 unselect : function(node){
32103 if(this.selNode == node){
32104 this.clearSelections();
32109 * Clear all selections
32111 clearSelections : function(){
32112 var n = this.selNode;
32114 n.ui.onSelectedChange(false);
32115 this.selNode = null;
32116 this.fireEvent("selectionchange", this, null);
32122 * Get the selected node
32123 * @return {TreeNode} The selected node
32125 getSelectedNode : function(){
32126 return this.selNode;
32130 * Returns true if the node is selected
32131 * @param {TreeNode} node The node to check
32132 * @return {Boolean}
32134 isSelected : function(node){
32135 return this.selNode == node;
32139 * Selects the node above the selected node in the tree, intelligently walking the nodes
32140 * @return TreeNode The new selection
32142 selectPrevious : function(){
32143 var s = this.selNode || this.lastSelNode;
32147 var ps = s.previousSibling;
32149 if(!ps.isExpanded() || ps.childNodes.length < 1){
32150 return this.select(ps);
32152 var lc = ps.lastChild;
32153 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32156 return this.select(lc);
32158 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32159 return this.select(s.parentNode);
32165 * Selects the node above the selected node in the tree, intelligently walking the nodes
32166 * @return TreeNode The new selection
32168 selectNext : function(){
32169 var s = this.selNode || this.lastSelNode;
32173 if(s.firstChild && s.isExpanded()){
32174 return this.select(s.firstChild);
32175 }else if(s.nextSibling){
32176 return this.select(s.nextSibling);
32177 }else if(s.parentNode){
32179 s.parentNode.bubble(function(){
32180 if(this.nextSibling){
32181 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32190 onKeyDown : function(e){
32191 var s = this.selNode || this.lastSelNode;
32192 // undesirable, but required
32197 var k = e.getKey();
32205 this.selectPrevious();
32208 e.preventDefault();
32209 if(s.hasChildNodes()){
32210 if(!s.isExpanded()){
32212 }else if(s.firstChild){
32213 this.select(s.firstChild, e);
32218 e.preventDefault();
32219 if(s.hasChildNodes() && s.isExpanded()){
32221 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32222 this.select(s.parentNode, e);
32230 * @class Roo.tree.MultiSelectionModel
32231 * @extends Roo.util.Observable
32232 * Multi selection for a TreePanel.
32233 * @param {Object} cfg Configuration
32235 Roo.tree.MultiSelectionModel = function(){
32236 this.selNodes = [];
32240 * @event selectionchange
32241 * Fires when the selected nodes change
32242 * @param {MultiSelectionModel} this
32243 * @param {Array} nodes Array of the selected nodes
32245 "selectionchange" : true
32247 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32251 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32252 init : function(tree){
32254 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32255 tree.on("click", this.onNodeClick, this);
32258 onNodeClick : function(node, e){
32259 this.select(node, e, e.ctrlKey);
32264 * @param {TreeNode} node The node to select
32265 * @param {EventObject} e (optional) An event associated with the selection
32266 * @param {Boolean} keepExisting True to retain existing selections
32267 * @return {TreeNode} The selected node
32269 select : function(node, e, keepExisting){
32270 if(keepExisting !== true){
32271 this.clearSelections(true);
32273 if(this.isSelected(node)){
32274 this.lastSelNode = node;
32277 this.selNodes.push(node);
32278 this.selMap[node.id] = node;
32279 this.lastSelNode = node;
32280 node.ui.onSelectedChange(true);
32281 this.fireEvent("selectionchange", this, this.selNodes);
32287 * @param {TreeNode} node The node to unselect
32289 unselect : function(node){
32290 if(this.selMap[node.id]){
32291 node.ui.onSelectedChange(false);
32292 var sn = this.selNodes;
32295 index = sn.indexOf(node);
32297 for(var i = 0, len = sn.length; i < len; i++){
32305 this.selNodes.splice(index, 1);
32307 delete this.selMap[node.id];
32308 this.fireEvent("selectionchange", this, this.selNodes);
32313 * Clear all selections
32315 clearSelections : function(suppressEvent){
32316 var sn = this.selNodes;
32318 for(var i = 0, len = sn.length; i < len; i++){
32319 sn[i].ui.onSelectedChange(false);
32321 this.selNodes = [];
32323 if(suppressEvent !== true){
32324 this.fireEvent("selectionchange", this, this.selNodes);
32330 * Returns true if the node is selected
32331 * @param {TreeNode} node The node to check
32332 * @return {Boolean}
32334 isSelected : function(node){
32335 return this.selMap[node.id] ? true : false;
32339 * Returns an array of the selected nodes
32342 getSelectedNodes : function(){
32343 return this.selNodes;
32346 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32348 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32350 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32353 * Ext JS Library 1.1.1
32354 * Copyright(c) 2006-2007, Ext JS, LLC.
32356 * Originally Released Under LGPL - original licence link has changed is not relivant.
32359 * <script type="text/javascript">
32363 * @class Roo.tree.TreeNode
32364 * @extends Roo.data.Node
32365 * @cfg {String} text The text for this node
32366 * @cfg {Boolean} expanded true to start the node expanded
32367 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
32368 * @cfg {Boolean} allowDrop false if this node cannot be drop on
32369 * @cfg {Boolean} disabled true to start the node disabled
32370 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
32371 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
32372 * @cfg {String} cls A css class to be added to the node
32373 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
32374 * @cfg {String} href URL of the link used for the node (defaults to #)
32375 * @cfg {String} hrefTarget target frame for the link
32376 * @cfg {String} qtip An Ext QuickTip for the node
32377 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
32378 * @cfg {Boolean} singleClickExpand True for single click expand on this node
32379 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
32380 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
32381 * (defaults to undefined with no checkbox rendered)
32383 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32385 Roo.tree.TreeNode = function(attributes){
32386 attributes = attributes || {};
32387 if(typeof attributes == "string"){
32388 attributes = {text: attributes};
32390 this.childrenRendered = false;
32391 this.rendered = false;
32392 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
32393 this.expanded = attributes.expanded === true;
32394 this.isTarget = attributes.isTarget !== false;
32395 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
32396 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
32399 * Read-only. The text for this node. To change it use setText().
32402 this.text = attributes.text;
32404 * True if this node is disabled.
32407 this.disabled = attributes.disabled === true;
32411 * @event textchange
32412 * Fires when the text for this node is changed
32413 * @param {Node} this This node
32414 * @param {String} text The new text
32415 * @param {String} oldText The old text
32417 "textchange" : true,
32419 * @event beforeexpand
32420 * Fires before this node is expanded, return false to cancel.
32421 * @param {Node} this This node
32422 * @param {Boolean} deep
32423 * @param {Boolean} anim
32425 "beforeexpand" : true,
32427 * @event beforecollapse
32428 * Fires before this node is collapsed, return false to cancel.
32429 * @param {Node} this This node
32430 * @param {Boolean} deep
32431 * @param {Boolean} anim
32433 "beforecollapse" : true,
32436 * Fires when this node is expanded
32437 * @param {Node} this This node
32441 * @event disabledchange
32442 * Fires when the disabled status of this node changes
32443 * @param {Node} this This node
32444 * @param {Boolean} disabled
32446 "disabledchange" : true,
32449 * Fires when this node is collapsed
32450 * @param {Node} this This node
32454 * @event beforeclick
32455 * Fires before click processing. Return false to cancel the default action.
32456 * @param {Node} this This node
32457 * @param {Roo.EventObject} e The event object
32459 "beforeclick":true,
32461 * @event checkchange
32462 * Fires when a node with a checkbox's checked property changes
32463 * @param {Node} this This node
32464 * @param {Boolean} checked
32466 "checkchange":true,
32469 * Fires when this node is clicked
32470 * @param {Node} this This node
32471 * @param {Roo.EventObject} e The event object
32476 * Fires when this node is double clicked
32477 * @param {Node} this This node
32478 * @param {Roo.EventObject} e The event object
32482 * @event contextmenu
32483 * Fires when this node is right clicked
32484 * @param {Node} this This node
32485 * @param {Roo.EventObject} e The event object
32487 "contextmenu":true,
32489 * @event beforechildrenrendered
32490 * Fires right before the child nodes for this node are rendered
32491 * @param {Node} this This node
32493 "beforechildrenrendered":true
32496 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
32499 * Read-only. The UI for this node
32502 this.ui = new uiClass(this);
32504 // finally support items[]
32505 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
32510 Roo.each(this.attributes.items, function(c) {
32511 this.appendChild(Roo.factory(c,Roo.Tree));
32513 delete this.attributes.items;
32518 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
32519 preventHScroll: true,
32521 * Returns true if this node is expanded
32522 * @return {Boolean}
32524 isExpanded : function(){
32525 return this.expanded;
32529 * Returns the UI object for this node
32530 * @return {TreeNodeUI}
32532 getUI : function(){
32536 // private override
32537 setFirstChild : function(node){
32538 var of = this.firstChild;
32539 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
32540 if(this.childrenRendered && of && node != of){
32541 of.renderIndent(true, true);
32544 this.renderIndent(true, true);
32548 // private override
32549 setLastChild : function(node){
32550 var ol = this.lastChild;
32551 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
32552 if(this.childrenRendered && ol && node != ol){
32553 ol.renderIndent(true, true);
32556 this.renderIndent(true, true);
32560 // these methods are overridden to provide lazy rendering support
32561 // private override
32562 appendChild : function()
32564 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
32565 if(node && this.childrenRendered){
32568 this.ui.updateExpandIcon();
32572 // private override
32573 removeChild : function(node){
32574 this.ownerTree.getSelectionModel().unselect(node);
32575 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
32576 // if it's been rendered remove dom node
32577 if(this.childrenRendered){
32580 if(this.childNodes.length < 1){
32581 this.collapse(false, false);
32583 this.ui.updateExpandIcon();
32585 if(!this.firstChild) {
32586 this.childrenRendered = false;
32591 // private override
32592 insertBefore : function(node, refNode){
32593 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
32594 if(newNode && refNode && this.childrenRendered){
32597 this.ui.updateExpandIcon();
32602 * Sets the text for this node
32603 * @param {String} text
32605 setText : function(text){
32606 var oldText = this.text;
32608 this.attributes.text = text;
32609 if(this.rendered){ // event without subscribing
32610 this.ui.onTextChange(this, text, oldText);
32612 this.fireEvent("textchange", this, text, oldText);
32616 * Triggers selection of this node
32618 select : function(){
32619 this.getOwnerTree().getSelectionModel().select(this);
32623 * Triggers deselection of this node
32625 unselect : function(){
32626 this.getOwnerTree().getSelectionModel().unselect(this);
32630 * Returns true if this node is selected
32631 * @return {Boolean}
32633 isSelected : function(){
32634 return this.getOwnerTree().getSelectionModel().isSelected(this);
32638 * Expand this node.
32639 * @param {Boolean} deep (optional) True to expand all children as well
32640 * @param {Boolean} anim (optional) false to cancel the default animation
32641 * @param {Function} callback (optional) A callback to be called when
32642 * expanding this node completes (does not wait for deep expand to complete).
32643 * Called with 1 parameter, this node.
32645 expand : function(deep, anim, callback){
32646 if(!this.expanded){
32647 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
32650 if(!this.childrenRendered){
32651 this.renderChildren();
32653 this.expanded = true;
32654 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
32655 this.ui.animExpand(function(){
32656 this.fireEvent("expand", this);
32657 if(typeof callback == "function"){
32661 this.expandChildNodes(true);
32663 }.createDelegate(this));
32667 this.fireEvent("expand", this);
32668 if(typeof callback == "function"){
32673 if(typeof callback == "function"){
32678 this.expandChildNodes(true);
32682 isHiddenRoot : function(){
32683 return this.isRoot && !this.getOwnerTree().rootVisible;
32687 * Collapse this node.
32688 * @param {Boolean} deep (optional) True to collapse all children as well
32689 * @param {Boolean} anim (optional) false to cancel the default animation
32691 collapse : function(deep, anim){
32692 if(this.expanded && !this.isHiddenRoot()){
32693 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
32696 this.expanded = false;
32697 if((this.getOwnerTree().animate && anim !== false) || anim){
32698 this.ui.animCollapse(function(){
32699 this.fireEvent("collapse", this);
32701 this.collapseChildNodes(true);
32703 }.createDelegate(this));
32706 this.ui.collapse();
32707 this.fireEvent("collapse", this);
32711 var cs = this.childNodes;
32712 for(var i = 0, len = cs.length; i < len; i++) {
32713 cs[i].collapse(true, false);
32719 delayedExpand : function(delay){
32720 if(!this.expandProcId){
32721 this.expandProcId = this.expand.defer(delay, this);
32726 cancelExpand : function(){
32727 if(this.expandProcId){
32728 clearTimeout(this.expandProcId);
32730 this.expandProcId = false;
32734 * Toggles expanded/collapsed state of the node
32736 toggle : function(){
32745 * Ensures all parent nodes are expanded
32747 ensureVisible : function(callback){
32748 var tree = this.getOwnerTree();
32749 tree.expandPath(this.parentNode.getPath(), false, function(){
32750 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
32751 Roo.callback(callback);
32752 }.createDelegate(this));
32756 * Expand all child nodes
32757 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
32759 expandChildNodes : function(deep){
32760 var cs = this.childNodes;
32761 for(var i = 0, len = cs.length; i < len; i++) {
32762 cs[i].expand(deep);
32767 * Collapse all child nodes
32768 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
32770 collapseChildNodes : function(deep){
32771 var cs = this.childNodes;
32772 for(var i = 0, len = cs.length; i < len; i++) {
32773 cs[i].collapse(deep);
32778 * Disables this node
32780 disable : function(){
32781 this.disabled = true;
32783 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32784 this.ui.onDisableChange(this, true);
32786 this.fireEvent("disabledchange", this, true);
32790 * Enables this node
32792 enable : function(){
32793 this.disabled = false;
32794 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32795 this.ui.onDisableChange(this, false);
32797 this.fireEvent("disabledchange", this, false);
32801 renderChildren : function(suppressEvent){
32802 if(suppressEvent !== false){
32803 this.fireEvent("beforechildrenrendered", this);
32805 var cs = this.childNodes;
32806 for(var i = 0, len = cs.length; i < len; i++){
32807 cs[i].render(true);
32809 this.childrenRendered = true;
32813 sort : function(fn, scope){
32814 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32815 if(this.childrenRendered){
32816 var cs = this.childNodes;
32817 for(var i = 0, len = cs.length; i < len; i++){
32818 cs[i].render(true);
32824 render : function(bulkRender){
32825 this.ui.render(bulkRender);
32826 if(!this.rendered){
32827 this.rendered = true;
32829 this.expanded = false;
32830 this.expand(false, false);
32836 renderIndent : function(deep, refresh){
32838 this.ui.childIndent = null;
32840 this.ui.renderIndent();
32841 if(deep === true && this.childrenRendered){
32842 var cs = this.childNodes;
32843 for(var i = 0, len = cs.length; i < len; i++){
32844 cs[i].renderIndent(true, refresh);
32850 * Ext JS Library 1.1.1
32851 * Copyright(c) 2006-2007, Ext JS, LLC.
32853 * Originally Released Under LGPL - original licence link has changed is not relivant.
32856 * <script type="text/javascript">
32860 * @class Roo.tree.AsyncTreeNode
32861 * @extends Roo.tree.TreeNode
32862 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32864 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32866 Roo.tree.AsyncTreeNode = function(config){
32867 this.loaded = false;
32868 this.loading = false;
32869 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32871 * @event beforeload
32872 * Fires before this node is loaded, return false to cancel
32873 * @param {Node} this This node
32875 this.addEvents({'beforeload':true, 'load': true});
32878 * Fires when this node is loaded
32879 * @param {Node} this This node
32882 * The loader used by this node (defaults to using the tree's defined loader)
32887 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32888 expand : function(deep, anim, callback){
32889 if(this.loading){ // if an async load is already running, waiting til it's done
32891 var f = function(){
32892 if(!this.loading){ // done loading
32893 clearInterval(timer);
32894 this.expand(deep, anim, callback);
32896 }.createDelegate(this);
32897 timer = setInterval(f, 200);
32901 if(this.fireEvent("beforeload", this) === false){
32904 this.loading = true;
32905 this.ui.beforeLoad(this);
32906 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32908 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32912 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32916 * Returns true if this node is currently loading
32917 * @return {Boolean}
32919 isLoading : function(){
32920 return this.loading;
32923 loadComplete : function(deep, anim, callback){
32924 this.loading = false;
32925 this.loaded = true;
32926 this.ui.afterLoad(this);
32927 this.fireEvent("load", this);
32928 this.expand(deep, anim, callback);
32932 * Returns true if this node has been loaded
32933 * @return {Boolean}
32935 isLoaded : function(){
32936 return this.loaded;
32939 hasChildNodes : function(){
32940 if(!this.isLeaf() && !this.loaded){
32943 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32948 * Trigger a reload for this node
32949 * @param {Function} callback
32951 reload : function(callback){
32952 this.collapse(false, false);
32953 while(this.firstChild){
32954 this.removeChild(this.firstChild);
32956 this.childrenRendered = false;
32957 this.loaded = false;
32958 if(this.isHiddenRoot()){
32959 this.expanded = false;
32961 this.expand(false, false, callback);
32965 * Ext JS Library 1.1.1
32966 * Copyright(c) 2006-2007, Ext JS, LLC.
32968 * Originally Released Under LGPL - original licence link has changed is not relivant.
32971 * <script type="text/javascript">
32975 * @class Roo.tree.TreeNodeUI
32977 * @param {Object} node The node to render
32978 * The TreeNode UI implementation is separate from the
32979 * tree implementation. Unless you are customizing the tree UI,
32980 * you should never have to use this directly.
32982 Roo.tree.TreeNodeUI = function(node){
32984 this.rendered = false;
32985 this.animating = false;
32986 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32989 Roo.tree.TreeNodeUI.prototype = {
32990 removeChild : function(node){
32992 this.ctNode.removeChild(node.ui.getEl());
32996 beforeLoad : function(){
32997 this.addClass("x-tree-node-loading");
33000 afterLoad : function(){
33001 this.removeClass("x-tree-node-loading");
33004 onTextChange : function(node, text, oldText){
33006 this.textNode.innerHTML = text;
33010 onDisableChange : function(node, state){
33011 this.disabled = state;
33013 this.addClass("x-tree-node-disabled");
33015 this.removeClass("x-tree-node-disabled");
33019 onSelectedChange : function(state){
33022 this.addClass("x-tree-selected");
33025 this.removeClass("x-tree-selected");
33029 onMove : function(tree, node, oldParent, newParent, index, refNode){
33030 this.childIndent = null;
33032 var targetNode = newParent.ui.getContainer();
33033 if(!targetNode){//target not rendered
33034 this.holder = document.createElement("div");
33035 this.holder.appendChild(this.wrap);
33038 var insertBefore = refNode ? refNode.ui.getEl() : null;
33040 targetNode.insertBefore(this.wrap, insertBefore);
33042 targetNode.appendChild(this.wrap);
33044 this.node.renderIndent(true);
33048 addClass : function(cls){
33050 Roo.fly(this.elNode).addClass(cls);
33054 removeClass : function(cls){
33056 Roo.fly(this.elNode).removeClass(cls);
33060 remove : function(){
33062 this.holder = document.createElement("div");
33063 this.holder.appendChild(this.wrap);
33067 fireEvent : function(){
33068 return this.node.fireEvent.apply(this.node, arguments);
33071 initEvents : function(){
33072 this.node.on("move", this.onMove, this);
33073 var E = Roo.EventManager;
33074 var a = this.anchor;
33076 var el = Roo.fly(a, '_treeui');
33078 if(Roo.isOpera){ // opera render bug ignores the CSS
33079 el.setStyle("text-decoration", "none");
33082 el.on("click", this.onClick, this);
33083 el.on("dblclick", this.onDblClick, this);
33086 Roo.EventManager.on(this.checkbox,
33087 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33090 el.on("contextmenu", this.onContextMenu, this);
33092 var icon = Roo.fly(this.iconNode);
33093 icon.on("click", this.onClick, this);
33094 icon.on("dblclick", this.onDblClick, this);
33095 icon.on("contextmenu", this.onContextMenu, this);
33096 E.on(this.ecNode, "click", this.ecClick, this, true);
33098 if(this.node.disabled){
33099 this.addClass("x-tree-node-disabled");
33101 if(this.node.hidden){
33102 this.addClass("x-tree-node-disabled");
33104 var ot = this.node.getOwnerTree();
33105 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33106 if(dd && (!this.node.isRoot || ot.rootVisible)){
33107 Roo.dd.Registry.register(this.elNode, {
33109 handles: this.getDDHandles(),
33115 getDDHandles : function(){
33116 return [this.iconNode, this.textNode];
33121 this.wrap.style.display = "none";
33127 this.wrap.style.display = "";
33131 onContextMenu : function(e){
33132 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33133 e.preventDefault();
33135 this.fireEvent("contextmenu", this.node, e);
33139 onClick : function(e){
33144 if(this.fireEvent("beforeclick", this.node, e) !== false){
33145 if(!this.disabled && this.node.attributes.href){
33146 this.fireEvent("click", this.node, e);
33149 e.preventDefault();
33154 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33155 this.node.toggle();
33158 this.fireEvent("click", this.node, e);
33164 onDblClick : function(e){
33165 e.preventDefault();
33170 this.toggleCheck();
33172 if(!this.animating && this.node.hasChildNodes()){
33173 this.node.toggle();
33175 this.fireEvent("dblclick", this.node, e);
33178 onCheckChange : function(){
33179 var checked = this.checkbox.checked;
33180 this.node.attributes.checked = checked;
33181 this.fireEvent('checkchange', this.node, checked);
33184 ecClick : function(e){
33185 if(!this.animating && this.node.hasChildNodes()){
33186 this.node.toggle();
33190 startDrop : function(){
33191 this.dropping = true;
33194 // delayed drop so the click event doesn't get fired on a drop
33195 endDrop : function(){
33196 setTimeout(function(){
33197 this.dropping = false;
33198 }.createDelegate(this), 50);
33201 expand : function(){
33202 this.updateExpandIcon();
33203 this.ctNode.style.display = "";
33206 focus : function(){
33207 if(!this.node.preventHScroll){
33208 try{this.anchor.focus();
33210 }else if(!Roo.isIE){
33212 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33213 var l = noscroll.scrollLeft;
33214 this.anchor.focus();
33215 noscroll.scrollLeft = l;
33220 toggleCheck : function(value){
33221 var cb = this.checkbox;
33223 cb.checked = (value === undefined ? !cb.checked : value);
33229 this.anchor.blur();
33233 animExpand : function(callback){
33234 var ct = Roo.get(this.ctNode);
33236 if(!this.node.hasChildNodes()){
33237 this.updateExpandIcon();
33238 this.ctNode.style.display = "";
33239 Roo.callback(callback);
33242 this.animating = true;
33243 this.updateExpandIcon();
33246 callback : function(){
33247 this.animating = false;
33248 Roo.callback(callback);
33251 duration: this.node.ownerTree.duration || .25
33255 highlight : function(){
33256 var tree = this.node.getOwnerTree();
33257 Roo.fly(this.wrap).highlight(
33258 tree.hlColor || "C3DAF9",
33259 {endColor: tree.hlBaseColor}
33263 collapse : function(){
33264 this.updateExpandIcon();
33265 this.ctNode.style.display = "none";
33268 animCollapse : function(callback){
33269 var ct = Roo.get(this.ctNode);
33270 ct.enableDisplayMode('block');
33273 this.animating = true;
33274 this.updateExpandIcon();
33277 callback : function(){
33278 this.animating = false;
33279 Roo.callback(callback);
33282 duration: this.node.ownerTree.duration || .25
33286 getContainer : function(){
33287 return this.ctNode;
33290 getEl : function(){
33294 appendDDGhost : function(ghostNode){
33295 ghostNode.appendChild(this.elNode.cloneNode(true));
33298 getDDRepairXY : function(){
33299 return Roo.lib.Dom.getXY(this.iconNode);
33302 onRender : function(){
33306 render : function(bulkRender){
33307 var n = this.node, a = n.attributes;
33308 var targetNode = n.parentNode ?
33309 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33311 if(!this.rendered){
33312 this.rendered = true;
33314 this.renderElements(n, a, targetNode, bulkRender);
33317 if(this.textNode.setAttributeNS){
33318 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33320 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33323 this.textNode.setAttribute("ext:qtip", a.qtip);
33325 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33328 }else if(a.qtipCfg){
33329 a.qtipCfg.target = Roo.id(this.textNode);
33330 Roo.QuickTips.register(a.qtipCfg);
33333 if(!this.node.expanded){
33334 this.updateExpandIcon();
33337 if(bulkRender === true) {
33338 targetNode.appendChild(this.wrap);
33343 renderElements : function(n, a, targetNode, bulkRender)
33345 // add some indent caching, this helps performance when rendering a large tree
33346 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33347 var t = n.getOwnerTree();
33348 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33349 if (typeof(n.attributes.html) != 'undefined') {
33350 txt = n.attributes.html;
33352 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33353 var cb = typeof a.checked == 'boolean';
33354 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33355 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33356 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33357 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33358 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33359 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33360 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33361 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33362 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33363 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33366 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33367 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33368 n.nextSibling.ui.getEl(), buf.join(""));
33370 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33373 this.elNode = this.wrap.childNodes[0];
33374 this.ctNode = this.wrap.childNodes[1];
33375 var cs = this.elNode.childNodes;
33376 this.indentNode = cs[0];
33377 this.ecNode = cs[1];
33378 this.iconNode = cs[2];
33381 this.checkbox = cs[3];
33384 this.anchor = cs[index];
33385 this.textNode = cs[index].firstChild;
33388 getAnchor : function(){
33389 return this.anchor;
33392 getTextEl : function(){
33393 return this.textNode;
33396 getIconEl : function(){
33397 return this.iconNode;
33400 isChecked : function(){
33401 return this.checkbox ? this.checkbox.checked : false;
33404 updateExpandIcon : function(){
33406 var n = this.node, c1, c2;
33407 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
33408 var hasChild = n.hasChildNodes();
33412 c1 = "x-tree-node-collapsed";
33413 c2 = "x-tree-node-expanded";
33416 c1 = "x-tree-node-expanded";
33417 c2 = "x-tree-node-collapsed";
33420 this.removeClass("x-tree-node-leaf");
33421 this.wasLeaf = false;
33423 if(this.c1 != c1 || this.c2 != c2){
33424 Roo.fly(this.elNode).replaceClass(c1, c2);
33425 this.c1 = c1; this.c2 = c2;
33428 // this changes non-leafs into leafs if they have no children.
33429 // it's not very rational behaviour..
33431 if(!this.wasLeaf && this.node.leaf){
33432 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
33435 this.wasLeaf = true;
33438 var ecc = "x-tree-ec-icon "+cls;
33439 if(this.ecc != ecc){
33440 this.ecNode.className = ecc;
33446 getChildIndent : function(){
33447 if(!this.childIndent){
33451 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
33453 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
33455 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
33460 this.childIndent = buf.join("");
33462 return this.childIndent;
33465 renderIndent : function(){
33468 var p = this.node.parentNode;
33470 indent = p.ui.getChildIndent();
33472 if(this.indentMarkup != indent){ // don't rerender if not required
33473 this.indentNode.innerHTML = indent;
33474 this.indentMarkup = indent;
33476 this.updateExpandIcon();
33481 Roo.tree.RootTreeNodeUI = function(){
33482 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
33484 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
33485 render : function(){
33486 if(!this.rendered){
33487 var targetNode = this.node.ownerTree.innerCt.dom;
33488 this.node.expanded = true;
33489 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
33490 this.wrap = this.ctNode = targetNode.firstChild;
33493 collapse : function(){
33495 expand : function(){
33499 * Ext JS Library 1.1.1
33500 * Copyright(c) 2006-2007, Ext JS, LLC.
33502 * Originally Released Under LGPL - original licence link has changed is not relivant.
33505 * <script type="text/javascript">
33508 * @class Roo.tree.TreeLoader
33509 * @extends Roo.util.Observable
33510 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
33511 * nodes from a specified URL. The response must be a javascript Array definition
33512 * who's elements are node definition objects. eg:
33517 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
33518 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
33525 * The old style respose with just an array is still supported, but not recommended.
33528 * A server request is sent, and child nodes are loaded only when a node is expanded.
33529 * The loading node's id is passed to the server under the parameter name "node" to
33530 * enable the server to produce the correct child nodes.
33532 * To pass extra parameters, an event handler may be attached to the "beforeload"
33533 * event, and the parameters specified in the TreeLoader's baseParams property:
33535 myTreeLoader.on("beforeload", function(treeLoader, node) {
33536 this.baseParams.category = node.attributes.category;
33539 * This would pass an HTTP parameter called "category" to the server containing
33540 * the value of the Node's "category" attribute.
33542 * Creates a new Treeloader.
33543 * @param {Object} config A config object containing config properties.
33545 Roo.tree.TreeLoader = function(config){
33546 this.baseParams = {};
33547 this.requestMethod = "POST";
33548 Roo.apply(this, config);
33553 * @event beforeload
33554 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
33555 * @param {Object} This TreeLoader object.
33556 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33557 * @param {Object} callback The callback function specified in the {@link #load} call.
33562 * Fires when the node has been successfuly loaded.
33563 * @param {Object} This TreeLoader object.
33564 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33565 * @param {Object} response The response object containing the data from the server.
33569 * @event loadexception
33570 * Fires if the network request failed.
33571 * @param {Object} This TreeLoader object.
33572 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33573 * @param {Object} response The response object containing the data from the server.
33575 loadexception : true,
33578 * Fires before a node is created, enabling you to return custom Node types
33579 * @param {Object} This TreeLoader object.
33580 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
33585 Roo.tree.TreeLoader.superclass.constructor.call(this);
33588 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
33590 * @cfg {String} dataUrl The URL from which to request a Json string which
33591 * specifies an array of node definition object representing the child nodes
33595 * @cfg {String} requestMethod either GET or POST
33596 * defaults to POST (due to BC)
33600 * @cfg {Object} baseParams (optional) An object containing properties which
33601 * specify HTTP parameters to be passed to each request for child nodes.
33604 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
33605 * created by this loader. If the attributes sent by the server have an attribute in this object,
33606 * they take priority.
33609 * @cfg {Object} uiProviders (optional) An object containing properties which
33611 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
33612 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
33613 * <i>uiProvider</i> attribute of a returned child node is a string rather
33614 * than a reference to a TreeNodeUI implementation, this that string value
33615 * is used as a property name in the uiProviders object. You can define the provider named
33616 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
33621 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
33622 * child nodes before loading.
33624 clearOnLoad : true,
33627 * @cfg {String} root (optional) Default to false. Use this to read data from an object
33628 * property on loading, rather than expecting an array. (eg. more compatible to a standard
33629 * Grid query { data : [ .....] }
33634 * @cfg {String} queryParam (optional)
33635 * Name of the query as it will be passed on the querystring (defaults to 'node')
33636 * eg. the request will be ?node=[id]
33643 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
33644 * This is called automatically when a node is expanded, but may be used to reload
33645 * a node (or append new children if the {@link #clearOnLoad} option is false.)
33646 * @param {Roo.tree.TreeNode} node
33647 * @param {Function} callback
33649 load : function(node, callback){
33650 if(this.clearOnLoad){
33651 while(node.firstChild){
33652 node.removeChild(node.firstChild);
33655 if(node.attributes.children){ // preloaded json children
33656 var cs = node.attributes.children;
33657 for(var i = 0, len = cs.length; i < len; i++){
33658 node.appendChild(this.createNode(cs[i]));
33660 if(typeof callback == "function"){
33663 }else if(this.dataUrl){
33664 this.requestData(node, callback);
33668 getParams: function(node){
33669 var buf = [], bp = this.baseParams;
33670 for(var key in bp){
33671 if(typeof bp[key] != "function"){
33672 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
33675 var n = this.queryParam === false ? 'node' : this.queryParam;
33676 buf.push(n + "=", encodeURIComponent(node.id));
33677 return buf.join("");
33680 requestData : function(node, callback){
33681 if(this.fireEvent("beforeload", this, node, callback) !== false){
33682 this.transId = Roo.Ajax.request({
33683 method:this.requestMethod,
33684 url: this.dataUrl||this.url,
33685 success: this.handleResponse,
33686 failure: this.handleFailure,
33688 argument: {callback: callback, node: node},
33689 params: this.getParams(node)
33692 // if the load is cancelled, make sure we notify
33693 // the node that we are done
33694 if(typeof callback == "function"){
33700 isLoading : function(){
33701 return this.transId ? true : false;
33704 abort : function(){
33705 if(this.isLoading()){
33706 Roo.Ajax.abort(this.transId);
33711 createNode : function(attr)
33713 // apply baseAttrs, nice idea Corey!
33714 if(this.baseAttrs){
33715 Roo.applyIf(attr, this.baseAttrs);
33717 if(this.applyLoader !== false){
33718 attr.loader = this;
33720 // uiProvider = depreciated..
33722 if(typeof(attr.uiProvider) == 'string'){
33723 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
33724 /** eval:var:attr */ eval(attr.uiProvider);
33726 if(typeof(this.uiProviders['default']) != 'undefined') {
33727 attr.uiProvider = this.uiProviders['default'];
33730 this.fireEvent('create', this, attr);
33732 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
33734 new Roo.tree.TreeNode(attr) :
33735 new Roo.tree.AsyncTreeNode(attr));
33738 processResponse : function(response, node, callback)
33740 var json = response.responseText;
33743 var o = Roo.decode(json);
33745 if (this.root === false && typeof(o.success) != undefined) {
33746 this.root = 'data'; // the default behaviour for list like data..
33749 if (this.root !== false && !o.success) {
33750 // it's a failure condition.
33751 var a = response.argument;
33752 this.fireEvent("loadexception", this, a.node, response);
33753 Roo.log("Load failed - should have a handler really");
33759 if (this.root !== false) {
33763 for(var i = 0, len = o.length; i < len; i++){
33764 var n = this.createNode(o[i]);
33766 node.appendChild(n);
33769 if(typeof callback == "function"){
33770 callback(this, node);
33773 this.handleFailure(response);
33777 handleResponse : function(response){
33778 this.transId = false;
33779 var a = response.argument;
33780 this.processResponse(response, a.node, a.callback);
33781 this.fireEvent("load", this, a.node, response);
33784 handleFailure : function(response)
33786 // should handle failure better..
33787 this.transId = false;
33788 var a = response.argument;
33789 this.fireEvent("loadexception", this, a.node, response);
33790 if(typeof a.callback == "function"){
33791 a.callback(this, a.node);
33796 * Ext JS Library 1.1.1
33797 * Copyright(c) 2006-2007, Ext JS, LLC.
33799 * Originally Released Under LGPL - original licence link has changed is not relivant.
33802 * <script type="text/javascript">
33806 * @class Roo.tree.TreeFilter
33807 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
33808 * @param {TreePanel} tree
33809 * @param {Object} config (optional)
33811 Roo.tree.TreeFilter = function(tree, config){
33813 this.filtered = {};
33814 Roo.apply(this, config);
33817 Roo.tree.TreeFilter.prototype = {
33824 * Filter the data by a specific attribute.
33825 * @param {String/RegExp} value Either string that the attribute value
33826 * should start with or a RegExp to test against the attribute
33827 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
33828 * @param {TreeNode} startNode (optional) The node to start the filter at.
33830 filter : function(value, attr, startNode){
33831 attr = attr || "text";
33833 if(typeof value == "string"){
33834 var vlen = value.length;
33835 // auto clear empty filter
33836 if(vlen == 0 && this.clearBlank){
33840 value = value.toLowerCase();
33842 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
33844 }else if(value.exec){ // regex?
33846 return value.test(n.attributes[attr]);
33849 throw 'Illegal filter type, must be string or regex';
33851 this.filterBy(f, null, startNode);
33855 * Filter by a function. The passed function will be called with each
33856 * node in the tree (or from the startNode). If the function returns true, the node is kept
33857 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33858 * @param {Function} fn The filter function
33859 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33861 filterBy : function(fn, scope, startNode){
33862 startNode = startNode || this.tree.root;
33863 if(this.autoClear){
33866 var af = this.filtered, rv = this.reverse;
33867 var f = function(n){
33868 if(n == startNode){
33874 var m = fn.call(scope || n, n);
33882 startNode.cascade(f);
33885 if(typeof id != "function"){
33887 if(n && n.parentNode){
33888 n.parentNode.removeChild(n);
33896 * Clears the current filter. Note: with the "remove" option
33897 * set a filter cannot be cleared.
33899 clear : function(){
33901 var af = this.filtered;
33903 if(typeof id != "function"){
33910 this.filtered = {};
33915 * Ext JS Library 1.1.1
33916 * Copyright(c) 2006-2007, Ext JS, LLC.
33918 * Originally Released Under LGPL - original licence link has changed is not relivant.
33921 * <script type="text/javascript">
33926 * @class Roo.tree.TreeSorter
33927 * Provides sorting of nodes in a TreePanel
33929 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33930 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33931 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33932 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33933 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33934 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33936 * @param {TreePanel} tree
33937 * @param {Object} config
33939 Roo.tree.TreeSorter = function(tree, config){
33940 Roo.apply(this, config);
33941 tree.on("beforechildrenrendered", this.doSort, this);
33942 tree.on("append", this.updateSort, this);
33943 tree.on("insert", this.updateSort, this);
33945 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33946 var p = this.property || "text";
33947 var sortType = this.sortType;
33948 var fs = this.folderSort;
33949 var cs = this.caseSensitive === true;
33950 var leafAttr = this.leafAttr || 'leaf';
33952 this.sortFn = function(n1, n2){
33954 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33957 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33961 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33962 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33964 return dsc ? +1 : -1;
33966 return dsc ? -1 : +1;
33973 Roo.tree.TreeSorter.prototype = {
33974 doSort : function(node){
33975 node.sort(this.sortFn);
33978 compareNodes : function(n1, n2){
33979 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33982 updateSort : function(tree, node){
33983 if(node.childrenRendered){
33984 this.doSort.defer(1, this, [node]);
33989 * Ext JS Library 1.1.1
33990 * Copyright(c) 2006-2007, Ext JS, LLC.
33992 * Originally Released Under LGPL - original licence link has changed is not relivant.
33995 * <script type="text/javascript">
33998 if(Roo.dd.DropZone){
34000 Roo.tree.TreeDropZone = function(tree, config){
34001 this.allowParentInsert = false;
34002 this.allowContainerDrop = false;
34003 this.appendOnly = false;
34004 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34006 this.lastInsertClass = "x-tree-no-status";
34007 this.dragOverData = {};
34010 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34011 ddGroup : "TreeDD",
34014 expandDelay : 1000,
34016 expandNode : function(node){
34017 if(node.hasChildNodes() && !node.isExpanded()){
34018 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34022 queueExpand : function(node){
34023 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34026 cancelExpand : function(){
34027 if(this.expandProcId){
34028 clearTimeout(this.expandProcId);
34029 this.expandProcId = false;
34033 isValidDropPoint : function(n, pt, dd, e, data){
34034 if(!n || !data){ return false; }
34035 var targetNode = n.node;
34036 var dropNode = data.node;
34037 // default drop rules
34038 if(!(targetNode && targetNode.isTarget && pt)){
34041 if(pt == "append" && targetNode.allowChildren === false){
34044 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34047 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34050 // reuse the object
34051 var overEvent = this.dragOverData;
34052 overEvent.tree = this.tree;
34053 overEvent.target = targetNode;
34054 overEvent.data = data;
34055 overEvent.point = pt;
34056 overEvent.source = dd;
34057 overEvent.rawEvent = e;
34058 overEvent.dropNode = dropNode;
34059 overEvent.cancel = false;
34060 var result = this.tree.fireEvent("nodedragover", overEvent);
34061 return overEvent.cancel === false && result !== false;
34064 getDropPoint : function(e, n, dd)
34068 return tn.allowChildren !== false ? "append" : false; // always append for root
34070 var dragEl = n.ddel;
34071 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34072 var y = Roo.lib.Event.getPageY(e);
34073 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34075 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34076 var noAppend = tn.allowChildren === false;
34077 if(this.appendOnly || tn.parentNode.allowChildren === false){
34078 return noAppend ? false : "append";
34080 var noBelow = false;
34081 if(!this.allowParentInsert){
34082 noBelow = tn.hasChildNodes() && tn.isExpanded();
34084 var q = (b - t) / (noAppend ? 2 : 3);
34085 if(y >= t && y < (t + q)){
34087 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34094 onNodeEnter : function(n, dd, e, data)
34096 this.cancelExpand();
34099 onNodeOver : function(n, dd, e, data)
34102 var pt = this.getDropPoint(e, n, dd);
34105 // auto node expand check
34106 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34107 this.queueExpand(node);
34108 }else if(pt != "append"){
34109 this.cancelExpand();
34112 // set the insert point style on the target node
34113 var returnCls = this.dropNotAllowed;
34114 if(this.isValidDropPoint(n, pt, dd, e, data)){
34119 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34120 cls = "x-tree-drag-insert-above";
34121 }else if(pt == "below"){
34122 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34123 cls = "x-tree-drag-insert-below";
34125 returnCls = "x-tree-drop-ok-append";
34126 cls = "x-tree-drag-append";
34128 if(this.lastInsertClass != cls){
34129 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34130 this.lastInsertClass = cls;
34137 onNodeOut : function(n, dd, e, data){
34139 this.cancelExpand();
34140 this.removeDropIndicators(n);
34143 onNodeDrop : function(n, dd, e, data){
34144 var point = this.getDropPoint(e, n, dd);
34145 var targetNode = n.node;
34146 targetNode.ui.startDrop();
34147 if(!this.isValidDropPoint(n, point, dd, e, data)){
34148 targetNode.ui.endDrop();
34151 // first try to find the drop node
34152 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34155 target: targetNode,
34160 dropNode: dropNode,
34163 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34164 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34165 targetNode.ui.endDrop();
34168 // allow target changing
34169 targetNode = dropEvent.target;
34170 if(point == "append" && !targetNode.isExpanded()){
34171 targetNode.expand(false, null, function(){
34172 this.completeDrop(dropEvent);
34173 }.createDelegate(this));
34175 this.completeDrop(dropEvent);
34180 completeDrop : function(de){
34181 var ns = de.dropNode, p = de.point, t = de.target;
34182 if(!(ns instanceof Array)){
34186 for(var i = 0, len = ns.length; i < len; i++){
34189 t.parentNode.insertBefore(n, t);
34190 }else if(p == "below"){
34191 t.parentNode.insertBefore(n, t.nextSibling);
34197 if(this.tree.hlDrop){
34201 this.tree.fireEvent("nodedrop", de);
34204 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34205 if(this.tree.hlDrop){
34206 dropNode.ui.focus();
34207 dropNode.ui.highlight();
34209 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34212 getTree : function(){
34216 removeDropIndicators : function(n){
34219 Roo.fly(el).removeClass([
34220 "x-tree-drag-insert-above",
34221 "x-tree-drag-insert-below",
34222 "x-tree-drag-append"]);
34223 this.lastInsertClass = "_noclass";
34227 beforeDragDrop : function(target, e, id){
34228 this.cancelExpand();
34232 afterRepair : function(data){
34233 if(data && Roo.enableFx){
34234 data.node.ui.highlight();
34244 * Ext JS Library 1.1.1
34245 * Copyright(c) 2006-2007, Ext JS, LLC.
34247 * Originally Released Under LGPL - original licence link has changed is not relivant.
34250 * <script type="text/javascript">
34254 if(Roo.dd.DragZone){
34255 Roo.tree.TreeDragZone = function(tree, config){
34256 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34260 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34261 ddGroup : "TreeDD",
34263 onBeforeDrag : function(data, e){
34265 return n && n.draggable && !n.disabled;
34269 onInitDrag : function(e){
34270 var data = this.dragData;
34271 this.tree.getSelectionModel().select(data.node);
34272 this.proxy.update("");
34273 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34274 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34277 getRepairXY : function(e, data){
34278 return data.node.ui.getDDRepairXY();
34281 onEndDrag : function(data, e){
34282 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34287 onValidDrop : function(dd, e, id){
34288 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34292 beforeInvalidDrop : function(e, id){
34293 // this scrolls the original position back into view
34294 var sm = this.tree.getSelectionModel();
34295 sm.clearSelections();
34296 sm.select(this.dragData.node);
34301 * Ext JS Library 1.1.1
34302 * Copyright(c) 2006-2007, Ext JS, LLC.
34304 * Originally Released Under LGPL - original licence link has changed is not relivant.
34307 * <script type="text/javascript">
34310 * @class Roo.tree.TreeEditor
34311 * @extends Roo.Editor
34312 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34313 * as the editor field.
34315 * @param {Object} config (used to be the tree panel.)
34316 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34318 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34319 * @cfg {Roo.form.TextField|Object} field The field configuration
34323 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34326 if (oldconfig) { // old style..
34327 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34330 tree = config.tree;
34331 config.field = config.field || {};
34332 config.field.xtype = 'TextField';
34333 field = Roo.factory(config.field, Roo.form);
34335 config = config || {};
34340 * @event beforenodeedit
34341 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34342 * false from the handler of this event.
34343 * @param {Editor} this
34344 * @param {Roo.tree.Node} node
34346 "beforenodeedit" : true
34350 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34354 tree.on('beforeclick', this.beforeNodeClick, this);
34355 tree.getTreeEl().on('mousedown', this.hide, this);
34356 this.on('complete', this.updateNode, this);
34357 this.on('beforestartedit', this.fitToTree, this);
34358 this.on('startedit', this.bindScroll, this, {delay:10});
34359 this.on('specialkey', this.onSpecialKey, this);
34362 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34364 * @cfg {String} alignment
34365 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
34371 * @cfg {Boolean} hideEl
34372 * True to hide the bound element while the editor is displayed (defaults to false)
34376 * @cfg {String} cls
34377 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
34379 cls: "x-small-editor x-tree-editor",
34381 * @cfg {Boolean} shim
34382 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
34388 * @cfg {Number} maxWidth
34389 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
34390 * the containing tree element's size, it will be automatically limited for you to the container width, taking
34391 * scroll and client offsets into account prior to each edit.
34398 fitToTree : function(ed, el){
34399 var td = this.tree.getTreeEl().dom, nd = el.dom;
34400 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
34401 td.scrollLeft = nd.offsetLeft;
34405 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
34406 this.setSize(w, '');
34408 return this.fireEvent('beforenodeedit', this, this.editNode);
34413 triggerEdit : function(node){
34414 this.completeEdit();
34415 this.editNode = node;
34416 this.startEdit(node.ui.textNode, node.text);
34420 bindScroll : function(){
34421 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
34425 beforeNodeClick : function(node, e){
34426 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
34427 this.lastClick = new Date();
34428 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
34430 this.triggerEdit(node);
34437 updateNode : function(ed, value){
34438 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
34439 this.editNode.setText(value);
34443 onHide : function(){
34444 Roo.tree.TreeEditor.superclass.onHide.call(this);
34446 this.editNode.ui.focus();
34451 onSpecialKey : function(field, e){
34452 var k = e.getKey();
34456 }else if(k == e.ENTER && !e.hasModifier()){
34458 this.completeEdit();
34461 });//<Script type="text/javascript">
34464 * Ext JS Library 1.1.1
34465 * Copyright(c) 2006-2007, Ext JS, LLC.
34467 * Originally Released Under LGPL - original licence link has changed is not relivant.
34470 * <script type="text/javascript">
34474 * Not documented??? - probably should be...
34477 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
34478 //focus: Roo.emptyFn, // prevent odd scrolling behavior
34480 renderElements : function(n, a, targetNode, bulkRender){
34481 //consel.log("renderElements?");
34482 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34484 var t = n.getOwnerTree();
34485 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
34487 var cols = t.columns;
34488 var bw = t.borderWidth;
34490 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34491 var cb = typeof a.checked == "boolean";
34492 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
34493 var colcls = 'x-t-' + tid + '-c0';
34495 '<li class="x-tree-node">',
34498 '<div class="x-tree-node-el ', a.cls,'">',
34500 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
34503 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
34504 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
34505 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
34506 (a.icon ? ' x-tree-node-inline-icon' : ''),
34507 (a.iconCls ? ' '+a.iconCls : ''),
34508 '" unselectable="on" />',
34509 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
34510 (a.checked ? 'checked="checked" />' : ' />')) : ''),
34512 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
34513 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
34514 '<span unselectable="on" qtip="' + tx + '">',
34518 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
34519 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
34521 for(var i = 1, len = cols.length; i < len; i++){
34523 colcls = 'x-t-' + tid + '-c' +i;
34524 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
34525 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
34526 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
34532 '<div class="x-clear"></div></div>',
34533 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34536 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34537 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34538 n.nextSibling.ui.getEl(), buf.join(""));
34540 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34542 var el = this.wrap.firstChild;
34544 this.elNode = el.firstChild;
34545 this.ranchor = el.childNodes[1];
34546 this.ctNode = this.wrap.childNodes[1];
34547 var cs = el.firstChild.childNodes;
34548 this.indentNode = cs[0];
34549 this.ecNode = cs[1];
34550 this.iconNode = cs[2];
34553 this.checkbox = cs[3];
34556 this.anchor = cs[index];
34558 this.textNode = cs[index].firstChild;
34560 //el.on("click", this.onClick, this);
34561 //el.on("dblclick", this.onDblClick, this);
34564 // console.log(this);
34566 initEvents : function(){
34567 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
34570 var a = this.ranchor;
34572 var el = Roo.get(a);
34574 if(Roo.isOpera){ // opera render bug ignores the CSS
34575 el.setStyle("text-decoration", "none");
34578 el.on("click", this.onClick, this);
34579 el.on("dblclick", this.onDblClick, this);
34580 el.on("contextmenu", this.onContextMenu, this);
34584 /*onSelectedChange : function(state){
34587 this.addClass("x-tree-selected");
34590 this.removeClass("x-tree-selected");
34593 addClass : function(cls){
34595 Roo.fly(this.elRow).addClass(cls);
34601 removeClass : function(cls){
34603 Roo.fly(this.elRow).removeClass(cls);
34609 });//<Script type="text/javascript">
34613 * Ext JS Library 1.1.1
34614 * Copyright(c) 2006-2007, Ext JS, LLC.
34616 * Originally Released Under LGPL - original licence link has changed is not relivant.
34619 * <script type="text/javascript">
34624 * @class Roo.tree.ColumnTree
34625 * @extends Roo.data.TreePanel
34626 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
34627 * @cfg {int} borderWidth compined right/left border allowance
34629 * @param {String/HTMLElement/Element} el The container element
34630 * @param {Object} config
34632 Roo.tree.ColumnTree = function(el, config)
34634 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
34638 * Fire this event on a container when it resizes
34639 * @param {int} w Width
34640 * @param {int} h Height
34644 this.on('resize', this.onResize, this);
34647 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
34651 borderWidth: Roo.isBorderBox ? 0 : 2,
34654 render : function(){
34655 // add the header.....
34657 Roo.tree.ColumnTree.superclass.render.apply(this);
34659 this.el.addClass('x-column-tree');
34661 this.headers = this.el.createChild(
34662 {cls:'x-tree-headers'},this.innerCt.dom);
34664 var cols = this.columns, c;
34665 var totalWidth = 0;
34667 var len = cols.length;
34668 for(var i = 0; i < len; i++){
34670 totalWidth += c.width;
34671 this.headEls.push(this.headers.createChild({
34672 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
34674 cls:'x-tree-hd-text',
34677 style:'width:'+(c.width-this.borderWidth)+'px;'
34680 this.headers.createChild({cls:'x-clear'});
34681 // prevent floats from wrapping when clipped
34682 this.headers.setWidth(totalWidth);
34683 //this.innerCt.setWidth(totalWidth);
34684 this.innerCt.setStyle({ overflow: 'auto' });
34685 this.onResize(this.width, this.height);
34689 onResize : function(w,h)
34694 this.innerCt.setWidth(this.width);
34695 this.innerCt.setHeight(this.height-20);
34698 var cols = this.columns, c;
34699 var totalWidth = 0;
34701 var len = cols.length;
34702 for(var i = 0; i < len; i++){
34704 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
34705 // it's the expander..
34706 expEl = this.headEls[i];
34709 totalWidth += c.width;
34713 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
34715 this.headers.setWidth(w-20);
34724 * Ext JS Library 1.1.1
34725 * Copyright(c) 2006-2007, Ext JS, LLC.
34727 * Originally Released Under LGPL - original licence link has changed is not relivant.
34730 * <script type="text/javascript">
34734 * @class Roo.menu.Menu
34735 * @extends Roo.util.Observable
34736 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
34737 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
34739 * Creates a new Menu
34740 * @param {Object} config Configuration options
34742 Roo.menu.Menu = function(config){
34743 Roo.apply(this, config);
34744 this.id = this.id || Roo.id();
34747 * @event beforeshow
34748 * Fires before this menu is displayed
34749 * @param {Roo.menu.Menu} this
34753 * @event beforehide
34754 * Fires before this menu is hidden
34755 * @param {Roo.menu.Menu} this
34760 * Fires after this menu is displayed
34761 * @param {Roo.menu.Menu} this
34766 * Fires after this menu is hidden
34767 * @param {Roo.menu.Menu} this
34772 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
34773 * @param {Roo.menu.Menu} this
34774 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34775 * @param {Roo.EventObject} e
34780 * Fires when the mouse is hovering over this menu
34781 * @param {Roo.menu.Menu} this
34782 * @param {Roo.EventObject} e
34783 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34788 * Fires when the mouse exits this menu
34789 * @param {Roo.menu.Menu} this
34790 * @param {Roo.EventObject} e
34791 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34796 * Fires when a menu item contained in this menu is clicked
34797 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
34798 * @param {Roo.EventObject} e
34802 if (this.registerMenu) {
34803 Roo.menu.MenuMgr.register(this);
34806 var mis = this.items;
34807 this.items = new Roo.util.MixedCollection();
34809 this.add.apply(this, mis);
34813 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
34815 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
34819 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
34820 * for bottom-right shadow (defaults to "sides")
34824 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
34825 * this menu (defaults to "tl-tr?")
34827 subMenuAlign : "tl-tr?",
34829 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
34830 * relative to its element of origin (defaults to "tl-bl?")
34832 defaultAlign : "tl-bl?",
34834 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
34836 allowOtherMenus : false,
34838 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
34840 registerMenu : true,
34845 render : function(){
34849 var el = this.el = new Roo.Layer({
34851 shadow:this.shadow,
34853 parentEl: this.parentEl || document.body,
34857 this.keyNav = new Roo.menu.MenuNav(this);
34860 el.addClass("x-menu-plain");
34863 el.addClass(this.cls);
34865 // generic focus element
34866 this.focusEl = el.createChild({
34867 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
34869 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
34870 ul.on("click", this.onClick, this);
34871 ul.on("mouseover", this.onMouseOver, this);
34872 ul.on("mouseout", this.onMouseOut, this);
34873 this.items.each(function(item){
34878 var li = document.createElement("li");
34879 li.className = "x-menu-list-item";
34880 ul.dom.appendChild(li);
34881 item.render(li, this);
34888 autoWidth : function(){
34889 var el = this.el, ul = this.ul;
34893 var w = this.width;
34896 }else if(Roo.isIE){
34897 el.setWidth(this.minWidth);
34898 var t = el.dom.offsetWidth; // force recalc
34899 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34904 delayAutoWidth : function(){
34907 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34909 this.awTask.delay(20);
34914 findTargetItem : function(e){
34915 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34916 if(t && t.menuItemId){
34917 return this.items.get(t.menuItemId);
34922 onClick : function(e){
34924 if(t = this.findTargetItem(e)){
34926 this.fireEvent("click", this, t, e);
34931 setActiveItem : function(item, autoExpand){
34932 if(item != this.activeItem){
34933 if(this.activeItem){
34934 this.activeItem.deactivate();
34936 this.activeItem = item;
34937 item.activate(autoExpand);
34938 }else if(autoExpand){
34944 tryActivate : function(start, step){
34945 var items = this.items;
34946 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34947 var item = items.get(i);
34948 if(!item.disabled && item.canActivate){
34949 this.setActiveItem(item, false);
34957 onMouseOver : function(e){
34959 if(t = this.findTargetItem(e)){
34960 if(t.canActivate && !t.disabled){
34961 this.setActiveItem(t, true);
34964 this.fireEvent("mouseover", this, e, t);
34968 onMouseOut : function(e){
34970 if(t = this.findTargetItem(e)){
34971 if(t == this.activeItem && t.shouldDeactivate(e)){
34972 this.activeItem.deactivate();
34973 delete this.activeItem;
34976 this.fireEvent("mouseout", this, e, t);
34980 * Read-only. Returns true if the menu is currently displayed, else false.
34983 isVisible : function(){
34984 return this.el && !this.hidden;
34988 * Displays this menu relative to another element
34989 * @param {String/HTMLElement/Roo.Element} element The element to align to
34990 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34991 * the element (defaults to this.defaultAlign)
34992 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34994 show : function(el, pos, parentMenu){
34995 this.parentMenu = parentMenu;
34999 this.fireEvent("beforeshow", this);
35000 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35004 * Displays this menu at a specific xy position
35005 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35006 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35008 showAt : function(xy, parentMenu, /* private: */_e){
35009 this.parentMenu = parentMenu;
35014 this.fireEvent("beforeshow", this);
35015 xy = this.el.adjustForConstraints(xy);
35019 this.hidden = false;
35021 this.fireEvent("show", this);
35024 focus : function(){
35026 this.doFocus.defer(50, this);
35030 doFocus : function(){
35032 this.focusEl.focus();
35037 * Hides this menu and optionally all parent menus
35038 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35040 hide : function(deep){
35041 if(this.el && this.isVisible()){
35042 this.fireEvent("beforehide", this);
35043 if(this.activeItem){
35044 this.activeItem.deactivate();
35045 this.activeItem = null;
35048 this.hidden = true;
35049 this.fireEvent("hide", this);
35051 if(deep === true && this.parentMenu){
35052 this.parentMenu.hide(true);
35057 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35058 * Any of the following are valid:
35060 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35061 * <li>An HTMLElement object which will be converted to a menu item</li>
35062 * <li>A menu item config object that will be created as a new menu item</li>
35063 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35064 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35069 var menu = new Roo.menu.Menu();
35071 // Create a menu item to add by reference
35072 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35074 // Add a bunch of items at once using different methods.
35075 // Only the last item added will be returned.
35076 var item = menu.add(
35077 menuItem, // add existing item by ref
35078 'Dynamic Item', // new TextItem
35079 '-', // new separator
35080 { text: 'Config Item' } // new item by config
35083 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35084 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35087 var a = arguments, l = a.length, item;
35088 for(var i = 0; i < l; i++){
35090 if ((typeof(el) == "object") && el.xtype && el.xns) {
35091 el = Roo.factory(el, Roo.menu);
35094 if(el.render){ // some kind of Item
35095 item = this.addItem(el);
35096 }else if(typeof el == "string"){ // string
35097 if(el == "separator" || el == "-"){
35098 item = this.addSeparator();
35100 item = this.addText(el);
35102 }else if(el.tagName || el.el){ // element
35103 item = this.addElement(el);
35104 }else if(typeof el == "object"){ // must be menu item config?
35105 item = this.addMenuItem(el);
35112 * Returns this menu's underlying {@link Roo.Element} object
35113 * @return {Roo.Element} The element
35115 getEl : function(){
35123 * Adds a separator bar to the menu
35124 * @return {Roo.menu.Item} The menu item that was added
35126 addSeparator : function(){
35127 return this.addItem(new Roo.menu.Separator());
35131 * Adds an {@link Roo.Element} object to the menu
35132 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35133 * @return {Roo.menu.Item} The menu item that was added
35135 addElement : function(el){
35136 return this.addItem(new Roo.menu.BaseItem(el));
35140 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35141 * @param {Roo.menu.Item} item The menu item to add
35142 * @return {Roo.menu.Item} The menu item that was added
35144 addItem : function(item){
35145 this.items.add(item);
35147 var li = document.createElement("li");
35148 li.className = "x-menu-list-item";
35149 this.ul.dom.appendChild(li);
35150 item.render(li, this);
35151 this.delayAutoWidth();
35157 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35158 * @param {Object} config A MenuItem config object
35159 * @return {Roo.menu.Item} The menu item that was added
35161 addMenuItem : function(config){
35162 if(!(config instanceof Roo.menu.Item)){
35163 if(typeof config.checked == "boolean"){ // must be check menu item config?
35164 config = new Roo.menu.CheckItem(config);
35166 config = new Roo.menu.Item(config);
35169 return this.addItem(config);
35173 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35174 * @param {String} text The text to display in the menu item
35175 * @return {Roo.menu.Item} The menu item that was added
35177 addText : function(text){
35178 return this.addItem(new Roo.menu.TextItem({ text : text }));
35182 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35183 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35184 * @param {Roo.menu.Item} item The menu item to add
35185 * @return {Roo.menu.Item} The menu item that was added
35187 insert : function(index, item){
35188 this.items.insert(index, item);
35190 var li = document.createElement("li");
35191 li.className = "x-menu-list-item";
35192 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35193 item.render(li, this);
35194 this.delayAutoWidth();
35200 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35201 * @param {Roo.menu.Item} item The menu item to remove
35203 remove : function(item){
35204 this.items.removeKey(item.id);
35209 * Removes and destroys all items in the menu
35211 removeAll : function(){
35213 while(f = this.items.first()){
35219 // MenuNav is a private utility class used internally by the Menu
35220 Roo.menu.MenuNav = function(menu){
35221 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35222 this.scope = this.menu = menu;
35225 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35226 doRelay : function(e, h){
35227 var k = e.getKey();
35228 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35229 this.menu.tryActivate(0, 1);
35232 return h.call(this.scope || this, e, this.menu);
35235 up : function(e, m){
35236 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35237 m.tryActivate(m.items.length-1, -1);
35241 down : function(e, m){
35242 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35243 m.tryActivate(0, 1);
35247 right : function(e, m){
35249 m.activeItem.expandMenu(true);
35253 left : function(e, m){
35255 if(m.parentMenu && m.parentMenu.activeItem){
35256 m.parentMenu.activeItem.activate();
35260 enter : function(e, m){
35262 e.stopPropagation();
35263 m.activeItem.onClick(e);
35264 m.fireEvent("click", this, m.activeItem);
35270 * Ext JS Library 1.1.1
35271 * Copyright(c) 2006-2007, Ext JS, LLC.
35273 * Originally Released Under LGPL - original licence link has changed is not relivant.
35276 * <script type="text/javascript">
35280 * @class Roo.menu.MenuMgr
35281 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35284 Roo.menu.MenuMgr = function(){
35285 var menus, active, groups = {}, attached = false, lastShow = new Date();
35287 // private - called when first menu is created
35290 active = new Roo.util.MixedCollection();
35291 Roo.get(document).addKeyListener(27, function(){
35292 if(active.length > 0){
35299 function hideAll(){
35300 if(active && active.length > 0){
35301 var c = active.clone();
35302 c.each(function(m){
35309 function onHide(m){
35311 if(active.length < 1){
35312 Roo.get(document).un("mousedown", onMouseDown);
35318 function onShow(m){
35319 var last = active.last();
35320 lastShow = new Date();
35323 Roo.get(document).on("mousedown", onMouseDown);
35327 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35328 m.parentMenu.activeChild = m;
35329 }else if(last && last.isVisible()){
35330 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35335 function onBeforeHide(m){
35337 m.activeChild.hide();
35339 if(m.autoHideTimer){
35340 clearTimeout(m.autoHideTimer);
35341 delete m.autoHideTimer;
35346 function onBeforeShow(m){
35347 var pm = m.parentMenu;
35348 if(!pm && !m.allowOtherMenus){
35350 }else if(pm && pm.activeChild && active != m){
35351 pm.activeChild.hide();
35356 function onMouseDown(e){
35357 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
35363 function onBeforeCheck(mi, state){
35365 var g = groups[mi.group];
35366 for(var i = 0, l = g.length; i < l; i++){
35368 g[i].setChecked(false);
35377 * Hides all menus that are currently visible
35379 hideAll : function(){
35384 register : function(menu){
35388 menus[menu.id] = menu;
35389 menu.on("beforehide", onBeforeHide);
35390 menu.on("hide", onHide);
35391 menu.on("beforeshow", onBeforeShow);
35392 menu.on("show", onShow);
35393 var g = menu.group;
35394 if(g && menu.events["checkchange"]){
35398 groups[g].push(menu);
35399 menu.on("checkchange", onCheck);
35404 * Returns a {@link Roo.menu.Menu} object
35405 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
35406 * be used to generate and return a new Menu instance.
35408 get : function(menu){
35409 if(typeof menu == "string"){ // menu id
35410 return menus[menu];
35411 }else if(menu.events){ // menu instance
35413 }else if(typeof menu.length == 'number'){ // array of menu items?
35414 return new Roo.menu.Menu({items:menu});
35415 }else{ // otherwise, must be a config
35416 return new Roo.menu.Menu(menu);
35421 unregister : function(menu){
35422 delete menus[menu.id];
35423 menu.un("beforehide", onBeforeHide);
35424 menu.un("hide", onHide);
35425 menu.un("beforeshow", onBeforeShow);
35426 menu.un("show", onShow);
35427 var g = menu.group;
35428 if(g && menu.events["checkchange"]){
35429 groups[g].remove(menu);
35430 menu.un("checkchange", onCheck);
35435 registerCheckable : function(menuItem){
35436 var g = menuItem.group;
35441 groups[g].push(menuItem);
35442 menuItem.on("beforecheckchange", onBeforeCheck);
35447 unregisterCheckable : function(menuItem){
35448 var g = menuItem.group;
35450 groups[g].remove(menuItem);
35451 menuItem.un("beforecheckchange", onBeforeCheck);
35457 * Ext JS Library 1.1.1
35458 * Copyright(c) 2006-2007, Ext JS, LLC.
35460 * Originally Released Under LGPL - original licence link has changed is not relivant.
35463 * <script type="text/javascript">
35468 * @class Roo.menu.BaseItem
35469 * @extends Roo.Component
35470 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
35471 * management and base configuration options shared by all menu components.
35473 * Creates a new BaseItem
35474 * @param {Object} config Configuration options
35476 Roo.menu.BaseItem = function(config){
35477 Roo.menu.BaseItem.superclass.constructor.call(this, config);
35482 * Fires when this item is clicked
35483 * @param {Roo.menu.BaseItem} this
35484 * @param {Roo.EventObject} e
35489 * Fires when this item is activated
35490 * @param {Roo.menu.BaseItem} this
35494 * @event deactivate
35495 * Fires when this item is deactivated
35496 * @param {Roo.menu.BaseItem} this
35502 this.on("click", this.handler, this.scope, true);
35506 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
35508 * @cfg {Function} handler
35509 * A function that will handle the click event of this menu item (defaults to undefined)
35512 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
35514 canActivate : false,
35517 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
35522 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
35524 activeClass : "x-menu-item-active",
35526 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
35528 hideOnClick : true,
35530 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
35535 ctype: "Roo.menu.BaseItem",
35538 actionMode : "container",
35541 render : function(container, parentMenu){
35542 this.parentMenu = parentMenu;
35543 Roo.menu.BaseItem.superclass.render.call(this, container);
35544 this.container.menuItemId = this.id;
35548 onRender : function(container, position){
35549 this.el = Roo.get(this.el);
35550 container.dom.appendChild(this.el.dom);
35554 onClick : function(e){
35555 if(!this.disabled && this.fireEvent("click", this, e) !== false
35556 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
35557 this.handleClick(e);
35564 activate : function(){
35568 var li = this.container;
35569 li.addClass(this.activeClass);
35570 this.region = li.getRegion().adjust(2, 2, -2, -2);
35571 this.fireEvent("activate", this);
35576 deactivate : function(){
35577 this.container.removeClass(this.activeClass);
35578 this.fireEvent("deactivate", this);
35582 shouldDeactivate : function(e){
35583 return !this.region || !this.region.contains(e.getPoint());
35587 handleClick : function(e){
35588 if(this.hideOnClick){
35589 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
35594 expandMenu : function(autoActivate){
35599 hideMenu : function(){
35604 * Ext JS Library 1.1.1
35605 * Copyright(c) 2006-2007, Ext JS, LLC.
35607 * Originally Released Under LGPL - original licence link has changed is not relivant.
35610 * <script type="text/javascript">
35614 * @class Roo.menu.Adapter
35615 * @extends Roo.menu.BaseItem
35616 * 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.
35617 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
35619 * Creates a new Adapter
35620 * @param {Object} config Configuration options
35622 Roo.menu.Adapter = function(component, config){
35623 Roo.menu.Adapter.superclass.constructor.call(this, config);
35624 this.component = component;
35626 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
35628 canActivate : true,
35631 onRender : function(container, position){
35632 this.component.render(container);
35633 this.el = this.component.getEl();
35637 activate : function(){
35641 this.component.focus();
35642 this.fireEvent("activate", this);
35647 deactivate : function(){
35648 this.fireEvent("deactivate", this);
35652 disable : function(){
35653 this.component.disable();
35654 Roo.menu.Adapter.superclass.disable.call(this);
35658 enable : function(){
35659 this.component.enable();
35660 Roo.menu.Adapter.superclass.enable.call(this);
35664 * Ext JS Library 1.1.1
35665 * Copyright(c) 2006-2007, Ext JS, LLC.
35667 * Originally Released Under LGPL - original licence link has changed is not relivant.
35670 * <script type="text/javascript">
35674 * @class Roo.menu.TextItem
35675 * @extends Roo.menu.BaseItem
35676 * Adds a static text string to a menu, usually used as either a heading or group separator.
35677 * Note: old style constructor with text is still supported.
35680 * Creates a new TextItem
35681 * @param {Object} cfg Configuration
35683 Roo.menu.TextItem = function(cfg){
35684 if (typeof(cfg) == 'string') {
35687 Roo.apply(this,cfg);
35690 Roo.menu.TextItem.superclass.constructor.call(this);
35693 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
35695 * @cfg {Boolean} text Text to show on item.
35700 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35702 hideOnClick : false,
35704 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
35706 itemCls : "x-menu-text",
35709 onRender : function(){
35710 var s = document.createElement("span");
35711 s.className = this.itemCls;
35712 s.innerHTML = this.text;
35714 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
35718 * Ext JS Library 1.1.1
35719 * Copyright(c) 2006-2007, Ext JS, LLC.
35721 * Originally Released Under LGPL - original licence link has changed is not relivant.
35724 * <script type="text/javascript">
35728 * @class Roo.menu.Separator
35729 * @extends Roo.menu.BaseItem
35730 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
35731 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
35733 * @param {Object} config Configuration options
35735 Roo.menu.Separator = function(config){
35736 Roo.menu.Separator.superclass.constructor.call(this, config);
35739 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
35741 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
35743 itemCls : "x-menu-sep",
35745 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35747 hideOnClick : false,
35750 onRender : function(li){
35751 var s = document.createElement("span");
35752 s.className = this.itemCls;
35753 s.innerHTML = " ";
35755 li.addClass("x-menu-sep-li");
35756 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
35760 * Ext JS Library 1.1.1
35761 * Copyright(c) 2006-2007, Ext JS, LLC.
35763 * Originally Released Under LGPL - original licence link has changed is not relivant.
35766 * <script type="text/javascript">
35769 * @class Roo.menu.Item
35770 * @extends Roo.menu.BaseItem
35771 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
35772 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
35773 * activation and click handling.
35775 * Creates a new Item
35776 * @param {Object} config Configuration options
35778 Roo.menu.Item = function(config){
35779 Roo.menu.Item.superclass.constructor.call(this, config);
35781 this.menu = Roo.menu.MenuMgr.get(this.menu);
35784 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
35787 * @cfg {String} text
35788 * The text to show on the menu item.
35792 * @cfg {String} HTML to render in menu
35793 * The text to show on the menu item (HTML version).
35797 * @cfg {String} icon
35798 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
35802 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
35804 itemCls : "x-menu-item",
35806 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
35808 canActivate : true,
35810 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
35813 // doc'd in BaseItem
35817 ctype: "Roo.menu.Item",
35820 onRender : function(container, position){
35821 var el = document.createElement("a");
35822 el.hideFocus = true;
35823 el.unselectable = "on";
35824 el.href = this.href || "#";
35825 if(this.hrefTarget){
35826 el.target = this.hrefTarget;
35828 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
35830 var html = this.html.length ? this.html : String.format('{0}',this.text);
35832 el.innerHTML = String.format(
35833 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
35834 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
35836 Roo.menu.Item.superclass.onRender.call(this, container, position);
35840 * Sets the text to display in this menu item
35841 * @param {String} text The text to display
35842 * @param {Boolean} isHTML true to indicate text is pure html.
35844 setText : function(text, isHTML){
35852 var html = this.html.length ? this.html : String.format('{0}',this.text);
35854 this.el.update(String.format(
35855 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
35856 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
35857 this.parentMenu.autoWidth();
35862 handleClick : function(e){
35863 if(!this.href){ // if no link defined, stop the event automatically
35866 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
35870 activate : function(autoExpand){
35871 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
35881 shouldDeactivate : function(e){
35882 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
35883 if(this.menu && this.menu.isVisible()){
35884 return !this.menu.getEl().getRegion().contains(e.getPoint());
35892 deactivate : function(){
35893 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35898 expandMenu : function(autoActivate){
35899 if(!this.disabled && this.menu){
35900 clearTimeout(this.hideTimer);
35901 delete this.hideTimer;
35902 if(!this.menu.isVisible() && !this.showTimer){
35903 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
35904 }else if (this.menu.isVisible() && autoActivate){
35905 this.menu.tryActivate(0, 1);
35911 deferExpand : function(autoActivate){
35912 delete this.showTimer;
35913 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35915 this.menu.tryActivate(0, 1);
35920 hideMenu : function(){
35921 clearTimeout(this.showTimer);
35922 delete this.showTimer;
35923 if(!this.hideTimer && this.menu && this.menu.isVisible()){
35924 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35929 deferHide : function(){
35930 delete this.hideTimer;
35935 * Ext JS Library 1.1.1
35936 * Copyright(c) 2006-2007, Ext JS, LLC.
35938 * Originally Released Under LGPL - original licence link has changed is not relivant.
35941 * <script type="text/javascript">
35945 * @class Roo.menu.CheckItem
35946 * @extends Roo.menu.Item
35947 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35949 * Creates a new CheckItem
35950 * @param {Object} config Configuration options
35952 Roo.menu.CheckItem = function(config){
35953 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35956 * @event beforecheckchange
35957 * Fires before the checked value is set, providing an opportunity to cancel if needed
35958 * @param {Roo.menu.CheckItem} this
35959 * @param {Boolean} checked The new checked value that will be set
35961 "beforecheckchange" : true,
35963 * @event checkchange
35964 * Fires after the checked value has been set
35965 * @param {Roo.menu.CheckItem} this
35966 * @param {Boolean} checked The checked value that was set
35968 "checkchange" : true
35970 if(this.checkHandler){
35971 this.on('checkchange', this.checkHandler, this.scope);
35974 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35976 * @cfg {String} group
35977 * All check items with the same group name will automatically be grouped into a single-select
35978 * radio button group (defaults to '')
35981 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35983 itemCls : "x-menu-item x-menu-check-item",
35985 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35987 groupClass : "x-menu-group-item",
35990 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35991 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35992 * initialized with checked = true will be rendered as checked.
35997 ctype: "Roo.menu.CheckItem",
36000 onRender : function(c){
36001 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36003 this.el.addClass(this.groupClass);
36005 Roo.menu.MenuMgr.registerCheckable(this);
36007 this.checked = false;
36008 this.setChecked(true, true);
36013 destroy : function(){
36015 Roo.menu.MenuMgr.unregisterCheckable(this);
36017 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36021 * Set the checked state of this item
36022 * @param {Boolean} checked The new checked value
36023 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36025 setChecked : function(state, suppressEvent){
36026 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36027 if(this.container){
36028 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36030 this.checked = state;
36031 if(suppressEvent !== true){
36032 this.fireEvent("checkchange", this, state);
36038 handleClick : function(e){
36039 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36040 this.setChecked(!this.checked);
36042 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36046 * Ext JS Library 1.1.1
36047 * Copyright(c) 2006-2007, Ext JS, LLC.
36049 * Originally Released Under LGPL - original licence link has changed is not relivant.
36052 * <script type="text/javascript">
36056 * @class Roo.menu.DateItem
36057 * @extends Roo.menu.Adapter
36058 * A menu item that wraps the {@link Roo.DatPicker} component.
36060 * Creates a new DateItem
36061 * @param {Object} config Configuration options
36063 Roo.menu.DateItem = function(config){
36064 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36065 /** The Roo.DatePicker object @type Roo.DatePicker */
36066 this.picker = this.component;
36067 this.addEvents({select: true});
36069 this.picker.on("render", function(picker){
36070 picker.getEl().swallowEvent("click");
36071 picker.container.addClass("x-menu-date-item");
36074 this.picker.on("select", this.onSelect, this);
36077 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36079 onSelect : function(picker, date){
36080 this.fireEvent("select", this, date, picker);
36081 Roo.menu.DateItem.superclass.handleClick.call(this);
36085 * Ext JS Library 1.1.1
36086 * Copyright(c) 2006-2007, Ext JS, LLC.
36088 * Originally Released Under LGPL - original licence link has changed is not relivant.
36091 * <script type="text/javascript">
36095 * @class Roo.menu.ColorItem
36096 * @extends Roo.menu.Adapter
36097 * A menu item that wraps the {@link Roo.ColorPalette} component.
36099 * Creates a new ColorItem
36100 * @param {Object} config Configuration options
36102 Roo.menu.ColorItem = function(config){
36103 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36104 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36105 this.palette = this.component;
36106 this.relayEvents(this.palette, ["select"]);
36107 if(this.selectHandler){
36108 this.on('select', this.selectHandler, this.scope);
36111 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36113 * Ext JS Library 1.1.1
36114 * Copyright(c) 2006-2007, Ext JS, LLC.
36116 * Originally Released Under LGPL - original licence link has changed is not relivant.
36119 * <script type="text/javascript">
36124 * @class Roo.menu.DateMenu
36125 * @extends Roo.menu.Menu
36126 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36128 * Creates a new DateMenu
36129 * @param {Object} config Configuration options
36131 Roo.menu.DateMenu = function(config){
36132 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36134 var di = new Roo.menu.DateItem(config);
36137 * The {@link Roo.DatePicker} instance for this DateMenu
36140 this.picker = di.picker;
36143 * @param {DatePicker} picker
36144 * @param {Date} date
36146 this.relayEvents(di, ["select"]);
36147 this.on('beforeshow', function(){
36149 this.picker.hideMonthPicker(false);
36153 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36157 * Ext JS Library 1.1.1
36158 * Copyright(c) 2006-2007, Ext JS, LLC.
36160 * Originally Released Under LGPL - original licence link has changed is not relivant.
36163 * <script type="text/javascript">
36168 * @class Roo.menu.ColorMenu
36169 * @extends Roo.menu.Menu
36170 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36172 * Creates a new ColorMenu
36173 * @param {Object} config Configuration options
36175 Roo.menu.ColorMenu = function(config){
36176 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36178 var ci = new Roo.menu.ColorItem(config);
36181 * The {@link Roo.ColorPalette} instance for this ColorMenu
36182 * @type ColorPalette
36184 this.palette = ci.palette;
36187 * @param {ColorPalette} palette
36188 * @param {String} color
36190 this.relayEvents(ci, ["select"]);
36192 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36194 * Ext JS Library 1.1.1
36195 * Copyright(c) 2006-2007, Ext JS, LLC.
36197 * Originally Released Under LGPL - original licence link has changed is not relivant.
36200 * <script type="text/javascript">
36204 * @class Roo.form.Field
36205 * @extends Roo.BoxComponent
36206 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36208 * Creates a new Field
36209 * @param {Object} config Configuration options
36211 Roo.form.Field = function(config){
36212 Roo.form.Field.superclass.constructor.call(this, config);
36215 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36217 * @cfg {String} fieldLabel Label to use when rendering a form.
36220 * @cfg {String} qtip Mouse over tip
36224 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36226 invalidClass : "x-form-invalid",
36228 * @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")
36230 invalidText : "The value in this field is invalid",
36232 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36234 focusClass : "x-form-focus",
36236 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36237 automatic validation (defaults to "keyup").
36239 validationEvent : "keyup",
36241 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36243 validateOnBlur : true,
36245 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36247 validationDelay : 250,
36249 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36250 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36252 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36254 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36256 fieldClass : "x-form-field",
36258 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36261 ----------- ----------------------------------------------------------------------
36262 qtip Display a quick tip when the user hovers over the field
36263 title Display a default browser title attribute popup
36264 under Add a block div beneath the field containing the error text
36265 side Add an error icon to the right of the field with a popup on hover
36266 [element id] Add the error text directly to the innerHTML of the specified element
36269 msgTarget : 'qtip',
36271 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36276 * @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.
36281 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36286 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36288 inputType : undefined,
36291 * @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).
36293 tabIndex : undefined,
36296 isFormField : true,
36301 * @property {Roo.Element} fieldEl
36302 * Element Containing the rendered Field (with label etc.)
36305 * @cfg {Mixed} value A value to initialize this field with.
36310 * @cfg {String} name The field's HTML name attribute.
36313 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36317 initComponent : function(){
36318 Roo.form.Field.superclass.initComponent.call(this);
36322 * Fires when this field receives input focus.
36323 * @param {Roo.form.Field} this
36328 * Fires when this field loses input focus.
36329 * @param {Roo.form.Field} this
36333 * @event specialkey
36334 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36335 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36336 * @param {Roo.form.Field} this
36337 * @param {Roo.EventObject} e The event object
36342 * Fires just before the field blurs if the field value has changed.
36343 * @param {Roo.form.Field} this
36344 * @param {Mixed} newValue The new value
36345 * @param {Mixed} oldValue The original value
36350 * Fires after the field has been marked as invalid.
36351 * @param {Roo.form.Field} this
36352 * @param {String} msg The validation message
36357 * Fires after the field has been validated with no errors.
36358 * @param {Roo.form.Field} this
36363 * Fires after the key up
36364 * @param {Roo.form.Field} this
36365 * @param {Roo.EventObject} e The event Object
36372 * Returns the name attribute of the field if available
36373 * @return {String} name The field name
36375 getName: function(){
36376 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
36380 onRender : function(ct, position){
36381 Roo.form.Field.superclass.onRender.call(this, ct, position);
36383 var cfg = this.getAutoCreate();
36385 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
36387 if (!cfg.name.length) {
36390 if(this.inputType){
36391 cfg.type = this.inputType;
36393 this.el = ct.createChild(cfg, position);
36395 var type = this.el.dom.type;
36397 if(type == 'password'){
36400 this.el.addClass('x-form-'+type);
36403 this.el.dom.readOnly = true;
36405 if(this.tabIndex !== undefined){
36406 this.el.dom.setAttribute('tabIndex', this.tabIndex);
36409 this.el.addClass([this.fieldClass, this.cls]);
36414 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
36415 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
36416 * @return {Roo.form.Field} this
36418 applyTo : function(target){
36419 this.allowDomMove = false;
36420 this.el = Roo.get(target);
36421 this.render(this.el.dom.parentNode);
36426 initValue : function(){
36427 if(this.value !== undefined){
36428 this.setValue(this.value);
36429 }else if(this.el.dom.value.length > 0){
36430 this.setValue(this.el.dom.value);
36435 * Returns true if this field has been changed since it was originally loaded and is not disabled.
36437 isDirty : function() {
36438 if(this.disabled) {
36441 return String(this.getValue()) !== String(this.originalValue);
36445 afterRender : function(){
36446 Roo.form.Field.superclass.afterRender.call(this);
36451 fireKey : function(e){
36452 //Roo.log('field ' + e.getKey());
36453 if(e.isNavKeyPress()){
36454 this.fireEvent("specialkey", this, e);
36459 * Resets the current field value to the originally loaded value and clears any validation messages
36461 reset : function(){
36462 this.setValue(this.originalValue);
36463 this.clearInvalid();
36467 initEvents : function(){
36468 // safari killled keypress - so keydown is now used..
36469 this.el.on("keydown" , this.fireKey, this);
36470 this.el.on("focus", this.onFocus, this);
36471 this.el.on("blur", this.onBlur, this);
36472 this.el.relayEvent('keyup', this);
36474 // reference to original value for reset
36475 this.originalValue = this.getValue();
36479 onFocus : function(){
36480 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
36481 this.el.addClass(this.focusClass);
36483 if(!this.hasFocus){
36484 this.hasFocus = true;
36485 this.startValue = this.getValue();
36486 this.fireEvent("focus", this);
36490 beforeBlur : Roo.emptyFn,
36493 onBlur : function(){
36495 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
36496 this.el.removeClass(this.focusClass);
36498 this.hasFocus = false;
36499 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
36502 var v = this.getValue();
36503 if(String(v) !== String(this.startValue)){
36504 this.fireEvent('change', this, v, this.startValue);
36506 this.fireEvent("blur", this);
36510 * Returns whether or not the field value is currently valid
36511 * @param {Boolean} preventMark True to disable marking the field invalid
36512 * @return {Boolean} True if the value is valid, else false
36514 isValid : function(preventMark){
36518 var restore = this.preventMark;
36519 this.preventMark = preventMark === true;
36520 var v = this.validateValue(this.processValue(this.getRawValue()));
36521 this.preventMark = restore;
36526 * Validates the field value
36527 * @return {Boolean} True if the value is valid, else false
36529 validate : function(){
36530 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
36531 this.clearInvalid();
36537 processValue : function(value){
36542 // Subclasses should provide the validation implementation by overriding this
36543 validateValue : function(value){
36548 * Mark this field as invalid
36549 * @param {String} msg The validation message
36551 markInvalid : function(msg){
36552 if(!this.rendered || this.preventMark){ // not rendered
36555 this.el.addClass(this.invalidClass);
36556 msg = msg || this.invalidText;
36557 switch(this.msgTarget){
36559 this.el.dom.qtip = msg;
36560 this.el.dom.qclass = 'x-form-invalid-tip';
36561 if(Roo.QuickTips){ // fix for floating editors interacting with DND
36562 Roo.QuickTips.enable();
36566 this.el.dom.title = msg;
36570 var elp = this.el.findParent('.x-form-element', 5, true);
36571 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
36572 this.errorEl.setWidth(elp.getWidth(true)-20);
36574 this.errorEl.update(msg);
36575 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
36578 if(!this.errorIcon){
36579 var elp = this.el.findParent('.x-form-element', 5, true);
36580 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
36582 this.alignErrorIcon();
36583 this.errorIcon.dom.qtip = msg;
36584 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
36585 this.errorIcon.show();
36586 this.on('resize', this.alignErrorIcon, this);
36589 var t = Roo.getDom(this.msgTarget);
36591 t.style.display = this.msgDisplay;
36594 this.fireEvent('invalid', this, msg);
36598 alignErrorIcon : function(){
36599 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
36603 * Clear any invalid styles/messages for this field
36605 clearInvalid : function(){
36606 if(!this.rendered || this.preventMark){ // not rendered
36609 this.el.removeClass(this.invalidClass);
36610 switch(this.msgTarget){
36612 this.el.dom.qtip = '';
36615 this.el.dom.title = '';
36619 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
36623 if(this.errorIcon){
36624 this.errorIcon.dom.qtip = '';
36625 this.errorIcon.hide();
36626 this.un('resize', this.alignErrorIcon, this);
36630 var t = Roo.getDom(this.msgTarget);
36632 t.style.display = 'none';
36635 this.fireEvent('valid', this);
36639 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
36640 * @return {Mixed} value The field value
36642 getRawValue : function(){
36643 var v = this.el.getValue();
36649 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
36650 * @return {Mixed} value The field value
36652 getValue : function(){
36653 var v = this.el.getValue();
36659 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
36660 * @param {Mixed} value The value to set
36662 setRawValue : function(v){
36663 return this.el.dom.value = (v === null || v === undefined ? '' : v);
36667 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
36668 * @param {Mixed} value The value to set
36670 setValue : function(v){
36673 this.el.dom.value = (v === null || v === undefined ? '' : v);
36678 adjustSize : function(w, h){
36679 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
36680 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
36684 adjustWidth : function(tag, w){
36685 tag = tag.toLowerCase();
36686 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
36687 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
36688 if(tag == 'input'){
36691 if(tag == 'textarea'){
36694 }else if(Roo.isOpera){
36695 if(tag == 'input'){
36698 if(tag == 'textarea'){
36708 // anything other than normal should be considered experimental
36709 Roo.form.Field.msgFx = {
36711 show: function(msgEl, f){
36712 msgEl.setDisplayed('block');
36715 hide : function(msgEl, f){
36716 msgEl.setDisplayed(false).update('');
36721 show: function(msgEl, f){
36722 msgEl.slideIn('t', {stopFx:true});
36725 hide : function(msgEl, f){
36726 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
36731 show: function(msgEl, f){
36732 msgEl.fixDisplay();
36733 msgEl.alignTo(f.el, 'tl-tr');
36734 msgEl.slideIn('l', {stopFx:true});
36737 hide : function(msgEl, f){
36738 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
36743 * Ext JS Library 1.1.1
36744 * Copyright(c) 2006-2007, Ext JS, LLC.
36746 * Originally Released Under LGPL - original licence link has changed is not relivant.
36749 * <script type="text/javascript">
36754 * @class Roo.form.TextField
36755 * @extends Roo.form.Field
36756 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
36757 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
36759 * Creates a new TextField
36760 * @param {Object} config Configuration options
36762 Roo.form.TextField = function(config){
36763 Roo.form.TextField.superclass.constructor.call(this, config);
36767 * Fires when the autosize function is triggered. The field may or may not have actually changed size
36768 * according to the default logic, but this event provides a hook for the developer to apply additional
36769 * logic at runtime to resize the field if needed.
36770 * @param {Roo.form.Field} this This text field
36771 * @param {Number} width The new field width
36777 Roo.extend(Roo.form.TextField, Roo.form.Field, {
36779 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
36783 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
36787 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
36791 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
36795 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
36799 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
36801 disableKeyFilter : false,
36803 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
36807 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
36811 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
36813 maxLength : Number.MAX_VALUE,
36815 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
36817 minLengthText : "The minimum length for this field is {0}",
36819 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
36821 maxLengthText : "The maximum length for this field is {0}",
36823 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
36825 selectOnFocus : false,
36827 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
36829 blankText : "This field is required",
36831 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
36832 * If available, this function will be called only after the basic validators all return true, and will be passed the
36833 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
36837 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
36838 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
36839 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
36843 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
36847 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
36853 initEvents : function()
36855 if (this.emptyText) {
36856 this.el.attr('placeholder', this.emptyText);
36859 Roo.form.TextField.superclass.initEvents.call(this);
36860 if(this.validationEvent == 'keyup'){
36861 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
36862 this.el.on('keyup', this.filterValidation, this);
36864 else if(this.validationEvent !== false){
36865 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
36868 if(this.selectOnFocus){
36869 this.on("focus", this.preFocus, this);
36872 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
36873 this.el.on("keypress", this.filterKeys, this);
36876 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
36877 this.el.on("click", this.autoSize, this);
36879 if(this.el.is('input[type=password]') && Roo.isSafari){
36880 this.el.on('keydown', this.SafariOnKeyDown, this);
36884 processValue : function(value){
36885 if(this.stripCharsRe){
36886 var newValue = value.replace(this.stripCharsRe, '');
36887 if(newValue !== value){
36888 this.setRawValue(newValue);
36895 filterValidation : function(e){
36896 if(!e.isNavKeyPress()){
36897 this.validationTask.delay(this.validationDelay);
36902 onKeyUp : function(e){
36903 if(!e.isNavKeyPress()){
36909 * Resets the current field value to the originally-loaded value and clears any validation messages.
36912 reset : function(){
36913 Roo.form.TextField.superclass.reset.call(this);
36919 preFocus : function(){
36921 if(this.selectOnFocus){
36922 this.el.dom.select();
36928 filterKeys : function(e){
36929 var k = e.getKey();
36930 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36933 var c = e.getCharCode(), cc = String.fromCharCode(c);
36934 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36937 if(!this.maskRe.test(cc)){
36942 setValue : function(v){
36944 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36950 * Validates a value according to the field's validation rules and marks the field as invalid
36951 * if the validation fails
36952 * @param {Mixed} value The value to validate
36953 * @return {Boolean} True if the value is valid, else false
36955 validateValue : function(value){
36956 if(value.length < 1) { // if it's blank
36957 if(this.allowBlank){
36958 this.clearInvalid();
36961 this.markInvalid(this.blankText);
36965 if(value.length < this.minLength){
36966 this.markInvalid(String.format(this.minLengthText, this.minLength));
36969 if(value.length > this.maxLength){
36970 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36974 var vt = Roo.form.VTypes;
36975 if(!vt[this.vtype](value, this)){
36976 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36980 if(typeof this.validator == "function"){
36981 var msg = this.validator(value);
36983 this.markInvalid(msg);
36987 if(this.regex && !this.regex.test(value)){
36988 this.markInvalid(this.regexText);
36995 * Selects text in this field
36996 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36997 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36999 selectText : function(start, end){
37000 var v = this.getRawValue();
37002 start = start === undefined ? 0 : start;
37003 end = end === undefined ? v.length : end;
37004 var d = this.el.dom;
37005 if(d.setSelectionRange){
37006 d.setSelectionRange(start, end);
37007 }else if(d.createTextRange){
37008 var range = d.createTextRange();
37009 range.moveStart("character", start);
37010 range.moveEnd("character", v.length-end);
37017 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37018 * This only takes effect if grow = true, and fires the autosize event.
37020 autoSize : function(){
37021 if(!this.grow || !this.rendered){
37025 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37028 var v = el.dom.value;
37029 var d = document.createElement('div');
37030 d.appendChild(document.createTextNode(v));
37034 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37035 this.el.setWidth(w);
37036 this.fireEvent("autosize", this, w);
37040 SafariOnKeyDown : function(event)
37042 // this is a workaround for a password hang bug on chrome/ webkit.
37044 var isSelectAll = false;
37046 if(this.el.dom.selectionEnd > 0){
37047 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37049 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37050 event.preventDefault();
37055 if(isSelectAll){ // backspace and delete key
37057 event.preventDefault();
37058 // this is very hacky as keydown always get's upper case.
37060 var cc = String.fromCharCode(event.getCharCode());
37061 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37069 * Ext JS Library 1.1.1
37070 * Copyright(c) 2006-2007, Ext JS, LLC.
37072 * Originally Released Under LGPL - original licence link has changed is not relivant.
37075 * <script type="text/javascript">
37079 * @class Roo.form.Hidden
37080 * @extends Roo.form.TextField
37081 * Simple Hidden element used on forms
37083 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37086 * Creates a new Hidden form element.
37087 * @param {Object} config Configuration options
37092 // easy hidden field...
37093 Roo.form.Hidden = function(config){
37094 Roo.form.Hidden.superclass.constructor.call(this, config);
37097 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37099 inputType: 'hidden',
37102 labelSeparator: '',
37104 itemCls : 'x-form-item-display-none'
37112 * Ext JS Library 1.1.1
37113 * Copyright(c) 2006-2007, Ext JS, LLC.
37115 * Originally Released Under LGPL - original licence link has changed is not relivant.
37118 * <script type="text/javascript">
37122 * @class Roo.form.TriggerField
37123 * @extends Roo.form.TextField
37124 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37125 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37126 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37127 * for which you can provide a custom implementation. For example:
37129 var trigger = new Roo.form.TriggerField();
37130 trigger.onTriggerClick = myTriggerFn;
37131 trigger.applyTo('my-field');
37134 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37135 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37136 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37137 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37139 * Create a new TriggerField.
37140 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37141 * to the base TextField)
37143 Roo.form.TriggerField = function(config){
37144 this.mimicing = false;
37145 Roo.form.TriggerField.superclass.constructor.call(this, config);
37148 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37150 * @cfg {String} triggerClass A CSS class to apply to the trigger
37153 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37154 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37156 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37158 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37162 /** @cfg {Boolean} grow @hide */
37163 /** @cfg {Number} growMin @hide */
37164 /** @cfg {Number} growMax @hide */
37170 autoSize: Roo.emptyFn,
37174 deferHeight : true,
37177 actionMode : 'wrap',
37179 onResize : function(w, h){
37180 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37181 if(typeof w == 'number'){
37182 var x = w - this.trigger.getWidth();
37183 this.el.setWidth(this.adjustWidth('input', x));
37184 this.trigger.setStyle('left', x+'px');
37189 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37192 getResizeEl : function(){
37197 getPositionEl : function(){
37202 alignErrorIcon : function(){
37203 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37207 onRender : function(ct, position){
37208 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37209 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37210 this.trigger = this.wrap.createChild(this.triggerConfig ||
37211 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37212 if(this.hideTrigger){
37213 this.trigger.setDisplayed(false);
37215 this.initTrigger();
37217 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37222 initTrigger : function(){
37223 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37224 this.trigger.addClassOnOver('x-form-trigger-over');
37225 this.trigger.addClassOnClick('x-form-trigger-click');
37229 onDestroy : function(){
37231 this.trigger.removeAllListeners();
37232 this.trigger.remove();
37235 this.wrap.remove();
37237 Roo.form.TriggerField.superclass.onDestroy.call(this);
37241 onFocus : function(){
37242 Roo.form.TriggerField.superclass.onFocus.call(this);
37243 if(!this.mimicing){
37244 this.wrap.addClass('x-trigger-wrap-focus');
37245 this.mimicing = true;
37246 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37247 if(this.monitorTab){
37248 this.el.on("keydown", this.checkTab, this);
37254 checkTab : function(e){
37255 if(e.getKey() == e.TAB){
37256 this.triggerBlur();
37261 onBlur : function(){
37266 mimicBlur : function(e, t){
37267 if(!this.wrap.contains(t) && this.validateBlur()){
37268 this.triggerBlur();
37273 triggerBlur : function(){
37274 this.mimicing = false;
37275 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37276 if(this.monitorTab){
37277 this.el.un("keydown", this.checkTab, this);
37279 this.wrap.removeClass('x-trigger-wrap-focus');
37280 Roo.form.TriggerField.superclass.onBlur.call(this);
37284 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37285 validateBlur : function(e, t){
37290 onDisable : function(){
37291 Roo.form.TriggerField.superclass.onDisable.call(this);
37293 this.wrap.addClass('x-item-disabled');
37298 onEnable : function(){
37299 Roo.form.TriggerField.superclass.onEnable.call(this);
37301 this.wrap.removeClass('x-item-disabled');
37306 onShow : function(){
37307 var ae = this.getActionEl();
37310 ae.dom.style.display = '';
37311 ae.dom.style.visibility = 'visible';
37317 onHide : function(){
37318 var ae = this.getActionEl();
37319 ae.dom.style.display = 'none';
37323 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37324 * by an implementing function.
37326 * @param {EventObject} e
37328 onTriggerClick : Roo.emptyFn
37331 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37332 // to be extended by an implementing class. For an example of implementing this class, see the custom
37333 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37334 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37335 initComponent : function(){
37336 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37338 this.triggerConfig = {
37339 tag:'span', cls:'x-form-twin-triggers', cn:[
37340 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37341 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
37345 getTrigger : function(index){
37346 return this.triggers[index];
37349 initTrigger : function(){
37350 var ts = this.trigger.select('.x-form-trigger', true);
37351 this.wrap.setStyle('overflow', 'hidden');
37352 var triggerField = this;
37353 ts.each(function(t, all, index){
37354 t.hide = function(){
37355 var w = triggerField.wrap.getWidth();
37356 this.dom.style.display = 'none';
37357 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37359 t.show = function(){
37360 var w = triggerField.wrap.getWidth();
37361 this.dom.style.display = '';
37362 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37364 var triggerIndex = 'Trigger'+(index+1);
37366 if(this['hide'+triggerIndex]){
37367 t.dom.style.display = 'none';
37369 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
37370 t.addClassOnOver('x-form-trigger-over');
37371 t.addClassOnClick('x-form-trigger-click');
37373 this.triggers = ts.elements;
37376 onTrigger1Click : Roo.emptyFn,
37377 onTrigger2Click : Roo.emptyFn
37380 * Ext JS Library 1.1.1
37381 * Copyright(c) 2006-2007, Ext JS, LLC.
37383 * Originally Released Under LGPL - original licence link has changed is not relivant.
37386 * <script type="text/javascript">
37390 * @class Roo.form.TextArea
37391 * @extends Roo.form.TextField
37392 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
37393 * support for auto-sizing.
37395 * Creates a new TextArea
37396 * @param {Object} config Configuration options
37398 Roo.form.TextArea = function(config){
37399 Roo.form.TextArea.superclass.constructor.call(this, config);
37400 // these are provided exchanges for backwards compat
37401 // minHeight/maxHeight were replaced by growMin/growMax to be
37402 // compatible with TextField growing config values
37403 if(this.minHeight !== undefined){
37404 this.growMin = this.minHeight;
37406 if(this.maxHeight !== undefined){
37407 this.growMax = this.maxHeight;
37411 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
37413 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
37417 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
37421 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
37422 * in the field (equivalent to setting overflow: hidden, defaults to false)
37424 preventScrollbars: false,
37426 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37427 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
37431 onRender : function(ct, position){
37433 this.defaultAutoCreate = {
37435 style:"width:300px;height:60px;",
37436 autocomplete: "off"
37439 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
37441 this.textSizeEl = Roo.DomHelper.append(document.body, {
37442 tag: "pre", cls: "x-form-grow-sizer"
37444 if(this.preventScrollbars){
37445 this.el.setStyle("overflow", "hidden");
37447 this.el.setHeight(this.growMin);
37451 onDestroy : function(){
37452 if(this.textSizeEl){
37453 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
37455 Roo.form.TextArea.superclass.onDestroy.call(this);
37459 onKeyUp : function(e){
37460 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
37466 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
37467 * This only takes effect if grow = true, and fires the autosize event if the height changes.
37469 autoSize : function(){
37470 if(!this.grow || !this.textSizeEl){
37474 var v = el.dom.value;
37475 var ts = this.textSizeEl;
37478 ts.appendChild(document.createTextNode(v));
37481 Roo.fly(ts).setWidth(this.el.getWidth());
37483 v = "  ";
37486 v = v.replace(/\n/g, '<p> </p>');
37488 v += " \n ";
37491 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
37492 if(h != this.lastHeight){
37493 this.lastHeight = h;
37494 this.el.setHeight(h);
37495 this.fireEvent("autosize", this, h);
37500 * Ext JS Library 1.1.1
37501 * Copyright(c) 2006-2007, Ext JS, LLC.
37503 * Originally Released Under LGPL - original licence link has changed is not relivant.
37506 * <script type="text/javascript">
37511 * @class Roo.form.NumberField
37512 * @extends Roo.form.TextField
37513 * Numeric text field that provides automatic keystroke filtering and numeric validation.
37515 * Creates a new NumberField
37516 * @param {Object} config Configuration options
37518 Roo.form.NumberField = function(config){
37519 Roo.form.NumberField.superclass.constructor.call(this, config);
37522 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
37524 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
37526 fieldClass: "x-form-field x-form-num-field",
37528 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
37530 allowDecimals : true,
37532 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
37534 decimalSeparator : ".",
37536 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
37538 decimalPrecision : 2,
37540 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
37542 allowNegative : true,
37544 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
37546 minValue : Number.NEGATIVE_INFINITY,
37548 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
37550 maxValue : Number.MAX_VALUE,
37552 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
37554 minText : "The minimum value for this field is {0}",
37556 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
37558 maxText : "The maximum value for this field is {0}",
37560 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
37561 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
37563 nanText : "{0} is not a valid number",
37566 initEvents : function(){
37567 Roo.form.NumberField.superclass.initEvents.call(this);
37568 var allowed = "0123456789";
37569 if(this.allowDecimals){
37570 allowed += this.decimalSeparator;
37572 if(this.allowNegative){
37575 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
37576 var keyPress = function(e){
37577 var k = e.getKey();
37578 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
37581 var c = e.getCharCode();
37582 if(allowed.indexOf(String.fromCharCode(c)) === -1){
37586 this.el.on("keypress", keyPress, this);
37590 validateValue : function(value){
37591 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
37594 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37597 var num = this.parseValue(value);
37599 this.markInvalid(String.format(this.nanText, value));
37602 if(num < this.minValue){
37603 this.markInvalid(String.format(this.minText, this.minValue));
37606 if(num > this.maxValue){
37607 this.markInvalid(String.format(this.maxText, this.maxValue));
37613 getValue : function(){
37614 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
37618 parseValue : function(value){
37619 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
37620 return isNaN(value) ? '' : value;
37624 fixPrecision : function(value){
37625 var nan = isNaN(value);
37626 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
37627 return nan ? '' : value;
37629 return parseFloat(value).toFixed(this.decimalPrecision);
37632 setValue : function(v){
37633 v = this.fixPrecision(v);
37634 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
37638 decimalPrecisionFcn : function(v){
37639 return Math.floor(v);
37642 beforeBlur : function(){
37643 var v = this.parseValue(this.getRawValue());
37650 * Ext JS Library 1.1.1
37651 * Copyright(c) 2006-2007, Ext JS, LLC.
37653 * Originally Released Under LGPL - original licence link has changed is not relivant.
37656 * <script type="text/javascript">
37660 * @class Roo.form.DateField
37661 * @extends Roo.form.TriggerField
37662 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
37664 * Create a new DateField
37665 * @param {Object} config
37667 Roo.form.DateField = function(config){
37668 Roo.form.DateField.superclass.constructor.call(this, config);
37674 * Fires when a date is selected
37675 * @param {Roo.form.DateField} combo This combo box
37676 * @param {Date} date The date selected
37683 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
37684 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
37685 this.ddMatch = null;
37686 if(this.disabledDates){
37687 var dd = this.disabledDates;
37689 for(var i = 0; i < dd.length; i++){
37691 if(i != dd.length-1) re += "|";
37693 this.ddMatch = new RegExp(re + ")");
37697 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
37699 * @cfg {String} format
37700 * The default date format string which can be overriden for localization support. The format must be
37701 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
37705 * @cfg {String} altFormats
37706 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
37707 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
37709 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
37711 * @cfg {Array} disabledDays
37712 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
37714 disabledDays : null,
37716 * @cfg {String} disabledDaysText
37717 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
37719 disabledDaysText : "Disabled",
37721 * @cfg {Array} disabledDates
37722 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
37723 * expression so they are very powerful. Some examples:
37725 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
37726 * <li>["03/08", "09/16"] would disable those days for every year</li>
37727 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
37728 * <li>["03/../2006"] would disable every day in March 2006</li>
37729 * <li>["^03"] would disable every day in every March</li>
37731 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
37732 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
37734 disabledDates : null,
37736 * @cfg {String} disabledDatesText
37737 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
37739 disabledDatesText : "Disabled",
37741 * @cfg {Date/String} minValue
37742 * The minimum allowed date. Can be either a Javascript date object or a string date in a
37743 * valid format (defaults to null).
37747 * @cfg {Date/String} maxValue
37748 * The maximum allowed date. Can be either a Javascript date object or a string date in a
37749 * valid format (defaults to null).
37753 * @cfg {String} minText
37754 * The error text to display when the date in the cell is before minValue (defaults to
37755 * 'The date in this field must be after {minValue}').
37757 minText : "The date in this field must be equal to or after {0}",
37759 * @cfg {String} maxText
37760 * The error text to display when the date in the cell is after maxValue (defaults to
37761 * 'The date in this field must be before {maxValue}').
37763 maxText : "The date in this field must be equal to or before {0}",
37765 * @cfg {String} invalidText
37766 * The error text to display when the date in the field is invalid (defaults to
37767 * '{value} is not a valid date - it must be in the format {format}').
37769 invalidText : "{0} is not a valid date - it must be in the format {1}",
37771 * @cfg {String} triggerClass
37772 * An additional CSS class used to style the trigger button. The trigger will always get the
37773 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
37774 * which displays a calendar icon).
37776 triggerClass : 'x-form-date-trigger',
37780 * @cfg {Boolean} useIso
37781 * if enabled, then the date field will use a hidden field to store the
37782 * real value as iso formated date. default (false)
37786 * @cfg {String/Object} autoCreate
37787 * A DomHelper element spec, or true for a default element spec (defaults to
37788 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
37791 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
37794 hiddenField: false,
37796 onRender : function(ct, position)
37798 Roo.form.DateField.superclass.onRender.call(this, ct, position);
37800 //this.el.dom.removeAttribute('name');
37801 Roo.log("Changing name?");
37802 this.el.dom.setAttribute('name', this.name + '____hidden___' );
37803 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
37805 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
37806 // prevent input submission
37807 this.hiddenName = this.name;
37814 validateValue : function(value)
37816 value = this.formatDate(value);
37817 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
37818 Roo.log('super failed');
37821 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37824 var svalue = value;
37825 value = this.parseDate(value);
37827 Roo.log('parse date failed' + svalue);
37828 this.markInvalid(String.format(this.invalidText, svalue, this.format));
37831 var time = value.getTime();
37832 if(this.minValue && time < this.minValue.getTime()){
37833 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
37836 if(this.maxValue && time > this.maxValue.getTime()){
37837 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
37840 if(this.disabledDays){
37841 var day = value.getDay();
37842 for(var i = 0; i < this.disabledDays.length; i++) {
37843 if(day === this.disabledDays[i]){
37844 this.markInvalid(this.disabledDaysText);
37849 var fvalue = this.formatDate(value);
37850 if(this.ddMatch && this.ddMatch.test(fvalue)){
37851 this.markInvalid(String.format(this.disabledDatesText, fvalue));
37858 // Provides logic to override the default TriggerField.validateBlur which just returns true
37859 validateBlur : function(){
37860 return !this.menu || !this.menu.isVisible();
37863 getName: function()
37865 // returns hidden if it's set..
37866 if (!this.rendered) {return ''};
37867 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37872 * Returns the current date value of the date field.
37873 * @return {Date} The date value
37875 getValue : function(){
37877 return this.hiddenField ?
37878 this.hiddenField.value :
37879 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
37883 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
37884 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
37885 * (the default format used is "m/d/y").
37888 //All of these calls set the same date value (May 4, 2006)
37890 //Pass a date object:
37891 var dt = new Date('5/4/06');
37892 dateField.setValue(dt);
37894 //Pass a date string (default format):
37895 dateField.setValue('5/4/06');
37897 //Pass a date string (custom format):
37898 dateField.format = 'Y-m-d';
37899 dateField.setValue('2006-5-4');
37901 * @param {String/Date} date The date or valid date string
37903 setValue : function(date){
37904 if (this.hiddenField) {
37905 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
37907 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
37908 // make sure the value field is always stored as a date..
37909 this.value = this.parseDate(date);
37915 parseDate : function(value){
37916 if(!value || value instanceof Date){
37919 var v = Date.parseDate(value, this.format);
37920 if (!v && this.useIso) {
37921 v = Date.parseDate(value, 'Y-m-d');
37923 if(!v && this.altFormats){
37924 if(!this.altFormatsArray){
37925 this.altFormatsArray = this.altFormats.split("|");
37927 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
37928 v = Date.parseDate(value, this.altFormatsArray[i]);
37935 formatDate : function(date, fmt){
37936 return (!date || !(date instanceof Date)) ?
37937 date : date.dateFormat(fmt || this.format);
37942 select: function(m, d){
37945 this.fireEvent('select', this, d);
37947 show : function(){ // retain focus styling
37951 this.focus.defer(10, this);
37952 var ml = this.menuListeners;
37953 this.menu.un("select", ml.select, this);
37954 this.menu.un("show", ml.show, this);
37955 this.menu.un("hide", ml.hide, this);
37960 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37961 onTriggerClick : function(){
37965 if(this.menu == null){
37966 this.menu = new Roo.menu.DateMenu();
37968 Roo.apply(this.menu.picker, {
37969 showClear: this.allowBlank,
37970 minDate : this.minValue,
37971 maxDate : this.maxValue,
37972 disabledDatesRE : this.ddMatch,
37973 disabledDatesText : this.disabledDatesText,
37974 disabledDays : this.disabledDays,
37975 disabledDaysText : this.disabledDaysText,
37976 format : this.useIso ? 'Y-m-d' : this.format,
37977 minText : String.format(this.minText, this.formatDate(this.minValue)),
37978 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37980 this.menu.on(Roo.apply({}, this.menuListeners, {
37983 this.menu.picker.setValue(this.getValue() || new Date());
37984 this.menu.show(this.el, "tl-bl?");
37987 beforeBlur : function(){
37988 var v = this.parseDate(this.getRawValue());
37994 /** @cfg {Boolean} grow @hide */
37995 /** @cfg {Number} growMin @hide */
37996 /** @cfg {Number} growMax @hide */
38003 * Ext JS Library 1.1.1
38004 * Copyright(c) 2006-2007, Ext JS, LLC.
38006 * Originally Released Under LGPL - original licence link has changed is not relivant.
38009 * <script type="text/javascript">
38013 * @class Roo.form.MonthField
38014 * @extends Roo.form.TriggerField
38015 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38017 * Create a new MonthField
38018 * @param {Object} config
38020 Roo.form.MonthField = function(config){
38022 Roo.form.MonthField.superclass.constructor.call(this, config);
38028 * Fires when a date is selected
38029 * @param {Roo.form.MonthFieeld} combo This combo box
38030 * @param {Date} date The date selected
38037 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38038 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38039 this.ddMatch = null;
38040 if(this.disabledDates){
38041 var dd = this.disabledDates;
38043 for(var i = 0; i < dd.length; i++){
38045 if(i != dd.length-1) re += "|";
38047 this.ddMatch = new RegExp(re + ")");
38051 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38053 * @cfg {String} format
38054 * The default date format string which can be overriden for localization support. The format must be
38055 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38059 * @cfg {String} altFormats
38060 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38061 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38063 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38065 * @cfg {Array} disabledDays
38066 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38068 disabledDays : [0,1,2,3,4,5,6],
38070 * @cfg {String} disabledDaysText
38071 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38073 disabledDaysText : "Disabled",
38075 * @cfg {Array} disabledDates
38076 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38077 * expression so they are very powerful. Some examples:
38079 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38080 * <li>["03/08", "09/16"] would disable those days for every year</li>
38081 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38082 * <li>["03/../2006"] would disable every day in March 2006</li>
38083 * <li>["^03"] would disable every day in every March</li>
38085 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38086 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38088 disabledDates : null,
38090 * @cfg {String} disabledDatesText
38091 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38093 disabledDatesText : "Disabled",
38095 * @cfg {Date/String} minValue
38096 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38097 * valid format (defaults to null).
38101 * @cfg {Date/String} maxValue
38102 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38103 * valid format (defaults to null).
38107 * @cfg {String} minText
38108 * The error text to display when the date in the cell is before minValue (defaults to
38109 * 'The date in this field must be after {minValue}').
38111 minText : "The date in this field must be equal to or after {0}",
38113 * @cfg {String} maxTextf
38114 * The error text to display when the date in the cell is after maxValue (defaults to
38115 * 'The date in this field must be before {maxValue}').
38117 maxText : "The date in this field must be equal to or before {0}",
38119 * @cfg {String} invalidText
38120 * The error text to display when the date in the field is invalid (defaults to
38121 * '{value} is not a valid date - it must be in the format {format}').
38123 invalidText : "{0} is not a valid date - it must be in the format {1}",
38125 * @cfg {String} triggerClass
38126 * An additional CSS class used to style the trigger button. The trigger will always get the
38127 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38128 * which displays a calendar icon).
38130 triggerClass : 'x-form-date-trigger',
38134 * @cfg {Boolean} useIso
38135 * if enabled, then the date field will use a hidden field to store the
38136 * real value as iso formated date. default (true)
38140 * @cfg {String/Object} autoCreate
38141 * A DomHelper element spec, or true for a default element spec (defaults to
38142 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38145 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38148 hiddenField: false,
38150 hideMonthPicker : false,
38152 onRender : function(ct, position)
38154 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38156 this.el.dom.removeAttribute('name');
38157 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38159 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38160 // prevent input submission
38161 this.hiddenName = this.name;
38168 validateValue : function(value)
38170 value = this.formatDate(value);
38171 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38174 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38177 var svalue = value;
38178 value = this.parseDate(value);
38180 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38183 var time = value.getTime();
38184 if(this.minValue && time < this.minValue.getTime()){
38185 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38188 if(this.maxValue && time > this.maxValue.getTime()){
38189 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38192 /*if(this.disabledDays){
38193 var day = value.getDay();
38194 for(var i = 0; i < this.disabledDays.length; i++) {
38195 if(day === this.disabledDays[i]){
38196 this.markInvalid(this.disabledDaysText);
38202 var fvalue = this.formatDate(value);
38203 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38204 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38212 // Provides logic to override the default TriggerField.validateBlur which just returns true
38213 validateBlur : function(){
38214 return !this.menu || !this.menu.isVisible();
38218 * Returns the current date value of the date field.
38219 * @return {Date} The date value
38221 getValue : function(){
38225 return this.hiddenField ?
38226 this.hiddenField.value :
38227 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38231 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38232 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38233 * (the default format used is "m/d/y").
38236 //All of these calls set the same date value (May 4, 2006)
38238 //Pass a date object:
38239 var dt = new Date('5/4/06');
38240 monthField.setValue(dt);
38242 //Pass a date string (default format):
38243 monthField.setValue('5/4/06');
38245 //Pass a date string (custom format):
38246 monthField.format = 'Y-m-d';
38247 monthField.setValue('2006-5-4');
38249 * @param {String/Date} date The date or valid date string
38251 setValue : function(date){
38252 Roo.log('month setValue' + date);
38253 // can only be first of month..
38255 var val = this.parseDate(date);
38257 if (this.hiddenField) {
38258 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38260 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38261 this.value = this.parseDate(date);
38265 parseDate : function(value){
38266 if(!value || value instanceof Date){
38267 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38270 var v = Date.parseDate(value, this.format);
38271 if (!v && this.useIso) {
38272 v = Date.parseDate(value, 'Y-m-d');
38276 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38280 if(!v && this.altFormats){
38281 if(!this.altFormatsArray){
38282 this.altFormatsArray = this.altFormats.split("|");
38284 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38285 v = Date.parseDate(value, this.altFormatsArray[i]);
38292 formatDate : function(date, fmt){
38293 return (!date || !(date instanceof Date)) ?
38294 date : date.dateFormat(fmt || this.format);
38299 select: function(m, d){
38301 this.fireEvent('select', this, d);
38303 show : function(){ // retain focus styling
38307 this.focus.defer(10, this);
38308 var ml = this.menuListeners;
38309 this.menu.un("select", ml.select, this);
38310 this.menu.un("show", ml.show, this);
38311 this.menu.un("hide", ml.hide, this);
38315 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38316 onTriggerClick : function(){
38320 if(this.menu == null){
38321 this.menu = new Roo.menu.DateMenu();
38325 Roo.apply(this.menu.picker, {
38327 showClear: this.allowBlank,
38328 minDate : this.minValue,
38329 maxDate : this.maxValue,
38330 disabledDatesRE : this.ddMatch,
38331 disabledDatesText : this.disabledDatesText,
38333 format : this.useIso ? 'Y-m-d' : this.format,
38334 minText : String.format(this.minText, this.formatDate(this.minValue)),
38335 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38338 this.menu.on(Roo.apply({}, this.menuListeners, {
38346 // hide month picker get's called when we called by 'before hide';
38348 var ignorehide = true;
38349 p.hideMonthPicker = function(disableAnim){
38353 if(this.monthPicker){
38354 Roo.log("hideMonthPicker called");
38355 if(disableAnim === true){
38356 this.monthPicker.hide();
38358 this.monthPicker.slideOut('t', {duration:.2});
38359 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
38360 p.fireEvent("select", this, this.value);
38366 Roo.log('picker set value');
38367 Roo.log(this.getValue());
38368 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
38369 m.show(this.el, 'tl-bl?');
38370 ignorehide = false;
38371 // this will trigger hideMonthPicker..
38374 // hidden the day picker
38375 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
38381 p.showMonthPicker.defer(100, p);
38387 beforeBlur : function(){
38388 var v = this.parseDate(this.getRawValue());
38394 /** @cfg {Boolean} grow @hide */
38395 /** @cfg {Number} growMin @hide */
38396 /** @cfg {Number} growMax @hide */
38403 * Ext JS Library 1.1.1
38404 * Copyright(c) 2006-2007, Ext JS, LLC.
38406 * Originally Released Under LGPL - original licence link has changed is not relivant.
38409 * <script type="text/javascript">
38414 * @class Roo.form.ComboBox
38415 * @extends Roo.form.TriggerField
38416 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
38418 * Create a new ComboBox.
38419 * @param {Object} config Configuration options
38421 Roo.form.ComboBox = function(config){
38422 Roo.form.ComboBox.superclass.constructor.call(this, config);
38426 * Fires when the dropdown list is expanded
38427 * @param {Roo.form.ComboBox} combo This combo box
38432 * Fires when the dropdown list is collapsed
38433 * @param {Roo.form.ComboBox} combo This combo box
38437 * @event beforeselect
38438 * Fires before a list item is selected. Return false to cancel the selection.
38439 * @param {Roo.form.ComboBox} combo This combo box
38440 * @param {Roo.data.Record} record The data record returned from the underlying store
38441 * @param {Number} index The index of the selected item in the dropdown list
38443 'beforeselect' : true,
38446 * Fires when a list item is selected
38447 * @param {Roo.form.ComboBox} combo This combo box
38448 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
38449 * @param {Number} index The index of the selected item in the dropdown list
38453 * @event beforequery
38454 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
38455 * The event object passed has these properties:
38456 * @param {Roo.form.ComboBox} combo This combo box
38457 * @param {String} query The query
38458 * @param {Boolean} forceAll true to force "all" query
38459 * @param {Boolean} cancel true to cancel the query
38460 * @param {Object} e The query event object
38462 'beforequery': true,
38465 * Fires when the 'add' icon is pressed (add a listener to enable add button)
38466 * @param {Roo.form.ComboBox} combo This combo box
38471 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
38472 * @param {Roo.form.ComboBox} combo This combo box
38473 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
38479 if(this.transform){
38480 this.allowDomMove = false;
38481 var s = Roo.getDom(this.transform);
38482 if(!this.hiddenName){
38483 this.hiddenName = s.name;
38486 this.mode = 'local';
38487 var d = [], opts = s.options;
38488 for(var i = 0, len = opts.length;i < len; i++){
38490 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
38492 this.value = value;
38494 d.push([value, o.text]);
38496 this.store = new Roo.data.SimpleStore({
38498 fields: ['value', 'text'],
38501 this.valueField = 'value';
38502 this.displayField = 'text';
38504 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
38505 if(!this.lazyRender){
38506 this.target = true;
38507 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
38508 s.parentNode.removeChild(s); // remove it
38509 this.render(this.el.parentNode);
38511 s.parentNode.removeChild(s); // remove it
38516 this.store = Roo.factory(this.store, Roo.data);
38519 this.selectedIndex = -1;
38520 if(this.mode == 'local'){
38521 if(config.queryDelay === undefined){
38522 this.queryDelay = 10;
38524 if(config.minChars === undefined){
38530 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
38532 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
38535 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
38536 * rendering into an Roo.Editor, defaults to false)
38539 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
38540 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
38543 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
38546 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
38547 * the dropdown list (defaults to undefined, with no header element)
38551 * @cfg {String/Roo.Template} tpl The template to use to render the output
38555 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
38557 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
38559 listWidth: undefined,
38561 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
38562 * mode = 'remote' or 'text' if mode = 'local')
38564 displayField: undefined,
38566 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
38567 * mode = 'remote' or 'value' if mode = 'local').
38568 * Note: use of a valueField requires the user make a selection
38569 * in order for a value to be mapped.
38571 valueField: undefined,
38575 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
38576 * field's data value (defaults to the underlying DOM element's name)
38578 hiddenName: undefined,
38580 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
38584 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
38586 selectedClass: 'x-combo-selected',
38588 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
38589 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
38590 * which displays a downward arrow icon).
38592 triggerClass : 'x-form-arrow-trigger',
38594 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
38598 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
38599 * anchor positions (defaults to 'tl-bl')
38601 listAlign: 'tl-bl?',
38603 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
38607 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
38608 * query specified by the allQuery config option (defaults to 'query')
38610 triggerAction: 'query',
38612 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
38613 * (defaults to 4, does not apply if editable = false)
38617 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
38618 * delay (typeAheadDelay) if it matches a known value (defaults to false)
38622 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
38623 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
38627 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
38628 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
38632 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
38633 * when editable = true (defaults to false)
38635 selectOnFocus:false,
38637 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
38639 queryParam: 'query',
38641 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
38642 * when mode = 'remote' (defaults to 'Loading...')
38644 loadingText: 'Loading...',
38646 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
38650 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
38654 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
38655 * traditional select (defaults to true)
38659 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
38663 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
38667 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
38668 * listWidth has a higher value)
38672 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
38673 * allow the user to set arbitrary text into the field (defaults to false)
38675 forceSelection:false,
38677 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
38678 * if typeAhead = true (defaults to 250)
38680 typeAheadDelay : 250,
38682 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
38683 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
38685 valueNotFoundText : undefined,
38687 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
38689 blockFocus : false,
38692 * @cfg {Boolean} disableClear Disable showing of clear button.
38694 disableClear : false,
38696 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
38698 alwaysQuery : false,
38704 // element that contains real text value.. (when hidden is used..)
38707 onRender : function(ct, position){
38708 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
38709 if(this.hiddenName){
38710 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
38712 this.hiddenField.value =
38713 this.hiddenValue !== undefined ? this.hiddenValue :
38714 this.value !== undefined ? this.value : '';
38716 // prevent input submission
38717 this.el.dom.removeAttribute('name');
38722 this.el.dom.setAttribute('autocomplete', 'off');
38725 var cls = 'x-combo-list';
38727 this.list = new Roo.Layer({
38728 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
38731 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
38732 this.list.setWidth(lw);
38733 this.list.swallowEvent('mousewheel');
38734 this.assetHeight = 0;
38737 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
38738 this.assetHeight += this.header.getHeight();
38741 this.innerList = this.list.createChild({cls:cls+'-inner'});
38742 this.innerList.on('mouseover', this.onViewOver, this);
38743 this.innerList.on('mousemove', this.onViewMove, this);
38744 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38746 if(this.allowBlank && !this.pageSize && !this.disableClear){
38747 this.footer = this.list.createChild({cls:cls+'-ft'});
38748 this.pageTb = new Roo.Toolbar(this.footer);
38752 this.footer = this.list.createChild({cls:cls+'-ft'});
38753 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
38754 {pageSize: this.pageSize});
38758 if (this.pageTb && this.allowBlank && !this.disableClear) {
38760 this.pageTb.add(new Roo.Toolbar.Fill(), {
38761 cls: 'x-btn-icon x-btn-clear',
38763 handler: function()
38766 _this.clearValue();
38767 _this.onSelect(false, -1);
38772 this.assetHeight += this.footer.getHeight();
38777 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
38780 this.view = new Roo.View(this.innerList, this.tpl, {
38781 singleSelect:true, store: this.store, selectedClass: this.selectedClass
38784 this.view.on('click', this.onViewClick, this);
38786 this.store.on('beforeload', this.onBeforeLoad, this);
38787 this.store.on('load', this.onLoad, this);
38788 this.store.on('loadexception', this.onLoadException, this);
38790 if(this.resizable){
38791 this.resizer = new Roo.Resizable(this.list, {
38792 pinned:true, handles:'se'
38794 this.resizer.on('resize', function(r, w, h){
38795 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
38796 this.listWidth = w;
38797 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
38798 this.restrictHeight();
38800 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
38802 if(!this.editable){
38803 this.editable = true;
38804 this.setEditable(false);
38808 if (typeof(this.events.add.listeners) != 'undefined') {
38810 this.addicon = this.wrap.createChild(
38811 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
38813 this.addicon.on('click', function(e) {
38814 this.fireEvent('add', this);
38817 if (typeof(this.events.edit.listeners) != 'undefined') {
38819 this.editicon = this.wrap.createChild(
38820 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
38821 if (this.addicon) {
38822 this.editicon.setStyle('margin-left', '40px');
38824 this.editicon.on('click', function(e) {
38826 // we fire even if inothing is selected..
38827 this.fireEvent('edit', this, this.lastData );
38837 initEvents : function(){
38838 Roo.form.ComboBox.superclass.initEvents.call(this);
38840 this.keyNav = new Roo.KeyNav(this.el, {
38841 "up" : function(e){
38842 this.inKeyMode = true;
38846 "down" : function(e){
38847 if(!this.isExpanded()){
38848 this.onTriggerClick();
38850 this.inKeyMode = true;
38855 "enter" : function(e){
38856 this.onViewClick();
38860 "esc" : function(e){
38864 "tab" : function(e){
38865 this.onViewClick(false);
38866 this.fireEvent("specialkey", this, e);
38872 doRelay : function(foo, bar, hname){
38873 if(hname == 'down' || this.scope.isExpanded()){
38874 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
38881 this.queryDelay = Math.max(this.queryDelay || 10,
38882 this.mode == 'local' ? 10 : 250);
38883 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
38884 if(this.typeAhead){
38885 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
38887 if(this.editable !== false){
38888 this.el.on("keyup", this.onKeyUp, this);
38890 if(this.forceSelection){
38891 this.on('blur', this.doForce, this);
38895 onDestroy : function(){
38897 this.view.setStore(null);
38898 this.view.el.removeAllListeners();
38899 this.view.el.remove();
38900 this.view.purgeListeners();
38903 this.list.destroy();
38906 this.store.un('beforeload', this.onBeforeLoad, this);
38907 this.store.un('load', this.onLoad, this);
38908 this.store.un('loadexception', this.onLoadException, this);
38910 Roo.form.ComboBox.superclass.onDestroy.call(this);
38914 fireKey : function(e){
38915 if(e.isNavKeyPress() && !this.list.isVisible()){
38916 this.fireEvent("specialkey", this, e);
38921 onResize: function(w, h){
38922 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
38924 if(typeof w != 'number'){
38925 // we do not handle it!?!?
38928 var tw = this.trigger.getWidth();
38929 tw += this.addicon ? this.addicon.getWidth() : 0;
38930 tw += this.editicon ? this.editicon.getWidth() : 0;
38932 this.el.setWidth( this.adjustWidth('input', x));
38934 this.trigger.setStyle('left', x+'px');
38936 if(this.list && this.listWidth === undefined){
38937 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
38938 this.list.setWidth(lw);
38939 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38947 * Allow or prevent the user from directly editing the field text. If false is passed,
38948 * the user will only be able to select from the items defined in the dropdown list. This method
38949 * is the runtime equivalent of setting the 'editable' config option at config time.
38950 * @param {Boolean} value True to allow the user to directly edit the field text
38952 setEditable : function(value){
38953 if(value == this.editable){
38956 this.editable = value;
38958 this.el.dom.setAttribute('readOnly', true);
38959 this.el.on('mousedown', this.onTriggerClick, this);
38960 this.el.addClass('x-combo-noedit');
38962 this.el.dom.setAttribute('readOnly', false);
38963 this.el.un('mousedown', this.onTriggerClick, this);
38964 this.el.removeClass('x-combo-noedit');
38969 onBeforeLoad : function(){
38970 if(!this.hasFocus){
38973 this.innerList.update(this.loadingText ?
38974 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
38975 this.restrictHeight();
38976 this.selectedIndex = -1;
38980 onLoad : function(){
38981 if(!this.hasFocus){
38984 if(this.store.getCount() > 0){
38986 this.restrictHeight();
38987 if(this.lastQuery == this.allQuery){
38989 this.el.dom.select();
38991 if(!this.selectByValue(this.value, true)){
38992 this.select(0, true);
38996 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
38997 this.taTask.delay(this.typeAheadDelay);
39001 this.onEmptyResults();
39006 onLoadException : function()
39009 Roo.log(this.store.reader.jsonData);
39010 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39011 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39017 onTypeAhead : function(){
39018 if(this.store.getCount() > 0){
39019 var r = this.store.getAt(0);
39020 var newValue = r.data[this.displayField];
39021 var len = newValue.length;
39022 var selStart = this.getRawValue().length;
39023 if(selStart != len){
39024 this.setRawValue(newValue);
39025 this.selectText(selStart, newValue.length);
39031 onSelect : function(record, index){
39032 if(this.fireEvent('beforeselect', this, record, index) !== false){
39033 this.setFromData(index > -1 ? record.data : false);
39035 this.fireEvent('select', this, record, index);
39040 * Returns the currently selected field value or empty string if no value is set.
39041 * @return {String} value The selected value
39043 getValue : function(){
39044 if(this.valueField){
39045 return typeof this.value != 'undefined' ? this.value : '';
39047 return Roo.form.ComboBox.superclass.getValue.call(this);
39052 * Clears any text/value currently set in the field
39054 clearValue : function(){
39055 if(this.hiddenField){
39056 this.hiddenField.value = '';
39059 this.setRawValue('');
39060 this.lastSelectionText = '';
39065 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39066 * will be displayed in the field. If the value does not match the data value of an existing item,
39067 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39068 * Otherwise the field will be blank (although the value will still be set).
39069 * @param {String} value The value to match
39071 setValue : function(v){
39073 if(this.valueField){
39074 var r = this.findRecord(this.valueField, v);
39076 text = r.data[this.displayField];
39077 }else if(this.valueNotFoundText !== undefined){
39078 text = this.valueNotFoundText;
39081 this.lastSelectionText = text;
39082 if(this.hiddenField){
39083 this.hiddenField.value = v;
39085 Roo.form.ComboBox.superclass.setValue.call(this, text);
39089 * @property {Object} the last set data for the element
39094 * Sets the value of the field based on a object which is related to the record format for the store.
39095 * @param {Object} value the value to set as. or false on reset?
39097 setFromData : function(o){
39098 var dv = ''; // display value
39099 var vv = ''; // value value..
39101 if (this.displayField) {
39102 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39104 // this is an error condition!!!
39105 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39108 if(this.valueField){
39109 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39111 if(this.hiddenField){
39112 this.hiddenField.value = vv;
39114 this.lastSelectionText = dv;
39115 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39119 // no hidden field.. - we store the value in 'value', but still display
39120 // display field!!!!
39121 this.lastSelectionText = dv;
39122 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39128 reset : function(){
39129 // overridden so that last data is reset..
39130 this.setValue(this.originalValue);
39131 this.clearInvalid();
39132 this.lastData = false;
39134 this.view.clearSelections();
39138 findRecord : function(prop, value){
39140 if(this.store.getCount() > 0){
39141 this.store.each(function(r){
39142 if(r.data[prop] == value){
39152 getName: function()
39154 // returns hidden if it's set..
39155 if (!this.rendered) {return ''};
39156 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39160 onViewMove : function(e, t){
39161 this.inKeyMode = false;
39165 onViewOver : function(e, t){
39166 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39169 var item = this.view.findItemFromChild(t);
39171 var index = this.view.indexOf(item);
39172 this.select(index, false);
39177 onViewClick : function(doFocus)
39179 var index = this.view.getSelectedIndexes()[0];
39180 var r = this.store.getAt(index);
39182 this.onSelect(r, index);
39184 if(doFocus !== false && !this.blockFocus){
39190 restrictHeight : function(){
39191 this.innerList.dom.style.height = '';
39192 var inner = this.innerList.dom;
39193 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39194 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39195 this.list.beginUpdate();
39196 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39197 this.list.alignTo(this.el, this.listAlign);
39198 this.list.endUpdate();
39202 onEmptyResults : function(){
39207 * Returns true if the dropdown list is expanded, else false.
39209 isExpanded : function(){
39210 return this.list.isVisible();
39214 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39215 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39216 * @param {String} value The data value of the item to select
39217 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39218 * selected item if it is not currently in view (defaults to true)
39219 * @return {Boolean} True if the value matched an item in the list, else false
39221 selectByValue : function(v, scrollIntoView){
39222 if(v !== undefined && v !== null){
39223 var r = this.findRecord(this.valueField || this.displayField, v);
39225 this.select(this.store.indexOf(r), scrollIntoView);
39233 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39234 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39235 * @param {Number} index The zero-based index of the list item to select
39236 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39237 * selected item if it is not currently in view (defaults to true)
39239 select : function(index, scrollIntoView){
39240 this.selectedIndex = index;
39241 this.view.select(index);
39242 if(scrollIntoView !== false){
39243 var el = this.view.getNode(index);
39245 this.innerList.scrollChildIntoView(el, false);
39251 selectNext : function(){
39252 var ct = this.store.getCount();
39254 if(this.selectedIndex == -1){
39256 }else if(this.selectedIndex < ct-1){
39257 this.select(this.selectedIndex+1);
39263 selectPrev : function(){
39264 var ct = this.store.getCount();
39266 if(this.selectedIndex == -1){
39268 }else if(this.selectedIndex != 0){
39269 this.select(this.selectedIndex-1);
39275 onKeyUp : function(e){
39276 if(this.editable !== false && !e.isSpecialKey()){
39277 this.lastKey = e.getKey();
39278 this.dqTask.delay(this.queryDelay);
39283 validateBlur : function(){
39284 return !this.list || !this.list.isVisible();
39288 initQuery : function(){
39289 this.doQuery(this.getRawValue());
39293 doForce : function(){
39294 if(this.el.dom.value.length > 0){
39295 this.el.dom.value =
39296 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39302 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39303 * query allowing the query action to be canceled if needed.
39304 * @param {String} query The SQL query to execute
39305 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39306 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39307 * saved in the current store (defaults to false)
39309 doQuery : function(q, forceAll){
39310 if(q === undefined || q === null){
39315 forceAll: forceAll,
39319 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39323 forceAll = qe.forceAll;
39324 if(forceAll === true || (q.length >= this.minChars)){
39325 if(this.lastQuery != q || this.alwaysQuery){
39326 this.lastQuery = q;
39327 if(this.mode == 'local'){
39328 this.selectedIndex = -1;
39330 this.store.clearFilter();
39332 this.store.filter(this.displayField, q);
39336 this.store.baseParams[this.queryParam] = q;
39338 params: this.getParams(q)
39343 this.selectedIndex = -1;
39350 getParams : function(q){
39352 //p[this.queryParam] = q;
39355 p.limit = this.pageSize;
39361 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
39363 collapse : function(){
39364 if(!this.isExpanded()){
39368 Roo.get(document).un('mousedown', this.collapseIf, this);
39369 Roo.get(document).un('mousewheel', this.collapseIf, this);
39370 if (!this.editable) {
39371 Roo.get(document).un('keydown', this.listKeyPress, this);
39373 this.fireEvent('collapse', this);
39377 collapseIf : function(e){
39378 if(!e.within(this.wrap) && !e.within(this.list)){
39384 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
39386 expand : function(){
39387 if(this.isExpanded() || !this.hasFocus){
39390 this.list.alignTo(this.el, this.listAlign);
39392 Roo.get(document).on('mousedown', this.collapseIf, this);
39393 Roo.get(document).on('mousewheel', this.collapseIf, this);
39394 if (!this.editable) {
39395 Roo.get(document).on('keydown', this.listKeyPress, this);
39398 this.fireEvent('expand', this);
39402 // Implements the default empty TriggerField.onTriggerClick function
39403 onTriggerClick : function(){
39407 if(this.isExpanded()){
39409 if (!this.blockFocus) {
39414 this.hasFocus = true;
39415 if(this.triggerAction == 'all') {
39416 this.doQuery(this.allQuery, true);
39418 this.doQuery(this.getRawValue());
39420 if (!this.blockFocus) {
39425 listKeyPress : function(e)
39427 //Roo.log('listkeypress');
39428 // scroll to first matching element based on key pres..
39429 if (e.isSpecialKey()) {
39432 var k = String.fromCharCode(e.getKey()).toUpperCase();
39435 var csel = this.view.getSelectedNodes();
39436 var cselitem = false;
39438 var ix = this.view.indexOf(csel[0]);
39439 cselitem = this.store.getAt(ix);
39440 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
39446 this.store.each(function(v) {
39448 // start at existing selection.
39449 if (cselitem.id == v.id) {
39455 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
39456 match = this.store.indexOf(v);
39461 if (match === false) {
39462 return true; // no more action?
39465 this.view.select(match);
39466 var sn = Roo.get(this.view.getSelectedNodes()[0])
39467 sn.scrollIntoView(sn.dom.parentNode, false);
39471 * @cfg {Boolean} grow
39475 * @cfg {Number} growMin
39479 * @cfg {Number} growMax
39487 * Copyright(c) 2010-2012, Roo J Solutions Limited
39494 * @class Roo.form.ComboBoxArray
39495 * @extends Roo.form.TextField
39496 * A facebook style adder... for lists of email / people / countries etc...
39497 * pick multiple items from a combo box, and shows each one.
39499 * Fred [x] Brian [x] [Pick another |v]
39502 * For this to work: it needs various extra information
39503 * - normal combo problay has
39505 * + displayField, valueField
39507 * For our purpose...
39510 * If we change from 'extends' to wrapping...
39517 * Create a new ComboBoxArray.
39518 * @param {Object} config Configuration options
39522 Roo.form.ComboBoxArray = function(config)
39525 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
39527 this.items = new Roo.util.MixedCollection(false);
39529 // construct the child combo...
39539 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
39542 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
39547 // behavies liek a hiddne field
39548 inputType: 'hidden',
39550 * @cfg {Number} width The width of the box that displays the selected element
39557 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
39561 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
39563 hiddenName : false,
39566 // private the array of items that are displayed..
39568 // private - the hidden field el.
39570 // private - the filed el..
39573 //validateValue : function() { return true; }, // all values are ok!
39574 //onAddClick: function() { },
39576 onRender : function(ct, position)
39579 // create the standard hidden element
39580 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
39583 // give fake names to child combo;
39584 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
39585 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
39587 this.combo = Roo.factory(this.combo, Roo.form);
39588 this.combo.onRender(ct, position);
39589 if (typeof(this.combo.width) != 'undefined') {
39590 this.combo.onResize(this.combo.width,0);
39593 this.combo.initEvents();
39595 // assigned so form know we need to do this..
39596 this.store = this.combo.store;
39597 this.valueField = this.combo.valueField;
39598 this.displayField = this.combo.displayField ;
39601 this.combo.wrap.addClass('x-cbarray-grp');
39603 var cbwrap = this.combo.wrap.createChild(
39604 {tag: 'div', cls: 'x-cbarray-cb'},
39609 this.hiddenEl = this.combo.wrap.createChild({
39610 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
39612 this.el = this.combo.wrap.createChild({
39613 tag: 'input', type:'hidden' , name: this.name, value : ''
39615 // this.el.dom.removeAttribute("name");
39618 this.outerWrap = this.combo.wrap;
39619 this.wrap = cbwrap;
39621 this.outerWrap.setWidth(this.width);
39622 this.outerWrap.dom.removeChild(this.el.dom);
39624 this.wrap.dom.appendChild(this.el.dom);
39625 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
39626 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
39628 this.combo.trigger.setStyle('position','relative');
39629 this.combo.trigger.setStyle('left', '0px');
39630 this.combo.trigger.setStyle('top', '2px');
39632 this.combo.el.setStyle('vertical-align', 'text-bottom');
39634 //this.trigger.setStyle('vertical-align', 'top');
39636 // this should use the code from combo really... on('add' ....)
39640 this.adder = this.outerWrap.createChild(
39641 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
39643 this.adder.on('click', function(e) {
39644 _t.fireEvent('adderclick', this, e);
39648 //this.adder.on('click', this.onAddClick, _t);
39651 this.combo.on('select', function(cb, rec, ix) {
39652 this.addItem(rec.data);
39655 cb.el.dom.value = '';
39656 //cb.lastData = rec.data;
39665 getName: function()
39667 // returns hidden if it's set..
39668 if (!this.rendered) {return ''};
39669 return this.hiddenName ? this.hiddenName : this.name;
39674 onResize: function(w, h){
39677 // not sure if this is needed..
39678 //this.combo.onResize(w,h);
39680 if(typeof w != 'number'){
39681 // we do not handle it!?!?
39684 var tw = this.combo.trigger.getWidth();
39685 tw += this.addicon ? this.addicon.getWidth() : 0;
39686 tw += this.editicon ? this.editicon.getWidth() : 0;
39688 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
39690 this.combo.trigger.setStyle('left', '0px');
39692 if(this.list && this.listWidth === undefined){
39693 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
39694 this.list.setWidth(lw);
39695 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39702 addItem: function(rec)
39704 var valueField = this.combo.valueField;
39705 var displayField = this.combo.displayField;
39706 if (this.items.indexOfKey(rec[valueField]) > -1) {
39707 //console.log("GOT " + rec.data.id);
39711 var x = new Roo.form.ComboBoxArray.Item({
39712 //id : rec[this.idField],
39714 displayField : displayField ,
39715 tipField : displayField ,
39719 this.items.add(rec[valueField],x);
39720 // add it before the element..
39721 this.updateHiddenEl();
39722 x.render(this.outerWrap, this.wrap.dom);
39723 // add the image handler..
39726 updateHiddenEl : function()
39729 if (!this.hiddenEl) {
39733 var idField = this.combo.valueField;
39735 this.items.each(function(f) {
39736 ar.push(f.data[idField]);
39739 this.hiddenEl.dom.value = ar.join(',');
39745 //Roo.form.ComboBoxArray.superclass.reset.call(this);
39746 this.items.each(function(f) {
39749 this.el.dom.value = '';
39750 if (this.hiddenEl) {
39751 this.hiddenEl.dom.value = '';
39755 getValue: function()
39757 return this.hiddenEl ? this.hiddenEl.dom.value : '';
39759 setValue: function(v) // not a valid action - must use addItems..
39766 if (this.store.isLocal && (typeof(v) == 'string')) {
39767 // then we can use the store to find the values..
39768 // comma seperated at present.. this needs to allow JSON based encoding..
39769 this.hiddenEl.value = v;
39771 Roo.each(v.split(','), function(k) {
39772 Roo.log("CHECK " + this.valueField + ',' + k);
39773 var li = this.store.query(this.valueField, k);
39778 add[this.valueField] = k;
39779 add[this.displayField] = li.item(0).data[this.displayField];
39785 if (typeof(v) == 'object') {
39786 // then let's assume it's an array of objects..
39787 Roo.each(v, function(l) {
39795 setFromData: function(v)
39797 // this recieves an object, if setValues is called.
39799 this.el.dom.value = v[this.displayField];
39800 this.hiddenEl.dom.value = v[this.valueField];
39801 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
39804 var kv = v[this.valueField];
39805 var dv = v[this.displayField];
39806 kv = typeof(kv) != 'string' ? '' : kv;
39807 dv = typeof(dv) != 'string' ? '' : dv;
39810 var keys = kv.split(',');
39811 var display = dv.split(',');
39812 for (var i = 0 ; i < keys.length; i++) {
39815 add[this.valueField] = keys[i];
39816 add[this.displayField] = display[i];
39824 validateValue : function(value){
39825 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
39834 * @class Roo.form.ComboBoxArray.Item
39835 * @extends Roo.BoxComponent
39836 * A selected item in the list
39837 * Fred [x] Brian [x] [Pick another |v]
39840 * Create a new item.
39841 * @param {Object} config Configuration options
39844 Roo.form.ComboBoxArray.Item = function(config) {
39845 config.id = Roo.id();
39846 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
39849 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
39852 displayField : false,
39856 defaultAutoCreate : {
39858 cls: 'x-cbarray-item',
39865 src : Roo.BLANK_IMAGE_URL ,
39873 onRender : function(ct, position)
39875 Roo.form.Field.superclass.onRender.call(this, ct, position);
39878 var cfg = this.getAutoCreate();
39879 this.el = ct.createChild(cfg, position);
39882 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
39884 this.el.child('div').dom.innerHTML = this.cb.renderer ?
39885 this.cb.renderer(this.data) :
39886 String.format('{0}',this.data[this.displayField]);
39889 this.el.child('div').dom.setAttribute('qtip',
39890 String.format('{0}',this.data[this.tipField])
39893 this.el.child('img').on('click', this.remove, this);
39897 remove : function()
39900 this.cb.items.remove(this);
39901 this.el.child('img').un('click', this.remove, this);
39903 this.cb.updateHiddenEl();
39909 * Ext JS Library 1.1.1
39910 * Copyright(c) 2006-2007, Ext JS, LLC.
39912 * Originally Released Under LGPL - original licence link has changed is not relivant.
39915 * <script type="text/javascript">
39918 * @class Roo.form.Checkbox
39919 * @extends Roo.form.Field
39920 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
39922 * Creates a new Checkbox
39923 * @param {Object} config Configuration options
39925 Roo.form.Checkbox = function(config){
39926 Roo.form.Checkbox.superclass.constructor.call(this, config);
39930 * Fires when the checkbox is checked or unchecked.
39931 * @param {Roo.form.Checkbox} this This checkbox
39932 * @param {Boolean} checked The new checked value
39938 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
39940 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
39942 focusClass : undefined,
39944 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
39946 fieldClass: "x-form-field",
39948 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
39952 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39953 * {tag: "input", type: "checkbox", autocomplete: "off"})
39955 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
39957 * @cfg {String} boxLabel The text that appears beside the checkbox
39961 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
39965 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
39967 valueOff: '0', // value when not checked..
39969 actionMode : 'viewEl',
39972 itemCls : 'x-menu-check-item x-form-item',
39973 groupClass : 'x-menu-group-item',
39974 inputType : 'hidden',
39977 inSetChecked: false, // check that we are not calling self...
39979 inputElement: false, // real input element?
39980 basedOn: false, // ????
39982 isFormField: true, // not sure where this is needed!!!!
39984 onResize : function(){
39985 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
39986 if(!this.boxLabel){
39987 this.el.alignTo(this.wrap, 'c-c');
39991 initEvents : function(){
39992 Roo.form.Checkbox.superclass.initEvents.call(this);
39993 this.el.on("click", this.onClick, this);
39994 this.el.on("change", this.onClick, this);
39998 getResizeEl : function(){
40002 getPositionEl : function(){
40007 onRender : function(ct, position){
40008 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40010 if(this.inputValue !== undefined){
40011 this.el.dom.value = this.inputValue;
40014 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40015 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40016 var viewEl = this.wrap.createChild({
40017 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40018 this.viewEl = viewEl;
40019 this.wrap.on('click', this.onClick, this);
40021 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40022 this.el.on('propertychange', this.setFromHidden, this); //ie
40027 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40028 // viewEl.on('click', this.onClick, this);
40030 //if(this.checked){
40031 this.setChecked(this.checked);
40033 //this.checked = this.el.dom;
40039 initValue : Roo.emptyFn,
40042 * Returns the checked state of the checkbox.
40043 * @return {Boolean} True if checked, else false
40045 getValue : function(){
40047 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40049 return this.valueOff;
40054 onClick : function(){
40055 this.setChecked(!this.checked);
40057 //if(this.el.dom.checked != this.checked){
40058 // this.setValue(this.el.dom.checked);
40063 * Sets the checked state of the checkbox.
40064 * On is always based on a string comparison between inputValue and the param.
40065 * @param {Boolean/String} value - the value to set
40066 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40068 setValue : function(v,suppressEvent){
40071 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40072 //if(this.el && this.el.dom){
40073 // this.el.dom.checked = this.checked;
40074 // this.el.dom.defaultChecked = this.checked;
40076 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40077 //this.fireEvent("check", this, this.checked);
40080 setChecked : function(state,suppressEvent)
40082 if (this.inSetChecked) {
40083 this.checked = state;
40089 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40091 this.checked = state;
40092 if(suppressEvent !== true){
40093 this.fireEvent('check', this, state);
40095 this.inSetChecked = true;
40096 this.el.dom.value = state ? this.inputValue : this.valueOff;
40097 this.inSetChecked = false;
40100 // handle setting of hidden value by some other method!!?!?
40101 setFromHidden: function()
40106 //console.log("SET FROM HIDDEN");
40107 //alert('setFrom hidden');
40108 this.setValue(this.el.dom.value);
40111 onDestroy : function()
40114 Roo.get(this.viewEl).remove();
40117 Roo.form.Checkbox.superclass.onDestroy.call(this);
40122 * Ext JS Library 1.1.1
40123 * Copyright(c) 2006-2007, Ext JS, LLC.
40125 * Originally Released Under LGPL - original licence link has changed is not relivant.
40128 * <script type="text/javascript">
40132 * @class Roo.form.Radio
40133 * @extends Roo.form.Checkbox
40134 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40135 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40137 * Creates a new Radio
40138 * @param {Object} config Configuration options
40140 Roo.form.Radio = function(){
40141 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40143 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40144 inputType: 'radio',
40147 * If this radio is part of a group, it will return the selected value
40150 getGroupValue : function(){
40151 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40155 onRender : function(ct, position){
40156 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40158 if(this.inputValue !== undefined){
40159 this.el.dom.value = this.inputValue;
40162 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40163 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40164 //var viewEl = this.wrap.createChild({
40165 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40166 //this.viewEl = viewEl;
40167 //this.wrap.on('click', this.onClick, this);
40169 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40170 //this.el.on('propertychange', this.setFromHidden, this); //ie
40175 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40176 // viewEl.on('click', this.onClick, this);
40179 this.el.dom.checked = 'checked' ;
40185 });//<script type="text/javascript">
40188 * Ext JS Library 1.1.1
40189 * Copyright(c) 2006-2007, Ext JS, LLC.
40190 * licensing@extjs.com
40192 * http://www.extjs.com/license
40198 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
40199 * - IE ? - no idea how much works there.
40207 * @class Ext.form.HtmlEditor
40208 * @extends Ext.form.Field
40209 * Provides a lightweight HTML Editor component.
40211 * This has been tested on Fireforx / Chrome.. IE may not be so great..
40213 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
40214 * supported by this editor.</b><br/><br/>
40215 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
40216 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40218 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
40220 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
40224 * @cfg {String} createLinkText The default text for the create link prompt
40226 createLinkText : 'Please enter the URL for the link:',
40228 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
40230 defaultLinkValue : 'http:/'+'/',
40233 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40238 * @cfg {Number} height (in pixels)
40242 * @cfg {Number} width (in pixels)
40247 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
40250 stylesheets: false,
40255 // private properties
40256 validationEvent : false,
40258 initialized : false,
40260 sourceEditMode : false,
40261 onFocus : Roo.emptyFn,
40263 hideMode:'offsets',
40265 defaultAutoCreate : { // modified by initCompnoent..
40267 style:"width:500px;height:300px;",
40268 autocomplete: "off"
40272 initComponent : function(){
40275 * @event initialize
40276 * Fires when the editor is fully initialized (including the iframe)
40277 * @param {HtmlEditor} this
40282 * Fires when the editor is first receives the focus. Any insertion must wait
40283 * until after this event.
40284 * @param {HtmlEditor} this
40288 * @event beforesync
40289 * Fires before the textarea is updated with content from the editor iframe. Return false
40290 * to cancel the sync.
40291 * @param {HtmlEditor} this
40292 * @param {String} html
40296 * @event beforepush
40297 * Fires before the iframe editor is updated with content from the textarea. Return false
40298 * to cancel the push.
40299 * @param {HtmlEditor} this
40300 * @param {String} html
40305 * Fires when the textarea is updated with content from the editor iframe.
40306 * @param {HtmlEditor} this
40307 * @param {String} html
40312 * Fires when the iframe editor is updated with content from the textarea.
40313 * @param {HtmlEditor} this
40314 * @param {String} html
40318 * @event editmodechange
40319 * Fires when the editor switches edit modes
40320 * @param {HtmlEditor} this
40321 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
40323 editmodechange: true,
40325 * @event editorevent
40326 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40327 * @param {HtmlEditor} this
40331 this.defaultAutoCreate = {
40333 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
40334 autocomplete: "off"
40339 * Protected method that will not generally be called directly. It
40340 * is called when the editor creates its toolbar. Override this method if you need to
40341 * add custom toolbar buttons.
40342 * @param {HtmlEditor} editor
40344 createToolbar : function(editor){
40345 if (!editor.toolbars || !editor.toolbars.length) {
40346 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
40349 for (var i =0 ; i < editor.toolbars.length;i++) {
40350 editor.toolbars[i] = Roo.factory(
40351 typeof(editor.toolbars[i]) == 'string' ?
40352 { xtype: editor.toolbars[i]} : editor.toolbars[i],
40353 Roo.form.HtmlEditor);
40354 editor.toolbars[i].init(editor);
40361 * Protected method that will not generally be called directly. It
40362 * is called when the editor initializes the iframe with HTML contents. Override this method if you
40363 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
40365 getDocMarkup : function(){
40368 if (this.stylesheets === false) {
40370 Roo.get(document.head).select('style').each(function(node) {
40371 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40374 Roo.get(document.head).select('link').each(function(node) {
40375 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40378 } else if (!this.stylesheets.length) {
40380 st = '<style type="text/css">' +
40381 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40384 Roo.each(this.stylesheets, function(s) {
40385 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
40390 st += '<style type="text/css">' +
40391 'IMG { cursor: pointer } ' +
40395 return '<html><head>' + st +
40396 //<style type="text/css">' +
40397 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40399 ' </head><body class="roo-htmleditor-body"></body></html>';
40403 onRender : function(ct, position)
40406 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
40407 this.el.dom.style.border = '0 none';
40408 this.el.dom.setAttribute('tabIndex', -1);
40409 this.el.addClass('x-hidden');
40410 if(Roo.isIE){ // fix IE 1px bogus margin
40411 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
40413 this.wrap = this.el.wrap({
40414 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
40417 if (this.resizable) {
40418 this.resizeEl = new Roo.Resizable(this.wrap, {
40422 minHeight : this.height,
40423 height: this.height,
40424 handles : this.resizable,
40427 resize : function(r, w, h) {
40428 _t.onResize(w,h); // -something
40435 this.frameId = Roo.id();
40437 this.createToolbar(this);
40441 var iframe = this.wrap.createChild({
40444 name: this.frameId,
40445 frameBorder : 'no',
40446 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
40450 // console.log(iframe);
40451 //this.wrap.dom.appendChild(iframe);
40453 this.iframe = iframe.dom;
40455 this.assignDocWin();
40457 this.doc.designMode = 'on';
40460 this.doc.write(this.getDocMarkup());
40464 var task = { // must defer to wait for browser to be ready
40466 //console.log("run task?" + this.doc.readyState);
40467 this.assignDocWin();
40468 if(this.doc.body || this.doc.readyState == 'complete'){
40470 this.doc.designMode="on";
40474 Roo.TaskMgr.stop(task);
40475 this.initEditor.defer(10, this);
40482 Roo.TaskMgr.start(task);
40485 this.setSize(this.wrap.getSize());
40487 if (this.resizeEl) {
40488 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
40489 // should trigger onReize..
40494 onResize : function(w, h)
40496 //Roo.log('resize: ' +w + ',' + h );
40497 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
40498 if(this.el && this.iframe){
40499 if(typeof w == 'number'){
40500 var aw = w - this.wrap.getFrameWidth('lr');
40501 this.el.setWidth(this.adjustWidth('textarea', aw));
40502 this.iframe.style.width = aw + 'px';
40504 if(typeof h == 'number'){
40506 for (var i =0; i < this.toolbars.length;i++) {
40507 // fixme - ask toolbars for heights?
40508 tbh += this.toolbars[i].tb.el.getHeight();
40509 if (this.toolbars[i].footer) {
40510 tbh += this.toolbars[i].footer.el.getHeight();
40517 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
40518 ah -= 5; // knock a few pixes off for look..
40519 this.el.setHeight(this.adjustWidth('textarea', ah));
40520 this.iframe.style.height = ah + 'px';
40522 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
40529 * Toggles the editor between standard and source edit mode.
40530 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
40532 toggleSourceEdit : function(sourceEditMode){
40534 this.sourceEditMode = sourceEditMode === true;
40536 if(this.sourceEditMode){
40538 // Roo.log(this.syncValue());
40540 this.iframe.className = 'x-hidden';
40541 this.el.removeClass('x-hidden');
40542 this.el.dom.removeAttribute('tabIndex');
40546 // Roo.log(this.pushValue());
40548 this.iframe.className = '';
40549 this.el.addClass('x-hidden');
40550 this.el.dom.setAttribute('tabIndex', -1);
40553 this.setSize(this.wrap.getSize());
40554 this.fireEvent('editmodechange', this, this.sourceEditMode);
40557 // private used internally
40558 createLink : function(){
40559 var url = prompt(this.createLinkText, this.defaultLinkValue);
40560 if(url && url != 'http:/'+'/'){
40561 this.relayCmd('createlink', url);
40565 // private (for BoxComponent)
40566 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40568 // private (for BoxComponent)
40569 getResizeEl : function(){
40573 // private (for BoxComponent)
40574 getPositionEl : function(){
40579 initEvents : function(){
40580 this.originalValue = this.getValue();
40584 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
40587 markInvalid : Roo.emptyFn,
40589 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
40592 clearInvalid : Roo.emptyFn,
40594 setValue : function(v){
40595 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
40600 * Protected method that will not generally be called directly. If you need/want
40601 * custom HTML cleanup, this is the method you should override.
40602 * @param {String} html The HTML to be cleaned
40603 * return {String} The cleaned HTML
40605 cleanHtml : function(html){
40606 html = String(html);
40607 if(html.length > 5){
40608 if(Roo.isSafari){ // strip safari nonsense
40609 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
40612 if(html == ' '){
40619 * Protected method that will not generally be called directly. Syncs the contents
40620 * of the editor iframe with the textarea.
40622 syncValue : function(){
40623 if(this.initialized){
40624 var bd = (this.doc.body || this.doc.documentElement);
40625 //this.cleanUpPaste(); -- this is done else where and causes havoc..
40626 var html = bd.innerHTML;
40628 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
40629 var m = bs.match(/text-align:(.*?);/i);
40631 html = '<div style="'+m[0]+'">' + html + '</div>';
40634 html = this.cleanHtml(html);
40635 // fix up the special chars.. normaly like back quotes in word...
40636 // however we do not want to do this with chinese..
40637 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
40638 var cc = b.charCodeAt();
40640 (cc >= 0x4E00 && cc < 0xA000 ) ||
40641 (cc >= 0x3400 && cc < 0x4E00 ) ||
40642 (cc >= 0xf900 && cc < 0xfb00 )
40648 if(this.fireEvent('beforesync', this, html) !== false){
40649 this.el.dom.value = html;
40650 this.fireEvent('sync', this, html);
40656 * Protected method that will not generally be called directly. Pushes the value of the textarea
40657 * into the iframe editor.
40659 pushValue : function(){
40660 if(this.initialized){
40661 var v = this.el.dom.value;
40667 if(this.fireEvent('beforepush', this, v) !== false){
40668 var d = (this.doc.body || this.doc.documentElement);
40670 this.cleanUpPaste();
40671 this.el.dom.value = d.innerHTML;
40672 this.fireEvent('push', this, v);
40678 deferFocus : function(){
40679 this.focus.defer(10, this);
40683 focus : function(){
40684 if(this.win && !this.sourceEditMode){
40691 assignDocWin: function()
40693 var iframe = this.iframe;
40696 this.doc = iframe.contentWindow.document;
40697 this.win = iframe.contentWindow;
40699 if (!Roo.get(this.frameId)) {
40702 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
40703 this.win = Roo.get(this.frameId).dom.contentWindow;
40708 initEditor : function(){
40709 //console.log("INIT EDITOR");
40710 this.assignDocWin();
40714 this.doc.designMode="on";
40716 this.doc.write(this.getDocMarkup());
40719 var dbody = (this.doc.body || this.doc.documentElement);
40720 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
40721 // this copies styles from the containing element into thsi one..
40722 // not sure why we need all of this..
40723 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
40724 ss['background-attachment'] = 'fixed'; // w3c
40725 dbody.bgProperties = 'fixed'; // ie
40726 Roo.DomHelper.applyStyles(dbody, ss);
40727 Roo.EventManager.on(this.doc, {
40728 //'mousedown': this.onEditorEvent,
40729 'mouseup': this.onEditorEvent,
40730 'dblclick': this.onEditorEvent,
40731 'click': this.onEditorEvent,
40732 'keyup': this.onEditorEvent,
40737 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
40739 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
40740 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
40742 this.initialized = true;
40744 this.fireEvent('initialize', this);
40749 onDestroy : function(){
40755 for (var i =0; i < this.toolbars.length;i++) {
40756 // fixme - ask toolbars for heights?
40757 this.toolbars[i].onDestroy();
40760 this.wrap.dom.innerHTML = '';
40761 this.wrap.remove();
40766 onFirstFocus : function(){
40768 this.assignDocWin();
40771 this.activated = true;
40772 for (var i =0; i < this.toolbars.length;i++) {
40773 this.toolbars[i].onFirstFocus();
40776 if(Roo.isGecko){ // prevent silly gecko errors
40778 var s = this.win.getSelection();
40779 if(!s.focusNode || s.focusNode.nodeType != 3){
40780 var r = s.getRangeAt(0);
40781 r.selectNodeContents((this.doc.body || this.doc.documentElement));
40786 this.execCmd('useCSS', true);
40787 this.execCmd('styleWithCSS', false);
40790 this.fireEvent('activate', this);
40794 adjustFont: function(btn){
40795 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
40796 //if(Roo.isSafari){ // safari
40799 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
40800 if(Roo.isSafari){ // safari
40801 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
40802 v = (v < 10) ? 10 : v;
40803 v = (v > 48) ? 48 : v;
40804 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
40809 v = Math.max(1, v+adjust);
40811 this.execCmd('FontSize', v );
40814 onEditorEvent : function(e){
40815 this.fireEvent('editorevent', this, e);
40816 // this.updateToolbar();
40817 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
40820 insertTag : function(tg)
40822 // could be a bit smarter... -> wrap the current selected tRoo..
40823 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
40825 range = this.createRange(this.getSelection());
40826 var wrappingNode = this.doc.createElement(tg.toLowerCase());
40827 wrappingNode.appendChild(range.extractContents());
40828 range.insertNode(wrappingNode);
40835 this.execCmd("formatblock", tg);
40839 insertText : function(txt)
40843 var range = this.createRange();
40844 range.deleteContents();
40845 //alert(Sender.getAttribute('label'));
40847 range.insertNode(this.doc.createTextNode(txt));
40851 relayBtnCmd : function(btn){
40852 this.relayCmd(btn.cmd);
40856 * Executes a Midas editor command on the editor document and performs necessary focus and
40857 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
40858 * @param {String} cmd The Midas command
40859 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
40861 relayCmd : function(cmd, value){
40863 this.execCmd(cmd, value);
40864 this.fireEvent('editorevent', this);
40865 //this.updateToolbar();
40870 * Executes a Midas editor command directly on the editor document.
40871 * For visual commands, you should use {@link #relayCmd} instead.
40872 * <b>This should only be called after the editor is initialized.</b>
40873 * @param {String} cmd The Midas command
40874 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
40876 execCmd : function(cmd, value){
40877 this.doc.execCommand(cmd, false, value === undefined ? null : value);
40884 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
40886 * @param {String} text | dom node..
40888 insertAtCursor : function(text)
40893 if(!this.activated){
40899 var r = this.doc.selection.createRange();
40910 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
40914 // from jquery ui (MIT licenced)
40916 var win = this.win;
40918 if (win.getSelection && win.getSelection().getRangeAt) {
40919 range = win.getSelection().getRangeAt(0);
40920 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
40921 range.insertNode(node);
40922 } else if (win.document.selection && win.document.selection.createRange) {
40923 // no firefox support
40924 var txt = typeof(text) == 'string' ? text : text.outerHTML;
40925 win.document.selection.createRange().pasteHTML(txt);
40927 // no firefox support
40928 var txt = typeof(text) == 'string' ? text : text.outerHTML;
40929 this.execCmd('InsertHTML', txt);
40938 mozKeyPress : function(e){
40940 var c = e.getCharCode(), cmd;
40943 c = String.fromCharCode(c).toLowerCase();
40957 this.cleanUpPaste.defer(100, this);
40965 e.preventDefault();
40973 fixKeys : function(){ // load time branching for fastest keydown performance
40975 return function(e){
40976 var k = e.getKey(), r;
40979 r = this.doc.selection.createRange();
40982 r.pasteHTML('    ');
40989 r = this.doc.selection.createRange();
40991 var target = r.parentElement();
40992 if(!target || target.tagName.toLowerCase() != 'li'){
40994 r.pasteHTML('<br />');
41000 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41001 this.cleanUpPaste.defer(100, this);
41007 }else if(Roo.isOpera){
41008 return function(e){
41009 var k = e.getKey();
41013 this.execCmd('InsertHTML','    ');
41016 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41017 this.cleanUpPaste.defer(100, this);
41022 }else if(Roo.isSafari){
41023 return function(e){
41024 var k = e.getKey();
41028 this.execCmd('InsertText','\t');
41032 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41033 this.cleanUpPaste.defer(100, this);
41041 getAllAncestors: function()
41043 var p = this.getSelectedNode();
41046 a.push(p); // push blank onto stack..
41047 p = this.getParentElement();
41051 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41055 a.push(this.doc.body);
41059 lastSelNode : false,
41062 getSelection : function()
41064 this.assignDocWin();
41065 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41068 getSelectedNode: function()
41070 // this may only work on Gecko!!!
41072 // should we cache this!!!!
41077 var range = this.createRange(this.getSelection()).cloneRange();
41080 var parent = range.parentElement();
41082 var testRange = range.duplicate();
41083 testRange.moveToElementText(parent);
41084 if (testRange.inRange(range)) {
41087 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41090 parent = parent.parentElement;
41095 // is ancestor a text element.
41096 var ac = range.commonAncestorContainer;
41097 if (ac.nodeType == 3) {
41098 ac = ac.parentNode;
41101 var ar = ac.childNodes;
41104 var other_nodes = [];
41105 var has_other_nodes = false;
41106 for (var i=0;i<ar.length;i++) {
41107 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41110 // fullly contained node.
41112 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41117 // probably selected..
41118 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41119 other_nodes.push(ar[i]);
41123 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41128 has_other_nodes = true;
41130 if (!nodes.length && other_nodes.length) {
41131 nodes= other_nodes;
41133 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41139 createRange: function(sel)
41141 // this has strange effects when using with
41142 // top toolbar - not sure if it's a great idea.
41143 //this.editor.contentWindow.focus();
41144 if (typeof sel != "undefined") {
41146 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41148 return this.doc.createRange();
41151 return this.doc.createRange();
41154 getParentElement: function()
41157 this.assignDocWin();
41158 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41160 var range = this.createRange(sel);
41163 var p = range.commonAncestorContainer;
41164 while (p.nodeType == 3) { // text node
41175 * Range intersection.. the hard stuff...
41179 * [ -- selected range --- ]
41183 * if end is before start or hits it. fail.
41184 * if start is after end or hits it fail.
41186 * if either hits (but other is outside. - then it's not
41192 // @see http://www.thismuchiknow.co.uk/?p=64.
41193 rangeIntersectsNode : function(range, node)
41195 var nodeRange = node.ownerDocument.createRange();
41197 nodeRange.selectNode(node);
41199 nodeRange.selectNodeContents(node);
41202 var rangeStartRange = range.cloneRange();
41203 rangeStartRange.collapse(true);
41205 var rangeEndRange = range.cloneRange();
41206 rangeEndRange.collapse(false);
41208 var nodeStartRange = nodeRange.cloneRange();
41209 nodeStartRange.collapse(true);
41211 var nodeEndRange = nodeRange.cloneRange();
41212 nodeEndRange.collapse(false);
41214 return rangeStartRange.compareBoundaryPoints(
41215 Range.START_TO_START, nodeEndRange) == -1 &&
41216 rangeEndRange.compareBoundaryPoints(
41217 Range.START_TO_START, nodeStartRange) == 1;
41221 rangeCompareNode : function(range, node)
41223 var nodeRange = node.ownerDocument.createRange();
41225 nodeRange.selectNode(node);
41227 nodeRange.selectNodeContents(node);
41231 range.collapse(true);
41233 nodeRange.collapse(true);
41235 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41236 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41238 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41240 var nodeIsBefore = ss == 1;
41241 var nodeIsAfter = ee == -1;
41243 if (nodeIsBefore && nodeIsAfter)
41245 if (!nodeIsBefore && nodeIsAfter)
41246 return 1; //right trailed.
41248 if (nodeIsBefore && !nodeIsAfter)
41249 return 2; // left trailed.
41254 // private? - in a new class?
41255 cleanUpPaste : function()
41257 // cleans up the whole document..
41258 Roo.log('cleanuppaste');
41259 this.cleanUpChildren(this.doc.body);
41260 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41261 if (clean != this.doc.body.innerHTML) {
41262 this.doc.body.innerHTML = clean;
41267 cleanWordChars : function(input) {// change the chars to hex code
41268 var he = Roo.form.HtmlEditor;
41270 var output = input;
41271 Roo.each(he.swapCodes, function(sw) {
41272 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41274 output = output.replace(swapper, sw[1]);
41281 cleanUpChildren : function (n)
41283 if (!n.childNodes.length) {
41286 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41287 this.cleanUpChild(n.childNodes[i]);
41294 cleanUpChild : function (node)
41297 //console.log(node);
41298 if (node.nodeName == "#text") {
41299 // clean up silly Windows -- stuff?
41302 if (node.nodeName == "#comment") {
41303 node.parentNode.removeChild(node);
41304 // clean up silly Windows -- stuff?
41308 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
41310 node.parentNode.removeChild(node);
41315 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
41317 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41318 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41320 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41321 // remove_keep_children = true;
41324 if (remove_keep_children) {
41325 this.cleanUpChildren(node);
41326 // inserts everything just before this node...
41327 while (node.childNodes.length) {
41328 var cn = node.childNodes[0];
41329 node.removeChild(cn);
41330 node.parentNode.insertBefore(cn, node);
41332 node.parentNode.removeChild(node);
41336 if (!node.attributes || !node.attributes.length) {
41337 this.cleanUpChildren(node);
41341 function cleanAttr(n,v)
41344 if (v.match(/^\./) || v.match(/^\//)) {
41347 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41350 if (v.match(/^#/)) {
41353 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41354 node.removeAttribute(n);
41358 function cleanStyle(n,v)
41360 if (v.match(/expression/)) { //XSS?? should we even bother..
41361 node.removeAttribute(n);
41364 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.form.HtmlEditor.cwhite : ed.cwhite;
41365 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.form.HtmlEditor.cblack : ed.cblack;
41368 var parts = v.split(/;/);
41371 Roo.each(parts, function(p) {
41372 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
41376 var l = p.split(':').shift().replace(/\s+/g,'');
41377 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
41380 if ( cblack.indexOf(l) > -1) {
41381 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41382 //node.removeAttribute(n);
41386 // only allow 'c whitelisted system attributes'
41387 if ( cwhite.length && cwhite.indexOf(l) < 0) {
41388 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41389 //node.removeAttribute(n);
41399 if (clean.length) {
41400 node.setAttribute(n, clean.join(';'));
41402 node.removeAttribute(n);
41408 for (var i = node.attributes.length-1; i > -1 ; i--) {
41409 var a = node.attributes[i];
41412 if (a.name.toLowerCase().substr(0,2)=='on') {
41413 node.removeAttribute(a.name);
41416 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
41417 node.removeAttribute(a.name);
41420 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
41421 cleanAttr(a.name,a.value); // fixme..
41424 if (a.name == 'style') {
41425 cleanStyle(a.name,a.value);
41428 /// clean up MS crap..
41429 // tecnically this should be a list of valid class'es..
41432 if (a.name == 'class') {
41433 if (a.value.match(/^Mso/)) {
41434 node.className = '';
41437 if (a.value.match(/body/)) {
41438 node.className = '';
41449 this.cleanUpChildren(node);
41455 // hide stuff that is not compatible
41469 * @event specialkey
41473 * @cfg {String} fieldClass @hide
41476 * @cfg {String} focusClass @hide
41479 * @cfg {String} autoCreate @hide
41482 * @cfg {String} inputType @hide
41485 * @cfg {String} invalidClass @hide
41488 * @cfg {String} invalidText @hide
41491 * @cfg {String} msgFx @hide
41494 * @cfg {String} validateOnBlur @hide
41498 Roo.form.HtmlEditor.white = [
41499 'area', 'br', 'img', 'input', 'hr', 'wbr',
41501 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
41502 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
41503 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
41504 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
41505 'table', 'ul', 'xmp',
41507 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
41510 'dir', 'menu', 'ol', 'ul', 'dl',
41516 Roo.form.HtmlEditor.black = [
41517 // 'embed', 'object', // enable - backend responsiblity to clean thiese
41519 'base', 'basefont', 'bgsound', 'blink', 'body',
41520 'frame', 'frameset', 'head', 'html', 'ilayer',
41521 'iframe', 'layer', 'link', 'meta', 'object',
41522 'script', 'style' ,'title', 'xml' // clean later..
41524 Roo.form.HtmlEditor.clean = [
41525 'script', 'style', 'title', 'xml'
41527 Roo.form.HtmlEditor.remove = [
41532 Roo.form.HtmlEditor.ablack = [
41536 Roo.form.HtmlEditor.aclean = [
41537 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
41541 Roo.form.HtmlEditor.pwhite= [
41542 'http', 'https', 'mailto'
41545 // white listed style attributes.
41546 Roo.form.HtmlEditor.cwhite= [
41547 // 'text-align', /// default is to allow most things..
41553 // black listed style attributes.
41554 Roo.form.HtmlEditor.cblack= [
41555 // 'font-size' -- this can be set by the project
41559 Roo.form.HtmlEditor.swapCodes =[
41570 // <script type="text/javascript">
41573 * Ext JS Library 1.1.1
41574 * Copyright(c) 2006-2007, Ext JS, LLC.
41580 * @class Roo.form.HtmlEditorToolbar1
41585 new Roo.form.HtmlEditor({
41588 new Roo.form.HtmlEditorToolbar1({
41589 disable : { fonts: 1 , format: 1, ..., ... , ...],
41595 * @cfg {Object} disable List of elements to disable..
41596 * @cfg {Array} btns List of additional buttons.
41600 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
41603 Roo.form.HtmlEditor.ToolbarStandard = function(config)
41606 Roo.apply(this, config);
41608 // default disabled, based on 'good practice'..
41609 this.disable = this.disable || {};
41610 Roo.applyIf(this.disable, {
41613 specialElements : true
41617 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
41618 // dont call parent... till later.
41621 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
41629 * @cfg {Object} disable List of toolbar elements to disable
41634 * @cfg {Array} fontFamilies An array of available font families
41652 // "á" , ?? a acute?
41657 "°" // , // degrees
41659 // "é" , // e ecute
41660 // "ú" , // u ecute?
41663 specialElements : [
41665 text: "Insert Table",
41668 ihtml : '<table><tr><td>Cell</td></tr></table>'
41672 text: "Insert Image",
41675 ihtml : '<img src="about:blank"/>'
41684 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
41685 "input:submit", "input:button", "select", "textarea", "label" ],
41688 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
41690 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
41698 * @cfg {String} defaultFont default font to use.
41700 defaultFont: 'tahoma',
41702 fontSelect : false,
41705 formatCombo : false,
41707 init : function(editor)
41709 this.editor = editor;
41712 var fid = editor.frameId;
41714 function btn(id, toggle, handler){
41715 var xid = fid + '-'+ id ;
41719 cls : 'x-btn-icon x-edit-'+id,
41720 enableToggle:toggle !== false,
41721 scope: editor, // was editor...
41722 handler:handler||editor.relayBtnCmd,
41723 clickEvent:'mousedown',
41724 tooltip: etb.buttonTips[id] || undefined, ///tips ???
41731 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
41733 // stop form submits
41734 tb.el.on('click', function(e){
41735 e.preventDefault(); // what does this do?
41738 if(!this.disable.font) { // && !Roo.isSafari){
41739 /* why no safari for fonts
41740 editor.fontSelect = tb.el.createChild({
41743 cls:'x-font-select',
41744 html: this.createFontOptions()
41747 editor.fontSelect.on('change', function(){
41748 var font = editor.fontSelect.dom.value;
41749 editor.relayCmd('fontname', font);
41750 editor.deferFocus();
41754 editor.fontSelect.dom,
41760 if(!this.disable.formats){
41761 this.formatCombo = new Roo.form.ComboBox({
41762 store: new Roo.data.SimpleStore({
41765 data : this.formats // from states.js
41769 //autoCreate : {tag: "div", size: "20"},
41770 displayField:'tag',
41774 triggerAction: 'all',
41775 emptyText:'Add tag',
41776 selectOnFocus:true,
41779 'select': function(c, r, i) {
41780 editor.insertTag(r.get('tag'));
41786 tb.addField(this.formatCombo);
41790 if(!this.disable.format){
41797 if(!this.disable.fontSize){
41802 btn('increasefontsize', false, editor.adjustFont),
41803 btn('decreasefontsize', false, editor.adjustFont)
41808 if(!this.disable.colors){
41811 id:editor.frameId +'-forecolor',
41812 cls:'x-btn-icon x-edit-forecolor',
41813 clickEvent:'mousedown',
41814 tooltip: this.buttonTips['forecolor'] || undefined,
41816 menu : new Roo.menu.ColorMenu({
41817 allowReselect: true,
41818 focus: Roo.emptyFn,
41821 selectHandler: function(cp, color){
41822 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
41823 editor.deferFocus();
41826 clickEvent:'mousedown'
41829 id:editor.frameId +'backcolor',
41830 cls:'x-btn-icon x-edit-backcolor',
41831 clickEvent:'mousedown',
41832 tooltip: this.buttonTips['backcolor'] || undefined,
41834 menu : new Roo.menu.ColorMenu({
41835 focus: Roo.emptyFn,
41838 allowReselect: true,
41839 selectHandler: function(cp, color){
41841 editor.execCmd('useCSS', false);
41842 editor.execCmd('hilitecolor', color);
41843 editor.execCmd('useCSS', true);
41844 editor.deferFocus();
41846 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
41847 Roo.isSafari || Roo.isIE ? '#'+color : color);
41848 editor.deferFocus();
41852 clickEvent:'mousedown'
41857 // now add all the items...
41860 if(!this.disable.alignments){
41863 btn('justifyleft'),
41864 btn('justifycenter'),
41865 btn('justifyright')
41869 //if(!Roo.isSafari){
41870 if(!this.disable.links){
41873 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
41877 if(!this.disable.lists){
41880 btn('insertorderedlist'),
41881 btn('insertunorderedlist')
41884 if(!this.disable.sourceEdit){
41887 btn('sourceedit', true, function(btn){
41888 this.toggleSourceEdit(btn.pressed);
41895 // special menu.. - needs to be tidied up..
41896 if (!this.disable.special) {
41899 cls: 'x-edit-none',
41905 for (var i =0; i < this.specialChars.length; i++) {
41906 smenu.menu.items.push({
41908 html: this.specialChars[i],
41909 handler: function(a,b) {
41910 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
41911 //editor.insertAtCursor(a.html);
41925 if (!this.disable.cleanStyles) {
41927 cls: 'x-btn-icon x-btn-clear',
41933 for (var i =0; i < this.cleanStyles.length; i++) {
41934 cmenu.menu.items.push({
41935 actiontype : this.cleanStyles[i],
41936 html: 'Remove ' + this.cleanStyles[i],
41937 handler: function(a,b) {
41940 var c = Roo.get(editor.doc.body);
41941 c.select('[style]').each(function(s) {
41942 s.dom.style.removeProperty(a.actiontype);
41953 if (!this.disable.specialElements) {
41956 cls: 'x-edit-none',
41961 for (var i =0; i < this.specialElements.length; i++) {
41962 semenu.menu.items.push(
41964 handler: function(a,b) {
41965 editor.insertAtCursor(this.ihtml);
41967 }, this.specialElements[i])
41979 for(var i =0; i< this.btns.length;i++) {
41980 var b = Roo.factory(this.btns[i],Roo.form);
41981 b.cls = 'x-edit-none';
41990 // disable everything...
41992 this.tb.items.each(function(item){
41993 if(item.id != editor.frameId+ '-sourceedit'){
41997 this.rendered = true;
41999 // the all the btns;
42000 editor.on('editorevent', this.updateToolbar, this);
42001 // other toolbars need to implement this..
42002 //editor.on('editmodechange', this.updateToolbar, this);
42008 * Protected method that will not generally be called directly. It triggers
42009 * a toolbar update by reading the markup state of the current selection in the editor.
42011 updateToolbar: function(){
42013 if(!this.editor.activated){
42014 this.editor.onFirstFocus();
42018 var btns = this.tb.items.map,
42019 doc = this.editor.doc,
42020 frameId = this.editor.frameId;
42022 if(!this.disable.font && !Roo.isSafari){
42024 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
42025 if(name != this.fontSelect.dom.value){
42026 this.fontSelect.dom.value = name;
42030 if(!this.disable.format){
42031 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
42032 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
42033 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
42035 if(!this.disable.alignments){
42036 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
42037 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
42038 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
42040 if(!Roo.isSafari && !this.disable.lists){
42041 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
42042 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
42045 var ans = this.editor.getAllAncestors();
42046 if (this.formatCombo) {
42049 var store = this.formatCombo.store;
42050 this.formatCombo.setValue("");
42051 for (var i =0; i < ans.length;i++) {
42052 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
42054 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
42062 // hides menus... - so this cant be on a menu...
42063 Roo.menu.MenuMgr.hideAll();
42065 //this.editorsyncValue();
42069 createFontOptions : function(){
42070 var buf = [], fs = this.fontFamilies, ff, lc;
42074 for(var i = 0, len = fs.length; i< len; i++){
42076 lc = ff.toLowerCase();
42078 '<option value="',lc,'" style="font-family:',ff,';"',
42079 (this.defaultFont == lc ? ' selected="true">' : '>'),
42084 return buf.join('');
42087 toggleSourceEdit : function(sourceEditMode){
42088 if(sourceEditMode === undefined){
42089 sourceEditMode = !this.sourceEditMode;
42091 this.sourceEditMode = sourceEditMode === true;
42092 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
42093 // just toggle the button?
42094 if(btn.pressed !== this.editor.sourceEditMode){
42095 btn.toggle(this.editor.sourceEditMode);
42099 if(this.sourceEditMode){
42100 this.tb.items.each(function(item){
42101 if(item.cmd != 'sourceedit'){
42107 if(this.initialized){
42108 this.tb.items.each(function(item){
42114 // tell the editor that it's been pressed..
42115 this.editor.toggleSourceEdit(sourceEditMode);
42119 * Object collection of toolbar tooltips for the buttons in the editor. The key
42120 * is the command id associated with that button and the value is a valid QuickTips object.
42125 title: 'Bold (Ctrl+B)',
42126 text: 'Make the selected text bold.',
42127 cls: 'x-html-editor-tip'
42130 title: 'Italic (Ctrl+I)',
42131 text: 'Make the selected text italic.',
42132 cls: 'x-html-editor-tip'
42140 title: 'Bold (Ctrl+B)',
42141 text: 'Make the selected text bold.',
42142 cls: 'x-html-editor-tip'
42145 title: 'Italic (Ctrl+I)',
42146 text: 'Make the selected text italic.',
42147 cls: 'x-html-editor-tip'
42150 title: 'Underline (Ctrl+U)',
42151 text: 'Underline the selected text.',
42152 cls: 'x-html-editor-tip'
42154 increasefontsize : {
42155 title: 'Grow Text',
42156 text: 'Increase the font size.',
42157 cls: 'x-html-editor-tip'
42159 decreasefontsize : {
42160 title: 'Shrink Text',
42161 text: 'Decrease the font size.',
42162 cls: 'x-html-editor-tip'
42165 title: 'Text Highlight Color',
42166 text: 'Change the background color of the selected text.',
42167 cls: 'x-html-editor-tip'
42170 title: 'Font Color',
42171 text: 'Change the color of the selected text.',
42172 cls: 'x-html-editor-tip'
42175 title: 'Align Text Left',
42176 text: 'Align text to the left.',
42177 cls: 'x-html-editor-tip'
42180 title: 'Center Text',
42181 text: 'Center text in the editor.',
42182 cls: 'x-html-editor-tip'
42185 title: 'Align Text Right',
42186 text: 'Align text to the right.',
42187 cls: 'x-html-editor-tip'
42189 insertunorderedlist : {
42190 title: 'Bullet List',
42191 text: 'Start a bulleted list.',
42192 cls: 'x-html-editor-tip'
42194 insertorderedlist : {
42195 title: 'Numbered List',
42196 text: 'Start a numbered list.',
42197 cls: 'x-html-editor-tip'
42200 title: 'Hyperlink',
42201 text: 'Make the selected text a hyperlink.',
42202 cls: 'x-html-editor-tip'
42205 title: 'Source Edit',
42206 text: 'Switch to source editing mode.',
42207 cls: 'x-html-editor-tip'
42211 onDestroy : function(){
42214 this.tb.items.each(function(item){
42216 item.menu.removeAll();
42218 item.menu.el.destroy();
42226 onFirstFocus: function() {
42227 this.tb.items.each(function(item){
42236 // <script type="text/javascript">
42239 * Ext JS Library 1.1.1
42240 * Copyright(c) 2006-2007, Ext JS, LLC.
42247 * @class Roo.form.HtmlEditor.ToolbarContext
42252 new Roo.form.HtmlEditor({
42255 { xtype: 'ToolbarStandard', styles : {} }
42256 { xtype: 'ToolbarContext', disable : {} }
42262 * @config : {Object} disable List of elements to disable.. (not done yet.)
42263 * @config : {Object} styles Map of styles available.
42267 Roo.form.HtmlEditor.ToolbarContext = function(config)
42270 Roo.apply(this, config);
42271 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42272 // dont call parent... till later.
42273 this.styles = this.styles || {};
42278 Roo.form.HtmlEditor.ToolbarContext.types = {
42290 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
42352 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
42357 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
42367 style : 'fontFamily',
42368 displayField: 'display',
42369 optname : 'font-family',
42418 // should we really allow this??
42419 // should this just be
42430 style : 'fontFamily',
42431 displayField: 'display',
42432 optname : 'font-family',
42439 style : 'fontFamily',
42440 displayField: 'display',
42441 optname : 'font-family',
42448 style : 'fontFamily',
42449 displayField: 'display',
42450 optname : 'font-family',
42461 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
42462 Roo.form.HtmlEditor.ToolbarContext.stores = false;
42464 Roo.form.HtmlEditor.ToolbarContext.options = {
42466 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
42467 [ 'Courier New', 'Courier New'],
42468 [ 'Tahoma', 'Tahoma'],
42469 [ 'Times New Roman,serif', 'Times'],
42470 [ 'Verdana','Verdana' ]
42474 // fixme - these need to be configurable..
42477 Roo.form.HtmlEditor.ToolbarContext.types
42480 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
42488 * @cfg {Object} disable List of toolbar elements to disable
42493 * @cfg {Object} styles List of styles
42494 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
42496 * These must be defined in the page, so they get rendered correctly..
42507 init : function(editor)
42509 this.editor = editor;
42512 var fid = editor.frameId;
42514 function btn(id, toggle, handler){
42515 var xid = fid + '-'+ id ;
42519 cls : 'x-btn-icon x-edit-'+id,
42520 enableToggle:toggle !== false,
42521 scope: editor, // was editor...
42522 handler:handler||editor.relayBtnCmd,
42523 clickEvent:'mousedown',
42524 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42528 // create a new element.
42529 var wdiv = editor.wrap.createChild({
42531 }, editor.wrap.dom.firstChild.nextSibling, true);
42533 // can we do this more than once??
42535 // stop form submits
42538 // disable everything...
42539 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
42540 this.toolbars = {};
42542 for (var i in ty) {
42544 this.toolbars[i] = this.buildToolbar(ty[i],i);
42546 this.tb = this.toolbars.BODY;
42548 this.buildFooter();
42549 this.footer.show();
42550 editor.on('hide', function( ) { this.footer.hide() }, this);
42551 editor.on('show', function( ) { this.footer.show() }, this);
42554 this.rendered = true;
42556 // the all the btns;
42557 editor.on('editorevent', this.updateToolbar, this);
42558 // other toolbars need to implement this..
42559 //editor.on('editmodechange', this.updateToolbar, this);
42565 * Protected method that will not generally be called directly. It triggers
42566 * a toolbar update by reading the markup state of the current selection in the editor.
42568 updateToolbar: function(editor,ev,sel){
42571 // capture mouse up - this is handy for selecting images..
42572 // perhaps should go somewhere else...
42573 if(!this.editor.activated){
42574 this.editor.onFirstFocus();
42578 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
42579 // selectNode - might want to handle IE?
42581 (ev.type == 'mouseup' || ev.type == 'click' ) &&
42582 ev.target && ev.target.tagName == 'IMG') {
42583 // they have click on an image...
42584 // let's see if we can change the selection...
42587 var nodeRange = sel.ownerDocument.createRange();
42589 nodeRange.selectNode(sel);
42591 nodeRange.selectNodeContents(sel);
42593 //nodeRange.collapse(true);
42594 var s = editor.win.getSelection();
42595 s.removeAllRanges();
42596 s.addRange(nodeRange);
42600 var updateFooter = sel ? false : true;
42603 var ans = this.editor.getAllAncestors();
42606 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
42609 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
42610 sel = sel ? sel : this.editor.doc.body;
42611 sel = sel.tagName.length ? sel : this.editor.doc.body;
42614 // pick a menu that exists..
42615 var tn = sel.tagName.toUpperCase();
42616 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
42618 tn = sel.tagName.toUpperCase();
42620 var lastSel = this.tb.selectedNode
42622 this.tb.selectedNode = sel;
42624 // if current menu does not match..
42625 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
42628 ///console.log("show: " + tn);
42629 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
42632 this.tb.items.first().el.innerHTML = tn + ': ';
42635 // update attributes
42636 if (this.tb.fields) {
42637 this.tb.fields.each(function(e) {
42639 e.setValue(sel.style[e.stylename]);
42642 e.setValue(sel.getAttribute(e.attrname));
42646 var hasStyles = false;
42647 for(var i in this.styles) {
42654 var st = this.tb.fields.item(0);
42656 st.store.removeAll();
42659 var cn = sel.className.split(/\s+/);
42662 if (this.styles['*']) {
42664 Roo.each(this.styles['*'], function(v) {
42665 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
42668 if (this.styles[tn]) {
42669 Roo.each(this.styles[tn], function(v) {
42670 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
42674 st.store.loadData(avs);
42678 // flag our selected Node.
42679 this.tb.selectedNode = sel;
42682 Roo.menu.MenuMgr.hideAll();
42686 if (!updateFooter) {
42687 //this.footDisp.dom.innerHTML = '';
42690 // update the footer
42694 this.footerEls = ans.reverse();
42695 Roo.each(this.footerEls, function(a,i) {
42696 if (!a) { return; }
42697 html += html.length ? ' > ' : '';
42699 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
42704 var sz = this.footDisp.up('td').getSize();
42705 this.footDisp.dom.style.width = (sz.width -10) + 'px';
42706 this.footDisp.dom.style.marginLeft = '5px';
42708 this.footDisp.dom.style.overflow = 'hidden';
42710 this.footDisp.dom.innerHTML = html;
42712 //this.editorsyncValue();
42719 onDestroy : function(){
42722 this.tb.items.each(function(item){
42724 item.menu.removeAll();
42726 item.menu.el.destroy();
42734 onFirstFocus: function() {
42735 // need to do this for all the toolbars..
42736 this.tb.items.each(function(item){
42740 buildToolbar: function(tlist, nm)
42742 var editor = this.editor;
42743 // create a new element.
42744 var wdiv = editor.wrap.createChild({
42746 }, editor.wrap.dom.firstChild.nextSibling, true);
42749 var tb = new Roo.Toolbar(wdiv);
42752 tb.add(nm+ ": ");
42755 for(var i in this.styles) {
42760 if (styles && styles.length) {
42762 // this needs a multi-select checkbox...
42763 tb.addField( new Roo.form.ComboBox({
42764 store: new Roo.data.SimpleStore({
42766 fields: ['val', 'selected'],
42769 name : '-roo-edit-className',
42770 attrname : 'className',
42771 displayField: 'val',
42775 triggerAction: 'all',
42776 emptyText:'Select Style',
42777 selectOnFocus:true,
42780 'select': function(c, r, i) {
42781 // initial support only for on class per el..
42782 tb.selectedNode.className = r ? r.get('val') : '';
42783 editor.syncValue();
42790 var tbc = Roo.form.HtmlEditor.ToolbarContext;
42791 var tbops = tbc.options;
42793 for (var i in tlist) {
42795 var item = tlist[i];
42796 tb.add(item.title + ": ");
42799 //optname == used so you can configure the options available..
42800 var opts = item.opts ? item.opts : false;
42801 if (item.optname) {
42802 opts = tbops[item.optname];
42807 // opts == pulldown..
42808 tb.addField( new Roo.form.ComboBox({
42809 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
42811 fields: ['val', 'display'],
42814 name : '-roo-edit-' + i,
42816 stylename : item.style ? item.style : false,
42817 displayField: item.displayField ? item.displayField : 'val',
42818 valueField : 'val',
42820 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
42822 triggerAction: 'all',
42823 emptyText:'Select',
42824 selectOnFocus:true,
42825 width: item.width ? item.width : 130,
42827 'select': function(c, r, i) {
42829 tb.selectedNode.style[c.stylename] = r.get('val');
42832 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
42841 tb.addField( new Roo.form.TextField({
42844 //allowBlank:false,
42849 tb.addField( new Roo.form.TextField({
42850 name: '-roo-edit-' + i,
42857 'change' : function(f, nv, ov) {
42858 tb.selectedNode.setAttribute(f.attrname, nv);
42867 text: 'Remove Tag',
42870 click : function ()
42873 // undo does not work.
42875 var sn = tb.selectedNode;
42877 var pn = sn.parentNode;
42879 var stn = sn.childNodes[0];
42880 var en = sn.childNodes[sn.childNodes.length - 1 ];
42881 while (sn.childNodes.length) {
42882 var node = sn.childNodes[0];
42883 sn.removeChild(node);
42885 pn.insertBefore(node, sn);
42888 pn.removeChild(sn);
42889 var range = editor.createRange();
42891 range.setStart(stn,0);
42892 range.setEnd(en,0); //????
42893 //range.selectNode(sel);
42896 var selection = editor.getSelection();
42897 selection.removeAllRanges();
42898 selection.addRange(range);
42902 //_this.updateToolbar(null, null, pn);
42903 _this.updateToolbar(null, null, null);
42904 _this.footDisp.dom.innerHTML = '';
42914 tb.el.on('click', function(e){
42915 e.preventDefault(); // what does this do?
42917 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
42920 // dont need to disable them... as they will get hidden
42925 buildFooter : function()
42928 var fel = this.editor.wrap.createChild();
42929 this.footer = new Roo.Toolbar(fel);
42930 // toolbar has scrolly on left / right?
42931 var footDisp= new Roo.Toolbar.Fill();
42937 handler : function() {
42938 _t.footDisp.scrollTo('left',0,true)
42942 this.footer.add( footDisp );
42947 handler : function() {
42949 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
42953 var fel = Roo.get(footDisp.el);
42954 fel.addClass('x-editor-context');
42955 this.footDispWrap = fel;
42956 this.footDispWrap.overflow = 'hidden';
42958 this.footDisp = fel.createChild();
42959 this.footDispWrap.on('click', this.onContextClick, this)
42963 onContextClick : function (ev,dom)
42965 ev.preventDefault();
42966 var cn = dom.className;
42968 if (!cn.match(/x-ed-loc-/)) {
42971 var n = cn.split('-').pop();
42972 var ans = this.footerEls;
42976 var range = this.editor.createRange();
42978 range.selectNodeContents(sel);
42979 //range.selectNode(sel);
42982 var selection = this.editor.getSelection();
42983 selection.removeAllRanges();
42984 selection.addRange(range);
42988 this.updateToolbar(null, null, sel);
43005 * Ext JS Library 1.1.1
43006 * Copyright(c) 2006-2007, Ext JS, LLC.
43008 * Originally Released Under LGPL - original licence link has changed is not relivant.
43011 * <script type="text/javascript">
43015 * @class Roo.form.BasicForm
43016 * @extends Roo.util.Observable
43017 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
43019 * @param {String/HTMLElement/Roo.Element} el The form element or its id
43020 * @param {Object} config Configuration options
43022 Roo.form.BasicForm = function(el, config){
43023 this.allItems = [];
43024 this.childForms = [];
43025 Roo.apply(this, config);
43027 * The Roo.form.Field items in this form.
43028 * @type MixedCollection
43032 this.items = new Roo.util.MixedCollection(false, function(o){
43033 return o.id || (o.id = Roo.id());
43037 * @event beforeaction
43038 * Fires before any action is performed. Return false to cancel the action.
43039 * @param {Form} this
43040 * @param {Action} action The action to be performed
43042 beforeaction: true,
43044 * @event actionfailed
43045 * Fires when an action fails.
43046 * @param {Form} this
43047 * @param {Action} action The action that failed
43049 actionfailed : true,
43051 * @event actioncomplete
43052 * Fires when an action is completed.
43053 * @param {Form} this
43054 * @param {Action} action The action that completed
43056 actioncomplete : true
43061 Roo.form.BasicForm.superclass.constructor.call(this);
43064 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
43066 * @cfg {String} method
43067 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
43070 * @cfg {DataReader} reader
43071 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
43072 * This is optional as there is built-in support for processing JSON.
43075 * @cfg {DataReader} errorReader
43076 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
43077 * This is completely optional as there is built-in support for processing JSON.
43080 * @cfg {String} url
43081 * The URL to use for form actions if one isn't supplied in the action options.
43084 * @cfg {Boolean} fileUpload
43085 * Set to true if this form is a file upload.
43089 * @cfg {Object} baseParams
43090 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
43095 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
43100 activeAction : null,
43103 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
43104 * or setValues() data instead of when the form was first created.
43106 trackResetOnLoad : false,
43110 * childForms - used for multi-tab forms
43113 childForms : false,
43116 * allItems - full list of fields.
43122 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
43123 * element by passing it or its id or mask the form itself by passing in true.
43126 waitMsgTarget : false,
43129 initEl : function(el){
43130 this.el = Roo.get(el);
43131 this.id = this.el.id || Roo.id();
43132 this.el.on('submit', this.onSubmit, this);
43133 this.el.addClass('x-form');
43137 onSubmit : function(e){
43142 * Returns true if client-side validation on the form is successful.
43145 isValid : function(){
43147 this.items.each(function(f){
43156 * Returns true if any fields in this form have changed since their original load.
43159 isDirty : function(){
43161 this.items.each(function(f){
43171 * Performs a predefined action (submit or load) or custom actions you define on this form.
43172 * @param {String} actionName The name of the action type
43173 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
43174 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
43175 * accept other config options):
43177 Property Type Description
43178 ---------------- --------------- ----------------------------------------------------------------------------------
43179 url String The url for the action (defaults to the form's url)
43180 method String The form method to use (defaults to the form's method, or POST if not defined)
43181 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
43182 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
43183 validate the form on the client (defaults to false)
43185 * @return {BasicForm} this
43187 doAction : function(action, options){
43188 if(typeof action == 'string'){
43189 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
43191 if(this.fireEvent('beforeaction', this, action) !== false){
43192 this.beforeAction(action);
43193 action.run.defer(100, action);
43199 * Shortcut to do a submit action.
43200 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43201 * @return {BasicForm} this
43203 submit : function(options){
43204 this.doAction('submit', options);
43209 * Shortcut to do a load action.
43210 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43211 * @return {BasicForm} this
43213 load : function(options){
43214 this.doAction('load', options);
43219 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
43220 * @param {Record} record The record to edit
43221 * @return {BasicForm} this
43223 updateRecord : function(record){
43224 record.beginEdit();
43225 var fs = record.fields;
43226 fs.each(function(f){
43227 var field = this.findField(f.name);
43229 record.set(f.name, field.getValue());
43237 * Loads an Roo.data.Record into this form.
43238 * @param {Record} record The record to load
43239 * @return {BasicForm} this
43241 loadRecord : function(record){
43242 this.setValues(record.data);
43247 beforeAction : function(action){
43248 var o = action.options;
43251 if(this.waitMsgTarget === true){
43252 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
43253 }else if(this.waitMsgTarget){
43254 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
43255 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
43257 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
43263 afterAction : function(action, success){
43264 this.activeAction = null;
43265 var o = action.options;
43267 if(this.waitMsgTarget === true){
43269 }else if(this.waitMsgTarget){
43270 this.waitMsgTarget.unmask();
43272 Roo.MessageBox.updateProgress(1);
43273 Roo.MessageBox.hide();
43280 Roo.callback(o.success, o.scope, [this, action]);
43281 this.fireEvent('actioncomplete', this, action);
43285 // failure condition..
43286 // we have a scenario where updates need confirming.
43287 // eg. if a locking scenario exists..
43288 // we look for { errors : { needs_confirm : true }} in the response.
43290 (typeof(action.result) != 'undefined') &&
43291 (typeof(action.result.errors) != 'undefined') &&
43292 (typeof(action.result.errors.needs_confirm) != 'undefined')
43295 Roo.MessageBox.confirm(
43296 "Change requires confirmation",
43297 action.result.errorMsg,
43302 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
43312 Roo.callback(o.failure, o.scope, [this, action]);
43313 // show an error message if no failed handler is set..
43314 if (!this.hasListener('actionfailed')) {
43315 Roo.MessageBox.alert("Error",
43316 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
43317 action.result.errorMsg :
43318 "Saving Failed, please check your entries or try again"
43322 this.fireEvent('actionfailed', this, action);
43328 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
43329 * @param {String} id The value to search for
43332 findField : function(id){
43333 var field = this.items.get(id);
43335 this.items.each(function(f){
43336 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
43342 return field || null;
43346 * Add a secondary form to this one,
43347 * Used to provide tabbed forms. One form is primary, with hidden values
43348 * which mirror the elements from the other forms.
43350 * @param {Roo.form.Form} form to add.
43353 addForm : function(form)
43356 if (this.childForms.indexOf(form) > -1) {
43360 this.childForms.push(form);
43362 Roo.each(form.allItems, function (fe) {
43364 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
43365 if (this.findField(n)) { // already added..
43368 var add = new Roo.form.Hidden({
43371 add.render(this.el);
43378 * Mark fields in this form invalid in bulk.
43379 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
43380 * @return {BasicForm} this
43382 markInvalid : function(errors){
43383 if(errors instanceof Array){
43384 for(var i = 0, len = errors.length; i < len; i++){
43385 var fieldError = errors[i];
43386 var f = this.findField(fieldError.id);
43388 f.markInvalid(fieldError.msg);
43394 if(typeof errors[id] != 'function' && (field = this.findField(id))){
43395 field.markInvalid(errors[id]);
43399 Roo.each(this.childForms || [], function (f) {
43400 f.markInvalid(errors);
43407 * Set values for fields in this form in bulk.
43408 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
43409 * @return {BasicForm} this
43411 setValues : function(values){
43412 if(values instanceof Array){ // array of objects
43413 for(var i = 0, len = values.length; i < len; i++){
43415 var f = this.findField(v.id);
43417 f.setValue(v.value);
43418 if(this.trackResetOnLoad){
43419 f.originalValue = f.getValue();
43423 }else{ // object hash
43426 if(typeof values[id] != 'function' && (field = this.findField(id))){
43428 if (field.setFromData &&
43429 field.valueField &&
43430 field.displayField &&
43431 // combos' with local stores can
43432 // be queried via setValue()
43433 // to set their value..
43434 (field.store && !field.store.isLocal)
43438 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
43439 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
43440 field.setFromData(sd);
43443 field.setValue(values[id]);
43447 if(this.trackResetOnLoad){
43448 field.originalValue = field.getValue();
43454 Roo.each(this.childForms || [], function (f) {
43455 f.setValues(values);
43462 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
43463 * they are returned as an array.
43464 * @param {Boolean} asString
43467 getValues : function(asString){
43468 if (this.childForms) {
43469 // copy values from the child forms
43470 Roo.each(this.childForms, function (f) {
43471 this.setValues(f.getValues());
43477 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
43478 if(asString === true){
43481 return Roo.urlDecode(fs);
43485 * Returns the fields in this form as an object with key/value pairs.
43486 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
43489 getFieldValues : function(with_hidden)
43491 if (this.childForms) {
43492 // copy values from the child forms
43493 // should this call getFieldValues - probably not as we do not currently copy
43494 // hidden fields when we generate..
43495 Roo.each(this.childForms, function (f) {
43496 this.setValues(f.getValues());
43501 this.items.each(function(f){
43502 if (!f.getName()) {
43505 var v = f.getValue();
43506 if (f.inputType =='radio') {
43507 if (typeof(ret[f.getName()]) == 'undefined') {
43508 ret[f.getName()] = ''; // empty..
43511 if (!f.el.dom.checked) {
43515 v = f.el.dom.value;
43519 // not sure if this supported any more..
43520 if ((typeof(v) == 'object') && f.getRawValue) {
43521 v = f.getRawValue() ; // dates..
43523 // combo boxes where name != hiddenName...
43524 if (f.name != f.getName()) {
43525 ret[f.name] = f.getRawValue();
43527 ret[f.getName()] = v;
43534 * Clears all invalid messages in this form.
43535 * @return {BasicForm} this
43537 clearInvalid : function(){
43538 this.items.each(function(f){
43542 Roo.each(this.childForms || [], function (f) {
43551 * Resets this form.
43552 * @return {BasicForm} this
43554 reset : function(){
43555 this.items.each(function(f){
43559 Roo.each(this.childForms || [], function (f) {
43568 * Add Roo.form components to this form.
43569 * @param {Field} field1
43570 * @param {Field} field2 (optional)
43571 * @param {Field} etc (optional)
43572 * @return {BasicForm} this
43575 this.items.addAll(Array.prototype.slice.call(arguments, 0));
43581 * Removes a field from the items collection (does NOT remove its markup).
43582 * @param {Field} field
43583 * @return {BasicForm} this
43585 remove : function(field){
43586 this.items.remove(field);
43591 * Looks at the fields in this form, checks them for an id attribute,
43592 * and calls applyTo on the existing dom element with that id.
43593 * @return {BasicForm} this
43595 render : function(){
43596 this.items.each(function(f){
43597 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
43605 * Calls {@link Ext#apply} for all fields in this form with the passed object.
43606 * @param {Object} values
43607 * @return {BasicForm} this
43609 applyToFields : function(o){
43610 this.items.each(function(f){
43617 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
43618 * @param {Object} values
43619 * @return {BasicForm} this
43621 applyIfToFields : function(o){
43622 this.items.each(function(f){
43630 Roo.BasicForm = Roo.form.BasicForm;/*
43632 * Ext JS Library 1.1.1
43633 * Copyright(c) 2006-2007, Ext JS, LLC.
43635 * Originally Released Under LGPL - original licence link has changed is not relivant.
43638 * <script type="text/javascript">
43642 * @class Roo.form.Form
43643 * @extends Roo.form.BasicForm
43644 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
43646 * @param {Object} config Configuration options
43648 Roo.form.Form = function(config){
43650 if (config.items) {
43651 xitems = config.items;
43652 delete config.items;
43656 Roo.form.Form.superclass.constructor.call(this, null, config);
43657 this.url = this.url || this.action;
43659 this.root = new Roo.form.Layout(Roo.applyIf({
43663 this.active = this.root;
43665 * Array of all the buttons that have been added to this form via {@link addButton}
43669 this.allItems = [];
43672 * @event clientvalidation
43673 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
43674 * @param {Form} this
43675 * @param {Boolean} valid true if the form has passed client-side validation
43677 clientvalidation: true,
43680 * Fires when the form is rendered
43681 * @param {Roo.form.Form} form
43686 if (this.progressUrl) {
43687 // push a hidden field onto the list of fields..
43691 name : 'UPLOAD_IDENTIFIER'
43696 Roo.each(xitems, this.addxtype, this);
43702 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
43704 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
43707 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
43710 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
43712 buttonAlign:'center',
43715 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
43720 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
43721 * This property cascades to child containers if not set.
43726 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
43727 * fires a looping event with that state. This is required to bind buttons to the valid
43728 * state using the config value formBind:true on the button.
43730 monitorValid : false,
43733 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
43738 * @cfg {String} progressUrl - Url to return progress data
43741 progressUrl : false,
43744 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
43745 * fields are added and the column is closed. If no fields are passed the column remains open
43746 * until end() is called.
43747 * @param {Object} config The config to pass to the column
43748 * @param {Field} field1 (optional)
43749 * @param {Field} field2 (optional)
43750 * @param {Field} etc (optional)
43751 * @return Column The column container object
43753 column : function(c){
43754 var col = new Roo.form.Column(c);
43756 if(arguments.length > 1){ // duplicate code required because of Opera
43757 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43764 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
43765 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
43766 * until end() is called.
43767 * @param {Object} config The config to pass to the fieldset
43768 * @param {Field} field1 (optional)
43769 * @param {Field} field2 (optional)
43770 * @param {Field} etc (optional)
43771 * @return FieldSet The fieldset container object
43773 fieldset : function(c){
43774 var fs = new Roo.form.FieldSet(c);
43776 if(arguments.length > 1){ // duplicate code required because of Opera
43777 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43784 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
43785 * fields are added and the container is closed. If no fields are passed the container remains open
43786 * until end() is called.
43787 * @param {Object} config The config to pass to the Layout
43788 * @param {Field} field1 (optional)
43789 * @param {Field} field2 (optional)
43790 * @param {Field} etc (optional)
43791 * @return Layout The container object
43793 container : function(c){
43794 var l = new Roo.form.Layout(c);
43796 if(arguments.length > 1){ // duplicate code required because of Opera
43797 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43804 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
43805 * @param {Object} container A Roo.form.Layout or subclass of Layout
43806 * @return {Form} this
43808 start : function(c){
43809 // cascade label info
43810 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
43811 this.active.stack.push(c);
43812 c.ownerCt = this.active;
43818 * Closes the current open container
43819 * @return {Form} this
43822 if(this.active == this.root){
43825 this.active = this.active.ownerCt;
43830 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
43831 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
43832 * as the label of the field.
43833 * @param {Field} field1
43834 * @param {Field} field2 (optional)
43835 * @param {Field} etc. (optional)
43836 * @return {Form} this
43839 this.active.stack.push.apply(this.active.stack, arguments);
43840 this.allItems.push.apply(this.allItems,arguments);
43842 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
43843 if(a[i].isFormField){
43848 Roo.form.Form.superclass.add.apply(this, r);
43858 * Find any element that has been added to a form, using it's ID or name
43859 * This can include framesets, columns etc. along with regular fields..
43860 * @param {String} id - id or name to find.
43862 * @return {Element} e - or false if nothing found.
43864 findbyId : function(id)
43870 Roo.each(this.allItems, function(f){
43871 if (f.id == id || f.name == id ){
43882 * Render this form into the passed container. This should only be called once!
43883 * @param {String/HTMLElement/Element} container The element this component should be rendered into
43884 * @return {Form} this
43886 render : function(ct)
43892 var o = this.autoCreate || {
43894 method : this.method || 'POST',
43895 id : this.id || Roo.id()
43897 this.initEl(ct.createChild(o));
43899 this.root.render(this.el);
43903 this.items.each(function(f){
43904 f.render('x-form-el-'+f.id);
43907 if(this.buttons.length > 0){
43908 // tables are required to maintain order and for correct IE layout
43909 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
43910 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
43911 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
43913 var tr = tb.getElementsByTagName('tr')[0];
43914 for(var i = 0, len = this.buttons.length; i < len; i++) {
43915 var b = this.buttons[i];
43916 var td = document.createElement('td');
43917 td.className = 'x-form-btn-td';
43918 b.render(tr.appendChild(td));
43921 if(this.monitorValid){ // initialize after render
43922 this.startMonitoring();
43924 this.fireEvent('rendered', this);
43929 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
43930 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
43931 * object or a valid Roo.DomHelper element config
43932 * @param {Function} handler The function called when the button is clicked
43933 * @param {Object} scope (optional) The scope of the handler function
43934 * @return {Roo.Button}
43936 addButton : function(config, handler, scope){
43940 minWidth: this.minButtonWidth,
43943 if(typeof config == "string"){
43946 Roo.apply(bc, config);
43948 var btn = new Roo.Button(null, bc);
43949 this.buttons.push(btn);
43954 * Adds a series of form elements (using the xtype property as the factory method.
43955 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
43956 * @param {Object} config
43959 addxtype : function()
43961 var ar = Array.prototype.slice.call(arguments, 0);
43963 for(var i = 0; i < ar.length; i++) {
43965 continue; // skip -- if this happends something invalid got sent, we
43966 // should ignore it, as basically that interface element will not show up
43967 // and that should be pretty obvious!!
43970 if (Roo.form[ar[i].xtype]) {
43972 var fe = Roo.factory(ar[i], Roo.form);
43978 fe.store.form = this;
43983 this.allItems.push(fe);
43984 if (fe.items && fe.addxtype) {
43985 fe.addxtype.apply(fe, fe.items);
43995 // console.log('adding ' + ar[i].xtype);
43997 if (ar[i].xtype == 'Button') {
43998 //console.log('adding button');
43999 //console.log(ar[i]);
44000 this.addButton(ar[i]);
44001 this.allItems.push(fe);
44005 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
44006 alert('end is not supported on xtype any more, use items');
44008 // //console.log('adding end');
44016 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
44017 * option "monitorValid"
44019 startMonitoring : function(){
44022 Roo.TaskMgr.start({
44023 run : this.bindHandler,
44024 interval : this.monitorPoll || 200,
44031 * Stops monitoring of the valid state of this form
44033 stopMonitoring : function(){
44034 this.bound = false;
44038 bindHandler : function(){
44040 return false; // stops binding
44043 this.items.each(function(f){
44044 if(!f.isValid(true)){
44049 for(var i = 0, len = this.buttons.length; i < len; i++){
44050 var btn = this.buttons[i];
44051 if(btn.formBind === true && btn.disabled === valid){
44052 btn.setDisabled(!valid);
44055 this.fireEvent('clientvalidation', this, valid);
44069 Roo.Form = Roo.form.Form;
44072 * Ext JS Library 1.1.1
44073 * Copyright(c) 2006-2007, Ext JS, LLC.
44075 * Originally Released Under LGPL - original licence link has changed is not relivant.
44078 * <script type="text/javascript">
44082 * @class Roo.form.Action
44083 * Internal Class used to handle form actions
44085 * @param {Roo.form.BasicForm} el The form element or its id
44086 * @param {Object} config Configuration options
44090 // define the action interface
44091 Roo.form.Action = function(form, options){
44093 this.options = options || {};
44096 * Client Validation Failed
44099 Roo.form.Action.CLIENT_INVALID = 'client';
44101 * Server Validation Failed
44104 Roo.form.Action.SERVER_INVALID = 'server';
44106 * Connect to Server Failed
44109 Roo.form.Action.CONNECT_FAILURE = 'connect';
44111 * Reading Data from Server Failed
44114 Roo.form.Action.LOAD_FAILURE = 'load';
44116 Roo.form.Action.prototype = {
44118 failureType : undefined,
44119 response : undefined,
44120 result : undefined,
44122 // interface method
44123 run : function(options){
44127 // interface method
44128 success : function(response){
44132 // interface method
44133 handleResponse : function(response){
44137 // default connection failure
44138 failure : function(response){
44140 this.response = response;
44141 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44142 this.form.afterAction(this, false);
44145 processResponse : function(response){
44146 this.response = response;
44147 if(!response.responseText){
44150 this.result = this.handleResponse(response);
44151 return this.result;
44154 // utility functions used internally
44155 getUrl : function(appendParams){
44156 var url = this.options.url || this.form.url || this.form.el.dom.action;
44158 var p = this.getParams();
44160 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
44166 getMethod : function(){
44167 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
44170 getParams : function(){
44171 var bp = this.form.baseParams;
44172 var p = this.options.params;
44174 if(typeof p == "object"){
44175 p = Roo.urlEncode(Roo.applyIf(p, bp));
44176 }else if(typeof p == 'string' && bp){
44177 p += '&' + Roo.urlEncode(bp);
44180 p = Roo.urlEncode(bp);
44185 createCallback : function(){
44187 success: this.success,
44188 failure: this.failure,
44190 timeout: (this.form.timeout*1000),
44191 upload: this.form.fileUpload ? this.success : undefined
44196 Roo.form.Action.Submit = function(form, options){
44197 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
44200 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
44203 haveProgress : false,
44204 uploadComplete : false,
44206 // uploadProgress indicator.
44207 uploadProgress : function()
44209 if (!this.form.progressUrl) {
44213 if (!this.haveProgress) {
44214 Roo.MessageBox.progress("Uploading", "Uploading");
44216 if (this.uploadComplete) {
44217 Roo.MessageBox.hide();
44221 this.haveProgress = true;
44223 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
44225 var c = new Roo.data.Connection();
44227 url : this.form.progressUrl,
44232 success : function(req){
44233 //console.log(data);
44237 rdata = Roo.decode(req.responseText)
44239 Roo.log("Invalid data from server..");
44243 if (!rdata || !rdata.success) {
44245 Roo.MessageBox.alert(Roo.encode(rdata));
44248 var data = rdata.data;
44250 if (this.uploadComplete) {
44251 Roo.MessageBox.hide();
44256 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
44257 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
44260 this.uploadProgress.defer(2000,this);
44263 failure: function(data) {
44264 Roo.log('progress url failed ');
44275 // run get Values on the form, so it syncs any secondary forms.
44276 this.form.getValues();
44278 var o = this.options;
44279 var method = this.getMethod();
44280 var isPost = method == 'POST';
44281 if(o.clientValidation === false || this.form.isValid()){
44283 if (this.form.progressUrl) {
44284 this.form.findField('UPLOAD_IDENTIFIER').setValue(
44285 (new Date() * 1) + '' + Math.random());
44290 Roo.Ajax.request(Roo.apply(this.createCallback(), {
44291 form:this.form.el.dom,
44292 url:this.getUrl(!isPost),
44294 params:isPost ? this.getParams() : null,
44295 isUpload: this.form.fileUpload
44298 this.uploadProgress();
44300 }else if (o.clientValidation !== false){ // client validation failed
44301 this.failureType = Roo.form.Action.CLIENT_INVALID;
44302 this.form.afterAction(this, false);
44306 success : function(response)
44308 this.uploadComplete= true;
44309 if (this.haveProgress) {
44310 Roo.MessageBox.hide();
44314 var result = this.processResponse(response);
44315 if(result === true || result.success){
44316 this.form.afterAction(this, true);
44320 this.form.markInvalid(result.errors);
44321 this.failureType = Roo.form.Action.SERVER_INVALID;
44323 this.form.afterAction(this, false);
44325 failure : function(response)
44327 this.uploadComplete= true;
44328 if (this.haveProgress) {
44329 Roo.MessageBox.hide();
44332 this.response = response;
44333 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44334 this.form.afterAction(this, false);
44337 handleResponse : function(response){
44338 if(this.form.errorReader){
44339 var rs = this.form.errorReader.read(response);
44342 for(var i = 0, len = rs.records.length; i < len; i++) {
44343 var r = rs.records[i];
44344 errors[i] = r.data;
44347 if(errors.length < 1){
44351 success : rs.success,
44357 ret = Roo.decode(response.responseText);
44361 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
44371 Roo.form.Action.Load = function(form, options){
44372 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
44373 this.reader = this.form.reader;
44376 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
44381 Roo.Ajax.request(Roo.apply(
44382 this.createCallback(), {
44383 method:this.getMethod(),
44384 url:this.getUrl(false),
44385 params:this.getParams()
44389 success : function(response){
44391 var result = this.processResponse(response);
44392 if(result === true || !result.success || !result.data){
44393 this.failureType = Roo.form.Action.LOAD_FAILURE;
44394 this.form.afterAction(this, false);
44397 this.form.clearInvalid();
44398 this.form.setValues(result.data);
44399 this.form.afterAction(this, true);
44402 handleResponse : function(response){
44403 if(this.form.reader){
44404 var rs = this.form.reader.read(response);
44405 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
44407 success : rs.success,
44411 return Roo.decode(response.responseText);
44415 Roo.form.Action.ACTION_TYPES = {
44416 'load' : Roo.form.Action.Load,
44417 'submit' : Roo.form.Action.Submit
44420 * Ext JS Library 1.1.1
44421 * Copyright(c) 2006-2007, Ext JS, LLC.
44423 * Originally Released Under LGPL - original licence link has changed is not relivant.
44426 * <script type="text/javascript">
44430 * @class Roo.form.Layout
44431 * @extends Roo.Component
44432 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
44434 * @param {Object} config Configuration options
44436 Roo.form.Layout = function(config){
44438 if (config.items) {
44439 xitems = config.items;
44440 delete config.items;
44442 Roo.form.Layout.superclass.constructor.call(this, config);
44444 Roo.each(xitems, this.addxtype, this);
44448 Roo.extend(Roo.form.Layout, Roo.Component, {
44450 * @cfg {String/Object} autoCreate
44451 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
44454 * @cfg {String/Object/Function} style
44455 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
44456 * a function which returns such a specification.
44459 * @cfg {String} labelAlign
44460 * Valid values are "left," "top" and "right" (defaults to "left")
44463 * @cfg {Number} labelWidth
44464 * Fixed width in pixels of all field labels (defaults to undefined)
44467 * @cfg {Boolean} clear
44468 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
44472 * @cfg {String} labelSeparator
44473 * The separator to use after field labels (defaults to ':')
44475 labelSeparator : ':',
44477 * @cfg {Boolean} hideLabels
44478 * True to suppress the display of field labels in this layout (defaults to false)
44480 hideLabels : false,
44483 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
44488 onRender : function(ct, position){
44489 if(this.el){ // from markup
44490 this.el = Roo.get(this.el);
44491 }else { // generate
44492 var cfg = this.getAutoCreate();
44493 this.el = ct.createChild(cfg, position);
44496 this.el.applyStyles(this.style);
44498 if(this.labelAlign){
44499 this.el.addClass('x-form-label-'+this.labelAlign);
44501 if(this.hideLabels){
44502 this.labelStyle = "display:none";
44503 this.elementStyle = "padding-left:0;";
44505 if(typeof this.labelWidth == 'number'){
44506 this.labelStyle = "width:"+this.labelWidth+"px;";
44507 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
44509 if(this.labelAlign == 'top'){
44510 this.labelStyle = "width:auto;";
44511 this.elementStyle = "padding-left:0;";
44514 var stack = this.stack;
44515 var slen = stack.length;
44517 if(!this.fieldTpl){
44518 var t = new Roo.Template(
44519 '<div class="x-form-item {5}">',
44520 '<label for="{0}" style="{2}">{1}{4}</label>',
44521 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
44523 '</div><div class="x-form-clear-left"></div>'
44525 t.disableFormats = true;
44527 Roo.form.Layout.prototype.fieldTpl = t;
44529 for(var i = 0; i < slen; i++) {
44530 if(stack[i].isFormField){
44531 this.renderField(stack[i]);
44533 this.renderComponent(stack[i]);
44538 this.el.createChild({cls:'x-form-clear'});
44543 renderField : function(f){
44544 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
44547 f.labelStyle||this.labelStyle||'', //2
44548 this.elementStyle||'', //3
44549 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
44550 f.itemCls||this.itemCls||'' //5
44551 ], true).getPrevSibling());
44555 renderComponent : function(c){
44556 c.render(c.isLayout ? this.el : this.el.createChild());
44559 * Adds a object form elements (using the xtype property as the factory method.)
44560 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
44561 * @param {Object} config
44563 addxtype : function(o)
44565 // create the lement.
44566 o.form = this.form;
44567 var fe = Roo.factory(o, Roo.form);
44568 this.form.allItems.push(fe);
44569 this.stack.push(fe);
44571 if (fe.isFormField) {
44572 this.form.items.add(fe);
44580 * @class Roo.form.Column
44581 * @extends Roo.form.Layout
44582 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
44584 * @param {Object} config Configuration options
44586 Roo.form.Column = function(config){
44587 Roo.form.Column.superclass.constructor.call(this, config);
44590 Roo.extend(Roo.form.Column, Roo.form.Layout, {
44592 * @cfg {Number/String} width
44593 * The fixed width of the column in pixels or CSS value (defaults to "auto")
44596 * @cfg {String/Object} autoCreate
44597 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
44601 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
44604 onRender : function(ct, position){
44605 Roo.form.Column.superclass.onRender.call(this, ct, position);
44607 this.el.setWidth(this.width);
44614 * @class Roo.form.Row
44615 * @extends Roo.form.Layout
44616 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
44618 * @param {Object} config Configuration options
44622 Roo.form.Row = function(config){
44623 Roo.form.Row.superclass.constructor.call(this, config);
44626 Roo.extend(Roo.form.Row, Roo.form.Layout, {
44628 * @cfg {Number/String} width
44629 * The fixed width of the column in pixels or CSS value (defaults to "auto")
44632 * @cfg {Number/String} height
44633 * The fixed height of the column in pixels or CSS value (defaults to "auto")
44635 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
44639 onRender : function(ct, position){
44640 //console.log('row render');
44642 var t = new Roo.Template(
44643 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
44644 '<label for="{0}" style="{2}">{1}{4}</label>',
44645 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
44649 t.disableFormats = true;
44651 Roo.form.Layout.prototype.rowTpl = t;
44653 this.fieldTpl = this.rowTpl;
44655 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
44656 var labelWidth = 100;
44658 if ((this.labelAlign != 'top')) {
44659 if (typeof this.labelWidth == 'number') {
44660 labelWidth = this.labelWidth
44662 this.padWidth = 20 + labelWidth;
44666 Roo.form.Column.superclass.onRender.call(this, ct, position);
44668 this.el.setWidth(this.width);
44671 this.el.setHeight(this.height);
44676 renderField : function(f){
44677 f.fieldEl = this.fieldTpl.append(this.el, [
44678 f.id, f.fieldLabel,
44679 f.labelStyle||this.labelStyle||'',
44680 this.elementStyle||'',
44681 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
44682 f.itemCls||this.itemCls||'',
44683 f.width ? f.width + this.padWidth : 160 + this.padWidth
44690 * @class Roo.form.FieldSet
44691 * @extends Roo.form.Layout
44692 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
44694 * @param {Object} config Configuration options
44696 Roo.form.FieldSet = function(config){
44697 Roo.form.FieldSet.superclass.constructor.call(this, config);
44700 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
44702 * @cfg {String} legend
44703 * The text to display as the legend for the FieldSet (defaults to '')
44706 * @cfg {String/Object} autoCreate
44707 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
44711 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
44714 onRender : function(ct, position){
44715 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
44717 this.setLegend(this.legend);
44722 setLegend : function(text){
44724 this.el.child('legend').update(text);
44729 * Ext JS Library 1.1.1
44730 * Copyright(c) 2006-2007, Ext JS, LLC.
44732 * Originally Released Under LGPL - original licence link has changed is not relivant.
44735 * <script type="text/javascript">
44738 * @class Roo.form.VTypes
44739 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
44742 Roo.form.VTypes = function(){
44743 // closure these in so they are only created once.
44744 var alpha = /^[a-zA-Z_]+$/;
44745 var alphanum = /^[a-zA-Z0-9_]+$/;
44746 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
44747 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
44749 // All these messages and functions are configurable
44752 * The function used to validate email addresses
44753 * @param {String} value The email address
44755 'email' : function(v){
44756 return email.test(v);
44759 * The error text to display when the email validation function returns false
44762 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
44764 * The keystroke filter mask to be applied on email input
44767 'emailMask' : /[a-z0-9_\.\-@]/i,
44770 * The function used to validate URLs
44771 * @param {String} value The URL
44773 'url' : function(v){
44774 return url.test(v);
44777 * The error text to display when the url validation function returns false
44780 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
44783 * The function used to validate alpha values
44784 * @param {String} value The value
44786 'alpha' : function(v){
44787 return alpha.test(v);
44790 * The error text to display when the alpha validation function returns false
44793 'alphaText' : 'This field should only contain letters and _',
44795 * The keystroke filter mask to be applied on alpha input
44798 'alphaMask' : /[a-z_]/i,
44801 * The function used to validate alphanumeric values
44802 * @param {String} value The value
44804 'alphanum' : function(v){
44805 return alphanum.test(v);
44808 * The error text to display when the alphanumeric validation function returns false
44811 'alphanumText' : 'This field should only contain letters, numbers and _',
44813 * The keystroke filter mask to be applied on alphanumeric input
44816 'alphanumMask' : /[a-z0-9_]/i
44818 }();//<script type="text/javascript">
44821 * @class Roo.form.FCKeditor
44822 * @extends Roo.form.TextArea
44823 * Wrapper around the FCKEditor http://www.fckeditor.net
44825 * Creates a new FCKeditor
44826 * @param {Object} config Configuration options
44828 Roo.form.FCKeditor = function(config){
44829 Roo.form.FCKeditor.superclass.constructor.call(this, config);
44832 * @event editorinit
44833 * Fired when the editor is initialized - you can add extra handlers here..
44834 * @param {FCKeditor} this
44835 * @param {Object} the FCK object.
44842 Roo.form.FCKeditor.editors = { };
44843 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
44845 //defaultAutoCreate : {
44846 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
44850 * @cfg {Object} fck options - see fck manual for details.
44855 * @cfg {Object} fck toolbar set (Basic or Default)
44857 toolbarSet : 'Basic',
44859 * @cfg {Object} fck BasePath
44861 basePath : '/fckeditor/',
44869 onRender : function(ct, position)
44872 this.defaultAutoCreate = {
44874 style:"width:300px;height:60px;",
44875 autocomplete: "off"
44878 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
44881 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
44882 if(this.preventScrollbars){
44883 this.el.setStyle("overflow", "hidden");
44885 this.el.setHeight(this.growMin);
44888 //console.log('onrender' + this.getId() );
44889 Roo.form.FCKeditor.editors[this.getId()] = this;
44892 this.replaceTextarea() ;
44896 getEditor : function() {
44897 return this.fckEditor;
44900 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
44901 * @param {Mixed} value The value to set
44905 setValue : function(value)
44907 //console.log('setValue: ' + value);
44909 if(typeof(value) == 'undefined') { // not sure why this is happending...
44912 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44914 //if(!this.el || !this.getEditor()) {
44915 // this.value = value;
44916 //this.setValue.defer(100,this,[value]);
44920 if(!this.getEditor()) {
44924 this.getEditor().SetData(value);
44931 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
44932 * @return {Mixed} value The field value
44934 getValue : function()
44937 if (this.frame && this.frame.dom.style.display == 'none') {
44938 return Roo.form.FCKeditor.superclass.getValue.call(this);
44941 if(!this.el || !this.getEditor()) {
44943 // this.getValue.defer(100,this);
44948 var value=this.getEditor().GetData();
44949 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44950 return Roo.form.FCKeditor.superclass.getValue.call(this);
44956 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
44957 * @return {Mixed} value The field value
44959 getRawValue : function()
44961 if (this.frame && this.frame.dom.style.display == 'none') {
44962 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
44965 if(!this.el || !this.getEditor()) {
44966 //this.getRawValue.defer(100,this);
44973 var value=this.getEditor().GetData();
44974 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
44975 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
44979 setSize : function(w,h) {
44983 //if (this.frame && this.frame.dom.style.display == 'none') {
44984 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
44987 //if(!this.el || !this.getEditor()) {
44988 // this.setSize.defer(100,this, [w,h]);
44994 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
44996 this.frame.dom.setAttribute('width', w);
44997 this.frame.dom.setAttribute('height', h);
44998 this.frame.setSize(w,h);
45002 toggleSourceEdit : function(value) {
45006 this.el.dom.style.display = value ? '' : 'none';
45007 this.frame.dom.style.display = value ? 'none' : '';
45012 focus: function(tag)
45014 if (this.frame.dom.style.display == 'none') {
45015 return Roo.form.FCKeditor.superclass.focus.call(this);
45017 if(!this.el || !this.getEditor()) {
45018 this.focus.defer(100,this, [tag]);
45025 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
45026 this.getEditor().Focus();
45028 if (!this.getEditor().Selection.GetSelection()) {
45029 this.focus.defer(100,this, [tag]);
45034 var r = this.getEditor().EditorDocument.createRange();
45035 r.setStart(tgs[0],0);
45036 r.setEnd(tgs[0],0);
45037 this.getEditor().Selection.GetSelection().removeAllRanges();
45038 this.getEditor().Selection.GetSelection().addRange(r);
45039 this.getEditor().Focus();
45046 replaceTextarea : function()
45048 if ( document.getElementById( this.getId() + '___Frame' ) )
45050 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
45052 // We must check the elements firstly using the Id and then the name.
45053 var oTextarea = document.getElementById( this.getId() );
45055 var colElementsByName = document.getElementsByName( this.getId() ) ;
45057 oTextarea.style.display = 'none' ;
45059 if ( oTextarea.tabIndex ) {
45060 this.TabIndex = oTextarea.tabIndex ;
45063 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
45064 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
45065 this.frame = Roo.get(this.getId() + '___Frame')
45068 _getConfigHtml : function()
45072 for ( var o in this.fckconfig ) {
45073 sConfig += sConfig.length > 0 ? '&' : '';
45074 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
45077 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
45081 _getIFrameHtml : function()
45083 var sFile = 'fckeditor.html' ;
45084 /* no idea what this is about..
45087 if ( (/fcksource=true/i).test( window.top.location.search ) )
45088 sFile = 'fckeditor.original.html' ;
45093 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
45094 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
45097 var html = '<iframe id="' + this.getId() +
45098 '___Frame" src="' + sLink +
45099 '" width="' + this.width +
45100 '" height="' + this.height + '"' +
45101 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
45102 ' frameborder="0" scrolling="no"></iframe>' ;
45107 _insertHtmlBefore : function( html, element )
45109 if ( element.insertAdjacentHTML ) {
45111 element.insertAdjacentHTML( 'beforeBegin', html ) ;
45113 var oRange = document.createRange() ;
45114 oRange.setStartBefore( element ) ;
45115 var oFragment = oRange.createContextualFragment( html );
45116 element.parentNode.insertBefore( oFragment, element ) ;
45129 //Roo.reg('fckeditor', Roo.form.FCKeditor);
45131 function FCKeditor_OnComplete(editorInstance){
45132 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
45133 f.fckEditor = editorInstance;
45134 //console.log("loaded");
45135 f.fireEvent('editorinit', f, editorInstance);
45155 //<script type="text/javascript">
45157 * @class Roo.form.GridField
45158 * @extends Roo.form.Field
45159 * Embed a grid (or editable grid into a form)
45162 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
45164 * xgrid.store = Roo.data.Store
45165 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
45166 * xgrid.store.reader = Roo.data.JsonReader
45170 * Creates a new GridField
45171 * @param {Object} config Configuration options
45173 Roo.form.GridField = function(config){
45174 Roo.form.GridField.superclass.constructor.call(this, config);
45178 Roo.extend(Roo.form.GridField, Roo.form.Field, {
45180 * @cfg {Number} width - used to restrict width of grid..
45184 * @cfg {Number} height - used to restrict height of grid..
45188 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
45194 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45195 * {tag: "input", type: "checkbox", autocomplete: "off"})
45197 // defaultAutoCreate : { tag: 'div' },
45198 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45200 * @cfg {String} addTitle Text to include for adding a title.
45204 onResize : function(){
45205 Roo.form.Field.superclass.onResize.apply(this, arguments);
45208 initEvents : function(){
45209 // Roo.form.Checkbox.superclass.initEvents.call(this);
45210 // has no events...
45215 getResizeEl : function(){
45219 getPositionEl : function(){
45224 onRender : function(ct, position){
45226 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
45227 var style = this.style;
45230 Roo.form.GridField.superclass.onRender.call(this, ct, position);
45231 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
45232 this.viewEl = this.wrap.createChild({ tag: 'div' });
45234 this.viewEl.applyStyles(style);
45237 this.viewEl.setWidth(this.width);
45240 this.viewEl.setHeight(this.height);
45242 //if(this.inputValue !== undefined){
45243 //this.setValue(this.value);
45246 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
45249 this.grid.render();
45250 this.grid.getDataSource().on('remove', this.refreshValue, this);
45251 this.grid.getDataSource().on('update', this.refreshValue, this);
45252 this.grid.on('afteredit', this.refreshValue, this);
45258 * Sets the value of the item.
45259 * @param {String} either an object or a string..
45261 setValue : function(v){
45263 v = v || []; // empty set..
45264 // this does not seem smart - it really only affects memoryproxy grids..
45265 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
45266 var ds = this.grid.getDataSource();
45267 // assumes a json reader..
45269 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
45270 ds.loadData( data);
45272 // clear selection so it does not get stale.
45273 if (this.grid.sm) {
45274 this.grid.sm.clearSelections();
45277 Roo.form.GridField.superclass.setValue.call(this, v);
45278 this.refreshValue();
45279 // should load data in the grid really....
45283 refreshValue: function() {
45285 this.grid.getDataSource().each(function(r) {
45288 this.el.dom.value = Roo.encode(val);
45296 * Ext JS Library 1.1.1
45297 * Copyright(c) 2006-2007, Ext JS, LLC.
45299 * Originally Released Under LGPL - original licence link has changed is not relivant.
45302 * <script type="text/javascript">
45305 * @class Roo.form.DisplayField
45306 * @extends Roo.form.Field
45307 * A generic Field to display non-editable data.
45309 * Creates a new Display Field item.
45310 * @param {Object} config Configuration options
45312 Roo.form.DisplayField = function(config){
45313 Roo.form.DisplayField.superclass.constructor.call(this, config);
45317 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
45318 inputType: 'hidden',
45324 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45326 focusClass : undefined,
45328 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45330 fieldClass: 'x-form-field',
45333 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
45335 valueRenderer: undefined,
45339 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45340 * {tag: "input", type: "checkbox", autocomplete: "off"})
45343 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45345 onResize : function(){
45346 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
45350 initEvents : function(){
45351 // Roo.form.Checkbox.superclass.initEvents.call(this);
45352 // has no events...
45357 getResizeEl : function(){
45361 getPositionEl : function(){
45366 onRender : function(ct, position){
45368 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
45369 //if(this.inputValue !== undefined){
45370 this.wrap = this.el.wrap();
45372 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
45374 if (this.bodyStyle) {
45375 this.viewEl.applyStyles(this.bodyStyle);
45377 //this.viewEl.setStyle('padding', '2px');
45379 this.setValue(this.value);
45384 initValue : Roo.emptyFn,
45389 onClick : function(){
45394 * Sets the checked state of the checkbox.
45395 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
45397 setValue : function(v){
45399 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
45400 // this might be called before we have a dom element..
45401 if (!this.viewEl) {
45404 this.viewEl.dom.innerHTML = html;
45405 Roo.form.DisplayField.superclass.setValue.call(this, v);
45415 * @class Roo.form.DayPicker
45416 * @extends Roo.form.Field
45417 * A Day picker show [M] [T] [W] ....
45419 * Creates a new Day Picker
45420 * @param {Object} config Configuration options
45422 Roo.form.DayPicker= function(config){
45423 Roo.form.DayPicker.superclass.constructor.call(this, config);
45427 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
45429 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45431 focusClass : undefined,
45433 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45435 fieldClass: "x-form-field",
45438 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45439 * {tag: "input", type: "checkbox", autocomplete: "off"})
45441 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
45444 actionMode : 'viewEl',
45448 inputType : 'hidden',
45451 inputElement: false, // real input element?
45452 basedOn: false, // ????
45454 isFormField: true, // not sure where this is needed!!!!
45456 onResize : function(){
45457 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
45458 if(!this.boxLabel){
45459 this.el.alignTo(this.wrap, 'c-c');
45463 initEvents : function(){
45464 Roo.form.Checkbox.superclass.initEvents.call(this);
45465 this.el.on("click", this.onClick, this);
45466 this.el.on("change", this.onClick, this);
45470 getResizeEl : function(){
45474 getPositionEl : function(){
45480 onRender : function(ct, position){
45481 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
45483 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
45485 var r1 = '<table><tr>';
45486 var r2 = '<tr class="x-form-daypick-icons">';
45487 for (var i=0; i < 7; i++) {
45488 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
45489 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
45492 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
45493 viewEl.select('img').on('click', this.onClick, this);
45494 this.viewEl = viewEl;
45497 // this will not work on Chrome!!!
45498 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
45499 this.el.on('propertychange', this.setFromHidden, this); //ie
45507 initValue : Roo.emptyFn,
45510 * Returns the checked state of the checkbox.
45511 * @return {Boolean} True if checked, else false
45513 getValue : function(){
45514 return this.el.dom.value;
45519 onClick : function(e){
45520 //this.setChecked(!this.checked);
45521 Roo.get(e.target).toggleClass('x-menu-item-checked');
45522 this.refreshValue();
45523 //if(this.el.dom.checked != this.checked){
45524 // this.setValue(this.el.dom.checked);
45529 refreshValue : function()
45532 this.viewEl.select('img',true).each(function(e,i,n) {
45533 val += e.is(".x-menu-item-checked") ? String(n) : '';
45535 this.setValue(val, true);
45539 * Sets the checked state of the checkbox.
45540 * On is always based on a string comparison between inputValue and the param.
45541 * @param {Boolean/String} value - the value to set
45542 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
45544 setValue : function(v,suppressEvent){
45545 if (!this.el.dom) {
45548 var old = this.el.dom.value ;
45549 this.el.dom.value = v;
45550 if (suppressEvent) {
45554 // update display..
45555 this.viewEl.select('img',true).each(function(e,i,n) {
45557 var on = e.is(".x-menu-item-checked");
45558 var newv = v.indexOf(String(n)) > -1;
45560 e.toggleClass('x-menu-item-checked');
45566 this.fireEvent('change', this, v, old);
45571 // handle setting of hidden value by some other method!!?!?
45572 setFromHidden: function()
45577 //console.log("SET FROM HIDDEN");
45578 //alert('setFrom hidden');
45579 this.setValue(this.el.dom.value);
45582 onDestroy : function()
45585 Roo.get(this.viewEl).remove();
45588 Roo.form.DayPicker.superclass.onDestroy.call(this);
45592 * RooJS Library 1.1.1
45593 * Copyright(c) 2008-2011 Alan Knowles
45600 * @class Roo.form.ComboCheck
45601 * @extends Roo.form.ComboBox
45602 * A combobox for multiple select items.
45604 * FIXME - could do with a reset button..
45607 * Create a new ComboCheck
45608 * @param {Object} config Configuration options
45610 Roo.form.ComboCheck = function(config){
45611 Roo.form.ComboCheck.superclass.constructor.call(this, config);
45612 // should verify some data...
45614 // hiddenName = required..
45615 // displayField = required
45616 // valudField == required
45617 var req= [ 'hiddenName', 'displayField', 'valueField' ];
45619 Roo.each(req, function(e) {
45620 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
45621 throw "Roo.form.ComboCheck : missing value for: " + e;
45628 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
45633 selectedClass: 'x-menu-item-checked',
45636 onRender : function(ct, position){
45642 var cls = 'x-combo-list';
45645 this.tpl = new Roo.Template({
45646 html : '<div class="'+cls+'-item x-menu-check-item">' +
45647 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
45648 '<span>{' + this.displayField + '}</span>' +
45655 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
45656 this.view.singleSelect = false;
45657 this.view.multiSelect = true;
45658 this.view.toggleSelect = true;
45659 this.pageTb.add(new Roo.Toolbar.Fill(), {
45662 handler: function()
45669 onViewOver : function(e, t){
45675 onViewClick : function(doFocus,index){
45679 select: function () {
45680 //Roo.log("SELECT CALLED");
45683 selectByValue : function(xv, scrollIntoView){
45684 var ar = this.getValueArray();
45687 Roo.each(ar, function(v) {
45688 if(v === undefined || v === null){
45691 var r = this.findRecord(this.valueField, v);
45693 sels.push(this.store.indexOf(r))
45697 this.view.select(sels);
45703 onSelect : function(record, index){
45704 // Roo.log("onselect Called");
45705 // this is only called by the clear button now..
45706 this.view.clearSelections();
45707 this.setValue('[]');
45708 if (this.value != this.valueBefore) {
45709 this.fireEvent('change', this, this.value, this.valueBefore);
45710 this.valueBefore = this.value;
45713 getValueArray : function()
45718 //Roo.log(this.value);
45719 if (typeof(this.value) == 'undefined') {
45722 var ar = Roo.decode(this.value);
45723 return ar instanceof Array ? ar : []; //?? valid?
45726 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
45731 expand : function ()
45734 Roo.form.ComboCheck.superclass.expand.call(this);
45735 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
45736 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
45741 collapse : function(){
45742 Roo.form.ComboCheck.superclass.collapse.call(this);
45743 var sl = this.view.getSelectedIndexes();
45744 var st = this.store;
45748 Roo.each(sl, function(i) {
45750 nv.push(r.get(this.valueField));
45752 this.setValue(Roo.encode(nv));
45753 if (this.value != this.valueBefore) {
45755 this.fireEvent('change', this, this.value, this.valueBefore);
45756 this.valueBefore = this.value;
45761 setValue : function(v){
45765 var vals = this.getValueArray();
45767 Roo.each(vals, function(k) {
45768 var r = this.findRecord(this.valueField, k);
45770 tv.push(r.data[this.displayField]);
45771 }else if(this.valueNotFoundText !== undefined){
45772 tv.push( this.valueNotFoundText );
45777 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
45778 this.hiddenField.value = v;
45784 * Ext JS Library 1.1.1
45785 * Copyright(c) 2006-2007, Ext JS, LLC.
45787 * Originally Released Under LGPL - original licence link has changed is not relivant.
45790 * <script type="text/javascript">
45794 * @class Roo.form.Signature
45795 * @extends Roo.form.Field
45799 * @param {Object} config Configuration options
45802 Roo.form.Signature = function(config){
45803 Roo.form.Signature.superclass.constructor.call(this, config);
45805 this.addEvents({// not in used??
45808 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
45809 * @param {Roo.form.Signature} combo This combo box
45814 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
45815 * @param {Roo.form.ComboBox} combo This combo box
45816 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
45822 Roo.extend(Roo.form.Signature, Roo.form.Field, {
45824 * @cfg {Object} labels Label to use when rendering a form.
45828 * confirm : "Confirm"
45833 confirm : "Confirm"
45836 * @cfg {Number} width The signature panel width (defaults to 300)
45840 * @cfg {Number} height The signature panel height (defaults to 100)
45844 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
45846 allowBlank : false,
45849 // {Object} signPanel The signature SVG panel element (defaults to {})
45851 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
45852 isMouseDown : false,
45853 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
45854 isConfirmed : false,
45855 // {String} signatureTmp SVG mapping string (defaults to empty string)
45859 defaultAutoCreate : { // modified by initCompnoent..
45865 onRender : function(ct, position){
45867 Roo.form.Signature.superclass.onRender.call(this, ct, position);
45869 this.wrap = this.el.wrap({
45870 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
45873 this.createToolbar(this);
45874 this.signPanel = this.wrap.createChild({
45876 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
45880 this.svgID = Roo.id();
45881 this.svgEl = this.signPanel.createChild({
45882 xmlns : 'http://www.w3.org/2000/svg',
45884 id : this.svgID + "-svg",
45886 height: this.height,
45887 viewBox: '0 0 '+this.width+' '+this.height,
45891 id: this.svgID + "-svg-r",
45893 height: this.height,
45898 id: this.svgID + "-svg-l",
45900 y1: (this.height*0.8), // start set the line in 80% of height
45901 x2: this.width, // end
45902 y2: (this.height*0.8), // end set the line in 80% of height
45904 'stroke-width': "1",
45905 'stroke-dasharray': "3",
45906 'shape-rendering': "crispEdges",
45907 'pointer-events': "none"
45911 id: this.svgID + "-svg-p",
45913 'stroke-width': "3",
45915 'pointer-events': 'none'
45920 this.svgBox = this.svgEl.dom.getScreenCTM();
45922 createSVG : function(){
45923 var svg = this.signPanel;
45924 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
45927 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
45928 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
45929 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
45930 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
45931 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
45932 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
45933 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
45936 isTouchEvent : function(e){
45937 return e.type.match(/^touch/);
45939 getCoords : function (e) {
45940 var pt = this.svgEl.dom.createSVGPoint();
45943 if (this.isTouchEvent(e)) {
45944 pt.x = e.targetTouches[0].clientX
45945 pt.y = e.targetTouches[0].clientY;
45947 var a = this.svgEl.dom.getScreenCTM();
45948 var b = a.inverse();
45949 var mx = pt.matrixTransform(b);
45950 return mx.x + ',' + mx.y;
45952 //mouse event headler
45953 down : function (e) {
45954 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
45955 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
45957 this.isMouseDown = true;
45959 e.preventDefault();
45961 move : function (e) {
45962 if (this.isMouseDown) {
45963 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
45964 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
45967 e.preventDefault();
45969 up : function (e) {
45970 this.isMouseDown = false;
45971 var sp = this.signatureTmp.split(' ');
45974 if(!sp[sp.length-2].match(/^L/)){
45978 this.signatureTmp = sp.join(" ");
45981 if(this.getValue() != this.signatureTmp){
45982 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
45983 this.isConfirmed = false;
45985 e.preventDefault();
45989 * Protected method that will not generally be called directly. It
45990 * is called when the editor creates its toolbar. Override this method if you need to
45991 * add custom toolbar buttons.
45992 * @param {HtmlEditor} editor
45994 createToolbar : function(editor){
45995 function btn(id, toggle, handler){
45996 var xid = fid + '-'+ id ;
46000 cls : 'x-btn-icon x-edit-'+id,
46001 enableToggle:toggle !== false,
46002 scope: editor, // was editor...
46003 handler:handler||editor.relayBtnCmd,
46004 clickEvent:'mousedown',
46005 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46011 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46015 cls : ' x-signature-btn x-signature-'+id,
46016 scope: editor, // was editor...
46017 handler: this.reset,
46018 clickEvent:'mousedown',
46019 text: this.labels.clear
46026 cls : ' x-signature-btn x-signature-'+id,
46027 scope: editor, // was editor...
46028 handler: this.confirmHandler,
46029 clickEvent:'mousedown',
46030 text: this.labels.confirm
46037 * when user is clicked confirm then show this image.....
46039 * @return {String} Image Data URI
46041 getImageDataURI : function(){
46042 var svg = this.svgEl.dom.parentNode.innerHTML;
46043 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
46048 * @return {Boolean} this.isConfirmed
46050 getConfirmed : function(){
46051 return this.isConfirmed;
46055 * @return {Number} this.width
46057 getWidth : function(){
46062 * @return {Number} this.height
46064 getHeight : function(){
46065 return this.height;
46068 getSignature : function(){
46069 return this.signatureTmp;
46072 reset : function(){
46073 this.signatureTmp = '';
46074 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46075 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
46076 this.isConfirmed = false;
46077 Roo.form.Signature.superclass.reset.call(this);
46079 setSignature : function(s){
46080 this.signatureTmp = s;
46081 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46082 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
46084 this.isConfirmed = false;
46085 Roo.form.Signature.superclass.reset.call(this);
46088 // Roo.log(this.signPanel.dom.contentWindow.up())
46091 setConfirmed : function(){
46095 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
46098 confirmHandler : function(){
46099 if(!this.getSignature()){
46103 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
46104 this.setValue(this.getSignature());
46105 this.isConfirmed = true;
46107 this.fireEvent('confirm', this);
46110 // Subclasses should provide the validation implementation by overriding this
46111 validateValue : function(value){
46112 if(this.allowBlank){
46116 if(this.isConfirmed){
46123 * Ext JS Library 1.1.1
46124 * Copyright(c) 2006-2007, Ext JS, LLC.
46126 * Originally Released Under LGPL - original licence link has changed is not relivant.
46129 * <script type="text/javascript">
46134 * @class Roo.form.ComboBox
46135 * @extends Roo.form.TriggerField
46136 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
46138 * Create a new ComboBox.
46139 * @param {Object} config Configuration options
46141 Roo.form.Select = function(config){
46142 Roo.form.Select.superclass.constructor.call(this, config);
46146 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
46148 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
46151 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
46152 * rendering into an Roo.Editor, defaults to false)
46155 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
46156 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
46159 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
46162 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
46163 * the dropdown list (defaults to undefined, with no header element)
46167 * @cfg {String/Roo.Template} tpl The template to use to render the output
46171 defaultAutoCreate : {tag: "select" },
46173 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
46175 listWidth: undefined,
46177 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
46178 * mode = 'remote' or 'text' if mode = 'local')
46180 displayField: undefined,
46182 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
46183 * mode = 'remote' or 'value' if mode = 'local').
46184 * Note: use of a valueField requires the user make a selection
46185 * in order for a value to be mapped.
46187 valueField: undefined,
46191 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
46192 * field's data value (defaults to the underlying DOM element's name)
46194 hiddenName: undefined,
46196 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
46200 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
46202 selectedClass: 'x-combo-selected',
46204 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
46205 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
46206 * which displays a downward arrow icon).
46208 triggerClass : 'x-form-arrow-trigger',
46210 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
46214 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
46215 * anchor positions (defaults to 'tl-bl')
46217 listAlign: 'tl-bl?',
46219 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
46223 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
46224 * query specified by the allQuery config option (defaults to 'query')
46226 triggerAction: 'query',
46228 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
46229 * (defaults to 4, does not apply if editable = false)
46233 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
46234 * delay (typeAheadDelay) if it matches a known value (defaults to false)
46238 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
46239 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
46243 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
46244 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
46248 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
46249 * when editable = true (defaults to false)
46251 selectOnFocus:false,
46253 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
46255 queryParam: 'query',
46257 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
46258 * when mode = 'remote' (defaults to 'Loading...')
46260 loadingText: 'Loading...',
46262 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
46266 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
46270 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
46271 * traditional select (defaults to true)
46275 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
46279 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
46283 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
46284 * listWidth has a higher value)
46288 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
46289 * allow the user to set arbitrary text into the field (defaults to false)
46291 forceSelection:false,
46293 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
46294 * if typeAhead = true (defaults to 250)
46296 typeAheadDelay : 250,
46298 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
46299 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
46301 valueNotFoundText : undefined,
46304 * @cfg {String} defaultValue The value displayed after loading the store.
46309 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
46311 blockFocus : false,
46314 * @cfg {Boolean} disableClear Disable showing of clear button.
46316 disableClear : false,
46318 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
46320 alwaysQuery : false,
46326 // element that contains real text value.. (when hidden is used..)
46329 onRender : function(ct, position){
46330 Roo.form.Field.prototype.onRender.call(this, ct, position);
46333 this.store.on('beforeload', this.onBeforeLoad, this);
46334 this.store.on('load', this.onLoad, this);
46335 this.store.on('loadexception', this.onLoadException, this);
46336 this.store.load({});
46344 initEvents : function(){
46345 //Roo.form.ComboBox.superclass.initEvents.call(this);
46349 onDestroy : function(){
46352 this.store.un('beforeload', this.onBeforeLoad, this);
46353 this.store.un('load', this.onLoad, this);
46354 this.store.un('loadexception', this.onLoadException, this);
46356 //Roo.form.ComboBox.superclass.onDestroy.call(this);
46360 fireKey : function(e){
46361 if(e.isNavKeyPress() && !this.list.isVisible()){
46362 this.fireEvent("specialkey", this, e);
46367 onResize: function(w, h){
46375 * Allow or prevent the user from directly editing the field text. If false is passed,
46376 * the user will only be able to select from the items defined in the dropdown list. This method
46377 * is the runtime equivalent of setting the 'editable' config option at config time.
46378 * @param {Boolean} value True to allow the user to directly edit the field text
46380 setEditable : function(value){
46385 onBeforeLoad : function(){
46387 Roo.log("Select before load");
46390 this.innerList.update(this.loadingText ?
46391 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
46392 //this.restrictHeight();
46393 this.selectedIndex = -1;
46397 onLoad : function(){
46400 var dom = this.el.dom;
46401 dom.innerHTML = '';
46402 var od = dom.ownerDocument;
46404 if (this.emptyText) {
46405 var op = od.createElement('option');
46406 op.setAttribute('value', '');
46407 op.innerHTML = String.format('{0}', this.emptyText);
46408 dom.appendChild(op);
46410 if(this.store.getCount() > 0){
46412 var vf = this.valueField;
46413 var df = this.displayField;
46414 this.store.data.each(function(r) {
46415 // which colmsn to use... testing - cdoe / title..
46416 var op = od.createElement('option');
46417 op.setAttribute('value', r.data[vf]);
46418 op.innerHTML = String.format('{0}', r.data[df]);
46419 dom.appendChild(op);
46421 if (typeof(this.defaultValue != 'undefined')) {
46422 this.setValue(this.defaultValue);
46427 //this.onEmptyResults();
46432 onLoadException : function()
46434 dom.innerHTML = '';
46436 Roo.log("Select on load exception");
46440 Roo.log(this.store.reader.jsonData);
46441 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
46442 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
46448 onTypeAhead : function(){
46453 onSelect : function(record, index){
46454 Roo.log('on select?');
46456 if(this.fireEvent('beforeselect', this, record, index) !== false){
46457 this.setFromData(index > -1 ? record.data : false);
46459 this.fireEvent('select', this, record, index);
46464 * Returns the currently selected field value or empty string if no value is set.
46465 * @return {String} value The selected value
46467 getValue : function(){
46468 var dom = this.el.dom;
46469 this.value = dom.options[dom.selectedIndex].value;
46475 * Clears any text/value currently set in the field
46477 clearValue : function(){
46479 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
46484 * Sets the specified value into the field. If the value finds a match, the corresponding record text
46485 * will be displayed in the field. If the value does not match the data value of an existing item,
46486 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
46487 * Otherwise the field will be blank (although the value will still be set).
46488 * @param {String} value The value to match
46490 setValue : function(v){
46491 var d = this.el.dom;
46492 for (var i =0; i < d.options.length;i++) {
46493 if (v == d.options[i].value) {
46494 d.selectedIndex = i;
46502 * @property {Object} the last set data for the element
46507 * Sets the value of the field based on a object which is related to the record format for the store.
46508 * @param {Object} value the value to set as. or false on reset?
46510 setFromData : function(o){
46511 Roo.log('setfrom data?');
46517 reset : function(){
46521 findRecord : function(prop, value){
46526 if(this.store.getCount() > 0){
46527 this.store.each(function(r){
46528 if(r.data[prop] == value){
46538 getName: function()
46540 // returns hidden if it's set..
46541 if (!this.rendered) {return ''};
46542 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
46550 onEmptyResults : function(){
46551 Roo.log('empty results');
46556 * Returns true if the dropdown list is expanded, else false.
46558 isExpanded : function(){
46563 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
46564 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
46565 * @param {String} value The data value of the item to select
46566 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
46567 * selected item if it is not currently in view (defaults to true)
46568 * @return {Boolean} True if the value matched an item in the list, else false
46570 selectByValue : function(v, scrollIntoView){
46571 Roo.log('select By Value');
46574 if(v !== undefined && v !== null){
46575 var r = this.findRecord(this.valueField || this.displayField, v);
46577 this.select(this.store.indexOf(r), scrollIntoView);
46585 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
46586 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
46587 * @param {Number} index The zero-based index of the list item to select
46588 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
46589 * selected item if it is not currently in view (defaults to true)
46591 select : function(index, scrollIntoView){
46592 Roo.log('select ');
46595 this.selectedIndex = index;
46596 this.view.select(index);
46597 if(scrollIntoView !== false){
46598 var el = this.view.getNode(index);
46600 this.innerList.scrollChildIntoView(el, false);
46608 validateBlur : function(){
46615 initQuery : function(){
46616 this.doQuery(this.getRawValue());
46620 doForce : function(){
46621 if(this.el.dom.value.length > 0){
46622 this.el.dom.value =
46623 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
46629 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
46630 * query allowing the query action to be canceled if needed.
46631 * @param {String} query The SQL query to execute
46632 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
46633 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
46634 * saved in the current store (defaults to false)
46636 doQuery : function(q, forceAll){
46638 Roo.log('doQuery?');
46639 if(q === undefined || q === null){
46644 forceAll: forceAll,
46648 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
46652 forceAll = qe.forceAll;
46653 if(forceAll === true || (q.length >= this.minChars)){
46654 if(this.lastQuery != q || this.alwaysQuery){
46655 this.lastQuery = q;
46656 if(this.mode == 'local'){
46657 this.selectedIndex = -1;
46659 this.store.clearFilter();
46661 this.store.filter(this.displayField, q);
46665 this.store.baseParams[this.queryParam] = q;
46667 params: this.getParams(q)
46672 this.selectedIndex = -1;
46679 getParams : function(q){
46681 //p[this.queryParam] = q;
46684 p.limit = this.pageSize;
46690 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
46692 collapse : function(){
46697 collapseIf : function(e){
46702 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
46704 expand : function(){
46712 * @cfg {Boolean} grow
46716 * @cfg {Number} growMin
46720 * @cfg {Number} growMax
46728 setWidth : function()
46732 getResizeEl : function(){
46735 });//<script type="text/javasscript">
46739 * @class Roo.DDView
46740 * A DnD enabled version of Roo.View.
46741 * @param {Element/String} container The Element in which to create the View.
46742 * @param {String} tpl The template string used to create the markup for each element of the View
46743 * @param {Object} config The configuration properties. These include all the config options of
46744 * {@link Roo.View} plus some specific to this class.<br>
46746 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
46747 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
46749 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
46750 .x-view-drag-insert-above {
46751 border-top:1px dotted #3366cc;
46753 .x-view-drag-insert-below {
46754 border-bottom:1px dotted #3366cc;
46760 Roo.DDView = function(container, tpl, config) {
46761 Roo.DDView.superclass.constructor.apply(this, arguments);
46762 this.getEl().setStyle("outline", "0px none");
46763 this.getEl().unselectable();
46764 if (this.dragGroup) {
46765 this.setDraggable(this.dragGroup.split(","));
46767 if (this.dropGroup) {
46768 this.setDroppable(this.dropGroup.split(","));
46770 if (this.deletable) {
46771 this.setDeletable();
46773 this.isDirtyFlag = false;
46779 Roo.extend(Roo.DDView, Roo.View, {
46780 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
46781 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
46782 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
46783 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
46787 reset: Roo.emptyFn,
46789 clearInvalid: Roo.form.Field.prototype.clearInvalid,
46791 validate: function() {
46795 destroy: function() {
46796 this.purgeListeners();
46797 this.getEl.removeAllListeners();
46798 this.getEl().remove();
46799 if (this.dragZone) {
46800 if (this.dragZone.destroy) {
46801 this.dragZone.destroy();
46804 if (this.dropZone) {
46805 if (this.dropZone.destroy) {
46806 this.dropZone.destroy();
46811 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
46812 getName: function() {
46816 /** Loads the View from a JSON string representing the Records to put into the Store. */
46817 setValue: function(v) {
46819 throw "DDView.setValue(). DDView must be constructed with a valid Store";
46822 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
46823 this.store.proxy = new Roo.data.MemoryProxy(data);
46827 /** @return {String} a parenthesised list of the ids of the Records in the View. */
46828 getValue: function() {
46830 this.store.each(function(rec) {
46831 result += rec.id + ',';
46833 return result.substr(0, result.length - 1) + ')';
46836 getIds: function() {
46837 var i = 0, result = new Array(this.store.getCount());
46838 this.store.each(function(rec) {
46839 result[i++] = rec.id;
46844 isDirty: function() {
46845 return this.isDirtyFlag;
46849 * Part of the Roo.dd.DropZone interface. If no target node is found, the
46850 * whole Element becomes the target, and this causes the drop gesture to append.
46852 getTargetFromEvent : function(e) {
46853 var target = e.getTarget();
46854 while ((target !== null) && (target.parentNode != this.el.dom)) {
46855 target = target.parentNode;
46858 target = this.el.dom.lastChild || this.el.dom;
46864 * Create the drag data which consists of an object which has the property "ddel" as
46865 * the drag proxy element.
46867 getDragData : function(e) {
46868 var target = this.findItemFromChild(e.getTarget());
46870 this.handleSelection(e);
46871 var selNodes = this.getSelectedNodes();
46874 copy: this.copy || (this.allowCopy && e.ctrlKey),
46878 var selectedIndices = this.getSelectedIndexes();
46879 for (var i = 0; i < selectedIndices.length; i++) {
46880 dragData.records.push(this.store.getAt(selectedIndices[i]));
46882 if (selNodes.length == 1) {
46883 dragData.ddel = target.cloneNode(true); // the div element
46885 var div = document.createElement('div'); // create the multi element drag "ghost"
46886 div.className = 'multi-proxy';
46887 for (var i = 0, len = selNodes.length; i < len; i++) {
46888 div.appendChild(selNodes[i].cloneNode(true));
46890 dragData.ddel = div;
46892 //console.log(dragData)
46893 //console.log(dragData.ddel.innerHTML)
46896 //console.log('nodragData')
46900 /** Specify to which ddGroup items in this DDView may be dragged. */
46901 setDraggable: function(ddGroup) {
46902 if (ddGroup instanceof Array) {
46903 Roo.each(ddGroup, this.setDraggable, this);
46906 if (this.dragZone) {
46907 this.dragZone.addToGroup(ddGroup);
46909 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
46910 containerScroll: true,
46914 // Draggability implies selection. DragZone's mousedown selects the element.
46915 if (!this.multiSelect) { this.singleSelect = true; }
46917 // Wire the DragZone's handlers up to methods in *this*
46918 this.dragZone.getDragData = this.getDragData.createDelegate(this);
46922 /** Specify from which ddGroup this DDView accepts drops. */
46923 setDroppable: function(ddGroup) {
46924 if (ddGroup instanceof Array) {
46925 Roo.each(ddGroup, this.setDroppable, this);
46928 if (this.dropZone) {
46929 this.dropZone.addToGroup(ddGroup);
46931 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
46932 containerScroll: true,
46936 // Wire the DropZone's handlers up to methods in *this*
46937 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
46938 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
46939 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
46940 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
46941 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
46945 /** Decide whether to drop above or below a View node. */
46946 getDropPoint : function(e, n, dd){
46947 if (n == this.el.dom) { return "above"; }
46948 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
46949 var c = t + (b - t) / 2;
46950 var y = Roo.lib.Event.getPageY(e);
46958 onNodeEnter : function(n, dd, e, data){
46962 onNodeOver : function(n, dd, e, data){
46963 var pt = this.getDropPoint(e, n, dd);
46964 // set the insert point style on the target node
46965 var dragElClass = this.dropNotAllowed;
46968 if (pt == "above"){
46969 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
46970 targetElClass = "x-view-drag-insert-above";
46972 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
46973 targetElClass = "x-view-drag-insert-below";
46975 if (this.lastInsertClass != targetElClass){
46976 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
46977 this.lastInsertClass = targetElClass;
46980 return dragElClass;
46983 onNodeOut : function(n, dd, e, data){
46984 this.removeDropIndicators(n);
46987 onNodeDrop : function(n, dd, e, data){
46988 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
46991 var pt = this.getDropPoint(e, n, dd);
46992 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
46993 if (pt == "below") { insertAt++; }
46994 for (var i = 0; i < data.records.length; i++) {
46995 var r = data.records[i];
46996 var dup = this.store.getById(r.id);
46997 if (dup && (dd != this.dragZone)) {
46998 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
47001 this.store.insert(insertAt++, r.copy());
47003 data.source.isDirtyFlag = true;
47005 this.store.insert(insertAt++, r);
47007 this.isDirtyFlag = true;
47010 this.dragZone.cachedTarget = null;
47014 removeDropIndicators : function(n){
47016 Roo.fly(n).removeClass([
47017 "x-view-drag-insert-above",
47018 "x-view-drag-insert-below"]);
47019 this.lastInsertClass = "_noclass";
47024 * Utility method. Add a delete option to the DDView's context menu.
47025 * @param {String} imageUrl The URL of the "delete" icon image.
47027 setDeletable: function(imageUrl) {
47028 if (!this.singleSelect && !this.multiSelect) {
47029 this.singleSelect = true;
47031 var c = this.getContextMenu();
47032 this.contextMenu.on("itemclick", function(item) {
47035 this.remove(this.getSelectedIndexes());
47039 this.contextMenu.add({
47046 /** Return the context menu for this DDView. */
47047 getContextMenu: function() {
47048 if (!this.contextMenu) {
47049 // Create the View's context menu
47050 this.contextMenu = new Roo.menu.Menu({
47051 id: this.id + "-contextmenu"
47053 this.el.on("contextmenu", this.showContextMenu, this);
47055 return this.contextMenu;
47058 disableContextMenu: function() {
47059 if (this.contextMenu) {
47060 this.el.un("contextmenu", this.showContextMenu, this);
47064 showContextMenu: function(e, item) {
47065 item = this.findItemFromChild(e.getTarget());
47068 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
47069 this.contextMenu.showAt(e.getXY());
47074 * Remove {@link Roo.data.Record}s at the specified indices.
47075 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
47077 remove: function(selectedIndices) {
47078 selectedIndices = [].concat(selectedIndices);
47079 for (var i = 0; i < selectedIndices.length; i++) {
47080 var rec = this.store.getAt(selectedIndices[i]);
47081 this.store.remove(rec);
47086 * Double click fires the event, but also, if this is draggable, and there is only one other
47087 * related DropZone, it transfers the selected node.
47089 onDblClick : function(e){
47090 var item = this.findItemFromChild(e.getTarget());
47092 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
47095 if (this.dragGroup) {
47096 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
47097 while (targets.indexOf(this.dropZone) > -1) {
47098 targets.remove(this.dropZone);
47100 if (targets.length == 1) {
47101 this.dragZone.cachedTarget = null;
47102 var el = Roo.get(targets[0].getEl());
47103 var box = el.getBox(true);
47104 targets[0].onNodeDrop(el.dom, {
47106 xy: [box.x, box.y + box.height - 1]
47107 }, null, this.getDragData(e));
47113 handleSelection: function(e) {
47114 this.dragZone.cachedTarget = null;
47115 var item = this.findItemFromChild(e.getTarget());
47117 this.clearSelections(true);
47120 if (item && (this.multiSelect || this.singleSelect)){
47121 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
47122 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
47123 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
47124 this.unselect(item);
47126 this.select(item, this.multiSelect && e.ctrlKey);
47127 this.lastSelection = item;
47132 onItemClick : function(item, index, e){
47133 if(this.fireEvent("beforeclick", this, index, item, e) === false){
47139 unselect : function(nodeInfo, suppressEvent){
47140 var node = this.getNode(nodeInfo);
47141 if(node && this.isSelected(node)){
47142 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
47143 Roo.fly(node).removeClass(this.selectedClass);
47144 this.selections.remove(node);
47145 if(!suppressEvent){
47146 this.fireEvent("selectionchange", this, this.selections);
47154 * Ext JS Library 1.1.1
47155 * Copyright(c) 2006-2007, Ext JS, LLC.
47157 * Originally Released Under LGPL - original licence link has changed is not relivant.
47160 * <script type="text/javascript">
47164 * @class Roo.LayoutManager
47165 * @extends Roo.util.Observable
47166 * Base class for layout managers.
47168 Roo.LayoutManager = function(container, config){
47169 Roo.LayoutManager.superclass.constructor.call(this);
47170 this.el = Roo.get(container);
47171 // ie scrollbar fix
47172 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
47173 document.body.scroll = "no";
47174 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
47175 this.el.position('relative');
47177 this.id = this.el.id;
47178 this.el.addClass("x-layout-container");
47179 /** false to disable window resize monitoring @type Boolean */
47180 this.monitorWindowResize = true;
47185 * Fires when a layout is performed.
47186 * @param {Roo.LayoutManager} this
47190 * @event regionresized
47191 * Fires when the user resizes a region.
47192 * @param {Roo.LayoutRegion} region The resized region
47193 * @param {Number} newSize The new size (width for east/west, height for north/south)
47195 "regionresized" : true,
47197 * @event regioncollapsed
47198 * Fires when a region is collapsed.
47199 * @param {Roo.LayoutRegion} region The collapsed region
47201 "regioncollapsed" : true,
47203 * @event regionexpanded
47204 * Fires when a region is expanded.
47205 * @param {Roo.LayoutRegion} region The expanded region
47207 "regionexpanded" : true
47209 this.updating = false;
47210 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
47213 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
47215 * Returns true if this layout is currently being updated
47216 * @return {Boolean}
47218 isUpdating : function(){
47219 return this.updating;
47223 * Suspend the LayoutManager from doing auto-layouts while
47224 * making multiple add or remove calls
47226 beginUpdate : function(){
47227 this.updating = true;
47231 * Restore auto-layouts and optionally disable the manager from performing a layout
47232 * @param {Boolean} noLayout true to disable a layout update
47234 endUpdate : function(noLayout){
47235 this.updating = false;
47241 layout: function(){
47245 onRegionResized : function(region, newSize){
47246 this.fireEvent("regionresized", region, newSize);
47250 onRegionCollapsed : function(region){
47251 this.fireEvent("regioncollapsed", region);
47254 onRegionExpanded : function(region){
47255 this.fireEvent("regionexpanded", region);
47259 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
47260 * performs box-model adjustments.
47261 * @return {Object} The size as an object {width: (the width), height: (the height)}
47263 getViewSize : function(){
47265 if(this.el.dom != document.body){
47266 size = this.el.getSize();
47268 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
47270 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
47271 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
47276 * Returns the Element this layout is bound to.
47277 * @return {Roo.Element}
47279 getEl : function(){
47284 * Returns the specified region.
47285 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
47286 * @return {Roo.LayoutRegion}
47288 getRegion : function(target){
47289 return this.regions[target.toLowerCase()];
47292 onWindowResize : function(){
47293 if(this.monitorWindowResize){
47299 * Ext JS Library 1.1.1
47300 * Copyright(c) 2006-2007, Ext JS, LLC.
47302 * Originally Released Under LGPL - original licence link has changed is not relivant.
47305 * <script type="text/javascript">
47308 * @class Roo.BorderLayout
47309 * @extends Roo.LayoutManager
47310 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
47311 * please see: <br><br>
47312 * <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>
47313 * <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>
47316 var layout = new Roo.BorderLayout(document.body, {
47350 preferredTabWidth: 150
47355 var CP = Roo.ContentPanel;
47357 layout.beginUpdate();
47358 layout.add("north", new CP("north", "North"));
47359 layout.add("south", new CP("south", {title: "South", closable: true}));
47360 layout.add("west", new CP("west", {title: "West"}));
47361 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
47362 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
47363 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
47364 layout.getRegion("center").showPanel("center1");
47365 layout.endUpdate();
47368 <b>The container the layout is rendered into can be either the body element or any other element.
47369 If it is not the body element, the container needs to either be an absolute positioned element,
47370 or you will need to add "position:relative" to the css of the container. You will also need to specify
47371 the container size if it is not the body element.</b>
47374 * Create a new BorderLayout
47375 * @param {String/HTMLElement/Element} container The container this layout is bound to
47376 * @param {Object} config Configuration options
47378 Roo.BorderLayout = function(container, config){
47379 config = config || {};
47380 Roo.BorderLayout.superclass.constructor.call(this, container, config);
47381 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
47382 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
47383 var target = this.factory.validRegions[i];
47384 if(config[target]){
47385 this.addRegion(target, config[target]);
47390 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
47392 * Creates and adds a new region if it doesn't already exist.
47393 * @param {String} target The target region key (north, south, east, west or center).
47394 * @param {Object} config The regions config object
47395 * @return {BorderLayoutRegion} The new region
47397 addRegion : function(target, config){
47398 if(!this.regions[target]){
47399 var r = this.factory.create(target, this, config);
47400 this.bindRegion(target, r);
47402 return this.regions[target];
47406 bindRegion : function(name, r){
47407 this.regions[name] = r;
47408 r.on("visibilitychange", this.layout, this);
47409 r.on("paneladded", this.layout, this);
47410 r.on("panelremoved", this.layout, this);
47411 r.on("invalidated", this.layout, this);
47412 r.on("resized", this.onRegionResized, this);
47413 r.on("collapsed", this.onRegionCollapsed, this);
47414 r.on("expanded", this.onRegionExpanded, this);
47418 * Performs a layout update.
47420 layout : function(){
47421 if(this.updating) return;
47422 var size = this.getViewSize();
47423 var w = size.width;
47424 var h = size.height;
47429 //var x = 0, y = 0;
47431 var rs = this.regions;
47432 var north = rs["north"];
47433 var south = rs["south"];
47434 var west = rs["west"];
47435 var east = rs["east"];
47436 var center = rs["center"];
47437 //if(this.hideOnLayout){ // not supported anymore
47438 //c.el.setStyle("display", "none");
47440 if(north && north.isVisible()){
47441 var b = north.getBox();
47442 var m = north.getMargins();
47443 b.width = w - (m.left+m.right);
47446 centerY = b.height + b.y + m.bottom;
47447 centerH -= centerY;
47448 north.updateBox(this.safeBox(b));
47450 if(south && south.isVisible()){
47451 var b = south.getBox();
47452 var m = south.getMargins();
47453 b.width = w - (m.left+m.right);
47455 var totalHeight = (b.height + m.top + m.bottom);
47456 b.y = h - totalHeight + m.top;
47457 centerH -= totalHeight;
47458 south.updateBox(this.safeBox(b));
47460 if(west && west.isVisible()){
47461 var b = west.getBox();
47462 var m = west.getMargins();
47463 b.height = centerH - (m.top+m.bottom);
47465 b.y = centerY + m.top;
47466 var totalWidth = (b.width + m.left + m.right);
47467 centerX += totalWidth;
47468 centerW -= totalWidth;
47469 west.updateBox(this.safeBox(b));
47471 if(east && east.isVisible()){
47472 var b = east.getBox();
47473 var m = east.getMargins();
47474 b.height = centerH - (m.top+m.bottom);
47475 var totalWidth = (b.width + m.left + m.right);
47476 b.x = w - totalWidth + m.left;
47477 b.y = centerY + m.top;
47478 centerW -= totalWidth;
47479 east.updateBox(this.safeBox(b));
47482 var m = center.getMargins();
47484 x: centerX + m.left,
47485 y: centerY + m.top,
47486 width: centerW - (m.left+m.right),
47487 height: centerH - (m.top+m.bottom)
47489 //if(this.hideOnLayout){
47490 //center.el.setStyle("display", "block");
47492 center.updateBox(this.safeBox(centerBox));
47495 this.fireEvent("layout", this);
47499 safeBox : function(box){
47500 box.width = Math.max(0, box.width);
47501 box.height = Math.max(0, box.height);
47506 * Adds a ContentPanel (or subclass) to this layout.
47507 * @param {String} target The target region key (north, south, east, west or center).
47508 * @param {Roo.ContentPanel} panel The panel to add
47509 * @return {Roo.ContentPanel} The added panel
47511 add : function(target, panel){
47513 target = target.toLowerCase();
47514 return this.regions[target].add(panel);
47518 * Remove a ContentPanel (or subclass) to this layout.
47519 * @param {String} target The target region key (north, south, east, west or center).
47520 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
47521 * @return {Roo.ContentPanel} The removed panel
47523 remove : function(target, panel){
47524 target = target.toLowerCase();
47525 return this.regions[target].remove(panel);
47529 * Searches all regions for a panel with the specified id
47530 * @param {String} panelId
47531 * @return {Roo.ContentPanel} The panel or null if it wasn't found
47533 findPanel : function(panelId){
47534 var rs = this.regions;
47535 for(var target in rs){
47536 if(typeof rs[target] != "function"){
47537 var p = rs[target].getPanel(panelId);
47547 * Searches all regions for a panel with the specified id and activates (shows) it.
47548 * @param {String/ContentPanel} panelId The panels id or the panel itself
47549 * @return {Roo.ContentPanel} The shown panel or null
47551 showPanel : function(panelId) {
47552 var rs = this.regions;
47553 for(var target in rs){
47554 var r = rs[target];
47555 if(typeof r != "function"){
47556 if(r.hasPanel(panelId)){
47557 return r.showPanel(panelId);
47565 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
47566 * @param {Roo.state.Provider} provider (optional) An alternate state provider
47568 restoreState : function(provider){
47570 provider = Roo.state.Manager;
47572 var sm = new Roo.LayoutStateManager();
47573 sm.init(this, provider);
47577 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
47578 * object should contain properties for each region to add ContentPanels to, and each property's value should be
47579 * a valid ContentPanel config object. Example:
47581 // Create the main layout
47582 var layout = new Roo.BorderLayout('main-ct', {
47593 // Create and add multiple ContentPanels at once via configs
47596 id: 'source-files',
47598 title:'Ext Source Files',
47611 * @param {Object} regions An object containing ContentPanel configs by region name
47613 batchAdd : function(regions){
47614 this.beginUpdate();
47615 for(var rname in regions){
47616 var lr = this.regions[rname];
47618 this.addTypedPanels(lr, regions[rname]);
47625 addTypedPanels : function(lr, ps){
47626 if(typeof ps == 'string'){
47627 lr.add(new Roo.ContentPanel(ps));
47629 else if(ps instanceof Array){
47630 for(var i =0, len = ps.length; i < len; i++){
47631 this.addTypedPanels(lr, ps[i]);
47634 else if(!ps.events){ // raw config?
47636 delete ps.el; // prevent conflict
47637 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
47639 else { // panel object assumed!
47644 * Adds a xtype elements to the layout.
47648 xtype : 'ContentPanel',
47655 xtype : 'NestedLayoutPanel',
47661 items : [ ... list of content panels or nested layout panels.. ]
47665 * @param {Object} cfg Xtype definition of item to add.
47667 addxtype : function(cfg)
47669 // basically accepts a pannel...
47670 // can accept a layout region..!?!?
47671 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
47673 if (!cfg.xtype.match(/Panel$/)) {
47678 if (typeof(cfg.region) == 'undefined') {
47679 Roo.log("Failed to add Panel, region was not set");
47683 var region = cfg.region;
47689 xitems = cfg.items;
47696 case 'ContentPanel': // ContentPanel (el, cfg)
47697 case 'ScrollPanel': // ContentPanel (el, cfg)
47699 if(cfg.autoCreate) {
47700 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
47702 var el = this.el.createChild();
47703 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
47706 this.add(region, ret);
47710 case 'TreePanel': // our new panel!
47711 cfg.el = this.el.createChild();
47712 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
47713 this.add(region, ret);
47716 case 'NestedLayoutPanel':
47717 // create a new Layout (which is a Border Layout...
47718 var el = this.el.createChild();
47719 var clayout = cfg.layout;
47721 clayout.items = clayout.items || [];
47722 // replace this exitems with the clayout ones..
47723 xitems = clayout.items;
47726 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
47727 cfg.background = false;
47729 var layout = new Roo.BorderLayout(el, clayout);
47731 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
47732 //console.log('adding nested layout panel ' + cfg.toSource());
47733 this.add(region, ret);
47734 nb = {}; /// find first...
47739 // needs grid and region
47741 //var el = this.getRegion(region).el.createChild();
47742 var el = this.el.createChild();
47743 // create the grid first...
47745 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
47747 if (region == 'center' && this.active ) {
47748 cfg.background = false;
47750 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
47752 this.add(region, ret);
47753 if (cfg.background) {
47754 ret.on('activate', function(gp) {
47755 if (!gp.grid.rendered) {
47770 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
47772 // GridPanel (grid, cfg)
47775 this.beginUpdate();
47779 Roo.each(xitems, function(i) {
47780 region = nb && i.region ? i.region : false;
47782 var add = ret.addxtype(i);
47785 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
47786 if (!i.background) {
47787 abn[region] = nb[region] ;
47794 // make the last non-background panel active..
47795 //if (nb) { Roo.log(abn); }
47798 for(var r in abn) {
47799 region = this.getRegion(r);
47801 // tried using nb[r], but it does not work..
47803 region.showPanel(abn[r]);
47814 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
47815 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
47816 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
47817 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
47820 var CP = Roo.ContentPanel;
47822 var layout = Roo.BorderLayout.create({
47826 panels: [new CP("north", "North")]
47835 panels: [new CP("west", {title: "West"})]
47844 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
47853 panels: [new CP("south", {title: "South", closable: true})]
47860 preferredTabWidth: 150,
47862 new CP("center1", {title: "Close Me", closable: true}),
47863 new CP("center2", {title: "Center Panel", closable: false})
47868 layout.getRegion("center").showPanel("center1");
47873 Roo.BorderLayout.create = function(config, targetEl){
47874 var layout = new Roo.BorderLayout(targetEl || document.body, config);
47875 layout.beginUpdate();
47876 var regions = Roo.BorderLayout.RegionFactory.validRegions;
47877 for(var j = 0, jlen = regions.length; j < jlen; j++){
47878 var lr = regions[j];
47879 if(layout.regions[lr] && config[lr].panels){
47880 var r = layout.regions[lr];
47881 var ps = config[lr].panels;
47882 layout.addTypedPanels(r, ps);
47885 layout.endUpdate();
47890 Roo.BorderLayout.RegionFactory = {
47892 validRegions : ["north","south","east","west","center"],
47895 create : function(target, mgr, config){
47896 target = target.toLowerCase();
47897 if(config.lightweight || config.basic){
47898 return new Roo.BasicLayoutRegion(mgr, config, target);
47902 return new Roo.NorthLayoutRegion(mgr, config);
47904 return new Roo.SouthLayoutRegion(mgr, config);
47906 return new Roo.EastLayoutRegion(mgr, config);
47908 return new Roo.WestLayoutRegion(mgr, config);
47910 return new Roo.CenterLayoutRegion(mgr, config);
47912 throw 'Layout region "'+target+'" not supported.';
47916 * Ext JS Library 1.1.1
47917 * Copyright(c) 2006-2007, Ext JS, LLC.
47919 * Originally Released Under LGPL - original licence link has changed is not relivant.
47922 * <script type="text/javascript">
47926 * @class Roo.BasicLayoutRegion
47927 * @extends Roo.util.Observable
47928 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
47929 * and does not have a titlebar, tabs or any other features. All it does is size and position
47930 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
47932 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
47934 this.position = pos;
47937 * @scope Roo.BasicLayoutRegion
47941 * @event beforeremove
47942 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
47943 * @param {Roo.LayoutRegion} this
47944 * @param {Roo.ContentPanel} panel The panel
47945 * @param {Object} e The cancel event object
47947 "beforeremove" : true,
47949 * @event invalidated
47950 * Fires when the layout for this region is changed.
47951 * @param {Roo.LayoutRegion} this
47953 "invalidated" : true,
47955 * @event visibilitychange
47956 * Fires when this region is shown or hidden
47957 * @param {Roo.LayoutRegion} this
47958 * @param {Boolean} visibility true or false
47960 "visibilitychange" : true,
47962 * @event paneladded
47963 * Fires when a panel is added.
47964 * @param {Roo.LayoutRegion} this
47965 * @param {Roo.ContentPanel} panel The panel
47967 "paneladded" : true,
47969 * @event panelremoved
47970 * Fires when a panel is removed.
47971 * @param {Roo.LayoutRegion} this
47972 * @param {Roo.ContentPanel} panel The panel
47974 "panelremoved" : true,
47977 * Fires when this region is collapsed.
47978 * @param {Roo.LayoutRegion} this
47980 "collapsed" : true,
47983 * Fires when this region is expanded.
47984 * @param {Roo.LayoutRegion} this
47989 * Fires when this region is slid into view.
47990 * @param {Roo.LayoutRegion} this
47992 "slideshow" : true,
47995 * Fires when this region slides out of view.
47996 * @param {Roo.LayoutRegion} this
47998 "slidehide" : true,
48000 * @event panelactivated
48001 * Fires when a panel is activated.
48002 * @param {Roo.LayoutRegion} this
48003 * @param {Roo.ContentPanel} panel The activated panel
48005 "panelactivated" : true,
48008 * Fires when the user resizes this region.
48009 * @param {Roo.LayoutRegion} this
48010 * @param {Number} newSize The new size (width for east/west, height for north/south)
48014 /** A collection of panels in this region. @type Roo.util.MixedCollection */
48015 this.panels = new Roo.util.MixedCollection();
48016 this.panels.getKey = this.getPanelId.createDelegate(this);
48018 this.activePanel = null;
48019 // ensure listeners are added...
48021 if (config.listeners || config.events) {
48022 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
48023 listeners : config.listeners || {},
48024 events : config.events || {}
48028 if(skipConfig !== true){
48029 this.applyConfig(config);
48033 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
48034 getPanelId : function(p){
48038 applyConfig : function(config){
48039 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
48040 this.config = config;
48045 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
48046 * the width, for horizontal (north, south) the height.
48047 * @param {Number} newSize The new width or height
48049 resizeTo : function(newSize){
48050 var el = this.el ? this.el :
48051 (this.activePanel ? this.activePanel.getEl() : null);
48053 switch(this.position){
48056 el.setWidth(newSize);
48057 this.fireEvent("resized", this, newSize);
48061 el.setHeight(newSize);
48062 this.fireEvent("resized", this, newSize);
48068 getBox : function(){
48069 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
48072 getMargins : function(){
48073 return this.margins;
48076 updateBox : function(box){
48078 var el = this.activePanel.getEl();
48079 el.dom.style.left = box.x + "px";
48080 el.dom.style.top = box.y + "px";
48081 this.activePanel.setSize(box.width, box.height);
48085 * Returns the container element for this region.
48086 * @return {Roo.Element}
48088 getEl : function(){
48089 return this.activePanel;
48093 * Returns true if this region is currently visible.
48094 * @return {Boolean}
48096 isVisible : function(){
48097 return this.activePanel ? true : false;
48100 setActivePanel : function(panel){
48101 panel = this.getPanel(panel);
48102 if(this.activePanel && this.activePanel != panel){
48103 this.activePanel.setActiveState(false);
48104 this.activePanel.getEl().setLeftTop(-10000,-10000);
48106 this.activePanel = panel;
48107 panel.setActiveState(true);
48109 panel.setSize(this.box.width, this.box.height);
48111 this.fireEvent("panelactivated", this, panel);
48112 this.fireEvent("invalidated");
48116 * Show the specified panel.
48117 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
48118 * @return {Roo.ContentPanel} The shown panel or null
48120 showPanel : function(panel){
48121 if(panel = this.getPanel(panel)){
48122 this.setActivePanel(panel);
48128 * Get the active panel for this region.
48129 * @return {Roo.ContentPanel} The active panel or null
48131 getActivePanel : function(){
48132 return this.activePanel;
48136 * Add the passed ContentPanel(s)
48137 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
48138 * @return {Roo.ContentPanel} The panel added (if only one was added)
48140 add : function(panel){
48141 if(arguments.length > 1){
48142 for(var i = 0, len = arguments.length; i < len; i++) {
48143 this.add(arguments[i]);
48147 if(this.hasPanel(panel)){
48148 this.showPanel(panel);
48151 var el = panel.getEl();
48152 if(el.dom.parentNode != this.mgr.el.dom){
48153 this.mgr.el.dom.appendChild(el.dom);
48155 if(panel.setRegion){
48156 panel.setRegion(this);
48158 this.panels.add(panel);
48159 el.setStyle("position", "absolute");
48160 if(!panel.background){
48161 this.setActivePanel(panel);
48162 if(this.config.initialSize && this.panels.getCount()==1){
48163 this.resizeTo(this.config.initialSize);
48166 this.fireEvent("paneladded", this, panel);
48171 * Returns true if the panel is in this region.
48172 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48173 * @return {Boolean}
48175 hasPanel : function(panel){
48176 if(typeof panel == "object"){ // must be panel obj
48177 panel = panel.getId();
48179 return this.getPanel(panel) ? true : false;
48183 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
48184 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48185 * @param {Boolean} preservePanel Overrides the config preservePanel option
48186 * @return {Roo.ContentPanel} The panel that was removed
48188 remove : function(panel, preservePanel){
48189 panel = this.getPanel(panel);
48194 this.fireEvent("beforeremove", this, panel, e);
48195 if(e.cancel === true){
48198 var panelId = panel.getId();
48199 this.panels.removeKey(panelId);
48204 * Returns the panel specified or null if it's not in this region.
48205 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48206 * @return {Roo.ContentPanel}
48208 getPanel : function(id){
48209 if(typeof id == "object"){ // must be panel obj
48212 return this.panels.get(id);
48216 * Returns this regions position (north/south/east/west/center).
48219 getPosition: function(){
48220 return this.position;
48224 * Ext JS Library 1.1.1
48225 * Copyright(c) 2006-2007, Ext JS, LLC.
48227 * Originally Released Under LGPL - original licence link has changed is not relivant.
48230 * <script type="text/javascript">
48234 * @class Roo.LayoutRegion
48235 * @extends Roo.BasicLayoutRegion
48236 * This class represents a region in a layout manager.
48237 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
48238 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
48239 * @cfg {Boolean} floatable False to disable floating (defaults to true)
48240 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
48241 * @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})
48242 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
48243 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
48244 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
48245 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
48246 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
48247 * @cfg {String} title The title for the region (overrides panel titles)
48248 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
48249 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
48250 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
48251 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
48252 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
48253 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
48254 * the space available, similar to FireFox 1.5 tabs (defaults to false)
48255 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
48256 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
48257 * @cfg {Boolean} showPin True to show a pin button
48258 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
48259 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
48260 * @cfg {Boolean} disableTabTips True to disable tab tooltips
48261 * @cfg {Number} width For East/West panels
48262 * @cfg {Number} height For North/South panels
48263 * @cfg {Boolean} split To show the splitter
48264 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
48266 Roo.LayoutRegion = function(mgr, config, pos){
48267 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
48268 var dh = Roo.DomHelper;
48269 /** This region's container element
48270 * @type Roo.Element */
48271 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
48272 /** This region's title element
48273 * @type Roo.Element */
48275 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
48276 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
48277 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
48279 this.titleEl.enableDisplayMode();
48280 /** This region's title text element
48281 * @type HTMLElement */
48282 this.titleTextEl = this.titleEl.dom.firstChild;
48283 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
48284 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
48285 this.closeBtn.enableDisplayMode();
48286 this.closeBtn.on("click", this.closeClicked, this);
48287 this.closeBtn.hide();
48289 this.createBody(config);
48290 this.visible = true;
48291 this.collapsed = false;
48293 if(config.hideWhenEmpty){
48295 this.on("paneladded", this.validateVisibility, this);
48296 this.on("panelremoved", this.validateVisibility, this);
48298 this.applyConfig(config);
48301 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
48303 createBody : function(){
48304 /** This region's body element
48305 * @type Roo.Element */
48306 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
48309 applyConfig : function(c){
48310 if(c.collapsible && this.position != "center" && !this.collapsedEl){
48311 var dh = Roo.DomHelper;
48312 if(c.titlebar !== false){
48313 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
48314 this.collapseBtn.on("click", this.collapse, this);
48315 this.collapseBtn.enableDisplayMode();
48317 if(c.showPin === true || this.showPin){
48318 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
48319 this.stickBtn.enableDisplayMode();
48320 this.stickBtn.on("click", this.expand, this);
48321 this.stickBtn.hide();
48324 /** This region's collapsed element
48325 * @type Roo.Element */
48326 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
48327 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
48329 if(c.floatable !== false){
48330 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
48331 this.collapsedEl.on("click", this.collapseClick, this);
48334 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
48335 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
48336 id: "message", unselectable: "on", style:{"float":"left"}});
48337 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
48339 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
48340 this.expandBtn.on("click", this.expand, this);
48342 if(this.collapseBtn){
48343 this.collapseBtn.setVisible(c.collapsible == true);
48345 this.cmargins = c.cmargins || this.cmargins ||
48346 (this.position == "west" || this.position == "east" ?
48347 {top: 0, left: 2, right:2, bottom: 0} :
48348 {top: 2, left: 0, right:0, bottom: 2});
48349 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
48350 this.bottomTabs = c.tabPosition != "top";
48351 this.autoScroll = c.autoScroll || false;
48352 if(this.autoScroll){
48353 this.bodyEl.setStyle("overflow", "auto");
48355 this.bodyEl.setStyle("overflow", "hidden");
48357 //if(c.titlebar !== false){
48358 if((!c.titlebar && !c.title) || c.titlebar === false){
48359 this.titleEl.hide();
48361 this.titleEl.show();
48363 this.titleTextEl.innerHTML = c.title;
48367 this.duration = c.duration || .30;
48368 this.slideDuration = c.slideDuration || .45;
48371 this.collapse(true);
48378 * Returns true if this region is currently visible.
48379 * @return {Boolean}
48381 isVisible : function(){
48382 return this.visible;
48386 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
48387 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
48389 setCollapsedTitle : function(title){
48390 title = title || " ";
48391 if(this.collapsedTitleTextEl){
48392 this.collapsedTitleTextEl.innerHTML = title;
48396 getBox : function(){
48398 if(!this.collapsed){
48399 b = this.el.getBox(false, true);
48401 b = this.collapsedEl.getBox(false, true);
48406 getMargins : function(){
48407 return this.collapsed ? this.cmargins : this.margins;
48410 highlight : function(){
48411 this.el.addClass("x-layout-panel-dragover");
48414 unhighlight : function(){
48415 this.el.removeClass("x-layout-panel-dragover");
48418 updateBox : function(box){
48420 if(!this.collapsed){
48421 this.el.dom.style.left = box.x + "px";
48422 this.el.dom.style.top = box.y + "px";
48423 this.updateBody(box.width, box.height);
48425 this.collapsedEl.dom.style.left = box.x + "px";
48426 this.collapsedEl.dom.style.top = box.y + "px";
48427 this.collapsedEl.setSize(box.width, box.height);
48430 this.tabs.autoSizeTabs();
48434 updateBody : function(w, h){
48436 this.el.setWidth(w);
48437 w -= this.el.getBorderWidth("rl");
48438 if(this.config.adjustments){
48439 w += this.config.adjustments[0];
48443 this.el.setHeight(h);
48444 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
48445 h -= this.el.getBorderWidth("tb");
48446 if(this.config.adjustments){
48447 h += this.config.adjustments[1];
48449 this.bodyEl.setHeight(h);
48451 h = this.tabs.syncHeight(h);
48454 if(this.panelSize){
48455 w = w !== null ? w : this.panelSize.width;
48456 h = h !== null ? h : this.panelSize.height;
48458 if(this.activePanel){
48459 var el = this.activePanel.getEl();
48460 w = w !== null ? w : el.getWidth();
48461 h = h !== null ? h : el.getHeight();
48462 this.panelSize = {width: w, height: h};
48463 this.activePanel.setSize(w, h);
48465 if(Roo.isIE && this.tabs){
48466 this.tabs.el.repaint();
48471 * Returns the container element for this region.
48472 * @return {Roo.Element}
48474 getEl : function(){
48479 * Hides this region.
48482 if(!this.collapsed){
48483 this.el.dom.style.left = "-2000px";
48486 this.collapsedEl.dom.style.left = "-2000px";
48487 this.collapsedEl.hide();
48489 this.visible = false;
48490 this.fireEvent("visibilitychange", this, false);
48494 * Shows this region if it was previously hidden.
48497 if(!this.collapsed){
48500 this.collapsedEl.show();
48502 this.visible = true;
48503 this.fireEvent("visibilitychange", this, true);
48506 closeClicked : function(){
48507 if(this.activePanel){
48508 this.remove(this.activePanel);
48512 collapseClick : function(e){
48514 e.stopPropagation();
48517 e.stopPropagation();
48523 * Collapses this region.
48524 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
48526 collapse : function(skipAnim){
48527 if(this.collapsed) return;
48528 this.collapsed = true;
48530 this.split.el.hide();
48532 if(this.config.animate && skipAnim !== true){
48533 this.fireEvent("invalidated", this);
48534 this.animateCollapse();
48536 this.el.setLocation(-20000,-20000);
48538 this.collapsedEl.show();
48539 this.fireEvent("collapsed", this);
48540 this.fireEvent("invalidated", this);
48544 animateCollapse : function(){
48549 * Expands this region if it was previously collapsed.
48550 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
48551 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
48553 expand : function(e, skipAnim){
48554 if(e) e.stopPropagation();
48555 if(!this.collapsed || this.el.hasActiveFx()) return;
48557 this.afterSlideIn();
48560 this.collapsed = false;
48561 if(this.config.animate && skipAnim !== true){
48562 this.animateExpand();
48566 this.split.el.show();
48568 this.collapsedEl.setLocation(-2000,-2000);
48569 this.collapsedEl.hide();
48570 this.fireEvent("invalidated", this);
48571 this.fireEvent("expanded", this);
48575 animateExpand : function(){
48579 initTabs : function()
48581 this.bodyEl.setStyle("overflow", "hidden");
48582 var ts = new Roo.TabPanel(
48585 tabPosition: this.bottomTabs ? 'bottom' : 'top',
48586 disableTooltips: this.config.disableTabTips,
48587 toolbar : this.config.toolbar
48590 if(this.config.hideTabs){
48591 ts.stripWrap.setDisplayed(false);
48594 ts.resizeTabs = this.config.resizeTabs === true;
48595 ts.minTabWidth = this.config.minTabWidth || 40;
48596 ts.maxTabWidth = this.config.maxTabWidth || 250;
48597 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
48598 ts.monitorResize = false;
48599 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
48600 ts.bodyEl.addClass('x-layout-tabs-body');
48601 this.panels.each(this.initPanelAsTab, this);
48604 initPanelAsTab : function(panel){
48605 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
48606 this.config.closeOnTab && panel.isClosable());
48607 if(panel.tabTip !== undefined){
48608 ti.setTooltip(panel.tabTip);
48610 ti.on("activate", function(){
48611 this.setActivePanel(panel);
48613 if(this.config.closeOnTab){
48614 ti.on("beforeclose", function(t, e){
48616 this.remove(panel);
48622 updatePanelTitle : function(panel, title){
48623 if(this.activePanel == panel){
48624 this.updateTitle(title);
48627 var ti = this.tabs.getTab(panel.getEl().id);
48629 if(panel.tabTip !== undefined){
48630 ti.setTooltip(panel.tabTip);
48635 updateTitle : function(title){
48636 if(this.titleTextEl && !this.config.title){
48637 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
48641 setActivePanel : function(panel){
48642 panel = this.getPanel(panel);
48643 if(this.activePanel && this.activePanel != panel){
48644 this.activePanel.setActiveState(false);
48646 this.activePanel = panel;
48647 panel.setActiveState(true);
48648 if(this.panelSize){
48649 panel.setSize(this.panelSize.width, this.panelSize.height);
48652 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
48654 this.updateTitle(panel.getTitle());
48656 this.fireEvent("invalidated", this);
48658 this.fireEvent("panelactivated", this, panel);
48662 * Shows the specified panel.
48663 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
48664 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
48666 showPanel : function(panel){
48667 if(panel = this.getPanel(panel)){
48669 var tab = this.tabs.getTab(panel.getEl().id);
48670 if(tab.isHidden()){
48671 this.tabs.unhideTab(tab.id);
48675 this.setActivePanel(panel);
48682 * Get the active panel for this region.
48683 * @return {Roo.ContentPanel} The active panel or null
48685 getActivePanel : function(){
48686 return this.activePanel;
48689 validateVisibility : function(){
48690 if(this.panels.getCount() < 1){
48691 this.updateTitle(" ");
48692 this.closeBtn.hide();
48695 if(!this.isVisible()){
48702 * Adds the passed ContentPanel(s) to this region.
48703 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
48704 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
48706 add : function(panel){
48707 if(arguments.length > 1){
48708 for(var i = 0, len = arguments.length; i < len; i++) {
48709 this.add(arguments[i]);
48713 if(this.hasPanel(panel)){
48714 this.showPanel(panel);
48717 panel.setRegion(this);
48718 this.panels.add(panel);
48719 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
48720 this.bodyEl.dom.appendChild(panel.getEl().dom);
48721 if(panel.background !== true){
48722 this.setActivePanel(panel);
48724 this.fireEvent("paneladded", this, panel);
48730 this.initPanelAsTab(panel);
48732 if(panel.background !== true){
48733 this.tabs.activate(panel.getEl().id);
48735 this.fireEvent("paneladded", this, panel);
48740 * Hides the tab for the specified panel.
48741 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
48743 hidePanel : function(panel){
48744 if(this.tabs && (panel = this.getPanel(panel))){
48745 this.tabs.hideTab(panel.getEl().id);
48750 * Unhides the tab for a previously hidden panel.
48751 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
48753 unhidePanel : function(panel){
48754 if(this.tabs && (panel = this.getPanel(panel))){
48755 this.tabs.unhideTab(panel.getEl().id);
48759 clearPanels : function(){
48760 while(this.panels.getCount() > 0){
48761 this.remove(this.panels.first());
48766 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
48767 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
48768 * @param {Boolean} preservePanel Overrides the config preservePanel option
48769 * @return {Roo.ContentPanel} The panel that was removed
48771 remove : function(panel, preservePanel){
48772 panel = this.getPanel(panel);
48777 this.fireEvent("beforeremove", this, panel, e);
48778 if(e.cancel === true){
48781 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
48782 var panelId = panel.getId();
48783 this.panels.removeKey(panelId);
48785 document.body.appendChild(panel.getEl().dom);
48788 this.tabs.removeTab(panel.getEl().id);
48789 }else if (!preservePanel){
48790 this.bodyEl.dom.removeChild(panel.getEl().dom);
48792 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
48793 var p = this.panels.first();
48794 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
48795 tempEl.appendChild(p.getEl().dom);
48796 this.bodyEl.update("");
48797 this.bodyEl.dom.appendChild(p.getEl().dom);
48799 this.updateTitle(p.getTitle());
48801 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
48802 this.setActivePanel(p);
48804 panel.setRegion(null);
48805 if(this.activePanel == panel){
48806 this.activePanel = null;
48808 if(this.config.autoDestroy !== false && preservePanel !== true){
48809 try{panel.destroy();}catch(e){}
48811 this.fireEvent("panelremoved", this, panel);
48816 * Returns the TabPanel component used by this region
48817 * @return {Roo.TabPanel}
48819 getTabs : function(){
48823 createTool : function(parentEl, className){
48824 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
48825 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
48826 btn.addClassOnOver("x-layout-tools-button-over");
48831 * Ext JS Library 1.1.1
48832 * Copyright(c) 2006-2007, Ext JS, LLC.
48834 * Originally Released Under LGPL - original licence link has changed is not relivant.
48837 * <script type="text/javascript">
48843 * @class Roo.SplitLayoutRegion
48844 * @extends Roo.LayoutRegion
48845 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
48847 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
48848 this.cursor = cursor;
48849 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
48852 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
48853 splitTip : "Drag to resize.",
48854 collapsibleSplitTip : "Drag to resize. Double click to hide.",
48855 useSplitTips : false,
48857 applyConfig : function(config){
48858 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
48861 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
48862 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
48863 /** The SplitBar for this region
48864 * @type Roo.SplitBar */
48865 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
48866 this.split.on("moved", this.onSplitMove, this);
48867 this.split.useShim = config.useShim === true;
48868 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
48869 if(this.useSplitTips){
48870 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
48872 if(config.collapsible){
48873 this.split.el.on("dblclick", this.collapse, this);
48876 if(typeof config.minSize != "undefined"){
48877 this.split.minSize = config.minSize;
48879 if(typeof config.maxSize != "undefined"){
48880 this.split.maxSize = config.maxSize;
48882 if(config.hideWhenEmpty || config.hidden || config.collapsed){
48883 this.hideSplitter();
48888 getHMaxSize : function(){
48889 var cmax = this.config.maxSize || 10000;
48890 var center = this.mgr.getRegion("center");
48891 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
48894 getVMaxSize : function(){
48895 var cmax = this.config.maxSize || 10000;
48896 var center = this.mgr.getRegion("center");
48897 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
48900 onSplitMove : function(split, newSize){
48901 this.fireEvent("resized", this, newSize);
48905 * Returns the {@link Roo.SplitBar} for this region.
48906 * @return {Roo.SplitBar}
48908 getSplitBar : function(){
48913 this.hideSplitter();
48914 Roo.SplitLayoutRegion.superclass.hide.call(this);
48917 hideSplitter : function(){
48919 this.split.el.setLocation(-2000,-2000);
48920 this.split.el.hide();
48926 this.split.el.show();
48928 Roo.SplitLayoutRegion.superclass.show.call(this);
48931 beforeSlide: function(){
48932 if(Roo.isGecko){// firefox overflow auto bug workaround
48933 this.bodyEl.clip();
48934 if(this.tabs) this.tabs.bodyEl.clip();
48935 if(this.activePanel){
48936 this.activePanel.getEl().clip();
48938 if(this.activePanel.beforeSlide){
48939 this.activePanel.beforeSlide();
48945 afterSlide : function(){
48946 if(Roo.isGecko){// firefox overflow auto bug workaround
48947 this.bodyEl.unclip();
48948 if(this.tabs) this.tabs.bodyEl.unclip();
48949 if(this.activePanel){
48950 this.activePanel.getEl().unclip();
48951 if(this.activePanel.afterSlide){
48952 this.activePanel.afterSlide();
48958 initAutoHide : function(){
48959 if(this.autoHide !== false){
48960 if(!this.autoHideHd){
48961 var st = new Roo.util.DelayedTask(this.slideIn, this);
48962 this.autoHideHd = {
48963 "mouseout": function(e){
48964 if(!e.within(this.el, true)){
48968 "mouseover" : function(e){
48974 this.el.on(this.autoHideHd);
48978 clearAutoHide : function(){
48979 if(this.autoHide !== false){
48980 this.el.un("mouseout", this.autoHideHd.mouseout);
48981 this.el.un("mouseover", this.autoHideHd.mouseover);
48985 clearMonitor : function(){
48986 Roo.get(document).un("click", this.slideInIf, this);
48989 // these names are backwards but not changed for compat
48990 slideOut : function(){
48991 if(this.isSlid || this.el.hasActiveFx()){
48994 this.isSlid = true;
48995 if(this.collapseBtn){
48996 this.collapseBtn.hide();
48998 this.closeBtnState = this.closeBtn.getStyle('display');
48999 this.closeBtn.hide();
49001 this.stickBtn.show();
49004 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
49005 this.beforeSlide();
49006 this.el.setStyle("z-index", 10001);
49007 this.el.slideIn(this.getSlideAnchor(), {
49008 callback: function(){
49010 this.initAutoHide();
49011 Roo.get(document).on("click", this.slideInIf, this);
49012 this.fireEvent("slideshow", this);
49019 afterSlideIn : function(){
49020 this.clearAutoHide();
49021 this.isSlid = false;
49022 this.clearMonitor();
49023 this.el.setStyle("z-index", "");
49024 if(this.collapseBtn){
49025 this.collapseBtn.show();
49027 this.closeBtn.setStyle('display', this.closeBtnState);
49029 this.stickBtn.hide();
49031 this.fireEvent("slidehide", this);
49034 slideIn : function(cb){
49035 if(!this.isSlid || this.el.hasActiveFx()){
49039 this.isSlid = false;
49040 this.beforeSlide();
49041 this.el.slideOut(this.getSlideAnchor(), {
49042 callback: function(){
49043 this.el.setLeftTop(-10000, -10000);
49045 this.afterSlideIn();
49053 slideInIf : function(e){
49054 if(!e.within(this.el)){
49059 animateCollapse : function(){
49060 this.beforeSlide();
49061 this.el.setStyle("z-index", 20000);
49062 var anchor = this.getSlideAnchor();
49063 this.el.slideOut(anchor, {
49064 callback : function(){
49065 this.el.setStyle("z-index", "");
49066 this.collapsedEl.slideIn(anchor, {duration:.3});
49068 this.el.setLocation(-10000,-10000);
49070 this.fireEvent("collapsed", this);
49077 animateExpand : function(){
49078 this.beforeSlide();
49079 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
49080 this.el.setStyle("z-index", 20000);
49081 this.collapsedEl.hide({
49084 this.el.slideIn(this.getSlideAnchor(), {
49085 callback : function(){
49086 this.el.setStyle("z-index", "");
49089 this.split.el.show();
49091 this.fireEvent("invalidated", this);
49092 this.fireEvent("expanded", this);
49120 getAnchor : function(){
49121 return this.anchors[this.position];
49124 getCollapseAnchor : function(){
49125 return this.canchors[this.position];
49128 getSlideAnchor : function(){
49129 return this.sanchors[this.position];
49132 getAlignAdj : function(){
49133 var cm = this.cmargins;
49134 switch(this.position){
49150 getExpandAdj : function(){
49151 var c = this.collapsedEl, cm = this.cmargins;
49152 switch(this.position){
49154 return [-(cm.right+c.getWidth()+cm.left), 0];
49157 return [cm.right+c.getWidth()+cm.left, 0];
49160 return [0, -(cm.top+cm.bottom+c.getHeight())];
49163 return [0, cm.top+cm.bottom+c.getHeight()];
49169 * Ext JS Library 1.1.1
49170 * Copyright(c) 2006-2007, Ext JS, LLC.
49172 * Originally Released Under LGPL - original licence link has changed is not relivant.
49175 * <script type="text/javascript">
49178 * These classes are private internal classes
49180 Roo.CenterLayoutRegion = function(mgr, config){
49181 Roo.LayoutRegion.call(this, mgr, config, "center");
49182 this.visible = true;
49183 this.minWidth = config.minWidth || 20;
49184 this.minHeight = config.minHeight || 20;
49187 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
49189 // center panel can't be hidden
49193 // center panel can't be hidden
49196 getMinWidth: function(){
49197 return this.minWidth;
49200 getMinHeight: function(){
49201 return this.minHeight;
49206 Roo.NorthLayoutRegion = function(mgr, config){
49207 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
49209 this.split.placement = Roo.SplitBar.TOP;
49210 this.split.orientation = Roo.SplitBar.VERTICAL;
49211 this.split.el.addClass("x-layout-split-v");
49213 var size = config.initialSize || config.height;
49214 if(typeof size != "undefined"){
49215 this.el.setHeight(size);
49218 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
49219 orientation: Roo.SplitBar.VERTICAL,
49220 getBox : function(){
49221 if(this.collapsed){
49222 return this.collapsedEl.getBox();
49224 var box = this.el.getBox();
49226 box.height += this.split.el.getHeight();
49231 updateBox : function(box){
49232 if(this.split && !this.collapsed){
49233 box.height -= this.split.el.getHeight();
49234 this.split.el.setLeft(box.x);
49235 this.split.el.setTop(box.y+box.height);
49236 this.split.el.setWidth(box.width);
49238 if(this.collapsed){
49239 this.updateBody(box.width, null);
49241 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49245 Roo.SouthLayoutRegion = function(mgr, config){
49246 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
49248 this.split.placement = Roo.SplitBar.BOTTOM;
49249 this.split.orientation = Roo.SplitBar.VERTICAL;
49250 this.split.el.addClass("x-layout-split-v");
49252 var size = config.initialSize || config.height;
49253 if(typeof size != "undefined"){
49254 this.el.setHeight(size);
49257 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
49258 orientation: Roo.SplitBar.VERTICAL,
49259 getBox : function(){
49260 if(this.collapsed){
49261 return this.collapsedEl.getBox();
49263 var box = this.el.getBox();
49265 var sh = this.split.el.getHeight();
49272 updateBox : function(box){
49273 if(this.split && !this.collapsed){
49274 var sh = this.split.el.getHeight();
49277 this.split.el.setLeft(box.x);
49278 this.split.el.setTop(box.y-sh);
49279 this.split.el.setWidth(box.width);
49281 if(this.collapsed){
49282 this.updateBody(box.width, null);
49284 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49288 Roo.EastLayoutRegion = function(mgr, config){
49289 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
49291 this.split.placement = Roo.SplitBar.RIGHT;
49292 this.split.orientation = Roo.SplitBar.HORIZONTAL;
49293 this.split.el.addClass("x-layout-split-h");
49295 var size = config.initialSize || config.width;
49296 if(typeof size != "undefined"){
49297 this.el.setWidth(size);
49300 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
49301 orientation: Roo.SplitBar.HORIZONTAL,
49302 getBox : function(){
49303 if(this.collapsed){
49304 return this.collapsedEl.getBox();
49306 var box = this.el.getBox();
49308 var sw = this.split.el.getWidth();
49315 updateBox : function(box){
49316 if(this.split && !this.collapsed){
49317 var sw = this.split.el.getWidth();
49319 this.split.el.setLeft(box.x);
49320 this.split.el.setTop(box.y);
49321 this.split.el.setHeight(box.height);
49324 if(this.collapsed){
49325 this.updateBody(null, box.height);
49327 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49331 Roo.WestLayoutRegion = function(mgr, config){
49332 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
49334 this.split.placement = Roo.SplitBar.LEFT;
49335 this.split.orientation = Roo.SplitBar.HORIZONTAL;
49336 this.split.el.addClass("x-layout-split-h");
49338 var size = config.initialSize || config.width;
49339 if(typeof size != "undefined"){
49340 this.el.setWidth(size);
49343 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
49344 orientation: Roo.SplitBar.HORIZONTAL,
49345 getBox : function(){
49346 if(this.collapsed){
49347 return this.collapsedEl.getBox();
49349 var box = this.el.getBox();
49351 box.width += this.split.el.getWidth();
49356 updateBox : function(box){
49357 if(this.split && !this.collapsed){
49358 var sw = this.split.el.getWidth();
49360 this.split.el.setLeft(box.x+box.width);
49361 this.split.el.setTop(box.y);
49362 this.split.el.setHeight(box.height);
49364 if(this.collapsed){
49365 this.updateBody(null, box.height);
49367 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49372 * Ext JS Library 1.1.1
49373 * Copyright(c) 2006-2007, Ext JS, LLC.
49375 * Originally Released Under LGPL - original licence link has changed is not relivant.
49378 * <script type="text/javascript">
49383 * Private internal class for reading and applying state
49385 Roo.LayoutStateManager = function(layout){
49386 // default empty state
49395 Roo.LayoutStateManager.prototype = {
49396 init : function(layout, provider){
49397 this.provider = provider;
49398 var state = provider.get(layout.id+"-layout-state");
49400 var wasUpdating = layout.isUpdating();
49402 layout.beginUpdate();
49404 for(var key in state){
49405 if(typeof state[key] != "function"){
49406 var rstate = state[key];
49407 var r = layout.getRegion(key);
49410 r.resizeTo(rstate.size);
49412 if(rstate.collapsed == true){
49415 r.expand(null, true);
49421 layout.endUpdate();
49423 this.state = state;
49425 this.layout = layout;
49426 layout.on("regionresized", this.onRegionResized, this);
49427 layout.on("regioncollapsed", this.onRegionCollapsed, this);
49428 layout.on("regionexpanded", this.onRegionExpanded, this);
49431 storeState : function(){
49432 this.provider.set(this.layout.id+"-layout-state", this.state);
49435 onRegionResized : function(region, newSize){
49436 this.state[region.getPosition()].size = newSize;
49440 onRegionCollapsed : function(region){
49441 this.state[region.getPosition()].collapsed = true;
49445 onRegionExpanded : function(region){
49446 this.state[region.getPosition()].collapsed = false;
49451 * Ext JS Library 1.1.1
49452 * Copyright(c) 2006-2007, Ext JS, LLC.
49454 * Originally Released Under LGPL - original licence link has changed is not relivant.
49457 * <script type="text/javascript">
49460 * @class Roo.ContentPanel
49461 * @extends Roo.util.Observable
49462 * A basic ContentPanel element.
49463 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
49464 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
49465 * @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
49466 * @cfg {Boolean} closable True if the panel can be closed/removed
49467 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
49468 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
49469 * @cfg {Toolbar} toolbar A toolbar for this panel
49470 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
49471 * @cfg {String} title The title for this panel
49472 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
49473 * @cfg {String} url Calls {@link #setUrl} with this value
49474 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
49475 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
49476 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
49477 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
49480 * Create a new ContentPanel.
49481 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
49482 * @param {String/Object} config A string to set only the title or a config object
49483 * @param {String} content (optional) Set the HTML content for this panel
49484 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
49486 Roo.ContentPanel = function(el, config, content){
49490 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
49494 if (config && config.parentLayout) {
49495 el = config.parentLayout.el.createChild();
49498 if(el.autoCreate){ // xtype is available if this is called from factory
49502 this.el = Roo.get(el);
49503 if(!this.el && config && config.autoCreate){
49504 if(typeof config.autoCreate == "object"){
49505 if(!config.autoCreate.id){
49506 config.autoCreate.id = config.id||el;
49508 this.el = Roo.DomHelper.append(document.body,
49509 config.autoCreate, true);
49511 this.el = Roo.DomHelper.append(document.body,
49512 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
49515 this.closable = false;
49516 this.loaded = false;
49517 this.active = false;
49518 if(typeof config == "string"){
49519 this.title = config;
49521 Roo.apply(this, config);
49524 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
49525 this.wrapEl = this.el.wrap();
49526 this.toolbar.container = this.el.insertSibling(false, 'before');
49527 this.toolbar = new Roo.Toolbar(this.toolbar);
49530 // xtype created footer. - not sure if will work as we normally have to render first..
49531 if (this.footer && !this.footer.el && this.footer.xtype) {
49532 if (!this.wrapEl) {
49533 this.wrapEl = this.el.wrap();
49536 this.footer.container = this.wrapEl.createChild();
49538 this.footer = Roo.factory(this.footer, Roo);
49543 this.resizeEl = Roo.get(this.resizeEl, true);
49545 this.resizeEl = this.el;
49547 // handle view.xtype
49555 * Fires when this panel is activated.
49556 * @param {Roo.ContentPanel} this
49560 * @event deactivate
49561 * Fires when this panel is activated.
49562 * @param {Roo.ContentPanel} this
49564 "deactivate" : true,
49568 * Fires when this panel is resized if fitToFrame is true.
49569 * @param {Roo.ContentPanel} this
49570 * @param {Number} width The width after any component adjustments
49571 * @param {Number} height The height after any component adjustments
49577 * Fires when this tab is created
49578 * @param {Roo.ContentPanel} this
49589 if(this.autoScroll){
49590 this.resizeEl.setStyle("overflow", "auto");
49592 // fix randome scrolling
49593 this.el.on('scroll', function() {
49594 Roo.log('fix random scolling');
49595 this.scrollTo('top',0);
49598 content = content || this.content;
49600 this.setContent(content);
49602 if(config && config.url){
49603 this.setUrl(this.url, this.params, this.loadOnce);
49608 Roo.ContentPanel.superclass.constructor.call(this);
49610 if (this.view && typeof(this.view.xtype) != 'undefined') {
49611 this.view.el = this.el.appendChild(document.createElement("div"));
49612 this.view = Roo.factory(this.view);
49613 this.view.render && this.view.render(false, '');
49617 this.fireEvent('render', this);
49620 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
49622 setRegion : function(region){
49623 this.region = region;
49625 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
49627 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
49632 * Returns the toolbar for this Panel if one was configured.
49633 * @return {Roo.Toolbar}
49635 getToolbar : function(){
49636 return this.toolbar;
49639 setActiveState : function(active){
49640 this.active = active;
49642 this.fireEvent("deactivate", this);
49644 this.fireEvent("activate", this);
49648 * Updates this panel's element
49649 * @param {String} content The new content
49650 * @param {Boolean} loadScripts (optional) true to look for and process scripts
49652 setContent : function(content, loadScripts){
49653 this.el.update(content, loadScripts);
49656 ignoreResize : function(w, h){
49657 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
49660 this.lastSize = {width: w, height: h};
49665 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
49666 * @return {Roo.UpdateManager} The UpdateManager
49668 getUpdateManager : function(){
49669 return this.el.getUpdateManager();
49672 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
49673 * @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:
49676 url: "your-url.php",
49677 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
49678 callback: yourFunction,
49679 scope: yourObject, //(optional scope)
49682 text: "Loading...",
49687 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
49688 * 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.
49689 * @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}
49690 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
49691 * @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.
49692 * @return {Roo.ContentPanel} this
49695 var um = this.el.getUpdateManager();
49696 um.update.apply(um, arguments);
49702 * 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.
49703 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
49704 * @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)
49705 * @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)
49706 * @return {Roo.UpdateManager} The UpdateManager
49708 setUrl : function(url, params, loadOnce){
49709 if(this.refreshDelegate){
49710 this.removeListener("activate", this.refreshDelegate);
49712 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
49713 this.on("activate", this.refreshDelegate);
49714 return this.el.getUpdateManager();
49717 _handleRefresh : function(url, params, loadOnce){
49718 if(!loadOnce || !this.loaded){
49719 var updater = this.el.getUpdateManager();
49720 updater.update(url, params, this._setLoaded.createDelegate(this));
49724 _setLoaded : function(){
49725 this.loaded = true;
49729 * Returns this panel's id
49732 getId : function(){
49737 * Returns this panel's element - used by regiosn to add.
49738 * @return {Roo.Element}
49740 getEl : function(){
49741 return this.wrapEl || this.el;
49744 adjustForComponents : function(width, height)
49746 //Roo.log('adjustForComponents ');
49747 if(this.resizeEl != this.el){
49748 width -= this.el.getFrameWidth('lr');
49749 height -= this.el.getFrameWidth('tb');
49752 var te = this.toolbar.getEl();
49753 height -= te.getHeight();
49754 te.setWidth(width);
49757 var te = this.footer.getEl();
49758 Roo.log("footer:" + te.getHeight());
49760 height -= te.getHeight();
49761 te.setWidth(width);
49765 if(this.adjustments){
49766 width += this.adjustments[0];
49767 height += this.adjustments[1];
49769 return {"width": width, "height": height};
49772 setSize : function(width, height){
49773 if(this.fitToFrame && !this.ignoreResize(width, height)){
49774 if(this.fitContainer && this.resizeEl != this.el){
49775 this.el.setSize(width, height);
49777 var size = this.adjustForComponents(width, height);
49778 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
49779 this.fireEvent('resize', this, size.width, size.height);
49784 * Returns this panel's title
49787 getTitle : function(){
49792 * Set this panel's title
49793 * @param {String} title
49795 setTitle : function(title){
49796 this.title = title;
49798 this.region.updatePanelTitle(this, title);
49803 * Returns true is this panel was configured to be closable
49804 * @return {Boolean}
49806 isClosable : function(){
49807 return this.closable;
49810 beforeSlide : function(){
49812 this.resizeEl.clip();
49815 afterSlide : function(){
49817 this.resizeEl.unclip();
49821 * Force a content refresh from the URL specified in the {@link #setUrl} method.
49822 * Will fail silently if the {@link #setUrl} method has not been called.
49823 * This does not activate the panel, just updates its content.
49825 refresh : function(){
49826 if(this.refreshDelegate){
49827 this.loaded = false;
49828 this.refreshDelegate();
49833 * Destroys this panel
49835 destroy : function(){
49836 this.el.removeAllListeners();
49837 var tempEl = document.createElement("span");
49838 tempEl.appendChild(this.el.dom);
49839 tempEl.innerHTML = "";
49845 * form - if the content panel contains a form - this is a reference to it.
49846 * @type {Roo.form.Form}
49850 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
49851 * This contains a reference to it.
49857 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
49867 * @param {Object} cfg Xtype definition of item to add.
49870 addxtype : function(cfg) {
49872 if (cfg.xtype.match(/^Form$/)) {
49875 //if (this.footer) {
49876 // el = this.footer.container.insertSibling(false, 'before');
49878 el = this.el.createChild();
49881 this.form = new Roo.form.Form(cfg);
49884 if ( this.form.allItems.length) this.form.render(el.dom);
49887 // should only have one of theses..
49888 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
49889 // views.. should not be just added - used named prop 'view''
49891 cfg.el = this.el.appendChild(document.createElement("div"));
49894 var ret = new Roo.factory(cfg);
49896 ret.render && ret.render(false, ''); // render blank..
49905 * @class Roo.GridPanel
49906 * @extends Roo.ContentPanel
49908 * Create a new GridPanel.
49909 * @param {Roo.grid.Grid} grid The grid for this panel
49910 * @param {String/Object} config A string to set only the panel's title, or a config object
49912 Roo.GridPanel = function(grid, config){
49915 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
49916 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
49918 this.wrapper.dom.appendChild(grid.getGridEl().dom);
49920 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
49923 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
49925 // xtype created footer. - not sure if will work as we normally have to render first..
49926 if (this.footer && !this.footer.el && this.footer.xtype) {
49928 this.footer.container = this.grid.getView().getFooterPanel(true);
49929 this.footer.dataSource = this.grid.dataSource;
49930 this.footer = Roo.factory(this.footer, Roo);
49934 grid.monitorWindowResize = false; // turn off autosizing
49935 grid.autoHeight = false;
49936 grid.autoWidth = false;
49938 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
49941 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
49942 getId : function(){
49943 return this.grid.id;
49947 * Returns the grid for this panel
49948 * @return {Roo.grid.Grid}
49950 getGrid : function(){
49954 setSize : function(width, height){
49955 if(!this.ignoreResize(width, height)){
49956 var grid = this.grid;
49957 var size = this.adjustForComponents(width, height);
49958 grid.getGridEl().setSize(size.width, size.height);
49963 beforeSlide : function(){
49964 this.grid.getView().scroller.clip();
49967 afterSlide : function(){
49968 this.grid.getView().scroller.unclip();
49971 destroy : function(){
49972 this.grid.destroy();
49974 Roo.GridPanel.superclass.destroy.call(this);
49980 * @class Roo.NestedLayoutPanel
49981 * @extends Roo.ContentPanel
49983 * Create a new NestedLayoutPanel.
49986 * @param {Roo.BorderLayout} layout The layout for this panel
49987 * @param {String/Object} config A string to set only the title or a config object
49989 Roo.NestedLayoutPanel = function(layout, config)
49991 // construct with only one argument..
49992 /* FIXME - implement nicer consturctors
49993 if (layout.layout) {
49995 layout = config.layout;
49996 delete config.layout;
49998 if (layout.xtype && !layout.getEl) {
49999 // then layout needs constructing..
50000 layout = Roo.factory(layout, Roo);
50005 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
50007 layout.monitorWindowResize = false; // turn off autosizing
50008 this.layout = layout;
50009 this.layout.getEl().addClass("x-layout-nested-layout");
50016 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
50018 setSize : function(width, height){
50019 if(!this.ignoreResize(width, height)){
50020 var size = this.adjustForComponents(width, height);
50021 var el = this.layout.getEl();
50022 el.setSize(size.width, size.height);
50023 var touch = el.dom.offsetWidth;
50024 this.layout.layout();
50025 // ie requires a double layout on the first pass
50026 if(Roo.isIE && !this.initialized){
50027 this.initialized = true;
50028 this.layout.layout();
50033 // activate all subpanels if not currently active..
50035 setActiveState : function(active){
50036 this.active = active;
50038 this.fireEvent("deactivate", this);
50042 this.fireEvent("activate", this);
50043 // not sure if this should happen before or after..
50044 if (!this.layout) {
50045 return; // should not happen..
50048 for (var r in this.layout.regions) {
50049 reg = this.layout.getRegion(r);
50050 if (reg.getActivePanel()) {
50051 //reg.showPanel(reg.getActivePanel()); // force it to activate..
50052 reg.setActivePanel(reg.getActivePanel());
50055 if (!reg.panels.length) {
50058 reg.showPanel(reg.getPanel(0));
50067 * Returns the nested BorderLayout for this panel
50068 * @return {Roo.BorderLayout}
50070 getLayout : function(){
50071 return this.layout;
50075 * Adds a xtype elements to the layout of the nested panel
50079 xtype : 'ContentPanel',
50086 xtype : 'NestedLayoutPanel',
50092 items : [ ... list of content panels or nested layout panels.. ]
50096 * @param {Object} cfg Xtype definition of item to add.
50098 addxtype : function(cfg) {
50099 return this.layout.addxtype(cfg);
50104 Roo.ScrollPanel = function(el, config, content){
50105 config = config || {};
50106 config.fitToFrame = true;
50107 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
50109 this.el.dom.style.overflow = "hidden";
50110 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
50111 this.el.removeClass("x-layout-inactive-content");
50112 this.el.on("mousewheel", this.onWheel, this);
50114 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
50115 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
50116 up.unselectable(); down.unselectable();
50117 up.on("click", this.scrollUp, this);
50118 down.on("click", this.scrollDown, this);
50119 up.addClassOnOver("x-scroller-btn-over");
50120 down.addClassOnOver("x-scroller-btn-over");
50121 up.addClassOnClick("x-scroller-btn-click");
50122 down.addClassOnClick("x-scroller-btn-click");
50123 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
50125 this.resizeEl = this.el;
50126 this.el = wrap; this.up = up; this.down = down;
50129 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
50131 wheelIncrement : 5,
50132 scrollUp : function(){
50133 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
50136 scrollDown : function(){
50137 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
50140 afterScroll : function(){
50141 var el = this.resizeEl;
50142 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
50143 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
50144 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
50147 setSize : function(){
50148 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
50149 this.afterScroll();
50152 onWheel : function(e){
50153 var d = e.getWheelDelta();
50154 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
50155 this.afterScroll();
50159 setContent : function(content, loadScripts){
50160 this.resizeEl.update(content, loadScripts);
50174 * @class Roo.TreePanel
50175 * @extends Roo.ContentPanel
50177 * Create a new TreePanel. - defaults to fit/scoll contents.
50178 * @param {String/Object} config A string to set only the panel's title, or a config object
50179 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
50181 Roo.TreePanel = function(config){
50182 var el = config.el;
50183 var tree = config.tree;
50184 delete config.tree;
50185 delete config.el; // hopefull!
50187 // wrapper for IE7 strict & safari scroll issue
50189 var treeEl = el.createChild();
50190 config.resizeEl = treeEl;
50194 Roo.TreePanel.superclass.constructor.call(this, el, config);
50197 this.tree = new Roo.tree.TreePanel(treeEl , tree);
50198 //console.log(tree);
50199 this.on('activate', function()
50201 if (this.tree.rendered) {
50204 //console.log('render tree');
50205 this.tree.render();
50207 // this should not be needed.. - it's actually the 'el' that resizes?
50208 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
50210 //this.on('resize', function (cp, w, h) {
50211 // this.tree.innerCt.setWidth(w);
50212 // this.tree.innerCt.setHeight(h);
50213 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
50220 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
50237 * Ext JS Library 1.1.1
50238 * Copyright(c) 2006-2007, Ext JS, LLC.
50240 * Originally Released Under LGPL - original licence link has changed is not relivant.
50243 * <script type="text/javascript">
50248 * @class Roo.ReaderLayout
50249 * @extends Roo.BorderLayout
50250 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
50251 * center region containing two nested regions (a top one for a list view and one for item preview below),
50252 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
50253 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
50254 * expedites the setup of the overall layout and regions for this common application style.
50257 var reader = new Roo.ReaderLayout();
50258 var CP = Roo.ContentPanel; // shortcut for adding
50260 reader.beginUpdate();
50261 reader.add("north", new CP("north", "North"));
50262 reader.add("west", new CP("west", {title: "West"}));
50263 reader.add("east", new CP("east", {title: "East"}));
50265 reader.regions.listView.add(new CP("listView", "List"));
50266 reader.regions.preview.add(new CP("preview", "Preview"));
50267 reader.endUpdate();
50270 * Create a new ReaderLayout
50271 * @param {Object} config Configuration options
50272 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
50273 * document.body if omitted)
50275 Roo.ReaderLayout = function(config, renderTo){
50276 var c = config || {size:{}};
50277 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
50278 north: c.north !== false ? Roo.apply({
50282 }, c.north) : false,
50283 west: c.west !== false ? Roo.apply({
50291 margins:{left:5,right:0,bottom:5,top:5},
50292 cmargins:{left:5,right:5,bottom:5,top:5}
50293 }, c.west) : false,
50294 east: c.east !== false ? Roo.apply({
50302 margins:{left:0,right:5,bottom:5,top:5},
50303 cmargins:{left:5,right:5,bottom:5,top:5}
50304 }, c.east) : false,
50305 center: Roo.apply({
50306 tabPosition: 'top',
50310 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
50314 this.el.addClass('x-reader');
50316 this.beginUpdate();
50318 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
50319 south: c.preview !== false ? Roo.apply({
50326 cmargins:{top:5,left:0, right:0, bottom:0}
50327 }, c.preview) : false,
50328 center: Roo.apply({
50334 this.add('center', new Roo.NestedLayoutPanel(inner,
50335 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
50339 this.regions.preview = inner.getRegion('south');
50340 this.regions.listView = inner.getRegion('center');
50343 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
50345 * Ext JS Library 1.1.1
50346 * Copyright(c) 2006-2007, Ext JS, LLC.
50348 * Originally Released Under LGPL - original licence link has changed is not relivant.
50351 * <script type="text/javascript">
50355 * @class Roo.grid.Grid
50356 * @extends Roo.util.Observable
50357 * This class represents the primary interface of a component based grid control.
50358 * <br><br>Usage:<pre><code>
50359 var grid = new Roo.grid.Grid("my-container-id", {
50362 selModel: mySelectionModel,
50363 autoSizeColumns: true,
50364 monitorWindowResize: false,
50365 trackMouseOver: true
50370 * <b>Common Problems:</b><br/>
50371 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
50372 * element will correct this<br/>
50373 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
50374 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
50375 * are unpredictable.<br/>
50376 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
50377 * grid to calculate dimensions/offsets.<br/>
50379 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50380 * The container MUST have some type of size defined for the grid to fill. The container will be
50381 * automatically set to position relative if it isn't already.
50382 * @param {Object} config A config object that sets properties on this grid.
50384 Roo.grid.Grid = function(container, config){
50385 // initialize the container
50386 this.container = Roo.get(container);
50387 this.container.update("");
50388 this.container.setStyle("overflow", "hidden");
50389 this.container.addClass('x-grid-container');
50391 this.id = this.container.id;
50393 Roo.apply(this, config);
50394 // check and correct shorthanded configs
50396 this.dataSource = this.ds;
50400 this.colModel = this.cm;
50404 this.selModel = this.sm;
50408 if (this.selModel) {
50409 this.selModel = Roo.factory(this.selModel, Roo.grid);
50410 this.sm = this.selModel;
50411 this.sm.xmodule = this.xmodule || false;
50413 if (typeof(this.colModel.config) == 'undefined') {
50414 this.colModel = new Roo.grid.ColumnModel(this.colModel);
50415 this.cm = this.colModel;
50416 this.cm.xmodule = this.xmodule || false;
50418 if (this.dataSource) {
50419 this.dataSource= Roo.factory(this.dataSource, Roo.data);
50420 this.ds = this.dataSource;
50421 this.ds.xmodule = this.xmodule || false;
50428 this.container.setWidth(this.width);
50432 this.container.setHeight(this.height);
50439 * The raw click event for the entire grid.
50440 * @param {Roo.EventObject} e
50445 * The raw dblclick event for the entire grid.
50446 * @param {Roo.EventObject} e
50450 * @event contextmenu
50451 * The raw contextmenu event for the entire grid.
50452 * @param {Roo.EventObject} e
50454 "contextmenu" : true,
50457 * The raw mousedown event for the entire grid.
50458 * @param {Roo.EventObject} e
50460 "mousedown" : true,
50463 * The raw mouseup event for the entire grid.
50464 * @param {Roo.EventObject} e
50469 * The raw mouseover event for the entire grid.
50470 * @param {Roo.EventObject} e
50472 "mouseover" : true,
50475 * The raw mouseout event for the entire grid.
50476 * @param {Roo.EventObject} e
50481 * The raw keypress event for the entire grid.
50482 * @param {Roo.EventObject} e
50487 * The raw keydown event for the entire grid.
50488 * @param {Roo.EventObject} e
50496 * Fires when a cell is clicked
50497 * @param {Grid} this
50498 * @param {Number} rowIndex
50499 * @param {Number} columnIndex
50500 * @param {Roo.EventObject} e
50502 "cellclick" : true,
50504 * @event celldblclick
50505 * Fires when a cell is double clicked
50506 * @param {Grid} this
50507 * @param {Number} rowIndex
50508 * @param {Number} columnIndex
50509 * @param {Roo.EventObject} e
50511 "celldblclick" : true,
50514 * Fires when a row is clicked
50515 * @param {Grid} this
50516 * @param {Number} rowIndex
50517 * @param {Roo.EventObject} e
50521 * @event rowdblclick
50522 * Fires when a row is double clicked
50523 * @param {Grid} this
50524 * @param {Number} rowIndex
50525 * @param {Roo.EventObject} e
50527 "rowdblclick" : true,
50529 * @event headerclick
50530 * Fires when a header is clicked
50531 * @param {Grid} this
50532 * @param {Number} columnIndex
50533 * @param {Roo.EventObject} e
50535 "headerclick" : true,
50537 * @event headerdblclick
50538 * Fires when a header cell is double clicked
50539 * @param {Grid} this
50540 * @param {Number} columnIndex
50541 * @param {Roo.EventObject} e
50543 "headerdblclick" : true,
50545 * @event rowcontextmenu
50546 * Fires when a row is right clicked
50547 * @param {Grid} this
50548 * @param {Number} rowIndex
50549 * @param {Roo.EventObject} e
50551 "rowcontextmenu" : true,
50553 * @event cellcontextmenu
50554 * Fires when a cell is right clicked
50555 * @param {Grid} this
50556 * @param {Number} rowIndex
50557 * @param {Number} cellIndex
50558 * @param {Roo.EventObject} e
50560 "cellcontextmenu" : true,
50562 * @event headercontextmenu
50563 * Fires when a header is right clicked
50564 * @param {Grid} this
50565 * @param {Number} columnIndex
50566 * @param {Roo.EventObject} e
50568 "headercontextmenu" : true,
50570 * @event bodyscroll
50571 * Fires when the body element is scrolled
50572 * @param {Number} scrollLeft
50573 * @param {Number} scrollTop
50575 "bodyscroll" : true,
50577 * @event columnresize
50578 * Fires when the user resizes a column
50579 * @param {Number} columnIndex
50580 * @param {Number} newSize
50582 "columnresize" : true,
50584 * @event columnmove
50585 * Fires when the user moves a column
50586 * @param {Number} oldIndex
50587 * @param {Number} newIndex
50589 "columnmove" : true,
50592 * Fires when row(s) start being dragged
50593 * @param {Grid} this
50594 * @param {Roo.GridDD} dd The drag drop object
50595 * @param {event} e The raw browser event
50597 "startdrag" : true,
50600 * Fires when a drag operation is complete
50601 * @param {Grid} this
50602 * @param {Roo.GridDD} dd The drag drop object
50603 * @param {event} e The raw browser event
50608 * Fires when dragged row(s) are dropped on a valid DD target
50609 * @param {Grid} this
50610 * @param {Roo.GridDD} dd The drag drop object
50611 * @param {String} targetId The target drag drop object
50612 * @param {event} e The raw browser event
50617 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
50618 * @param {Grid} this
50619 * @param {Roo.GridDD} dd The drag drop object
50620 * @param {String} targetId The target drag drop object
50621 * @param {event} e The raw browser event
50626 * Fires when the dragged row(s) first cross another DD target while being dragged
50627 * @param {Grid} this
50628 * @param {Roo.GridDD} dd The drag drop object
50629 * @param {String} targetId The target drag drop object
50630 * @param {event} e The raw browser event
50632 "dragenter" : true,
50635 * Fires when the dragged row(s) leave another DD target while being dragged
50636 * @param {Grid} this
50637 * @param {Roo.GridDD} dd The drag drop object
50638 * @param {String} targetId The target drag drop object
50639 * @param {event} e The raw browser event
50644 * Fires when a row is rendered, so you can change add a style to it.
50645 * @param {GridView} gridview The grid view
50646 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
50652 * Fires when the grid is rendered
50653 * @param {Grid} grid
50658 Roo.grid.Grid.superclass.constructor.call(this);
50660 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
50663 * @cfg {String} ddGroup - drag drop group.
50667 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
50669 minColumnWidth : 25,
50672 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
50673 * <b>on initial render.</b> It is more efficient to explicitly size the columns
50674 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
50676 autoSizeColumns : false,
50679 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
50681 autoSizeHeaders : true,
50684 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
50686 monitorWindowResize : true,
50689 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
50690 * rows measured to get a columns size. Default is 0 (all rows).
50692 maxRowsToMeasure : 0,
50695 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
50697 trackMouseOver : true,
50700 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
50704 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
50706 enableDragDrop : false,
50709 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
50711 enableColumnMove : true,
50714 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
50716 enableColumnHide : true,
50719 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
50721 enableRowHeightSync : false,
50724 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
50729 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
50731 autoHeight : false,
50734 * @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.
50736 autoExpandColumn : false,
50739 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
50742 autoExpandMin : 50,
50745 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
50747 autoExpandMax : 1000,
50750 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
50755 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
50759 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
50769 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
50770 * of a fixed width. Default is false.
50773 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
50776 * Called once after all setup has been completed and the grid is ready to be rendered.
50777 * @return {Roo.grid.Grid} this
50779 render : function()
50781 var c = this.container;
50782 // try to detect autoHeight/width mode
50783 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
50784 this.autoHeight = true;
50786 var view = this.getView();
50789 c.on("click", this.onClick, this);
50790 c.on("dblclick", this.onDblClick, this);
50791 c.on("contextmenu", this.onContextMenu, this);
50792 c.on("keydown", this.onKeyDown, this);
50794 c.on("touchstart", this.onTouchStart, this);
50797 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
50799 this.getSelectionModel().init(this);
50804 this.loadMask = new Roo.LoadMask(this.container,
50805 Roo.apply({store:this.dataSource}, this.loadMask));
50809 if (this.toolbar && this.toolbar.xtype) {
50810 this.toolbar.container = this.getView().getHeaderPanel(true);
50811 this.toolbar = new Roo.Toolbar(this.toolbar);
50813 if (this.footer && this.footer.xtype) {
50814 this.footer.dataSource = this.getDataSource();
50815 this.footer.container = this.getView().getFooterPanel(true);
50816 this.footer = Roo.factory(this.footer, Roo);
50818 if (this.dropTarget && this.dropTarget.xtype) {
50819 delete this.dropTarget.xtype;
50820 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
50824 this.rendered = true;
50825 this.fireEvent('render', this);
50830 * Reconfigures the grid to use a different Store and Column Model.
50831 * The View will be bound to the new objects and refreshed.
50832 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
50833 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
50835 reconfigure : function(dataSource, colModel){
50837 this.loadMask.destroy();
50838 this.loadMask = new Roo.LoadMask(this.container,
50839 Roo.apply({store:dataSource}, this.loadMask));
50841 this.view.bind(dataSource, colModel);
50842 this.dataSource = dataSource;
50843 this.colModel = colModel;
50844 this.view.refresh(true);
50848 onKeyDown : function(e){
50849 this.fireEvent("keydown", e);
50853 * Destroy this grid.
50854 * @param {Boolean} removeEl True to remove the element
50856 destroy : function(removeEl, keepListeners){
50858 this.loadMask.destroy();
50860 var c = this.container;
50861 c.removeAllListeners();
50862 this.view.destroy();
50863 this.colModel.purgeListeners();
50864 if(!keepListeners){
50865 this.purgeListeners();
50868 if(removeEl === true){
50874 processEvent : function(name, e){
50875 // does this fire select???
50876 Roo.log('grid:processEvent ' + name);
50878 if (name != 'touchstart' ) {
50879 this.fireEvent(name, e);
50882 var t = e.getTarget();
50884 var header = v.findHeaderIndex(t);
50885 if(header !== false){
50886 this.fireEvent("header" + (name == 'touchstart' ? 'click' : name), this, header, e);
50888 var row = v.findRowIndex(t);
50889 var cell = v.findCellIndex(t);
50890 if (name == 'touchstart') {
50891 // first touch is always a click.
50892 // hopefull this happens after selection is updated.?
50895 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
50896 var cs = this.selModel.getSelectedCell();
50897 if (row == cs[0] && cell == cs[1]){
50901 if (typeof(this.selModel.getSelections) != 'undefined') {
50902 var cs = this.selModel.getSelections();
50903 var ds = this.dataSource;
50904 if (cs.length == 1 && ds.getAt(row) == cs[0]){
50915 this.fireEvent("row" + name, this, row, e);
50916 if(cell !== false){
50917 this.fireEvent("cell" + name, this, row, cell, e);
50924 onClick : function(e){
50925 this.processEvent("click", e);
50928 onTouchStart : function(e){
50929 this.processEvent("touchstart", e);
50933 onContextMenu : function(e, t){
50934 this.processEvent("contextmenu", e);
50938 onDblClick : function(e){
50939 this.processEvent("dblclick", e);
50943 walkCells : function(row, col, step, fn, scope){
50944 var cm = this.colModel, clen = cm.getColumnCount();
50945 var ds = this.dataSource, rlen = ds.getCount(), first = true;
50957 if(fn.call(scope || this, row, col, cm) === true){
50975 if(fn.call(scope || this, row, col, cm) === true){
50987 getSelections : function(){
50988 return this.selModel.getSelections();
50992 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
50993 * but if manual update is required this method will initiate it.
50995 autoSize : function(){
50997 this.view.layout();
50998 if(this.view.adjustForScroll){
50999 this.view.adjustForScroll();
51005 * Returns the grid's underlying element.
51006 * @return {Element} The element
51008 getGridEl : function(){
51009 return this.container;
51012 // private for compatibility, overridden by editor grid
51013 stopEditing : function(){},
51016 * Returns the grid's SelectionModel.
51017 * @return {SelectionModel}
51019 getSelectionModel : function(){
51020 if(!this.selModel){
51021 this.selModel = new Roo.grid.RowSelectionModel();
51023 return this.selModel;
51027 * Returns the grid's DataSource.
51028 * @return {DataSource}
51030 getDataSource : function(){
51031 return this.dataSource;
51035 * Returns the grid's ColumnModel.
51036 * @return {ColumnModel}
51038 getColumnModel : function(){
51039 return this.colModel;
51043 * Returns the grid's GridView object.
51044 * @return {GridView}
51046 getView : function(){
51048 this.view = new Roo.grid.GridView(this.viewConfig);
51053 * Called to get grid's drag proxy text, by default returns this.ddText.
51056 getDragDropText : function(){
51057 var count = this.selModel.getCount();
51058 return String.format(this.ddText, count, count == 1 ? '' : 's');
51062 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
51063 * %0 is replaced with the number of selected rows.
51066 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
51068 * Ext JS Library 1.1.1
51069 * Copyright(c) 2006-2007, Ext JS, LLC.
51071 * Originally Released Under LGPL - original licence link has changed is not relivant.
51074 * <script type="text/javascript">
51077 Roo.grid.AbstractGridView = function(){
51081 "beforerowremoved" : true,
51082 "beforerowsinserted" : true,
51083 "beforerefresh" : true,
51084 "rowremoved" : true,
51085 "rowsinserted" : true,
51086 "rowupdated" : true,
51089 Roo.grid.AbstractGridView.superclass.constructor.call(this);
51092 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
51093 rowClass : "x-grid-row",
51094 cellClass : "x-grid-cell",
51095 tdClass : "x-grid-td",
51096 hdClass : "x-grid-hd",
51097 splitClass : "x-grid-hd-split",
51099 init: function(grid){
51101 var cid = this.grid.getGridEl().id;
51102 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
51103 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
51104 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
51105 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
51108 getColumnRenderers : function(){
51109 var renderers = [];
51110 var cm = this.grid.colModel;
51111 var colCount = cm.getColumnCount();
51112 for(var i = 0; i < colCount; i++){
51113 renderers[i] = cm.getRenderer(i);
51118 getColumnIds : function(){
51120 var cm = this.grid.colModel;
51121 var colCount = cm.getColumnCount();
51122 for(var i = 0; i < colCount; i++){
51123 ids[i] = cm.getColumnId(i);
51128 getDataIndexes : function(){
51129 if(!this.indexMap){
51130 this.indexMap = this.buildIndexMap();
51132 return this.indexMap.colToData;
51135 getColumnIndexByDataIndex : function(dataIndex){
51136 if(!this.indexMap){
51137 this.indexMap = this.buildIndexMap();
51139 return this.indexMap.dataToCol[dataIndex];
51143 * Set a css style for a column dynamically.
51144 * @param {Number} colIndex The index of the column
51145 * @param {String} name The css property name
51146 * @param {String} value The css value
51148 setCSSStyle : function(colIndex, name, value){
51149 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
51150 Roo.util.CSS.updateRule(selector, name, value);
51153 generateRules : function(cm){
51154 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
51155 Roo.util.CSS.removeStyleSheet(rulesId);
51156 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51157 var cid = cm.getColumnId(i);
51158 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
51159 this.tdSelector, cid, " {\n}\n",
51160 this.hdSelector, cid, " {\n}\n",
51161 this.splitSelector, cid, " {\n}\n");
51163 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
51167 * Ext JS Library 1.1.1
51168 * Copyright(c) 2006-2007, Ext JS, LLC.
51170 * Originally Released Under LGPL - original licence link has changed is not relivant.
51173 * <script type="text/javascript">
51177 // This is a support class used internally by the Grid components
51178 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
51180 this.view = grid.getView();
51181 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
51182 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
51184 this.setHandleElId(Roo.id(hd));
51185 this.setOuterHandleElId(Roo.id(hd2));
51187 this.scroll = false;
51189 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
51191 getDragData : function(e){
51192 var t = Roo.lib.Event.getTarget(e);
51193 var h = this.view.findHeaderCell(t);
51195 return {ddel: h.firstChild, header:h};
51200 onInitDrag : function(e){
51201 this.view.headersDisabled = true;
51202 var clone = this.dragData.ddel.cloneNode(true);
51203 clone.id = Roo.id();
51204 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
51205 this.proxy.update(clone);
51209 afterValidDrop : function(){
51211 setTimeout(function(){
51212 v.headersDisabled = false;
51216 afterInvalidDrop : function(){
51218 setTimeout(function(){
51219 v.headersDisabled = false;
51225 * Ext JS Library 1.1.1
51226 * Copyright(c) 2006-2007, Ext JS, LLC.
51228 * Originally Released Under LGPL - original licence link has changed is not relivant.
51231 * <script type="text/javascript">
51234 // This is a support class used internally by the Grid components
51235 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
51237 this.view = grid.getView();
51238 // split the proxies so they don't interfere with mouse events
51239 this.proxyTop = Roo.DomHelper.append(document.body, {
51240 cls:"col-move-top", html:" "
51242 this.proxyBottom = Roo.DomHelper.append(document.body, {
51243 cls:"col-move-bottom", html:" "
51245 this.proxyTop.hide = this.proxyBottom.hide = function(){
51246 this.setLeftTop(-100,-100);
51247 this.setStyle("visibility", "hidden");
51249 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
51250 // temporarily disabled
51251 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
51252 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
51254 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
51255 proxyOffsets : [-4, -9],
51256 fly: Roo.Element.fly,
51258 getTargetFromEvent : function(e){
51259 var t = Roo.lib.Event.getTarget(e);
51260 var cindex = this.view.findCellIndex(t);
51261 if(cindex !== false){
51262 return this.view.getHeaderCell(cindex);
51267 nextVisible : function(h){
51268 var v = this.view, cm = this.grid.colModel;
51271 if(!cm.isHidden(v.getCellIndex(h))){
51279 prevVisible : function(h){
51280 var v = this.view, cm = this.grid.colModel;
51283 if(!cm.isHidden(v.getCellIndex(h))){
51291 positionIndicator : function(h, n, e){
51292 var x = Roo.lib.Event.getPageX(e);
51293 var r = Roo.lib.Dom.getRegion(n.firstChild);
51294 var px, pt, py = r.top + this.proxyOffsets[1];
51295 if((r.right - x) <= (r.right-r.left)/2){
51296 px = r.right+this.view.borderWidth;
51302 var oldIndex = this.view.getCellIndex(h);
51303 var newIndex = this.view.getCellIndex(n);
51305 if(this.grid.colModel.isFixed(newIndex)){
51309 var locked = this.grid.colModel.isLocked(newIndex);
51314 if(oldIndex < newIndex){
51317 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
51320 px += this.proxyOffsets[0];
51321 this.proxyTop.setLeftTop(px, py);
51322 this.proxyTop.show();
51323 if(!this.bottomOffset){
51324 this.bottomOffset = this.view.mainHd.getHeight();
51326 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
51327 this.proxyBottom.show();
51331 onNodeEnter : function(n, dd, e, data){
51332 if(data.header != n){
51333 this.positionIndicator(data.header, n, e);
51337 onNodeOver : function(n, dd, e, data){
51338 var result = false;
51339 if(data.header != n){
51340 result = this.positionIndicator(data.header, n, e);
51343 this.proxyTop.hide();
51344 this.proxyBottom.hide();
51346 return result ? this.dropAllowed : this.dropNotAllowed;
51349 onNodeOut : function(n, dd, e, data){
51350 this.proxyTop.hide();
51351 this.proxyBottom.hide();
51354 onNodeDrop : function(n, dd, e, data){
51355 var h = data.header;
51357 var cm = this.grid.colModel;
51358 var x = Roo.lib.Event.getPageX(e);
51359 var r = Roo.lib.Dom.getRegion(n.firstChild);
51360 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
51361 var oldIndex = this.view.getCellIndex(h);
51362 var newIndex = this.view.getCellIndex(n);
51363 var locked = cm.isLocked(newIndex);
51367 if(oldIndex < newIndex){
51370 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
51373 cm.setLocked(oldIndex, locked, true);
51374 cm.moveColumn(oldIndex, newIndex);
51375 this.grid.fireEvent("columnmove", oldIndex, newIndex);
51383 * Ext JS Library 1.1.1
51384 * Copyright(c) 2006-2007, Ext JS, LLC.
51386 * Originally Released Under LGPL - original licence link has changed is not relivant.
51389 * <script type="text/javascript">
51393 * @class Roo.grid.GridView
51394 * @extends Roo.util.Observable
51397 * @param {Object} config
51399 Roo.grid.GridView = function(config){
51400 Roo.grid.GridView.superclass.constructor.call(this);
51403 Roo.apply(this, config);
51406 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
51408 unselectable : 'unselectable="on"',
51409 unselectableCls : 'x-unselectable',
51412 rowClass : "x-grid-row",
51414 cellClass : "x-grid-col",
51416 tdClass : "x-grid-td",
51418 hdClass : "x-grid-hd",
51420 splitClass : "x-grid-split",
51422 sortClasses : ["sort-asc", "sort-desc"],
51424 enableMoveAnim : false,
51428 dh : Roo.DomHelper,
51430 fly : Roo.Element.fly,
51432 css : Roo.util.CSS,
51438 scrollIncrement : 22,
51440 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
51442 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
51444 bind : function(ds, cm){
51446 this.ds.un("load", this.onLoad, this);
51447 this.ds.un("datachanged", this.onDataChange, this);
51448 this.ds.un("add", this.onAdd, this);
51449 this.ds.un("remove", this.onRemove, this);
51450 this.ds.un("update", this.onUpdate, this);
51451 this.ds.un("clear", this.onClear, this);
51454 ds.on("load", this.onLoad, this);
51455 ds.on("datachanged", this.onDataChange, this);
51456 ds.on("add", this.onAdd, this);
51457 ds.on("remove", this.onRemove, this);
51458 ds.on("update", this.onUpdate, this);
51459 ds.on("clear", this.onClear, this);
51464 this.cm.un("widthchange", this.onColWidthChange, this);
51465 this.cm.un("headerchange", this.onHeaderChange, this);
51466 this.cm.un("hiddenchange", this.onHiddenChange, this);
51467 this.cm.un("columnmoved", this.onColumnMove, this);
51468 this.cm.un("columnlockchange", this.onColumnLock, this);
51471 this.generateRules(cm);
51472 cm.on("widthchange", this.onColWidthChange, this);
51473 cm.on("headerchange", this.onHeaderChange, this);
51474 cm.on("hiddenchange", this.onHiddenChange, this);
51475 cm.on("columnmoved", this.onColumnMove, this);
51476 cm.on("columnlockchange", this.onColumnLock, this);
51481 init: function(grid){
51482 Roo.grid.GridView.superclass.init.call(this, grid);
51484 this.bind(grid.dataSource, grid.colModel);
51486 grid.on("headerclick", this.handleHeaderClick, this);
51488 if(grid.trackMouseOver){
51489 grid.on("mouseover", this.onRowOver, this);
51490 grid.on("mouseout", this.onRowOut, this);
51492 grid.cancelTextSelection = function(){};
51493 this.gridId = grid.id;
51495 var tpls = this.templates || {};
51498 tpls.master = new Roo.Template(
51499 '<div class="x-grid" hidefocus="true">',
51500 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
51501 '<div class="x-grid-topbar"></div>',
51502 '<div class="x-grid-scroller"><div></div></div>',
51503 '<div class="x-grid-locked">',
51504 '<div class="x-grid-header">{lockedHeader}</div>',
51505 '<div class="x-grid-body">{lockedBody}</div>',
51507 '<div class="x-grid-viewport">',
51508 '<div class="x-grid-header">{header}</div>',
51509 '<div class="x-grid-body">{body}</div>',
51511 '<div class="x-grid-bottombar"></div>',
51513 '<div class="x-grid-resize-proxy"> </div>',
51516 tpls.master.disableformats = true;
51520 tpls.header = new Roo.Template(
51521 '<table border="0" cellspacing="0" cellpadding="0">',
51522 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
51525 tpls.header.disableformats = true;
51527 tpls.header.compile();
51530 tpls.hcell = new Roo.Template(
51531 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
51532 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
51535 tpls.hcell.disableFormats = true;
51537 tpls.hcell.compile();
51540 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
51541 this.unselectableCls + '" ' + this.unselectable +'> </div>');
51542 tpls.hsplit.disableFormats = true;
51544 tpls.hsplit.compile();
51547 tpls.body = new Roo.Template(
51548 '<table border="0" cellspacing="0" cellpadding="0">',
51549 "<tbody>{rows}</tbody>",
51552 tpls.body.disableFormats = true;
51554 tpls.body.compile();
51557 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
51558 tpls.row.disableFormats = true;
51560 tpls.row.compile();
51563 tpls.cell = new Roo.Template(
51564 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
51565 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
51566 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
51569 tpls.cell.disableFormats = true;
51571 tpls.cell.compile();
51573 this.templates = tpls;
51576 // remap these for backwards compat
51577 onColWidthChange : function(){
51578 this.updateColumns.apply(this, arguments);
51580 onHeaderChange : function(){
51581 this.updateHeaders.apply(this, arguments);
51583 onHiddenChange : function(){
51584 this.handleHiddenChange.apply(this, arguments);
51586 onColumnMove : function(){
51587 this.handleColumnMove.apply(this, arguments);
51589 onColumnLock : function(){
51590 this.handleLockChange.apply(this, arguments);
51593 onDataChange : function(){
51595 this.updateHeaderSortState();
51598 onClear : function(){
51602 onUpdate : function(ds, record){
51603 this.refreshRow(record);
51606 refreshRow : function(record){
51607 var ds = this.ds, index;
51608 if(typeof record == 'number'){
51610 record = ds.getAt(index);
51612 index = ds.indexOf(record);
51614 this.insertRows(ds, index, index, true);
51615 this.onRemove(ds, record, index+1, true);
51616 this.syncRowHeights(index, index);
51618 this.fireEvent("rowupdated", this, index, record);
51621 onAdd : function(ds, records, index){
51622 this.insertRows(ds, index, index + (records.length-1));
51625 onRemove : function(ds, record, index, isUpdate){
51626 if(isUpdate !== true){
51627 this.fireEvent("beforerowremoved", this, index, record);
51629 var bt = this.getBodyTable(), lt = this.getLockedTable();
51630 if(bt.rows[index]){
51631 bt.firstChild.removeChild(bt.rows[index]);
51633 if(lt.rows[index]){
51634 lt.firstChild.removeChild(lt.rows[index]);
51636 if(isUpdate !== true){
51637 this.stripeRows(index);
51638 this.syncRowHeights(index, index);
51640 this.fireEvent("rowremoved", this, index, record);
51644 onLoad : function(){
51645 this.scrollToTop();
51649 * Scrolls the grid to the top
51651 scrollToTop : function(){
51653 this.scroller.dom.scrollTop = 0;
51659 * Gets a panel in the header of the grid that can be used for toolbars etc.
51660 * After modifying the contents of this panel a call to grid.autoSize() may be
51661 * required to register any changes in size.
51662 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
51663 * @return Roo.Element
51665 getHeaderPanel : function(doShow){
51667 this.headerPanel.show();
51669 return this.headerPanel;
51673 * Gets a panel in the footer of the grid that can be used for toolbars etc.
51674 * After modifying the contents of this panel a call to grid.autoSize() may be
51675 * required to register any changes in size.
51676 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
51677 * @return Roo.Element
51679 getFooterPanel : function(doShow){
51681 this.footerPanel.show();
51683 return this.footerPanel;
51686 initElements : function(){
51687 var E = Roo.Element;
51688 var el = this.grid.getGridEl().dom.firstChild;
51689 var cs = el.childNodes;
51691 this.el = new E(el);
51693 this.focusEl = new E(el.firstChild);
51694 this.focusEl.swallowEvent("click", true);
51696 this.headerPanel = new E(cs[1]);
51697 this.headerPanel.enableDisplayMode("block");
51699 this.scroller = new E(cs[2]);
51700 this.scrollSizer = new E(this.scroller.dom.firstChild);
51702 this.lockedWrap = new E(cs[3]);
51703 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
51704 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
51706 this.mainWrap = new E(cs[4]);
51707 this.mainHd = new E(this.mainWrap.dom.firstChild);
51708 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
51710 this.footerPanel = new E(cs[5]);
51711 this.footerPanel.enableDisplayMode("block");
51713 this.resizeProxy = new E(cs[6]);
51715 this.headerSelector = String.format(
51716 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
51717 this.lockedHd.id, this.mainHd.id
51720 this.splitterSelector = String.format(
51721 '#{0} div.x-grid-split, #{1} div.x-grid-split',
51722 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
51725 idToCssName : function(s)
51727 return s.replace(/[^a-z0-9]+/ig, '-');
51730 getHeaderCell : function(index){
51731 return Roo.DomQuery.select(this.headerSelector)[index];
51734 getHeaderCellMeasure : function(index){
51735 return this.getHeaderCell(index).firstChild;
51738 getHeaderCellText : function(index){
51739 return this.getHeaderCell(index).firstChild.firstChild;
51742 getLockedTable : function(){
51743 return this.lockedBody.dom.firstChild;
51746 getBodyTable : function(){
51747 return this.mainBody.dom.firstChild;
51750 getLockedRow : function(index){
51751 return this.getLockedTable().rows[index];
51754 getRow : function(index){
51755 return this.getBodyTable().rows[index];
51758 getRowComposite : function(index){
51760 this.rowEl = new Roo.CompositeElementLite();
51762 var els = [], lrow, mrow;
51763 if(lrow = this.getLockedRow(index)){
51766 if(mrow = this.getRow(index)){
51769 this.rowEl.elements = els;
51773 * Gets the 'td' of the cell
51775 * @param {Integer} rowIndex row to select
51776 * @param {Integer} colIndex column to select
51780 getCell : function(rowIndex, colIndex){
51781 var locked = this.cm.getLockedCount();
51783 if(colIndex < locked){
51784 source = this.lockedBody.dom.firstChild;
51786 source = this.mainBody.dom.firstChild;
51787 colIndex -= locked;
51789 return source.rows[rowIndex].childNodes[colIndex];
51792 getCellText : function(rowIndex, colIndex){
51793 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
51796 getCellBox : function(cell){
51797 var b = this.fly(cell).getBox();
51798 if(Roo.isOpera){ // opera fails to report the Y
51799 b.y = cell.offsetTop + this.mainBody.getY();
51804 getCellIndex : function(cell){
51805 var id = String(cell.className).match(this.cellRE);
51807 return parseInt(id[1], 10);
51812 findHeaderIndex : function(n){
51813 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
51814 return r ? this.getCellIndex(r) : false;
51817 findHeaderCell : function(n){
51818 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
51819 return r ? r : false;
51822 findRowIndex : function(n){
51826 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
51827 return r ? r.rowIndex : false;
51830 findCellIndex : function(node){
51831 var stop = this.el.dom;
51832 while(node && node != stop){
51833 if(this.findRE.test(node.className)){
51834 return this.getCellIndex(node);
51836 node = node.parentNode;
51841 getColumnId : function(index){
51842 return this.cm.getColumnId(index);
51845 getSplitters : function()
51847 if(this.splitterSelector){
51848 return Roo.DomQuery.select(this.splitterSelector);
51854 getSplitter : function(index){
51855 return this.getSplitters()[index];
51858 onRowOver : function(e, t){
51860 if((row = this.findRowIndex(t)) !== false){
51861 this.getRowComposite(row).addClass("x-grid-row-over");
51865 onRowOut : function(e, t){
51867 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
51868 this.getRowComposite(row).removeClass("x-grid-row-over");
51872 renderHeaders : function(){
51874 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
51875 var cb = [], lb = [], sb = [], lsb = [], p = {};
51876 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51877 p.cellId = "x-grid-hd-0-" + i;
51878 p.splitId = "x-grid-csplit-0-" + i;
51879 p.id = cm.getColumnId(i);
51880 p.title = cm.getColumnTooltip(i) || "";
51881 p.value = cm.getColumnHeader(i) || "";
51882 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
51883 if(!cm.isLocked(i)){
51884 cb[cb.length] = ct.apply(p);
51885 sb[sb.length] = st.apply(p);
51887 lb[lb.length] = ct.apply(p);
51888 lsb[lsb.length] = st.apply(p);
51891 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
51892 ht.apply({cells: cb.join(""), splits:sb.join("")})];
51895 updateHeaders : function(){
51896 var html = this.renderHeaders();
51897 this.lockedHd.update(html[0]);
51898 this.mainHd.update(html[1]);
51902 * Focuses the specified row.
51903 * @param {Number} row The row index
51905 focusRow : function(row)
51907 //Roo.log('GridView.focusRow');
51908 var x = this.scroller.dom.scrollLeft;
51909 this.focusCell(row, 0, false);
51910 this.scroller.dom.scrollLeft = x;
51914 * Focuses the specified cell.
51915 * @param {Number} row The row index
51916 * @param {Number} col The column index
51917 * @param {Boolean} hscroll false to disable horizontal scrolling
51919 focusCell : function(row, col, hscroll)
51921 //Roo.log('GridView.focusCell');
51922 var el = this.ensureVisible(row, col, hscroll);
51923 this.focusEl.alignTo(el, "tl-tl");
51925 this.focusEl.focus();
51927 this.focusEl.focus.defer(1, this.focusEl);
51932 * Scrolls the specified cell into view
51933 * @param {Number} row The row index
51934 * @param {Number} col The column index
51935 * @param {Boolean} hscroll false to disable horizontal scrolling
51937 ensureVisible : function(row, col, hscroll)
51939 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
51940 //return null; //disable for testing.
51941 if(typeof row != "number"){
51942 row = row.rowIndex;
51944 if(row < 0 && row >= this.ds.getCount()){
51947 col = (col !== undefined ? col : 0);
51948 var cm = this.grid.colModel;
51949 while(cm.isHidden(col)){
51953 var el = this.getCell(row, col);
51957 var c = this.scroller.dom;
51959 var ctop = parseInt(el.offsetTop, 10);
51960 var cleft = parseInt(el.offsetLeft, 10);
51961 var cbot = ctop + el.offsetHeight;
51962 var cright = cleft + el.offsetWidth;
51964 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
51965 var stop = parseInt(c.scrollTop, 10);
51966 var sleft = parseInt(c.scrollLeft, 10);
51967 var sbot = stop + ch;
51968 var sright = sleft + c.clientWidth;
51970 Roo.log('GridView.ensureVisible:' +
51972 ' c.clientHeight:' + c.clientHeight +
51973 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
51981 c.scrollTop = ctop;
51982 //Roo.log("set scrolltop to ctop DISABLE?");
51983 }else if(cbot > sbot){
51984 //Roo.log("set scrolltop to cbot-ch");
51985 c.scrollTop = cbot-ch;
51988 if(hscroll !== false){
51990 c.scrollLeft = cleft;
51991 }else if(cright > sright){
51992 c.scrollLeft = cright-c.clientWidth;
51999 updateColumns : function(){
52000 this.grid.stopEditing();
52001 var cm = this.grid.colModel, colIds = this.getColumnIds();
52002 //var totalWidth = cm.getTotalWidth();
52004 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52005 //if(cm.isHidden(i)) continue;
52006 var w = cm.getColumnWidth(i);
52007 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
52008 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
52010 this.updateSplitters();
52013 generateRules : function(cm){
52014 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
52015 Roo.util.CSS.removeStyleSheet(rulesId);
52016 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52017 var cid = cm.getColumnId(i);
52019 if(cm.config[i].align){
52020 align = 'text-align:'+cm.config[i].align+';';
52023 if(cm.isHidden(i)){
52024 hidden = 'display:none;';
52026 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
52028 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
52029 this.hdSelector, cid, " {\n", align, width, "}\n",
52030 this.tdSelector, cid, " {\n",hidden,"\n}\n",
52031 this.splitSelector, cid, " {\n", hidden , "\n}\n");
52033 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52036 updateSplitters : function(){
52037 var cm = this.cm, s = this.getSplitters();
52038 if(s){ // splitters not created yet
52039 var pos = 0, locked = true;
52040 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52041 if(cm.isHidden(i)) continue;
52042 var w = cm.getColumnWidth(i); // make sure it's a number
52043 if(!cm.isLocked(i) && locked){
52048 s[i].style.left = (pos-this.splitOffset) + "px";
52053 handleHiddenChange : function(colModel, colIndex, hidden){
52055 this.hideColumn(colIndex);
52057 this.unhideColumn(colIndex);
52061 hideColumn : function(colIndex){
52062 var cid = this.getColumnId(colIndex);
52063 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
52064 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
52066 this.updateHeaders();
52068 this.updateSplitters();
52072 unhideColumn : function(colIndex){
52073 var cid = this.getColumnId(colIndex);
52074 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
52075 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
52078 this.updateHeaders();
52080 this.updateSplitters();
52084 insertRows : function(dm, firstRow, lastRow, isUpdate){
52085 if(firstRow == 0 && lastRow == dm.getCount()-1){
52089 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
52091 var s = this.getScrollState();
52092 var markup = this.renderRows(firstRow, lastRow);
52093 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
52094 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
52095 this.restoreScroll(s);
52097 this.fireEvent("rowsinserted", this, firstRow, lastRow);
52098 this.syncRowHeights(firstRow, lastRow);
52099 this.stripeRows(firstRow);
52105 bufferRows : function(markup, target, index){
52106 var before = null, trows = target.rows, tbody = target.tBodies[0];
52107 if(index < trows.length){
52108 before = trows[index];
52110 var b = document.createElement("div");
52111 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
52112 var rows = b.firstChild.rows;
52113 for(var i = 0, len = rows.length; i < len; i++){
52115 tbody.insertBefore(rows[0], before);
52117 tbody.appendChild(rows[0]);
52124 deleteRows : function(dm, firstRow, lastRow){
52125 if(dm.getRowCount()<1){
52126 this.fireEvent("beforerefresh", this);
52127 this.mainBody.update("");
52128 this.lockedBody.update("");
52129 this.fireEvent("refresh", this);
52131 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
52132 var bt = this.getBodyTable();
52133 var tbody = bt.firstChild;
52134 var rows = bt.rows;
52135 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
52136 tbody.removeChild(rows[firstRow]);
52138 this.stripeRows(firstRow);
52139 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
52143 updateRows : function(dataSource, firstRow, lastRow){
52144 var s = this.getScrollState();
52146 this.restoreScroll(s);
52149 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
52153 this.updateHeaderSortState();
52156 getScrollState : function(){
52158 var sb = this.scroller.dom;
52159 return {left: sb.scrollLeft, top: sb.scrollTop};
52162 stripeRows : function(startRow){
52163 if(!this.grid.stripeRows || this.ds.getCount() < 1){
52166 startRow = startRow || 0;
52167 var rows = this.getBodyTable().rows;
52168 var lrows = this.getLockedTable().rows;
52169 var cls = ' x-grid-row-alt ';
52170 for(var i = startRow, len = rows.length; i < len; i++){
52171 var row = rows[i], lrow = lrows[i];
52172 var isAlt = ((i+1) % 2 == 0);
52173 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
52174 if(isAlt == hasAlt){
52178 row.className += " x-grid-row-alt";
52180 row.className = row.className.replace("x-grid-row-alt", "");
52183 lrow.className = row.className;
52188 restoreScroll : function(state){
52189 //Roo.log('GridView.restoreScroll');
52190 var sb = this.scroller.dom;
52191 sb.scrollLeft = state.left;
52192 sb.scrollTop = state.top;
52196 syncScroll : function(){
52197 //Roo.log('GridView.syncScroll');
52198 var sb = this.scroller.dom;
52199 var sh = this.mainHd.dom;
52200 var bs = this.mainBody.dom;
52201 var lv = this.lockedBody.dom;
52202 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
52203 lv.scrollTop = bs.scrollTop = sb.scrollTop;
52206 handleScroll : function(e){
52208 var sb = this.scroller.dom;
52209 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
52213 handleWheel : function(e){
52214 var d = e.getWheelDelta();
52215 this.scroller.dom.scrollTop -= d*22;
52216 // set this here to prevent jumpy scrolling on large tables
52217 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
52221 renderRows : function(startRow, endRow){
52222 // pull in all the crap needed to render rows
52223 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
52224 var colCount = cm.getColumnCount();
52226 if(ds.getCount() < 1){
52230 // build a map for all the columns
52232 for(var i = 0; i < colCount; i++){
52233 var name = cm.getDataIndex(i);
52235 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
52236 renderer : cm.getRenderer(i),
52237 id : cm.getColumnId(i),
52238 locked : cm.isLocked(i)
52242 startRow = startRow || 0;
52243 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
52245 // records to render
52246 var rs = ds.getRange(startRow, endRow);
52248 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
52251 // As much as I hate to duplicate code, this was branched because FireFox really hates
52252 // [].join("") on strings. The performance difference was substantial enough to
52253 // branch this function
52254 doRender : Roo.isGecko ?
52255 function(cs, rs, ds, startRow, colCount, stripe){
52256 var ts = this.templates, ct = ts.cell, rt = ts.row;
52258 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
52260 var hasListener = this.grid.hasListener('rowclass');
52262 for(var j = 0, len = rs.length; j < len; j++){
52263 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
52264 for(var i = 0; i < colCount; i++){
52266 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
52268 p.css = p.attr = "";
52269 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
52270 if(p.value == undefined || p.value === "") p.value = " ";
52271 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
52272 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
52274 var markup = ct.apply(p);
52282 if(stripe && ((rowIndex+1) % 2 == 0)){
52283 alt.push("x-grid-row-alt")
52286 alt.push( " x-grid-dirty-row");
52289 if(this.getRowClass){
52290 alt.push(this.getRowClass(r, rowIndex));
52296 rowIndex : rowIndex,
52299 this.grid.fireEvent('rowclass', this, rowcfg);
52300 alt.push(rowcfg.rowClass);
52302 rp.alt = alt.join(" ");
52303 lbuf+= rt.apply(rp);
52305 buf+= rt.apply(rp);
52307 return [lbuf, buf];
52309 function(cs, rs, ds, startRow, colCount, stripe){
52310 var ts = this.templates, ct = ts.cell, rt = ts.row;
52312 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
52313 var hasListener = this.grid.hasListener('rowclass');
52316 for(var j = 0, len = rs.length; j < len; j++){
52317 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
52318 for(var i = 0; i < colCount; i++){
52320 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
52322 p.css = p.attr = "";
52323 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
52324 if(p.value == undefined || p.value === "") p.value = " ";
52325 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
52326 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
52329 var markup = ct.apply(p);
52331 cb[cb.length] = markup;
52333 lcb[lcb.length] = markup;
52337 if(stripe && ((rowIndex+1) % 2 == 0)){
52338 alt.push( "x-grid-row-alt");
52341 alt.push(" x-grid-dirty-row");
52344 if(this.getRowClass){
52345 alt.push( this.getRowClass(r, rowIndex));
52351 rowIndex : rowIndex,
52354 this.grid.fireEvent('rowclass', this, rowcfg);
52355 alt.push(rowcfg.rowClass);
52357 rp.alt = alt.join(" ");
52358 rp.cells = lcb.join("");
52359 lbuf[lbuf.length] = rt.apply(rp);
52360 rp.cells = cb.join("");
52361 buf[buf.length] = rt.apply(rp);
52363 return [lbuf.join(""), buf.join("")];
52366 renderBody : function(){
52367 var markup = this.renderRows();
52368 var bt = this.templates.body;
52369 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
52373 * Refreshes the grid
52374 * @param {Boolean} headersToo
52376 refresh : function(headersToo){
52377 this.fireEvent("beforerefresh", this);
52378 this.grid.stopEditing();
52379 var result = this.renderBody();
52380 this.lockedBody.update(result[0]);
52381 this.mainBody.update(result[1]);
52382 if(headersToo === true){
52383 this.updateHeaders();
52384 this.updateColumns();
52385 this.updateSplitters();
52386 this.updateHeaderSortState();
52388 this.syncRowHeights();
52390 this.fireEvent("refresh", this);
52393 handleColumnMove : function(cm, oldIndex, newIndex){
52394 this.indexMap = null;
52395 var s = this.getScrollState();
52396 this.refresh(true);
52397 this.restoreScroll(s);
52398 this.afterMove(newIndex);
52401 afterMove : function(colIndex){
52402 if(this.enableMoveAnim && Roo.enableFx){
52403 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
52405 // if multisort - fix sortOrder, and reload..
52406 if (this.grid.dataSource.multiSort) {
52407 // the we can call sort again..
52408 var dm = this.grid.dataSource;
52409 var cm = this.grid.colModel;
52411 for(var i = 0; i < cm.config.length; i++ ) {
52413 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
52414 continue; // dont' bother, it's not in sort list or being set.
52417 so.push(cm.config[i].dataIndex);
52420 dm.load(dm.lastOptions);
52427 updateCell : function(dm, rowIndex, dataIndex){
52428 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
52429 if(typeof colIndex == "undefined"){ // not present in grid
52432 var cm = this.grid.colModel;
52433 var cell = this.getCell(rowIndex, colIndex);
52434 var cellText = this.getCellText(rowIndex, colIndex);
52437 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
52438 id : cm.getColumnId(colIndex),
52439 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
52441 var renderer = cm.getRenderer(colIndex);
52442 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
52443 if(typeof val == "undefined" || val === "") val = " ";
52444 cellText.innerHTML = val;
52445 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
52446 this.syncRowHeights(rowIndex, rowIndex);
52449 calcColumnWidth : function(colIndex, maxRowsToMeasure){
52451 if(this.grid.autoSizeHeaders){
52452 var h = this.getHeaderCellMeasure(colIndex);
52453 maxWidth = Math.max(maxWidth, h.scrollWidth);
52456 if(this.cm.isLocked(colIndex)){
52457 tb = this.getLockedTable();
52460 tb = this.getBodyTable();
52461 index = colIndex - this.cm.getLockedCount();
52464 var rows = tb.rows;
52465 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
52466 for(var i = 0; i < stopIndex; i++){
52467 var cell = rows[i].childNodes[index].firstChild;
52468 maxWidth = Math.max(maxWidth, cell.scrollWidth);
52471 return maxWidth + /*margin for error in IE*/ 5;
52474 * Autofit a column to its content.
52475 * @param {Number} colIndex
52476 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
52478 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
52479 if(this.cm.isHidden(colIndex)){
52480 return; // can't calc a hidden column
52483 var cid = this.cm.getColumnId(colIndex);
52484 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
52485 if(this.grid.autoSizeHeaders){
52486 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
52489 var newWidth = this.calcColumnWidth(colIndex);
52490 this.cm.setColumnWidth(colIndex,
52491 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
52492 if(!suppressEvent){
52493 this.grid.fireEvent("columnresize", colIndex, newWidth);
52498 * Autofits all columns to their content and then expands to fit any extra space in the grid
52500 autoSizeColumns : function(){
52501 var cm = this.grid.colModel;
52502 var colCount = cm.getColumnCount();
52503 for(var i = 0; i < colCount; i++){
52504 this.autoSizeColumn(i, true, true);
52506 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
52509 this.updateColumns();
52515 * Autofits all columns to the grid's width proportionate with their current size
52516 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
52518 fitColumns : function(reserveScrollSpace){
52519 var cm = this.grid.colModel;
52520 var colCount = cm.getColumnCount();
52524 for (i = 0; i < colCount; i++){
52525 if(!cm.isHidden(i) && !cm.isFixed(i)){
52526 w = cm.getColumnWidth(i);
52532 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
52533 if(reserveScrollSpace){
52536 var frac = (avail - cm.getTotalWidth())/width;
52537 while (cols.length){
52540 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
52542 this.updateColumns();
52546 onRowSelect : function(rowIndex){
52547 var row = this.getRowComposite(rowIndex);
52548 row.addClass("x-grid-row-selected");
52551 onRowDeselect : function(rowIndex){
52552 var row = this.getRowComposite(rowIndex);
52553 row.removeClass("x-grid-row-selected");
52556 onCellSelect : function(row, col){
52557 var cell = this.getCell(row, col);
52559 Roo.fly(cell).addClass("x-grid-cell-selected");
52563 onCellDeselect : function(row, col){
52564 var cell = this.getCell(row, col);
52566 Roo.fly(cell).removeClass("x-grid-cell-selected");
52570 updateHeaderSortState : function(){
52572 // sort state can be single { field: xxx, direction : yyy}
52573 // or { xxx=>ASC , yyy : DESC ..... }
52576 if (!this.ds.multiSort) {
52577 var state = this.ds.getSortState();
52581 mstate[state.field] = state.direction;
52582 // FIXME... - this is not used here.. but might be elsewhere..
52583 this.sortState = state;
52586 mstate = this.ds.sortToggle;
52588 //remove existing sort classes..
52590 var sc = this.sortClasses;
52591 var hds = this.el.select(this.headerSelector).removeClass(sc);
52593 for(var f in mstate) {
52595 var sortColumn = this.cm.findColumnIndex(f);
52597 if(sortColumn != -1){
52598 var sortDir = mstate[f];
52599 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
52608 handleHeaderClick : function(g, index){
52609 if(this.headersDisabled){
52612 var dm = g.dataSource, cm = g.colModel;
52613 if(!cm.isSortable(index)){
52618 if (dm.multiSort) {
52619 // update the sortOrder
52621 for(var i = 0; i < cm.config.length; i++ ) {
52623 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
52624 continue; // dont' bother, it's not in sort list or being set.
52627 so.push(cm.config[i].dataIndex);
52633 dm.sort(cm.getDataIndex(index));
52637 destroy : function(){
52639 this.colMenu.removeAll();
52640 Roo.menu.MenuMgr.unregister(this.colMenu);
52641 this.colMenu.getEl().remove();
52642 delete this.colMenu;
52645 this.hmenu.removeAll();
52646 Roo.menu.MenuMgr.unregister(this.hmenu);
52647 this.hmenu.getEl().remove();
52650 if(this.grid.enableColumnMove){
52651 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
52653 for(var dd in dds){
52654 if(!dds[dd].config.isTarget && dds[dd].dragElId){
52655 var elid = dds[dd].dragElId;
52657 Roo.get(elid).remove();
52658 } else if(dds[dd].config.isTarget){
52659 dds[dd].proxyTop.remove();
52660 dds[dd].proxyBottom.remove();
52663 if(Roo.dd.DDM.locationCache[dd]){
52664 delete Roo.dd.DDM.locationCache[dd];
52667 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
52670 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
52671 this.bind(null, null);
52672 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
52675 handleLockChange : function(){
52676 this.refresh(true);
52679 onDenyColumnLock : function(){
52683 onDenyColumnHide : function(){
52687 handleHdMenuClick : function(item){
52688 var index = this.hdCtxIndex;
52689 var cm = this.cm, ds = this.ds;
52692 ds.sort(cm.getDataIndex(index), "ASC");
52695 ds.sort(cm.getDataIndex(index), "DESC");
52698 var lc = cm.getLockedCount();
52699 if(cm.getColumnCount(true) <= lc+1){
52700 this.onDenyColumnLock();
52704 cm.setLocked(index, true, true);
52705 cm.moveColumn(index, lc);
52706 this.grid.fireEvent("columnmove", index, lc);
52708 cm.setLocked(index, true);
52712 var lc = cm.getLockedCount();
52713 if((lc-1) != index){
52714 cm.setLocked(index, false, true);
52715 cm.moveColumn(index, lc-1);
52716 this.grid.fireEvent("columnmove", index, lc-1);
52718 cm.setLocked(index, false);
52722 index = cm.getIndexById(item.id.substr(4));
52724 if(item.checked && cm.getColumnCount(true) <= 1){
52725 this.onDenyColumnHide();
52728 cm.setHidden(index, item.checked);
52734 beforeColMenuShow : function(){
52735 var cm = this.cm, colCount = cm.getColumnCount();
52736 this.colMenu.removeAll();
52737 for(var i = 0; i < colCount; i++){
52738 this.colMenu.add(new Roo.menu.CheckItem({
52739 id: "col-"+cm.getColumnId(i),
52740 text: cm.getColumnHeader(i),
52741 checked: !cm.isHidden(i),
52747 handleHdCtx : function(g, index, e){
52749 var hd = this.getHeaderCell(index);
52750 this.hdCtxIndex = index;
52751 var ms = this.hmenu.items, cm = this.cm;
52752 ms.get("asc").setDisabled(!cm.isSortable(index));
52753 ms.get("desc").setDisabled(!cm.isSortable(index));
52754 if(this.grid.enableColLock !== false){
52755 ms.get("lock").setDisabled(cm.isLocked(index));
52756 ms.get("unlock").setDisabled(!cm.isLocked(index));
52758 this.hmenu.show(hd, "tl-bl");
52761 handleHdOver : function(e){
52762 var hd = this.findHeaderCell(e.getTarget());
52763 if(hd && !this.headersDisabled){
52764 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
52765 this.fly(hd).addClass("x-grid-hd-over");
52770 handleHdOut : function(e){
52771 var hd = this.findHeaderCell(e.getTarget());
52773 this.fly(hd).removeClass("x-grid-hd-over");
52777 handleSplitDblClick : function(e, t){
52778 var i = this.getCellIndex(t);
52779 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
52780 this.autoSizeColumn(i, true);
52785 render : function(){
52788 var colCount = cm.getColumnCount();
52790 if(this.grid.monitorWindowResize === true){
52791 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
52793 var header = this.renderHeaders();
52794 var body = this.templates.body.apply({rows:""});
52795 var html = this.templates.master.apply({
52798 lockedHeader: header[0],
52802 //this.updateColumns();
52804 this.grid.getGridEl().dom.innerHTML = html;
52806 this.initElements();
52808 // a kludge to fix the random scolling effect in webkit
52809 this.el.on("scroll", function() {
52810 this.el.dom.scrollTop=0; // hopefully not recursive..
52813 this.scroller.on("scroll", this.handleScroll, this);
52814 this.lockedBody.on("mousewheel", this.handleWheel, this);
52815 this.mainBody.on("mousewheel", this.handleWheel, this);
52817 this.mainHd.on("mouseover", this.handleHdOver, this);
52818 this.mainHd.on("mouseout", this.handleHdOut, this);
52819 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
52820 {delegate: "."+this.splitClass});
52822 this.lockedHd.on("mouseover", this.handleHdOver, this);
52823 this.lockedHd.on("mouseout", this.handleHdOut, this);
52824 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
52825 {delegate: "."+this.splitClass});
52827 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
52828 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
52831 this.updateSplitters();
52833 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
52834 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
52835 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
52838 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
52839 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
52841 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
52842 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
52844 if(this.grid.enableColLock !== false){
52845 this.hmenu.add('-',
52846 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
52847 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
52850 if(this.grid.enableColumnHide !== false){
52852 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
52853 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
52854 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
52856 this.hmenu.add('-',
52857 {id:"columns", text: this.columnsText, menu: this.colMenu}
52860 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
52862 this.grid.on("headercontextmenu", this.handleHdCtx, this);
52865 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
52866 this.dd = new Roo.grid.GridDragZone(this.grid, {
52867 ddGroup : this.grid.ddGroup || 'GridDD'
52873 for(var i = 0; i < colCount; i++){
52874 if(cm.isHidden(i)){
52875 this.hideColumn(i);
52877 if(cm.config[i].align){
52878 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
52879 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
52883 this.updateHeaderSortState();
52885 this.beforeInitialResize();
52888 // two part rendering gives faster view to the user
52889 this.renderPhase2.defer(1, this);
52892 renderPhase2 : function(){
52893 // render the rows now
52895 if(this.grid.autoSizeColumns){
52896 this.autoSizeColumns();
52900 beforeInitialResize : function(){
52904 onColumnSplitterMoved : function(i, w){
52905 this.userResized = true;
52906 var cm = this.grid.colModel;
52907 cm.setColumnWidth(i, w, true);
52908 var cid = cm.getColumnId(i);
52909 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
52910 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
52911 this.updateSplitters();
52913 this.grid.fireEvent("columnresize", i, w);
52916 syncRowHeights : function(startIndex, endIndex){
52917 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
52918 startIndex = startIndex || 0;
52919 var mrows = this.getBodyTable().rows;
52920 var lrows = this.getLockedTable().rows;
52921 var len = mrows.length-1;
52922 endIndex = Math.min(endIndex || len, len);
52923 for(var i = startIndex; i <= endIndex; i++){
52924 var m = mrows[i], l = lrows[i];
52925 var h = Math.max(m.offsetHeight, l.offsetHeight);
52926 m.style.height = l.style.height = h + "px";
52931 layout : function(initialRender, is2ndPass){
52933 var auto = g.autoHeight;
52934 var scrollOffset = 16;
52935 var c = g.getGridEl(), cm = this.cm,
52936 expandCol = g.autoExpandColumn,
52938 //c.beginMeasure();
52940 if(!c.dom.offsetWidth){ // display:none?
52942 this.lockedWrap.show();
52943 this.mainWrap.show();
52948 var hasLock = this.cm.isLocked(0);
52950 var tbh = this.headerPanel.getHeight();
52951 var bbh = this.footerPanel.getHeight();
52954 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
52955 var newHeight = ch + c.getBorderWidth("tb");
52957 newHeight = Math.min(g.maxHeight, newHeight);
52959 c.setHeight(newHeight);
52963 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
52966 var s = this.scroller;
52968 var csize = c.getSize(true);
52970 this.el.setSize(csize.width, csize.height);
52972 this.headerPanel.setWidth(csize.width);
52973 this.footerPanel.setWidth(csize.width);
52975 var hdHeight = this.mainHd.getHeight();
52976 var vw = csize.width;
52977 var vh = csize.height - (tbh + bbh);
52981 var bt = this.getBodyTable();
52982 var ltWidth = hasLock ?
52983 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
52985 var scrollHeight = bt.offsetHeight;
52986 var scrollWidth = ltWidth + bt.offsetWidth;
52987 var vscroll = false, hscroll = false;
52989 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
52991 var lw = this.lockedWrap, mw = this.mainWrap;
52992 var lb = this.lockedBody, mb = this.mainBody;
52994 setTimeout(function(){
52995 var t = s.dom.offsetTop;
52996 var w = s.dom.clientWidth,
52997 h = s.dom.clientHeight;
53000 lw.setSize(ltWidth, h);
53002 mw.setLeftTop(ltWidth, t);
53003 mw.setSize(w-ltWidth, h);
53005 lb.setHeight(h-hdHeight);
53006 mb.setHeight(h-hdHeight);
53008 if(is2ndPass !== true && !gv.userResized && expandCol){
53009 // high speed resize without full column calculation
53011 var ci = cm.getIndexById(expandCol);
53013 ci = cm.findColumnIndex(expandCol);
53015 ci = Math.max(0, ci); // make sure it's got at least the first col.
53016 var expandId = cm.getColumnId(ci);
53017 var tw = cm.getTotalWidth(false);
53018 var currentWidth = cm.getColumnWidth(ci);
53019 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
53020 if(currentWidth != cw){
53021 cm.setColumnWidth(ci, cw, true);
53022 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
53023 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
53024 gv.updateSplitters();
53025 gv.layout(false, true);
53037 onWindowResize : function(){
53038 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
53044 appendFooter : function(parentEl){
53048 sortAscText : "Sort Ascending",
53049 sortDescText : "Sort Descending",
53050 lockText : "Lock Column",
53051 unlockText : "Unlock Column",
53052 columnsText : "Columns"
53056 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
53057 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
53058 this.proxy.el.addClass('x-grid3-col-dd');
53061 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
53062 handleMouseDown : function(e){
53066 callHandleMouseDown : function(e){
53067 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
53072 * Ext JS Library 1.1.1
53073 * Copyright(c) 2006-2007, Ext JS, LLC.
53075 * Originally Released Under LGPL - original licence link has changed is not relivant.
53078 * <script type="text/javascript">
53082 // This is a support class used internally by the Grid components
53083 Roo.grid.SplitDragZone = function(grid, hd, hd2){
53085 this.view = grid.getView();
53086 this.proxy = this.view.resizeProxy;
53087 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
53088 "gridSplitters" + this.grid.getGridEl().id, {
53089 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
53091 this.setHandleElId(Roo.id(hd));
53092 this.setOuterHandleElId(Roo.id(hd2));
53093 this.scroll = false;
53095 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
53096 fly: Roo.Element.fly,
53098 b4StartDrag : function(x, y){
53099 this.view.headersDisabled = true;
53100 this.proxy.setHeight(this.view.mainWrap.getHeight());
53101 var w = this.cm.getColumnWidth(this.cellIndex);
53102 var minw = Math.max(w-this.grid.minColumnWidth, 0);
53103 this.resetConstraints();
53104 this.setXConstraint(minw, 1000);
53105 this.setYConstraint(0, 0);
53106 this.minX = x - minw;
53107 this.maxX = x + 1000;
53109 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
53113 handleMouseDown : function(e){
53114 ev = Roo.EventObject.setEvent(e);
53115 var t = this.fly(ev.getTarget());
53116 if(t.hasClass("x-grid-split")){
53117 this.cellIndex = this.view.getCellIndex(t.dom);
53118 this.split = t.dom;
53119 this.cm = this.grid.colModel;
53120 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
53121 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
53126 endDrag : function(e){
53127 this.view.headersDisabled = false;
53128 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
53129 var diff = endX - this.startPos;
53130 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
53133 autoOffset : function(){
53134 this.setDelta(0,0);
53138 * Ext JS Library 1.1.1
53139 * Copyright(c) 2006-2007, Ext JS, LLC.
53141 * Originally Released Under LGPL - original licence link has changed is not relivant.
53144 * <script type="text/javascript">
53148 // This is a support class used internally by the Grid components
53149 Roo.grid.GridDragZone = function(grid, config){
53150 this.view = grid.getView();
53151 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
53152 if(this.view.lockedBody){
53153 this.setHandleElId(Roo.id(this.view.mainBody.dom));
53154 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
53156 this.scroll = false;
53158 this.ddel = document.createElement('div');
53159 this.ddel.className = 'x-grid-dd-wrap';
53162 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
53163 ddGroup : "GridDD",
53165 getDragData : function(e){
53166 var t = Roo.lib.Event.getTarget(e);
53167 var rowIndex = this.view.findRowIndex(t);
53168 var sm = this.grid.selModel;
53170 //Roo.log(rowIndex);
53172 if (sm.getSelectedCell) {
53173 // cell selection..
53174 if (!sm.getSelectedCell()) {
53177 if (rowIndex != sm.getSelectedCell()[0]) {
53183 if(rowIndex !== false){
53188 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
53190 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
53193 if (e.hasModifier()){
53194 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
53197 Roo.log("getDragData");
53202 rowIndex: rowIndex,
53203 selections:sm.getSelections ? sm.getSelections() : (
53204 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
53211 onInitDrag : function(e){
53212 var data = this.dragData;
53213 this.ddel.innerHTML = this.grid.getDragDropText();
53214 this.proxy.update(this.ddel);
53215 // fire start drag?
53218 afterRepair : function(){
53219 this.dragging = false;
53222 getRepairXY : function(e, data){
53226 onEndDrag : function(data, e){
53230 onValidDrop : function(dd, e, id){
53235 beforeInvalidDrop : function(e, id){
53240 * Ext JS Library 1.1.1
53241 * Copyright(c) 2006-2007, Ext JS, LLC.
53243 * Originally Released Under LGPL - original licence link has changed is not relivant.
53246 * <script type="text/javascript">
53251 * @class Roo.grid.ColumnModel
53252 * @extends Roo.util.Observable
53253 * This is the default implementation of a ColumnModel used by the Grid. It defines
53254 * the columns in the grid.
53257 var colModel = new Roo.grid.ColumnModel([
53258 {header: "Ticker", width: 60, sortable: true, locked: true},
53259 {header: "Company Name", width: 150, sortable: true},
53260 {header: "Market Cap.", width: 100, sortable: true},
53261 {header: "$ Sales", width: 100, sortable: true, renderer: money},
53262 {header: "Employees", width: 100, sortable: true, resizable: false}
53267 * The config options listed for this class are options which may appear in each
53268 * individual column definition.
53269 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
53271 * @param {Object} config An Array of column config objects. See this class's
53272 * config objects for details.
53274 Roo.grid.ColumnModel = function(config){
53276 * The config passed into the constructor
53278 this.config = config;
53281 // if no id, create one
53282 // if the column does not have a dataIndex mapping,
53283 // map it to the order it is in the config
53284 for(var i = 0, len = config.length; i < len; i++){
53286 if(typeof c.dataIndex == "undefined"){
53289 if(typeof c.renderer == "string"){
53290 c.renderer = Roo.util.Format[c.renderer];
53292 if(typeof c.id == "undefined"){
53295 if(c.editor && c.editor.xtype){
53296 c.editor = Roo.factory(c.editor, Roo.grid);
53298 if(c.editor && c.editor.isFormField){
53299 c.editor = new Roo.grid.GridEditor(c.editor);
53301 this.lookup[c.id] = c;
53305 * The width of columns which have no width specified (defaults to 100)
53308 this.defaultWidth = 100;
53311 * Default sortable of columns which have no sortable specified (defaults to false)
53314 this.defaultSortable = false;
53318 * @event widthchange
53319 * Fires when the width of a column changes.
53320 * @param {ColumnModel} this
53321 * @param {Number} columnIndex The column index
53322 * @param {Number} newWidth The new width
53324 "widthchange": true,
53326 * @event headerchange
53327 * Fires when the text of a header changes.
53328 * @param {ColumnModel} this
53329 * @param {Number} columnIndex The column index
53330 * @param {Number} newText The new header text
53332 "headerchange": true,
53334 * @event hiddenchange
53335 * Fires when a column is hidden or "unhidden".
53336 * @param {ColumnModel} this
53337 * @param {Number} columnIndex The column index
53338 * @param {Boolean} hidden true if hidden, false otherwise
53340 "hiddenchange": true,
53342 * @event columnmoved
53343 * Fires when a column is moved.
53344 * @param {ColumnModel} this
53345 * @param {Number} oldIndex
53346 * @param {Number} newIndex
53348 "columnmoved" : true,
53350 * @event columlockchange
53351 * Fires when a column's locked state is changed
53352 * @param {ColumnModel} this
53353 * @param {Number} colIndex
53354 * @param {Boolean} locked true if locked
53356 "columnlockchange" : true
53358 Roo.grid.ColumnModel.superclass.constructor.call(this);
53360 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
53362 * @cfg {String} header The header text to display in the Grid view.
53365 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
53366 * {@link Roo.data.Record} definition from which to draw the column's value. If not
53367 * specified, the column's index is used as an index into the Record's data Array.
53370 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
53371 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
53374 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
53375 * Defaults to the value of the {@link #defaultSortable} property.
53376 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
53379 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
53382 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
53385 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
53388 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
53391 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
53392 * given the cell's data value. See {@link #setRenderer}. If not specified, the
53393 * default renderer uses the raw data value.
53396 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
53399 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
53403 * Returns the id of the column at the specified index.
53404 * @param {Number} index The column index
53405 * @return {String} the id
53407 getColumnId : function(index){
53408 return this.config[index].id;
53412 * Returns the column for a specified id.
53413 * @param {String} id The column id
53414 * @return {Object} the column
53416 getColumnById : function(id){
53417 return this.lookup[id];
53422 * Returns the column for a specified dataIndex.
53423 * @param {String} dataIndex The column dataIndex
53424 * @return {Object|Boolean} the column or false if not found
53426 getColumnByDataIndex: function(dataIndex){
53427 var index = this.findColumnIndex(dataIndex);
53428 return index > -1 ? this.config[index] : false;
53432 * Returns the index for a specified column id.
53433 * @param {String} id The column id
53434 * @return {Number} the index, or -1 if not found
53436 getIndexById : function(id){
53437 for(var i = 0, len = this.config.length; i < len; i++){
53438 if(this.config[i].id == id){
53446 * Returns the index for a specified column dataIndex.
53447 * @param {String} dataIndex The column dataIndex
53448 * @return {Number} the index, or -1 if not found
53451 findColumnIndex : function(dataIndex){
53452 for(var i = 0, len = this.config.length; i < len; i++){
53453 if(this.config[i].dataIndex == dataIndex){
53461 moveColumn : function(oldIndex, newIndex){
53462 var c = this.config[oldIndex];
53463 this.config.splice(oldIndex, 1);
53464 this.config.splice(newIndex, 0, c);
53465 this.dataMap = null;
53466 this.fireEvent("columnmoved", this, oldIndex, newIndex);
53469 isLocked : function(colIndex){
53470 return this.config[colIndex].locked === true;
53473 setLocked : function(colIndex, value, suppressEvent){
53474 if(this.isLocked(colIndex) == value){
53477 this.config[colIndex].locked = value;
53478 if(!suppressEvent){
53479 this.fireEvent("columnlockchange", this, colIndex, value);
53483 getTotalLockedWidth : function(){
53484 var totalWidth = 0;
53485 for(var i = 0; i < this.config.length; i++){
53486 if(this.isLocked(i) && !this.isHidden(i)){
53487 this.totalWidth += this.getColumnWidth(i);
53493 getLockedCount : function(){
53494 for(var i = 0, len = this.config.length; i < len; i++){
53495 if(!this.isLocked(i)){
53502 * Returns the number of columns.
53505 getColumnCount : function(visibleOnly){
53506 if(visibleOnly === true){
53508 for(var i = 0, len = this.config.length; i < len; i++){
53509 if(!this.isHidden(i)){
53515 return this.config.length;
53519 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
53520 * @param {Function} fn
53521 * @param {Object} scope (optional)
53522 * @return {Array} result
53524 getColumnsBy : function(fn, scope){
53526 for(var i = 0, len = this.config.length; i < len; i++){
53527 var c = this.config[i];
53528 if(fn.call(scope||this, c, i) === true){
53536 * Returns true if the specified column is sortable.
53537 * @param {Number} col The column index
53538 * @return {Boolean}
53540 isSortable : function(col){
53541 if(typeof this.config[col].sortable == "undefined"){
53542 return this.defaultSortable;
53544 return this.config[col].sortable;
53548 * Returns the rendering (formatting) function defined for the column.
53549 * @param {Number} col The column index.
53550 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
53552 getRenderer : function(col){
53553 if(!this.config[col].renderer){
53554 return Roo.grid.ColumnModel.defaultRenderer;
53556 return this.config[col].renderer;
53560 * Sets the rendering (formatting) function for a column.
53561 * @param {Number} col The column index
53562 * @param {Function} fn The function to use to process the cell's raw data
53563 * to return HTML markup for the grid view. The render function is called with
53564 * the following parameters:<ul>
53565 * <li>Data value.</li>
53566 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
53567 * <li>css A CSS style string to apply to the table cell.</li>
53568 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
53569 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
53570 * <li>Row index</li>
53571 * <li>Column index</li>
53572 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
53574 setRenderer : function(col, fn){
53575 this.config[col].renderer = fn;
53579 * Returns the width for the specified column.
53580 * @param {Number} col The column index
53583 getColumnWidth : function(col){
53584 return this.config[col].width * 1 || this.defaultWidth;
53588 * Sets the width for a column.
53589 * @param {Number} col The column index
53590 * @param {Number} width The new width
53592 setColumnWidth : function(col, width, suppressEvent){
53593 this.config[col].width = width;
53594 this.totalWidth = null;
53595 if(!suppressEvent){
53596 this.fireEvent("widthchange", this, col, width);
53601 * Returns the total width of all columns.
53602 * @param {Boolean} includeHidden True to include hidden column widths
53605 getTotalWidth : function(includeHidden){
53606 if(!this.totalWidth){
53607 this.totalWidth = 0;
53608 for(var i = 0, len = this.config.length; i < len; i++){
53609 if(includeHidden || !this.isHidden(i)){
53610 this.totalWidth += this.getColumnWidth(i);
53614 return this.totalWidth;
53618 * Returns the header for the specified column.
53619 * @param {Number} col The column index
53622 getColumnHeader : function(col){
53623 return this.config[col].header;
53627 * Sets the header for a column.
53628 * @param {Number} col The column index
53629 * @param {String} header The new header
53631 setColumnHeader : function(col, header){
53632 this.config[col].header = header;
53633 this.fireEvent("headerchange", this, col, header);
53637 * Returns the tooltip for the specified column.
53638 * @param {Number} col The column index
53641 getColumnTooltip : function(col){
53642 return this.config[col].tooltip;
53645 * Sets the tooltip for a column.
53646 * @param {Number} col The column index
53647 * @param {String} tooltip The new tooltip
53649 setColumnTooltip : function(col, tooltip){
53650 this.config[col].tooltip = tooltip;
53654 * Returns the dataIndex for the specified column.
53655 * @param {Number} col The column index
53658 getDataIndex : function(col){
53659 return this.config[col].dataIndex;
53663 * Sets the dataIndex for a column.
53664 * @param {Number} col The column index
53665 * @param {Number} dataIndex The new dataIndex
53667 setDataIndex : function(col, dataIndex){
53668 this.config[col].dataIndex = dataIndex;
53674 * Returns true if the cell is editable.
53675 * @param {Number} colIndex The column index
53676 * @param {Number} rowIndex The row index
53677 * @return {Boolean}
53679 isCellEditable : function(colIndex, rowIndex){
53680 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
53684 * Returns the editor defined for the cell/column.
53685 * return false or null to disable editing.
53686 * @param {Number} colIndex The column index
53687 * @param {Number} rowIndex The row index
53690 getCellEditor : function(colIndex, rowIndex){
53691 return this.config[colIndex].editor;
53695 * Sets if a column is editable.
53696 * @param {Number} col The column index
53697 * @param {Boolean} editable True if the column is editable
53699 setEditable : function(col, editable){
53700 this.config[col].editable = editable;
53705 * Returns true if the column is hidden.
53706 * @param {Number} colIndex The column index
53707 * @return {Boolean}
53709 isHidden : function(colIndex){
53710 return this.config[colIndex].hidden;
53715 * Returns true if the column width cannot be changed
53717 isFixed : function(colIndex){
53718 return this.config[colIndex].fixed;
53722 * Returns true if the column can be resized
53723 * @return {Boolean}
53725 isResizable : function(colIndex){
53726 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
53729 * Sets if a column is hidden.
53730 * @param {Number} colIndex The column index
53731 * @param {Boolean} hidden True if the column is hidden
53733 setHidden : function(colIndex, hidden){
53734 this.config[colIndex].hidden = hidden;
53735 this.totalWidth = null;
53736 this.fireEvent("hiddenchange", this, colIndex, hidden);
53740 * Sets the editor for a column.
53741 * @param {Number} col The column index
53742 * @param {Object} editor The editor object
53744 setEditor : function(col, editor){
53745 this.config[col].editor = editor;
53749 Roo.grid.ColumnModel.defaultRenderer = function(value){
53750 if(typeof value == "string" && value.length < 1){
53756 // Alias for backwards compatibility
53757 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
53760 * Ext JS Library 1.1.1
53761 * Copyright(c) 2006-2007, Ext JS, LLC.
53763 * Originally Released Under LGPL - original licence link has changed is not relivant.
53766 * <script type="text/javascript">
53770 * @class Roo.grid.AbstractSelectionModel
53771 * @extends Roo.util.Observable
53772 * Abstract base class for grid SelectionModels. It provides the interface that should be
53773 * implemented by descendant classes. This class should not be directly instantiated.
53776 Roo.grid.AbstractSelectionModel = function(){
53777 this.locked = false;
53778 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
53781 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
53782 /** @ignore Called by the grid automatically. Do not call directly. */
53783 init : function(grid){
53789 * Locks the selections.
53792 this.locked = true;
53796 * Unlocks the selections.
53798 unlock : function(){
53799 this.locked = false;
53803 * Returns true if the selections are locked.
53804 * @return {Boolean}
53806 isLocked : function(){
53807 return this.locked;
53811 * Ext JS Library 1.1.1
53812 * Copyright(c) 2006-2007, Ext JS, LLC.
53814 * Originally Released Under LGPL - original licence link has changed is not relivant.
53817 * <script type="text/javascript">
53820 * @extends Roo.grid.AbstractSelectionModel
53821 * @class Roo.grid.RowSelectionModel
53822 * The default SelectionModel used by {@link Roo.grid.Grid}.
53823 * It supports multiple selections and keyboard selection/navigation.
53825 * @param {Object} config
53827 Roo.grid.RowSelectionModel = function(config){
53828 Roo.apply(this, config);
53829 this.selections = new Roo.util.MixedCollection(false, function(o){
53834 this.lastActive = false;
53838 * @event selectionchange
53839 * Fires when the selection changes
53840 * @param {SelectionModel} this
53842 "selectionchange" : true,
53844 * @event afterselectionchange
53845 * Fires after the selection changes (eg. by key press or clicking)
53846 * @param {SelectionModel} this
53848 "afterselectionchange" : true,
53850 * @event beforerowselect
53851 * Fires when a row is selected being selected, return false to cancel.
53852 * @param {SelectionModel} this
53853 * @param {Number} rowIndex The selected index
53854 * @param {Boolean} keepExisting False if other selections will be cleared
53856 "beforerowselect" : true,
53859 * Fires when a row is selected.
53860 * @param {SelectionModel} this
53861 * @param {Number} rowIndex The selected index
53862 * @param {Roo.data.Record} r The record
53864 "rowselect" : true,
53866 * @event rowdeselect
53867 * Fires when a row is deselected.
53868 * @param {SelectionModel} this
53869 * @param {Number} rowIndex The selected index
53871 "rowdeselect" : true
53873 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
53874 this.locked = false;
53877 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
53879 * @cfg {Boolean} singleSelect
53880 * True to allow selection of only one row at a time (defaults to false)
53882 singleSelect : false,
53885 initEvents : function(){
53887 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
53888 this.grid.on("mousedown", this.handleMouseDown, this);
53889 }else{ // allow click to work like normal
53890 this.grid.on("rowclick", this.handleDragableRowClick, this);
53893 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
53894 "up" : function(e){
53896 this.selectPrevious(e.shiftKey);
53897 }else if(this.last !== false && this.lastActive !== false){
53898 var last = this.last;
53899 this.selectRange(this.last, this.lastActive-1);
53900 this.grid.getView().focusRow(this.lastActive);
53901 if(last !== false){
53905 this.selectFirstRow();
53907 this.fireEvent("afterselectionchange", this);
53909 "down" : function(e){
53911 this.selectNext(e.shiftKey);
53912 }else if(this.last !== false && this.lastActive !== false){
53913 var last = this.last;
53914 this.selectRange(this.last, this.lastActive+1);
53915 this.grid.getView().focusRow(this.lastActive);
53916 if(last !== false){
53920 this.selectFirstRow();
53922 this.fireEvent("afterselectionchange", this);
53927 var view = this.grid.view;
53928 view.on("refresh", this.onRefresh, this);
53929 view.on("rowupdated", this.onRowUpdated, this);
53930 view.on("rowremoved", this.onRemove, this);
53934 onRefresh : function(){
53935 var ds = this.grid.dataSource, i, v = this.grid.view;
53936 var s = this.selections;
53937 s.each(function(r){
53938 if((i = ds.indexOfId(r.id)) != -1){
53947 onRemove : function(v, index, r){
53948 this.selections.remove(r);
53952 onRowUpdated : function(v, index, r){
53953 if(this.isSelected(r)){
53954 v.onRowSelect(index);
53960 * @param {Array} records The records to select
53961 * @param {Boolean} keepExisting (optional) True to keep existing selections
53963 selectRecords : function(records, keepExisting){
53965 this.clearSelections();
53967 var ds = this.grid.dataSource;
53968 for(var i = 0, len = records.length; i < len; i++){
53969 this.selectRow(ds.indexOf(records[i]), true);
53974 * Gets the number of selected rows.
53977 getCount : function(){
53978 return this.selections.length;
53982 * Selects the first row in the grid.
53984 selectFirstRow : function(){
53989 * Select the last row.
53990 * @param {Boolean} keepExisting (optional) True to keep existing selections
53992 selectLastRow : function(keepExisting){
53993 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
53997 * Selects the row immediately following the last selected row.
53998 * @param {Boolean} keepExisting (optional) True to keep existing selections
54000 selectNext : function(keepExisting){
54001 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
54002 this.selectRow(this.last+1, keepExisting);
54003 this.grid.getView().focusRow(this.last);
54008 * Selects the row that precedes the last selected row.
54009 * @param {Boolean} keepExisting (optional) True to keep existing selections
54011 selectPrevious : function(keepExisting){
54013 this.selectRow(this.last-1, keepExisting);
54014 this.grid.getView().focusRow(this.last);
54019 * Returns the selected records
54020 * @return {Array} Array of selected records
54022 getSelections : function(){
54023 return [].concat(this.selections.items);
54027 * Returns the first selected record.
54030 getSelected : function(){
54031 return this.selections.itemAt(0);
54036 * Clears all selections.
54038 clearSelections : function(fast){
54039 if(this.locked) return;
54041 var ds = this.grid.dataSource;
54042 var s = this.selections;
54043 s.each(function(r){
54044 this.deselectRow(ds.indexOfId(r.id));
54048 this.selections.clear();
54055 * Selects all rows.
54057 selectAll : function(){
54058 if(this.locked) return;
54059 this.selections.clear();
54060 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
54061 this.selectRow(i, true);
54066 * Returns True if there is a selection.
54067 * @return {Boolean}
54069 hasSelection : function(){
54070 return this.selections.length > 0;
54074 * Returns True if the specified row is selected.
54075 * @param {Number/Record} record The record or index of the record to check
54076 * @return {Boolean}
54078 isSelected : function(index){
54079 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
54080 return (r && this.selections.key(r.id) ? true : false);
54084 * Returns True if the specified record id is selected.
54085 * @param {String} id The id of record to check
54086 * @return {Boolean}
54088 isIdSelected : function(id){
54089 return (this.selections.key(id) ? true : false);
54093 handleMouseDown : function(e, t){
54094 var view = this.grid.getView(), rowIndex;
54095 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
54098 if(e.shiftKey && this.last !== false){
54099 var last = this.last;
54100 this.selectRange(last, rowIndex, e.ctrlKey);
54101 this.last = last; // reset the last
54102 view.focusRow(rowIndex);
54104 var isSelected = this.isSelected(rowIndex);
54105 if(e.button !== 0 && isSelected){
54106 view.focusRow(rowIndex);
54107 }else if(e.ctrlKey && isSelected){
54108 this.deselectRow(rowIndex);
54109 }else if(!isSelected){
54110 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
54111 view.focusRow(rowIndex);
54114 this.fireEvent("afterselectionchange", this);
54117 handleDragableRowClick : function(grid, rowIndex, e)
54119 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
54120 this.selectRow(rowIndex, false);
54121 grid.view.focusRow(rowIndex);
54122 this.fireEvent("afterselectionchange", this);
54127 * Selects multiple rows.
54128 * @param {Array} rows Array of the indexes of the row to select
54129 * @param {Boolean} keepExisting (optional) True to keep existing selections
54131 selectRows : function(rows, keepExisting){
54133 this.clearSelections();
54135 for(var i = 0, len = rows.length; i < len; i++){
54136 this.selectRow(rows[i], true);
54141 * Selects a range of rows. All rows in between startRow and endRow are also selected.
54142 * @param {Number} startRow The index of the first row in the range
54143 * @param {Number} endRow The index of the last row in the range
54144 * @param {Boolean} keepExisting (optional) True to retain existing selections
54146 selectRange : function(startRow, endRow, keepExisting){
54147 if(this.locked) return;
54149 this.clearSelections();
54151 if(startRow <= endRow){
54152 for(var i = startRow; i <= endRow; i++){
54153 this.selectRow(i, true);
54156 for(var i = startRow; i >= endRow; i--){
54157 this.selectRow(i, true);
54163 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
54164 * @param {Number} startRow The index of the first row in the range
54165 * @param {Number} endRow The index of the last row in the range
54167 deselectRange : function(startRow, endRow, preventViewNotify){
54168 if(this.locked) return;
54169 for(var i = startRow; i <= endRow; i++){
54170 this.deselectRow(i, preventViewNotify);
54176 * @param {Number} row The index of the row to select
54177 * @param {Boolean} keepExisting (optional) True to keep existing selections
54179 selectRow : function(index, keepExisting, preventViewNotify){
54180 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
54181 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
54182 if(!keepExisting || this.singleSelect){
54183 this.clearSelections();
54185 var r = this.grid.dataSource.getAt(index);
54186 this.selections.add(r);
54187 this.last = this.lastActive = index;
54188 if(!preventViewNotify){
54189 this.grid.getView().onRowSelect(index);
54191 this.fireEvent("rowselect", this, index, r);
54192 this.fireEvent("selectionchange", this);
54198 * @param {Number} row The index of the row to deselect
54200 deselectRow : function(index, preventViewNotify){
54201 if(this.locked) return;
54202 if(this.last == index){
54205 if(this.lastActive == index){
54206 this.lastActive = false;
54208 var r = this.grid.dataSource.getAt(index);
54209 this.selections.remove(r);
54210 if(!preventViewNotify){
54211 this.grid.getView().onRowDeselect(index);
54213 this.fireEvent("rowdeselect", this, index);
54214 this.fireEvent("selectionchange", this);
54218 restoreLast : function(){
54220 this.last = this._last;
54225 acceptsNav : function(row, col, cm){
54226 return !cm.isHidden(col) && cm.isCellEditable(col, row);
54230 onEditorKey : function(field, e){
54231 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
54236 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
54238 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
54240 }else if(k == e.ENTER && !e.ctrlKey){
54244 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
54246 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
54248 }else if(k == e.ESC){
54252 g.startEditing(newCell[0], newCell[1]);
54257 * Ext JS Library 1.1.1
54258 * Copyright(c) 2006-2007, Ext JS, LLC.
54260 * Originally Released Under LGPL - original licence link has changed is not relivant.
54263 * <script type="text/javascript">
54266 * @class Roo.grid.CellSelectionModel
54267 * @extends Roo.grid.AbstractSelectionModel
54268 * This class provides the basic implementation for cell selection in a grid.
54270 * @param {Object} config The object containing the configuration of this model.
54271 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
54273 Roo.grid.CellSelectionModel = function(config){
54274 Roo.apply(this, config);
54276 this.selection = null;
54280 * @event beforerowselect
54281 * Fires before a cell is selected.
54282 * @param {SelectionModel} this
54283 * @param {Number} rowIndex The selected row index
54284 * @param {Number} colIndex The selected cell index
54286 "beforecellselect" : true,
54288 * @event cellselect
54289 * Fires when a cell is selected.
54290 * @param {SelectionModel} this
54291 * @param {Number} rowIndex The selected row index
54292 * @param {Number} colIndex The selected cell index
54294 "cellselect" : true,
54296 * @event selectionchange
54297 * Fires when the active selection changes.
54298 * @param {SelectionModel} this
54299 * @param {Object} selection null for no selection or an object (o) with two properties
54301 <li>o.record: the record object for the row the selection is in</li>
54302 <li>o.cell: An array of [rowIndex, columnIndex]</li>
54305 "selectionchange" : true,
54308 * Fires when the tab (or enter) was pressed on the last editable cell
54309 * You can use this to trigger add new row.
54310 * @param {SelectionModel} this
54314 * @event beforeeditnext
54315 * Fires before the next editable sell is made active
54316 * You can use this to skip to another cell or fire the tabend
54317 * if you set cell to false
54318 * @param {Object} eventdata object : { cell : [ row, col ] }
54320 "beforeeditnext" : true
54322 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
54325 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
54327 enter_is_tab: false,
54330 initEvents : function(){
54331 this.grid.on("mousedown", this.handleMouseDown, this);
54332 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
54333 var view = this.grid.view;
54334 view.on("refresh", this.onViewChange, this);
54335 view.on("rowupdated", this.onRowUpdated, this);
54336 view.on("beforerowremoved", this.clearSelections, this);
54337 view.on("beforerowsinserted", this.clearSelections, this);
54338 if(this.grid.isEditor){
54339 this.grid.on("beforeedit", this.beforeEdit, this);
54344 beforeEdit : function(e){
54345 this.select(e.row, e.column, false, true, e.record);
54349 onRowUpdated : function(v, index, r){
54350 if(this.selection && this.selection.record == r){
54351 v.onCellSelect(index, this.selection.cell[1]);
54356 onViewChange : function(){
54357 this.clearSelections(true);
54361 * Returns the currently selected cell,.
54362 * @return {Array} The selected cell (row, column) or null if none selected.
54364 getSelectedCell : function(){
54365 return this.selection ? this.selection.cell : null;
54369 * Clears all selections.
54370 * @param {Boolean} true to prevent the gridview from being notified about the change.
54372 clearSelections : function(preventNotify){
54373 var s = this.selection;
54375 if(preventNotify !== true){
54376 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
54378 this.selection = null;
54379 this.fireEvent("selectionchange", this, null);
54384 * Returns true if there is a selection.
54385 * @return {Boolean}
54387 hasSelection : function(){
54388 return this.selection ? true : false;
54392 handleMouseDown : function(e, t){
54393 var v = this.grid.getView();
54394 if(this.isLocked()){
54397 var row = v.findRowIndex(t);
54398 var cell = v.findCellIndex(t);
54399 if(row !== false && cell !== false){
54400 this.select(row, cell);
54406 * @param {Number} rowIndex
54407 * @param {Number} collIndex
54409 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
54410 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
54411 this.clearSelections();
54412 r = r || this.grid.dataSource.getAt(rowIndex);
54415 cell : [rowIndex, colIndex]
54417 if(!preventViewNotify){
54418 var v = this.grid.getView();
54419 v.onCellSelect(rowIndex, colIndex);
54420 if(preventFocus !== true){
54421 v.focusCell(rowIndex, colIndex);
54424 this.fireEvent("cellselect", this, rowIndex, colIndex);
54425 this.fireEvent("selectionchange", this, this.selection);
54430 isSelectable : function(rowIndex, colIndex, cm){
54431 return !cm.isHidden(colIndex);
54435 handleKeyDown : function(e){
54436 //Roo.log('Cell Sel Model handleKeyDown');
54437 if(!e.isNavKeyPress()){
54440 var g = this.grid, s = this.selection;
54443 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
54445 this.select(cell[0], cell[1]);
54450 var walk = function(row, col, step){
54451 return g.walkCells(row, col, step, sm.isSelectable, sm);
54453 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
54460 // handled by onEditorKey
54461 if (g.isEditor && g.editing) {
54465 newCell = walk(r, c-1, -1);
54467 newCell = walk(r, c+1, 1);
54472 newCell = walk(r+1, c, 1);
54476 newCell = walk(r-1, c, -1);
54480 newCell = walk(r, c+1, 1);
54484 newCell = walk(r, c-1, -1);
54489 if(g.isEditor && !g.editing){
54490 g.startEditing(r, c);
54499 this.select(newCell[0], newCell[1]);
54505 acceptsNav : function(row, col, cm){
54506 return !cm.isHidden(col) && cm.isCellEditable(col, row);
54510 * @param {Number} field (not used) - as it's normally used as a listener
54511 * @param {Number} e - event - fake it by using
54513 * var e = Roo.EventObjectImpl.prototype;
54514 * e.keyCode = e.TAB
54518 onEditorKey : function(field, e){
54520 var k = e.getKey(),
54523 ed = g.activeEditor,
54525 ///Roo.log('onEditorKey' + k);
54528 if (this.enter_is_tab && k == e.ENTER) {
54534 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
54536 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
54542 } else if(k == e.ENTER && !e.ctrlKey){
54545 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
54547 } else if(k == e.ESC){
54552 var ecall = { cell : newCell, forward : forward };
54553 this.fireEvent('beforeeditnext', ecall );
54554 newCell = ecall.cell;
54555 forward = ecall.forward;
54559 //Roo.log('next cell after edit');
54560 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
54561 } else if (forward) {
54562 // tabbed past last
54563 this.fireEvent.defer(100, this, ['tabend',this]);
54568 * Ext JS Library 1.1.1
54569 * Copyright(c) 2006-2007, Ext JS, LLC.
54571 * Originally Released Under LGPL - original licence link has changed is not relivant.
54574 * <script type="text/javascript">
54578 * @class Roo.grid.EditorGrid
54579 * @extends Roo.grid.Grid
54580 * Class for creating and editable grid.
54581 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
54582 * The container MUST have some type of size defined for the grid to fill. The container will be
54583 * automatically set to position relative if it isn't already.
54584 * @param {Object} dataSource The data model to bind to
54585 * @param {Object} colModel The column model with info about this grid's columns
54587 Roo.grid.EditorGrid = function(container, config){
54588 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
54589 this.getGridEl().addClass("xedit-grid");
54591 if(!this.selModel){
54592 this.selModel = new Roo.grid.CellSelectionModel();
54595 this.activeEditor = null;
54599 * @event beforeedit
54600 * Fires before cell editing is triggered. The edit event object has the following properties <br />
54601 * <ul style="padding:5px;padding-left:16px;">
54602 * <li>grid - This grid</li>
54603 * <li>record - The record being edited</li>
54604 * <li>field - The field name being edited</li>
54605 * <li>value - The value for the field being edited.</li>
54606 * <li>row - The grid row index</li>
54607 * <li>column - The grid column index</li>
54608 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
54610 * @param {Object} e An edit event (see above for description)
54612 "beforeedit" : true,
54615 * Fires after a cell is edited. <br />
54616 * <ul style="padding:5px;padding-left:16px;">
54617 * <li>grid - This grid</li>
54618 * <li>record - The record being edited</li>
54619 * <li>field - The field name being edited</li>
54620 * <li>value - The value being set</li>
54621 * <li>originalValue - The original value for the field, before the edit.</li>
54622 * <li>row - The grid row index</li>
54623 * <li>column - The grid column index</li>
54625 * @param {Object} e An edit event (see above for description)
54627 "afteredit" : true,
54629 * @event validateedit
54630 * Fires after a cell is edited, but before the value is set in the record.
54631 * You can use this to modify the value being set in the field, Return false
54632 * to cancel the change. The edit event object has the following properties <br />
54633 * <ul style="padding:5px;padding-left:16px;">
54634 * <li>editor - This editor</li>
54635 * <li>grid - This grid</li>
54636 * <li>record - The record being edited</li>
54637 * <li>field - The field name being edited</li>
54638 * <li>value - The value being set</li>
54639 * <li>originalValue - The original value for the field, before the edit.</li>
54640 * <li>row - The grid row index</li>
54641 * <li>column - The grid column index</li>
54642 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
54644 * @param {Object} e An edit event (see above for description)
54646 "validateedit" : true
54648 this.on("bodyscroll", this.stopEditing, this);
54649 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
54652 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
54654 * @cfg {Number} clicksToEdit
54655 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
54662 trackMouseOver: false, // causes very odd FF errors
54664 onCellDblClick : function(g, row, col){
54665 this.startEditing(row, col);
54668 onEditComplete : function(ed, value, startValue){
54669 this.editing = false;
54670 this.activeEditor = null;
54671 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
54673 var field = this.colModel.getDataIndex(ed.col);
54678 originalValue: startValue,
54685 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
54688 if(String(value) !== String(startValue)){
54690 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
54691 r.set(field, e.value);
54692 // if we are dealing with a combo box..
54693 // then we also set the 'name' colum to be the displayField
54694 if (ed.field.displayField && ed.field.name) {
54695 r.set(ed.field.name, ed.field.el.dom.value);
54698 delete e.cancel; //?? why!!!
54699 this.fireEvent("afteredit", e);
54702 this.fireEvent("afteredit", e); // always fire it!
54704 this.view.focusCell(ed.row, ed.col);
54708 * Starts editing the specified for the specified row/column
54709 * @param {Number} rowIndex
54710 * @param {Number} colIndex
54712 startEditing : function(row, col){
54713 this.stopEditing();
54714 if(this.colModel.isCellEditable(col, row)){
54715 this.view.ensureVisible(row, col, true);
54717 var r = this.dataSource.getAt(row);
54718 var field = this.colModel.getDataIndex(col);
54719 var cell = Roo.get(this.view.getCell(row,col));
54724 value: r.data[field],
54729 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
54730 this.editing = true;
54731 var ed = this.colModel.getCellEditor(col, row);
54737 ed.render(ed.parentEl || document.body);
54743 (function(){ // complex but required for focus issues in safari, ie and opera
54747 ed.on("complete", this.onEditComplete, this, {single: true});
54748 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
54749 this.activeEditor = ed;
54750 var v = r.data[field];
54751 ed.startEdit(this.view.getCell(row, col), v);
54752 // combo's with 'displayField and name set
54753 if (ed.field.displayField && ed.field.name) {
54754 ed.field.el.dom.value = r.data[ed.field.name];
54758 }).defer(50, this);
54764 * Stops any active editing
54766 stopEditing : function(){
54767 if(this.activeEditor){
54768 this.activeEditor.completeEdit();
54770 this.activeEditor = null;
54774 * Called to get grid's drag proxy text, by default returns this.ddText.
54777 getDragDropText : function(){
54778 var count = this.selModel.getSelectedCell() ? 1 : 0;
54779 return String.format(this.ddText, count, count == 1 ? '' : 's');
54784 * Ext JS Library 1.1.1
54785 * Copyright(c) 2006-2007, Ext JS, LLC.
54787 * Originally Released Under LGPL - original licence link has changed is not relivant.
54790 * <script type="text/javascript">
54793 // private - not really -- you end up using it !
54794 // This is a support class used internally by the Grid components
54797 * @class Roo.grid.GridEditor
54798 * @extends Roo.Editor
54799 * Class for creating and editable grid elements.
54800 * @param {Object} config any settings (must include field)
54802 Roo.grid.GridEditor = function(field, config){
54803 if (!config && field.field) {
54805 field = Roo.factory(config.field, Roo.form);
54807 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
54808 field.monitorTab = false;
54811 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
54814 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
54817 alignment: "tl-tl",
54820 cls: "x-small-editor x-grid-editor",
54825 * Ext JS Library 1.1.1
54826 * Copyright(c) 2006-2007, Ext JS, LLC.
54828 * Originally Released Under LGPL - original licence link has changed is not relivant.
54831 * <script type="text/javascript">
54836 Roo.grid.PropertyRecord = Roo.data.Record.create([
54837 {name:'name',type:'string'}, 'value'
54841 Roo.grid.PropertyStore = function(grid, source){
54843 this.store = new Roo.data.Store({
54844 recordType : Roo.grid.PropertyRecord
54846 this.store.on('update', this.onUpdate, this);
54848 this.setSource(source);
54850 Roo.grid.PropertyStore.superclass.constructor.call(this);
54855 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
54856 setSource : function(o){
54858 this.store.removeAll();
54861 if(this.isEditableValue(o[k])){
54862 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
54865 this.store.loadRecords({records: data}, {}, true);
54868 onUpdate : function(ds, record, type){
54869 if(type == Roo.data.Record.EDIT){
54870 var v = record.data['value'];
54871 var oldValue = record.modified['value'];
54872 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
54873 this.source[record.id] = v;
54875 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
54882 getProperty : function(row){
54883 return this.store.getAt(row);
54886 isEditableValue: function(val){
54887 if(val && val instanceof Date){
54889 }else if(typeof val == 'object' || typeof val == 'function'){
54895 setValue : function(prop, value){
54896 this.source[prop] = value;
54897 this.store.getById(prop).set('value', value);
54900 getSource : function(){
54901 return this.source;
54905 Roo.grid.PropertyColumnModel = function(grid, store){
54908 g.PropertyColumnModel.superclass.constructor.call(this, [
54909 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
54910 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
54912 this.store = store;
54913 this.bselect = Roo.DomHelper.append(document.body, {
54914 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
54915 {tag: 'option', value: 'true', html: 'true'},
54916 {tag: 'option', value: 'false', html: 'false'}
54919 Roo.id(this.bselect);
54922 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
54923 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
54924 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
54925 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
54926 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
54928 this.renderCellDelegate = this.renderCell.createDelegate(this);
54929 this.renderPropDelegate = this.renderProp.createDelegate(this);
54932 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
54936 valueText : 'Value',
54938 dateFormat : 'm/j/Y',
54941 renderDate : function(dateVal){
54942 return dateVal.dateFormat(this.dateFormat);
54945 renderBool : function(bVal){
54946 return bVal ? 'true' : 'false';
54949 isCellEditable : function(colIndex, rowIndex){
54950 return colIndex == 1;
54953 getRenderer : function(col){
54955 this.renderCellDelegate : this.renderPropDelegate;
54958 renderProp : function(v){
54959 return this.getPropertyName(v);
54962 renderCell : function(val){
54964 if(val instanceof Date){
54965 rv = this.renderDate(val);
54966 }else if(typeof val == 'boolean'){
54967 rv = this.renderBool(val);
54969 return Roo.util.Format.htmlEncode(rv);
54972 getPropertyName : function(name){
54973 var pn = this.grid.propertyNames;
54974 return pn && pn[name] ? pn[name] : name;
54977 getCellEditor : function(colIndex, rowIndex){
54978 var p = this.store.getProperty(rowIndex);
54979 var n = p.data['name'], val = p.data['value'];
54981 if(typeof(this.grid.customEditors[n]) == 'string'){
54982 return this.editors[this.grid.customEditors[n]];
54984 if(typeof(this.grid.customEditors[n]) != 'undefined'){
54985 return this.grid.customEditors[n];
54987 if(val instanceof Date){
54988 return this.editors['date'];
54989 }else if(typeof val == 'number'){
54990 return this.editors['number'];
54991 }else if(typeof val == 'boolean'){
54992 return this.editors['boolean'];
54994 return this.editors['string'];
55000 * @class Roo.grid.PropertyGrid
55001 * @extends Roo.grid.EditorGrid
55002 * This class represents the interface of a component based property grid control.
55003 * <br><br>Usage:<pre><code>
55004 var grid = new Roo.grid.PropertyGrid("my-container-id", {
55012 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55013 * The container MUST have some type of size defined for the grid to fill. The container will be
55014 * automatically set to position relative if it isn't already.
55015 * @param {Object} config A config object that sets properties on this grid.
55017 Roo.grid.PropertyGrid = function(container, config){
55018 config = config || {};
55019 var store = new Roo.grid.PropertyStore(this);
55020 this.store = store;
55021 var cm = new Roo.grid.PropertyColumnModel(this, store);
55022 store.store.sort('name', 'ASC');
55023 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
55026 enableColLock:false,
55027 enableColumnMove:false,
55029 trackMouseOver: false,
55032 this.getGridEl().addClass('x-props-grid');
55033 this.lastEditRow = null;
55034 this.on('columnresize', this.onColumnResize, this);
55037 * @event beforepropertychange
55038 * Fires before a property changes (return false to stop?)
55039 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
55040 * @param {String} id Record Id
55041 * @param {String} newval New Value
55042 * @param {String} oldval Old Value
55044 "beforepropertychange": true,
55046 * @event propertychange
55047 * Fires after a property changes
55048 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
55049 * @param {String} id Record Id
55050 * @param {String} newval New Value
55051 * @param {String} oldval Old Value
55053 "propertychange": true
55055 this.customEditors = this.customEditors || {};
55057 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
55060 * @cfg {Object} customEditors map of colnames=> custom editors.
55061 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
55062 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
55063 * false disables editing of the field.
55067 * @cfg {Object} propertyNames map of property Names to their displayed value
55070 render : function(){
55071 Roo.grid.PropertyGrid.superclass.render.call(this);
55072 this.autoSize.defer(100, this);
55075 autoSize : function(){
55076 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
55078 this.view.fitColumns();
55082 onColumnResize : function(){
55083 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
55087 * Sets the data for the Grid
55088 * accepts a Key => Value object of all the elements avaiable.
55089 * @param {Object} data to appear in grid.
55091 setSource : function(source){
55092 this.store.setSource(source);
55096 * Gets all the data from the grid.
55097 * @return {Object} data data stored in grid
55099 getSource : function(){
55100 return this.store.getSource();
55104 * Ext JS Library 1.1.1
55105 * Copyright(c) 2006-2007, Ext JS, LLC.
55107 * Originally Released Under LGPL - original licence link has changed is not relivant.
55110 * <script type="text/javascript">
55114 * @class Roo.LoadMask
55115 * A simple utility class for generically masking elements while loading data. If the element being masked has
55116 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
55117 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
55118 * element's UpdateManager load indicator and will be destroyed after the initial load.
55120 * Create a new LoadMask
55121 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
55122 * @param {Object} config The config object
55124 Roo.LoadMask = function(el, config){
55125 this.el = Roo.get(el);
55126 Roo.apply(this, config);
55128 this.store.on('beforeload', this.onBeforeLoad, this);
55129 this.store.on('load', this.onLoad, this);
55130 this.store.on('loadexception', this.onLoadException, this);
55131 this.removeMask = false;
55133 var um = this.el.getUpdateManager();
55134 um.showLoadIndicator = false; // disable the default indicator
55135 um.on('beforeupdate', this.onBeforeLoad, this);
55136 um.on('update', this.onLoad, this);
55137 um.on('failure', this.onLoad, this);
55138 this.removeMask = true;
55142 Roo.LoadMask.prototype = {
55144 * @cfg {Boolean} removeMask
55145 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
55146 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
55149 * @cfg {String} msg
55150 * The text to display in a centered loading message box (defaults to 'Loading...')
55152 msg : 'Loading...',
55154 * @cfg {String} msgCls
55155 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
55157 msgCls : 'x-mask-loading',
55160 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
55166 * Disables the mask to prevent it from being displayed
55168 disable : function(){
55169 this.disabled = true;
55173 * Enables the mask so that it can be displayed
55175 enable : function(){
55176 this.disabled = false;
55179 onLoadException : function()
55181 Roo.log(arguments);
55183 if (typeof(arguments[3]) != 'undefined') {
55184 Roo.MessageBox.alert("Error loading",arguments[3]);
55188 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
55189 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
55198 this.el.unmask(this.removeMask);
55201 onLoad : function()
55203 this.el.unmask(this.removeMask);
55207 onBeforeLoad : function(){
55208 if(!this.disabled){
55209 this.el.mask(this.msg, this.msgCls);
55214 destroy : function(){
55216 this.store.un('beforeload', this.onBeforeLoad, this);
55217 this.store.un('load', this.onLoad, this);
55218 this.store.un('loadexception', this.onLoadException, this);
55220 var um = this.el.getUpdateManager();
55221 um.un('beforeupdate', this.onBeforeLoad, this);
55222 um.un('update', this.onLoad, this);
55223 um.un('failure', this.onLoad, this);
55228 * Ext JS Library 1.1.1
55229 * Copyright(c) 2006-2007, Ext JS, LLC.
55231 * Originally Released Under LGPL - original licence link has changed is not relivant.
55234 * <script type="text/javascript">
55239 * @class Roo.XTemplate
55240 * @extends Roo.Template
55241 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
55243 var t = new Roo.XTemplate(
55244 '<select name="{name}">',
55245 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
55249 // then append, applying the master template values
55252 * Supported features:
55257 {a_variable} - output encoded.
55258 {a_variable.format:("Y-m-d")} - call a method on the variable
55259 {a_variable:raw} - unencoded output
55260 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
55261 {a_variable:this.method_on_template(...)} - call a method on the template object.
55266 <tpl for="a_variable or condition.."></tpl>
55267 <tpl if="a_variable or condition"></tpl>
55268 <tpl exec="some javascript"></tpl>
55269 <tpl name="named_template"></tpl> (experimental)
55271 <tpl for="."></tpl> - just iterate the property..
55272 <tpl for=".."></tpl> - iterates with the parent (probably the template)
55276 Roo.XTemplate = function()
55278 Roo.XTemplate.superclass.constructor.apply(this, arguments);
55285 Roo.extend(Roo.XTemplate, Roo.Template, {
55288 * The various sub templates
55293 * basic tag replacing syntax
55296 * // you can fake an object call by doing this
55300 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
55303 * compile the template
55305 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
55308 compile: function()
55312 s = ['<tpl>', s, '</tpl>'].join('');
55314 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
55315 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
55316 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
55317 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
55318 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
55323 while(true == !!(m = s.match(re))){
55324 var forMatch = m[0].match(nameRe),
55325 ifMatch = m[0].match(ifRe),
55326 execMatch = m[0].match(execRe),
55327 namedMatch = m[0].match(namedRe),
55332 name = forMatch && forMatch[1] ? forMatch[1] : '';
55335 // if - puts fn into test..
55336 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
55338 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
55343 // exec - calls a function... returns empty if true is returned.
55344 exp = execMatch && execMatch[1] ? execMatch[1] : null;
55346 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
55354 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
55355 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
55356 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
55359 var uid = namedMatch ? namedMatch[1] : id;
55363 id: namedMatch ? namedMatch[1] : id,
55370 s = s.replace(m[0], '');
55372 s = s.replace(m[0], '{xtpl'+ id + '}');
55377 for(var i = tpls.length-1; i >= 0; --i){
55378 this.compileTpl(tpls[i]);
55379 this.tpls[tpls[i].id] = tpls[i];
55381 this.master = tpls[tpls.length-1];
55385 * same as applyTemplate, except it's done to one of the subTemplates
55386 * when using named templates, you can do:
55388 * var str = pl.applySubTemplate('your-name', values);
55391 * @param {Number} id of the template
55392 * @param {Object} values to apply to template
55393 * @param {Object} parent (normaly the instance of this object)
55395 applySubTemplate : function(id, values, parent)
55399 var t = this.tpls[id];
55403 if(t.test && !t.test.call(this, values, parent)){
55407 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
55408 Roo.log(e.toString());
55414 if(t.exec && t.exec.call(this, values, parent)){
55418 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
55419 Roo.log(e.toString());
55424 var vs = t.target ? t.target.call(this, values, parent) : values;
55425 parent = t.target ? values : parent;
55426 if(t.target && vs instanceof Array){
55428 for(var i = 0, len = vs.length; i < len; i++){
55429 buf[buf.length] = t.compiled.call(this, vs[i], parent);
55431 return buf.join('');
55433 return t.compiled.call(this, vs, parent);
55435 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
55436 Roo.log(e.toString());
55437 Roo.log(t.compiled);
55442 compileTpl : function(tpl)
55444 var fm = Roo.util.Format;
55445 var useF = this.disableFormats !== true;
55446 var sep = Roo.isGecko ? "+" : ",";
55447 var undef = function(str) {
55448 Roo.log("Property not found :" + str);
55452 var fn = function(m, name, format, args)
55454 //Roo.log(arguments);
55455 args = args ? args.replace(/\\'/g,"'") : args;
55456 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
55457 if (typeof(format) == 'undefined') {
55458 format= 'htmlEncode';
55460 if (format == 'raw' ) {
55464 if(name.substr(0, 4) == 'xtpl'){
55465 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
55468 // build an array of options to determine if value is undefined..
55470 // basically get 'xxxx.yyyy' then do
55471 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
55472 // (function () { Roo.log("Property not found"); return ''; })() :
55477 Roo.each(name.split('.'), function(st) {
55478 lookfor += (lookfor.length ? '.': '') + st;
55479 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
55482 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
55485 if(format && useF){
55487 args = args ? ',' + args : "";
55489 if(format.substr(0, 5) != "this."){
55490 format = "fm." + format + '(';
55492 format = 'this.call("'+ format.substr(5) + '", ';
55496 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
55500 // called with xxyx.yuu:(test,test)
55502 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
55504 // raw.. - :raw modifier..
55505 return "'"+ sep + udef_st + name + ")"+sep+"'";
55509 // branched to use + in gecko and [].join() in others
55511 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
55512 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
55515 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
55516 body.push(tpl.body.replace(/(\r\n|\n)/g,
55517 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
55518 body.push("'].join('');};};");
55519 body = body.join('');
55522 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
55524 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
55530 applyTemplate : function(values){
55531 return this.master.compiled.call(this, values, {});
55532 //var s = this.subs;
55535 apply : function(){
55536 return this.applyTemplate.apply(this, arguments);
55541 Roo.XTemplate.from = function(el){
55542 el = Roo.getDom(el);
55543 return new Roo.XTemplate(el.value || el.innerHTML);
55545 * Original code for Roojs - LGPL
55546 * <script type="text/javascript">
55550 * @class Roo.XComponent
55551 * A delayed Element creator...
55552 * Or a way to group chunks of interface together.
55554 * Mypart.xyx = new Roo.XComponent({
55556 parent : 'Mypart.xyz', // empty == document.element.!!
55560 disabled : function() {}
55562 tree : function() { // return an tree of xtype declared components
55566 xtype : 'NestedLayoutPanel',
55573 * It can be used to build a big heiracy, with parent etc.
55574 * or you can just use this to render a single compoent to a dom element
55575 * MYPART.render(Roo.Element | String(id) | dom_element )
55577 * @extends Roo.util.Observable
55579 * @param cfg {Object} configuration of component
55582 Roo.XComponent = function(cfg) {
55583 Roo.apply(this, cfg);
55587 * Fires when this the componnt is built
55588 * @param {Roo.XComponent} c the component
55593 this.region = this.region || 'center'; // default..
55594 Roo.XComponent.register(this);
55595 this.modules = false;
55596 this.el = false; // where the layout goes..
55600 Roo.extend(Roo.XComponent, Roo.util.Observable, {
55603 * The created element (with Roo.factory())
55604 * @type {Roo.Layout}
55610 * for BC - use el in new code
55611 * @type {Roo.Layout}
55617 * for BC - use el in new code
55618 * @type {Roo.Layout}
55623 * @cfg {Function|boolean} disabled
55624 * If this module is disabled by some rule, return true from the funtion
55629 * @cfg {String} parent
55630 * Name of parent element which it get xtype added to..
55635 * @cfg {String} order
55636 * Used to set the order in which elements are created (usefull for multiple tabs)
55641 * @cfg {String} name
55642 * String to display while loading.
55646 * @cfg {String} region
55647 * Region to render component to (defaults to center)
55652 * @cfg {Array} items
55653 * A single item array - the first element is the root of the tree..
55654 * It's done this way to stay compatible with the Xtype system...
55660 * The method that retuns the tree of parts that make up this compoennt
55667 * render element to dom or tree
55668 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
55671 render : function(el)
55675 var hp = this.parent ? 1 : 0;
55677 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
55678 // if parent is a '#.....' string, then let's use that..
55679 var ename = this.parent.substr(1)
55680 this.parent = (this.parent == '#bootstrap') ? { el : true} : false; // flags it as a top module...
55681 el = Roo.get(ename);
55682 if (!el && !this.parent) {
55683 Roo.log("Warning - element can not be found :#" + ename );
55689 if (!this.parent) {
55691 el = el ? Roo.get(el) : false;
55693 // it's a top level one..
55695 el : new Roo.BorderLayout(el || document.body, {
55701 tabPosition: 'top',
55702 //resizeTabs: true,
55703 alwaysShowTabs: el && hp? false : true,
55704 hideTabs: el || !hp ? true : false,
55711 if (!this.parent.el) {
55712 // probably an old style ctor, which has been disabled.
55716 // The 'tree' method is '_tree now'
55718 var tree = this._tree ? this._tree() : this.tree();
55719 tree.region = tree.region || this.region;
55720 this.el = this.parent.el.addxtype(tree);
55721 this.fireEvent('built', this);
55723 this.panel = this.el;
55724 this.layout = this.panel.layout;
55725 this.parentLayout = this.parent.layout || false;
55731 Roo.apply(Roo.XComponent, {
55733 * @property hideProgress
55734 * true to disable the building progress bar.. usefull on single page renders.
55737 hideProgress : false,
55739 * @property buildCompleted
55740 * True when the builder has completed building the interface.
55743 buildCompleted : false,
55746 * @property topModule
55747 * the upper most module - uses document.element as it's constructor.
55754 * @property modules
55755 * array of modules to be created by registration system.
55756 * @type {Array} of Roo.XComponent
55761 * @property elmodules
55762 * array of modules to be created by which use #ID
55763 * @type {Array} of Roo.XComponent
55770 * Register components to be built later.
55772 * This solves the following issues
55773 * - Building is not done on page load, but after an authentication process has occured.
55774 * - Interface elements are registered on page load
55775 * - Parent Interface elements may not be loaded before child, so this handles that..
55782 module : 'Pman.Tab.projectMgr',
55784 parent : 'Pman.layout',
55785 disabled : false, // or use a function..
55788 * * @param {Object} details about module
55790 register : function(obj) {
55792 Roo.XComponent.event.fireEvent('register', obj);
55793 switch(typeof(obj.disabled) ) {
55799 if ( obj.disabled() ) {
55805 if (obj.disabled) {
55811 this.modules.push(obj);
55815 * convert a string to an object..
55816 * eg. 'AAA.BBB' -> finds AAA.BBB
55820 toObject : function(str)
55822 if (!str || typeof(str) == 'object') {
55825 if (str.substring(0,1) == '#') {
55829 var ar = str.split('.');
55834 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
55836 throw "Module not found : " + str;
55840 throw "Module not found : " + str;
55842 Roo.each(ar, function(e) {
55843 if (typeof(o[e]) == 'undefined') {
55844 throw "Module not found : " + str;
55855 * move modules into their correct place in the tree..
55858 preBuild : function ()
55861 Roo.each(this.modules , function (obj)
55863 Roo.XComponent.event.fireEvent('beforebuild', obj);
55865 var opar = obj.parent;
55867 obj.parent = this.toObject(opar);
55869 Roo.log("parent:toObject failed: " + e.toString());
55874 Roo.debug && Roo.log("GOT top level module");
55875 Roo.debug && Roo.log(obj);
55876 obj.modules = new Roo.util.MixedCollection(false,
55877 function(o) { return o.order + '' }
55879 this.topModule = obj;
55882 // parent is a string (usually a dom element name..)
55883 if (typeof(obj.parent) == 'string') {
55884 this.elmodules.push(obj);
55887 if (obj.parent.constructor != Roo.XComponent) {
55888 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
55890 if (!obj.parent.modules) {
55891 obj.parent.modules = new Roo.util.MixedCollection(false,
55892 function(o) { return o.order + '' }
55895 if (obj.parent.disabled) {
55896 obj.disabled = true;
55898 obj.parent.modules.add(obj);
55903 * make a list of modules to build.
55904 * @return {Array} list of modules.
55907 buildOrder : function()
55910 var cmp = function(a,b) {
55911 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
55913 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
55914 throw "No top level modules to build";
55917 // make a flat list in order of modules to build.
55918 var mods = this.topModule ? [ this.topModule ] : [];
55921 // elmodules (is a list of DOM based modules )
55922 Roo.each(this.elmodules, function(e) {
55924 if (!this.topModule &&
55925 typeof(e.parent) == 'string' &&
55926 e.parent.substring(0,1) == '#' &&
55927 Roo.get(e.parent.substr(1))
55930 _this.topModule = e;
55936 // add modules to their parents..
55937 var addMod = function(m) {
55938 Roo.debug && Roo.log("build Order: add: " + m.name);
55941 if (m.modules && !m.disabled) {
55942 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
55943 m.modules.keySort('ASC', cmp );
55944 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
55946 m.modules.each(addMod);
55948 Roo.debug && Roo.log("build Order: no child modules");
55950 // not sure if this is used any more..
55952 m.finalize.name = m.name + " (clean up) ";
55953 mods.push(m.finalize);
55957 if (this.topModule && this.topModule.modules) {
55958 this.topModule.modules.keySort('ASC', cmp );
55959 this.topModule.modules.each(addMod);
55965 * Build the registered modules.
55966 * @param {Object} parent element.
55967 * @param {Function} optional method to call after module has been added.
55975 var mods = this.buildOrder();
55977 //this.allmods = mods;
55978 //Roo.debug && Roo.log(mods);
55980 if (!mods.length) { // should not happen
55981 throw "NO modules!!!";
55985 var msg = "Building Interface...";
55986 // flash it up as modal - so we store the mask!?
55987 if (!this.hideProgress) {
55988 Roo.MessageBox.show({ title: 'loading' });
55989 Roo.MessageBox.show({
55990 title: "Please wait...",
55999 var total = mods.length;
56002 var progressRun = function() {
56003 if (!mods.length) {
56004 Roo.debug && Roo.log('hide?');
56005 if (!this.hideProgress) {
56006 Roo.MessageBox.hide();
56008 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
56014 var m = mods.shift();
56017 Roo.debug && Roo.log(m);
56018 // not sure if this is supported any more.. - modules that are are just function
56019 if (typeof(m) == 'function') {
56021 return progressRun.defer(10, _this);
56025 msg = "Building Interface " + (total - mods.length) +
56027 (m.name ? (' - ' + m.name) : '');
56028 Roo.debug && Roo.log(msg);
56029 if (!this.hideProgress) {
56030 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
56034 // is the module disabled?
56035 var disabled = (typeof(m.disabled) == 'function') ?
56036 m.disabled.call(m.module.disabled) : m.disabled;
56040 return progressRun(); // we do not update the display!
56048 // it's 10 on top level, and 1 on others??? why...
56049 return progressRun.defer(10, _this);
56052 progressRun.defer(1, _this);
56066 * wrapper for event.on - aliased later..
56067 * Typically use to register a event handler for register:
56069 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
56078 Roo.XComponent.event = new Roo.util.Observable({
56082 * Fires when an Component is registered,
56083 * set the disable property on the Component to stop registration.
56084 * @param {Roo.XComponent} c the component being registerd.
56089 * @event beforebuild
56090 * Fires before each Component is built
56091 * can be used to apply permissions.
56092 * @param {Roo.XComponent} c the component being registerd.
56095 'beforebuild' : true,
56097 * @event buildcomplete
56098 * Fires on the top level element when all elements have been built
56099 * @param {Roo.XComponent} the top level component.
56101 'buildcomplete' : true
56106 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);