4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
64 isTouch = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
212 sb = function(){sp.apply(this, arguments);};
214 var F = function(){}, sbp, spp = sp.prototype;
216 sbp = sb.prototype = new F();
220 if(spp.constructor == Object.prototype.constructor){
225 sb.override = function(o){
229 Roo.override(sb, overrides);
235 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
237 Roo.override(MyClass, {
238 newMethod1: function(){
241 newMethod2: function(foo){
246 * @param {Object} origclass The class to override
247 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
248 * containing one or more methods.
251 override : function(origclass, overrides){
253 var p = origclass.prototype;
254 for(var method in overrides){
255 p[method] = overrides[method];
260 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
266 * @param {String} namespace1
267 * @param {String} namespace2
268 * @param {String} etc
271 namespace : function(){
272 var a=arguments, o=null, i, j, d, rt;
273 for (i=0; i<a.length; ++i) {
277 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278 for (j=1; j<d.length; ++j) {
279 o[d[j]]=o[d[j]] || {};
285 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
290 * @param {String} classname
291 * @param {String} namespace (optional)
295 factory : function(c, ns)
297 // no xtype, no ns or c.xns - or forced off by c.xns
298 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
301 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302 if (c.constructor == ns[c.xtype]) {// already created...
306 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307 var ret = new ns[c.xtype](c);
311 c.xns = false; // prevent recursion..
315 * Logs to console if it can.
317 * @param {String|Object} string
322 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
329 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
333 urlEncode : function(o){
339 var ov = o[key], k = Roo.encodeURIComponent(key);
340 var type = typeof ov;
341 if(type == 'undefined'){
343 }else if(type != "function" && type != "object"){
344 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345 }else if(ov instanceof Array){
347 for(var i = 0, len = ov.length; i < len; i++) {
348 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
359 * Safe version of encodeURIComponent
360 * @param {String} data
364 encodeURIComponent : function (data)
367 return encodeURIComponent(data);
368 } catch(e) {} // should be an uri encode error.
370 if (data == '' || data == null){
373 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374 function nibble_to_hex(nibble){
375 var chars = '0123456789ABCDEF';
376 return chars.charAt(nibble);
378 data = data.toString();
380 for(var i=0; i<data.length; i++){
381 var c = data.charCodeAt(i);
382 var bs = new Array();
385 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388 bs[3] = 0x80 | (c & 0x3F);
389 }else if (c > 0x800){
391 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393 bs[2] = 0x80 | (c & 0x3F);
396 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397 bs[1] = 0x80 | (c & 0x3F);
402 for(var j=0; j<bs.length; j++){
404 var hex = nibble_to_hex((b & 0xF0) >>> 4)
405 + nibble_to_hex(b &0x0F);
414 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415 * @param {String} string
416 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417 * @return {Object} A literal with members
419 urlDecode : function(string, overwrite){
420 if(!string || !string.length){
424 var pairs = string.split('&');
425 var pair, name, value;
426 for(var i = 0, len = pairs.length; i < len; i++){
427 pair = pairs[i].split('=');
428 name = decodeURIComponent(pair[0]);
429 value = decodeURIComponent(pair[1]);
430 if(overwrite !== true){
431 if(typeof obj[name] == "undefined"){
433 }else if(typeof obj[name] == "string"){
434 obj[name] = [obj[name]];
435 obj[name].push(value);
437 obj[name].push(value);
447 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448 * passed array is not really an array, your function is called once with it.
449 * The supplied function is called with (Object item, Number index, Array allItems).
450 * @param {Array/NodeList/Mixed} array
451 * @param {Function} fn
452 * @param {Object} scope
454 each : function(array, fn, scope){
455 if(typeof array.length == "undefined" || typeof array == "string"){
458 for(var i = 0, len = array.length; i < len; i++){
459 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
464 combine : function(){
465 var as = arguments, l = as.length, r = [];
466 for(var i = 0; i < l; i++){
468 if(a instanceof Array){
470 }else if(a.length !== undefined && !a.substr){
471 r = r.concat(Array.prototype.slice.call(a, 0));
480 * Escapes the passed string for use in a regular expression
481 * @param {String} str
484 escapeRe : function(s) {
485 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
489 callback : function(cb, scope, args, delay){
490 if(typeof cb == "function"){
492 cb.defer(delay, scope, args || []);
494 cb.apply(scope, args || []);
500 * Return the dom node for the passed string (id), dom node, or Roo.Element
501 * @param {String/HTMLElement/Roo.Element} el
502 * @return HTMLElement
504 getDom : function(el){
508 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
512 * Shorthand for {@link Roo.ComponentMgr#get}
514 * @return Roo.Component
516 getCmp : function(id){
517 return Roo.ComponentMgr.get(id);
520 num : function(v, defaultValue){
521 if(typeof v != 'number'){
527 destroy : function(){
528 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
532 as.removeAllListeners();
536 if(typeof as.purgeListeners == 'function'){
539 if(typeof as.destroy == 'function'){
546 // inpired by a similar function in mootools library
548 * Returns the type of object that is passed in. If the object passed in is null or undefined it
549 * return false otherwise it returns one of the following values:<ul>
550 * <li><b>string</b>: If the object passed is a string</li>
551 * <li><b>number</b>: If the object passed is a number</li>
552 * <li><b>boolean</b>: If the object passed is a boolean value</li>
553 * <li><b>function</b>: If the object passed is a function reference</li>
554 * <li><b>object</b>: If the object passed is an object</li>
555 * <li><b>array</b>: If the object passed is an array</li>
556 * <li><b>regexp</b>: If the object passed is a regular expression</li>
557 * <li><b>element</b>: If the object passed is a DOM Element</li>
558 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561 * @param {Mixed} object
565 if(o === undefined || o === null){
572 if(t == 'object' && o.nodeName) {
574 case 1: return 'element';
575 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
578 if(t == 'object' || t == 'function') {
579 switch(o.constructor) {
580 case Array: return 'array';
581 case RegExp: return 'regexp';
583 if(typeof o.length == 'number' && typeof o.item == 'function') {
591 * Returns true if the passed value is null, undefined or an empty string (optional).
592 * @param {Mixed} value The value to test
593 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
596 isEmpty : function(v, allowBlank){
597 return v === null || v === undefined || (!allowBlank ? v === '' : false);
611 isBorderBox : isBorderBox,
613 isWindows : isWindows,
622 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
623 * you may want to set this to true.
626 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
631 * Selects a single element as a Roo Element
632 * This is about as close as you can get to jQuery's $('do crazy stuff')
633 * @param {String} selector The selector/xpath query
634 * @param {Node} root (optional) The start of the query (defaults to document).
635 * @return {Roo.Element}
637 selectNode : function(selector, root)
639 var node = Roo.DomQuery.selectNode(selector,root);
640 return node ? Roo.get(node) : new Roo.Element(false);
648 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
649 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
652 * Ext JS Library 1.1.1
653 * Copyright(c) 2006-2007, Ext JS, LLC.
655 * Originally Released Under LGPL - original licence link has changed is not relivant.
658 * <script type="text/javascript">
662 // wrappedn so fnCleanup is not in global scope...
664 function fnCleanUp() {
665 var p = Function.prototype;
666 delete p.createSequence;
668 delete p.createDelegate;
669 delete p.createCallback;
670 delete p.createInterceptor;
672 window.detachEvent("onunload", fnCleanUp);
674 window.attachEvent("onunload", fnCleanUp);
681 * These functions are available on every Function object (any JavaScript function).
683 Roo.apply(Function.prototype, {
685 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
686 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
687 * Will create a function that is bound to those 2 args.
688 * @return {Function} The new function
690 createCallback : function(/*args...*/){
691 // make args available, in function below
692 var args = arguments;
695 return method.apply(window, args);
700 * Creates a delegate (callback) that sets the scope to obj.
701 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
702 * Will create a function that is automatically scoped to this.
703 * @param {Object} obj (optional) The object for which the scope is set
704 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
705 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
706 * if a number the args are inserted at the specified position
707 * @return {Function} The new function
709 createDelegate : function(obj, args, appendArgs){
712 var callArgs = args || arguments;
713 if(appendArgs === true){
714 callArgs = Array.prototype.slice.call(arguments, 0);
715 callArgs = callArgs.concat(args);
716 }else if(typeof appendArgs == "number"){
717 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
718 var applyArgs = [appendArgs, 0].concat(args); // create method call params
719 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
721 return method.apply(obj || window, callArgs);
726 * Calls this function after the number of millseconds specified.
727 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
728 * @param {Object} obj (optional) The object for which the scope is set
729 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
730 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
731 * if a number the args are inserted at the specified position
732 * @return {Number} The timeout id that can be used with clearTimeout
734 defer : function(millis, obj, args, appendArgs){
735 var fn = this.createDelegate(obj, args, appendArgs);
737 return setTimeout(fn, millis);
743 * Create a combined function call sequence of the original function + the passed function.
744 * The resulting function returns the results of the original function.
745 * The passed fcn is called with the parameters of the original function
746 * @param {Function} fcn The function to sequence
747 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
748 * @return {Function} The new function
750 createSequence : function(fcn, scope){
751 if(typeof fcn != "function"){
756 var retval = method.apply(this || window, arguments);
757 fcn.apply(scope || this || window, arguments);
763 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
764 * The resulting function returns the results of the original function.
765 * The passed fcn is called with the parameters of the original function.
767 * @param {Function} fcn The function to call before the original
768 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
769 * @return {Function} The new function
771 createInterceptor : function(fcn, scope){
772 if(typeof fcn != "function"){
779 if(fcn.apply(scope || this || window, arguments) === false){
782 return method.apply(this || window, arguments);
788 * Ext JS Library 1.1.1
789 * Copyright(c) 2006-2007, Ext JS, LLC.
791 * Originally Released Under LGPL - original licence link has changed is not relivant.
794 * <script type="text/javascript">
797 Roo.applyIf(String, {
802 * Escapes the passed string for ' and \
803 * @param {String} string The string to escape
804 * @return {String} The escaped string
807 escape : function(string) {
808 return string.replace(/('|\\)/g, "\\$1");
812 * Pads the left side of a string with a specified character. This is especially useful
813 * for normalizing number and date strings. Example usage:
815 var s = String.leftPad('123', 5, '0');
816 // s now contains the string: '00123'
818 * @param {String} string The original string
819 * @param {Number} size The total length of the output string
820 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
821 * @return {String} The padded string
824 leftPad : function (val, size, ch) {
825 var result = new String(val);
826 if(ch === null || ch === undefined || ch === '') {
829 while (result.length < size) {
830 result = ch + result;
836 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
837 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
839 var cls = 'my-class', text = 'Some text';
840 var s = String.format('<div class="{0}">{1}</div>', cls, text);
841 // s now contains the string: '<div class="my-class">Some text</div>'
843 * @param {String} string The tokenized string to be formatted
844 * @param {String} value1 The value to replace token {0}
845 * @param {String} value2 Etc...
846 * @return {String} The formatted string
849 format : function(format){
850 var args = Array.prototype.slice.call(arguments, 1);
851 return format.replace(/\{(\d+)\}/g, function(m, i){
852 return Roo.util.Format.htmlEncode(args[i]);
858 * Utility function that allows you to easily switch a string between two alternating values. The passed value
859 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
860 * they are already different, the first value passed in is returned. Note that this method returns the new value
861 * but does not change the current string.
863 // alternate sort directions
864 sort = sort.toggle('ASC', 'DESC');
866 // instead of conditional logic:
867 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
869 * @param {String} value The value to compare to the current string
870 * @param {String} other The new value to use if the string already equals the first value passed in
871 * @return {String} The new value
874 String.prototype.toggle = function(value, other){
875 return this == value ? other : value;
878 * Ext JS Library 1.1.1
879 * Copyright(c) 2006-2007, Ext JS, LLC.
881 * Originally Released Under LGPL - original licence link has changed is not relivant.
884 * <script type="text/javascript">
890 Roo.applyIf(Number.prototype, {
892 * Checks whether or not the current number is within a desired range. If the number is already within the
893 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
894 * exceeded. Note that this method returns the constrained value but does not change the current number.
895 * @param {Number} min The minimum number in the range
896 * @param {Number} max The maximum number in the range
897 * @return {Number} The constrained value if outside the range, otherwise the current value
899 constrain : function(min, max){
900 return Math.min(Math.max(this, min), max);
904 * Ext JS Library 1.1.1
905 * Copyright(c) 2006-2007, Ext JS, LLC.
907 * Originally Released Under LGPL - original licence link has changed is not relivant.
910 * <script type="text/javascript">
915 Roo.applyIf(Array.prototype, {
917 * Checks whether or not the specified object exists in the array.
918 * @param {Object} o The object to check for
919 * @return {Number} The index of o in the array (or -1 if it is not found)
921 indexOf : function(o){
922 for (var i = 0, len = this.length; i < len; i++){
923 if(this[i] == o) return i;
929 * Removes the specified object from the array. If the object is not found nothing happens.
930 * @param {Object} o The object to remove
932 remove : function(o){
933 var index = this.indexOf(o);
935 this.splice(index, 1);
939 * Map (JS 1.6 compatibility)
940 * @param {Function} function to call
944 var len = this.length >>> 0;
945 if (typeof fun != "function")
946 throw new TypeError();
948 var res = new Array(len);
949 var thisp = arguments[1];
950 for (var i = 0; i < len; i++)
953 res[i] = fun.call(thisp, this[i], i, this);
964 * Ext JS Library 1.1.1
965 * Copyright(c) 2006-2007, Ext JS, LLC.
967 * Originally Released Under LGPL - original licence link has changed is not relivant.
970 * <script type="text/javascript">
976 * The date parsing and format syntax is a subset of
977 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
978 * supported will provide results equivalent to their PHP versions.
980 * Following is the list of all currently supported formats:
983 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
985 Format Output Description
986 ------ ---------- --------------------------------------------------------------
987 d 10 Day of the month, 2 digits with leading zeros
988 D Wed A textual representation of a day, three letters
989 j 10 Day of the month without leading zeros
990 l Wednesday A full textual representation of the day of the week
991 S th English ordinal day of month suffix, 2 chars (use with j)
992 w 3 Numeric representation of the day of the week
993 z 9 The julian date, or day of the year (0-365)
994 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
995 F January A full textual representation of the month
996 m 01 Numeric representation of a month, with leading zeros
997 M Jan Month name abbreviation, three letters
998 n 1 Numeric representation of a month, without leading zeros
999 t 31 Number of days in the given month
1000 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1001 Y 2007 A full numeric representation of a year, 4 digits
1002 y 07 A two digit representation of a year
1003 a pm Lowercase Ante meridiem and Post meridiem
1004 A PM Uppercase Ante meridiem and Post meridiem
1005 g 3 12-hour format of an hour without leading zeros
1006 G 15 24-hour format of an hour without leading zeros
1007 h 03 12-hour format of an hour with leading zeros
1008 H 15 24-hour format of an hour with leading zeros
1009 i 05 Minutes with leading zeros
1010 s 01 Seconds, with leading zeros
1011 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1012 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1013 T CST Timezone setting of the machine running the code
1014 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1017 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1019 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1020 document.write(dt.format('Y-m-d')); //2007-01-10
1021 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1022 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1025 * Here are some standard date/time patterns that you might find helpful. They
1026 * are not part of the source of Date.js, but to use them you can simply copy this
1027 * block of code into any script that is included after Date.js and they will also become
1028 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1031 ISO8601Long:"Y-m-d H:i:s",
1032 ISO8601Short:"Y-m-d",
1034 LongDate: "l, F d, Y",
1035 FullDateTime: "l, F d, Y g:i:s A",
1038 LongTime: "g:i:s A",
1039 SortableDateTime: "Y-m-d\\TH:i:s",
1040 UniversalSortableDateTime: "Y-m-d H:i:sO",
1047 var dt = new Date();
1048 document.write(dt.format(Date.patterns.ShortDate));
1053 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1054 * They generate precompiled functions from date formats instead of parsing and
1055 * processing the pattern every time you format a date. These functions are available
1056 * on every Date object (any javascript function).
1058 * The original article and download are here:
1059 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1066 Returns the number of milliseconds between this date and date
1067 @param {Date} date (optional) Defaults to now
1068 @return {Number} The diff in milliseconds
1069 @member Date getElapsed
1071 Date.prototype.getElapsed = function(date) {
1072 return Math.abs((date || new Date()).getTime()-this.getTime());
1074 // was in date file..
1078 Date.parseFunctions = {count:0};
1080 Date.parseRegexes = [];
1082 Date.formatFunctions = {count:0};
1085 Date.prototype.dateFormat = function(format) {
1086 if (Date.formatFunctions[format] == null) {
1087 Date.createNewFormat(format);
1089 var func = Date.formatFunctions[format];
1090 return this[func]();
1095 * Formats a date given the supplied format string
1096 * @param {String} format The format string
1097 * @return {String} The formatted date
1100 Date.prototype.format = Date.prototype.dateFormat;
1103 Date.createNewFormat = function(format) {
1104 var funcName = "format" + Date.formatFunctions.count++;
1105 Date.formatFunctions[format] = funcName;
1106 var code = "Date.prototype." + funcName + " = function(){return ";
1107 var special = false;
1109 for (var i = 0; i < format.length; ++i) {
1110 ch = format.charAt(i);
1111 if (!special && ch == "\\") {
1116 code += "'" + String.escape(ch) + "' + ";
1119 code += Date.getFormatCode(ch);
1122 /** eval:var:zzzzzzzzzzzzz */
1123 eval(code.substring(0, code.length - 3) + ";}");
1127 Date.getFormatCode = function(character) {
1128 switch (character) {
1130 return "String.leftPad(this.getDate(), 2, '0') + ";
1132 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1134 return "this.getDate() + ";
1136 return "Date.dayNames[this.getDay()] + ";
1138 return "this.getSuffix() + ";
1140 return "this.getDay() + ";
1142 return "this.getDayOfYear() + ";
1144 return "this.getWeekOfYear() + ";
1146 return "Date.monthNames[this.getMonth()] + ";
1148 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1150 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1152 return "(this.getMonth() + 1) + ";
1154 return "this.getDaysInMonth() + ";
1156 return "(this.isLeapYear() ? 1 : 0) + ";
1158 return "this.getFullYear() + ";
1160 return "('' + this.getFullYear()).substring(2, 4) + ";
1162 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1164 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1166 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1168 return "this.getHours() + ";
1170 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1172 return "String.leftPad(this.getHours(), 2, '0') + ";
1174 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1176 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1178 return "this.getGMTOffset() + ";
1180 return "this.getGMTColonOffset() + ";
1182 return "this.getTimezone() + ";
1184 return "(this.getTimezoneOffset() * -60) + ";
1186 return "'" + String.escape(character) + "' + ";
1191 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1192 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1193 * the date format that is not specified will default to the current date value for that part. Time parts can also
1194 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1195 * string or the parse operation will fail.
1198 //dt = Fri May 25 2007 (current date)
1199 var dt = new Date();
1201 //dt = Thu May 25 2006 (today's month/day in 2006)
1202 dt = Date.parseDate("2006", "Y");
1204 //dt = Sun Jan 15 2006 (all date parts specified)
1205 dt = Date.parseDate("2006-1-15", "Y-m-d");
1207 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1208 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1210 * @param {String} input The unparsed date as a string
1211 * @param {String} format The format the date is in
1212 * @return {Date} The parsed date
1215 Date.parseDate = function(input, format) {
1216 if (Date.parseFunctions[format] == null) {
1217 Date.createParser(format);
1219 var func = Date.parseFunctions[format];
1220 return Date[func](input);
1225 Date.createParser = function(format) {
1226 var funcName = "parse" + Date.parseFunctions.count++;
1227 var regexNum = Date.parseRegexes.length;
1228 var currentGroup = 1;
1229 Date.parseFunctions[format] = funcName;
1231 var code = "Date." + funcName + " = function(input){\n"
1232 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1233 + "var d = new Date();\n"
1234 + "y = d.getFullYear();\n"
1235 + "m = d.getMonth();\n"
1236 + "d = d.getDate();\n"
1237 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1238 + "if (results && results.length > 0) {";
1241 var special = false;
1243 for (var i = 0; i < format.length; ++i) {
1244 ch = format.charAt(i);
1245 if (!special && ch == "\\") {
1250 regex += String.escape(ch);
1253 var obj = Date.formatCodeToRegex(ch, currentGroup);
1254 currentGroup += obj.g;
1256 if (obj.g && obj.c) {
1262 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1263 + "{v = new Date(y, m, d, h, i, s);}\n"
1264 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1265 + "{v = new Date(y, m, d, h, i);}\n"
1266 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1267 + "{v = new Date(y, m, d, h);}\n"
1268 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1269 + "{v = new Date(y, m, d);}\n"
1270 + "else if (y >= 0 && m >= 0)\n"
1271 + "{v = new Date(y, m);}\n"
1272 + "else if (y >= 0)\n"
1273 + "{v = new Date(y);}\n"
1274 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1275 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1276 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1279 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1280 /** eval:var:zzzzzzzzzzzzz */
1285 Date.formatCodeToRegex = function(character, currentGroup) {
1286 switch (character) {
1290 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1293 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1294 s:"(\\d{1,2})"}; // day of month without leading zeroes
1297 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298 s:"(\\d{2})"}; // day of month with leading zeroes
1302 s:"(?:" + Date.dayNames.join("|") + ")"};
1306 s:"(?:st|nd|rd|th)"};
1321 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1322 s:"(" + Date.monthNames.join("|") + ")"};
1325 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1326 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1329 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1330 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1333 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1345 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1349 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1350 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1354 c:"if (results[" + currentGroup + "] == 'am') {\n"
1355 + "if (h == 12) { h = 0; }\n"
1356 + "} else { if (h < 12) { h += 12; }}",
1360 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1361 + "if (h == 12) { h = 0; }\n"
1362 + "} else { if (h < 12) { h += 12; }}",
1367 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1372 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1373 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1376 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1380 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1385 "o = results[", currentGroup, "];\n",
1386 "var sn = o.substring(0,1);\n", // get + / - sign
1387 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1388 "var mn = o.substring(3,5) % 60;\n", // get minutes
1389 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1390 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1392 s:"([+\-]\\d{2,4})"};
1398 "o = results[", currentGroup, "];\n",
1399 "var sn = o.substring(0,1);\n",
1400 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1401 "var mn = o.substring(4,6) % 60;\n",
1402 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1403 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1409 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1412 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1413 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1414 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1418 s:String.escape(character)};
1423 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1424 * @return {String} The abbreviated timezone name (e.g. 'CST')
1426 Date.prototype.getTimezone = function() {
1427 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1431 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1432 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1434 Date.prototype.getGMTOffset = function() {
1435 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1436 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1437 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1441 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1442 * @return {String} 2-characters representing hours and 2-characters representing minutes
1443 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1445 Date.prototype.getGMTColonOffset = function() {
1446 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1447 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1449 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1453 * Get the numeric day number of the year, adjusted for leap year.
1454 * @return {Number} 0 through 364 (365 in leap years)
1456 Date.prototype.getDayOfYear = function() {
1458 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1459 for (var i = 0; i < this.getMonth(); ++i) {
1460 num += Date.daysInMonth[i];
1462 return num + this.getDate() - 1;
1466 * Get the string representation of the numeric week number of the year
1467 * (equivalent to the format specifier 'W').
1468 * @return {String} '00' through '52'
1470 Date.prototype.getWeekOfYear = function() {
1471 // Skip to Thursday of this week
1472 var now = this.getDayOfYear() + (4 - this.getDay());
1473 // Find the first Thursday of the year
1474 var jan1 = new Date(this.getFullYear(), 0, 1);
1475 var then = (7 - jan1.getDay() + 4);
1476 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1480 * Whether or not the current date is in a leap year.
1481 * @return {Boolean} True if the current date is in a leap year, else false
1483 Date.prototype.isLeapYear = function() {
1484 var year = this.getFullYear();
1485 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1489 * Get the first day of the current month, adjusted for leap year. The returned value
1490 * is the numeric day index within the week (0-6) which can be used in conjunction with
1491 * the {@link #monthNames} array to retrieve the textual day name.
1494 var dt = new Date('1/10/2007');
1495 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1497 * @return {Number} The day number (0-6)
1499 Date.prototype.getFirstDayOfMonth = function() {
1500 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1501 return (day < 0) ? (day + 7) : day;
1505 * Get the last day of the current month, adjusted for leap year. The returned value
1506 * is the numeric day index within the week (0-6) which can be used in conjunction with
1507 * the {@link #monthNames} array to retrieve the textual day name.
1510 var dt = new Date('1/10/2007');
1511 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1513 * @return {Number} The day number (0-6)
1515 Date.prototype.getLastDayOfMonth = function() {
1516 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1517 return (day < 0) ? (day + 7) : day;
1522 * Get the first date of this date's month
1525 Date.prototype.getFirstDateOfMonth = function() {
1526 return new Date(this.getFullYear(), this.getMonth(), 1);
1530 * Get the last date of this date's month
1533 Date.prototype.getLastDateOfMonth = function() {
1534 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1537 * Get the number of days in the current month, adjusted for leap year.
1538 * @return {Number} The number of days in the month
1540 Date.prototype.getDaysInMonth = function() {
1541 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1542 return Date.daysInMonth[this.getMonth()];
1546 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1547 * @return {String} 'st, 'nd', 'rd' or 'th'
1549 Date.prototype.getSuffix = function() {
1550 switch (this.getDate()) {
1567 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1570 * An array of textual month names.
1571 * Override these values for international dates, for example...
1572 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1591 * An array of textual day names.
1592 * Override these values for international dates, for example...
1593 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1609 Date.monthNumbers = {
1624 * Creates and returns a new Date instance with the exact same date value as the called instance.
1625 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1626 * variable will also be changed. When the intention is to create a new variable that will not
1627 * modify the original instance, you should create a clone.
1629 * Example of correctly cloning a date:
1632 var orig = new Date('10/1/2006');
1635 document.write(orig); //returns 'Thu Oct 05 2006'!
1638 var orig = new Date('10/1/2006');
1639 var copy = orig.clone();
1641 document.write(orig); //returns 'Thu Oct 01 2006'
1643 * @return {Date} The new Date instance
1645 Date.prototype.clone = function() {
1646 return new Date(this.getTime());
1650 * Clears any time information from this date
1651 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1652 @return {Date} this or the clone
1654 Date.prototype.clearTime = function(clone){
1656 return this.clone().clearTime();
1661 this.setMilliseconds(0);
1666 // safari setMonth is broken
1668 Date.brokenSetMonth = Date.prototype.setMonth;
1669 Date.prototype.setMonth = function(num){
1671 var n = Math.ceil(-num);
1672 var back_year = Math.ceil(n/12);
1673 var month = (n % 12) ? 12 - n % 12 : 0 ;
1674 this.setFullYear(this.getFullYear() - back_year);
1675 return Date.brokenSetMonth.call(this, month);
1677 return Date.brokenSetMonth.apply(this, arguments);
1682 /** Date interval constant
1686 /** Date interval constant
1690 /** Date interval constant
1694 /** Date interval constant
1698 /** Date interval constant
1702 /** Date interval constant
1706 /** Date interval constant
1712 * Provides a convenient method of performing basic date arithmetic. This method
1713 * does not modify the Date instance being called - it creates and returns
1714 * a new Date instance containing the resulting date value.
1719 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1720 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1722 //Negative values will subtract correctly:
1723 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1724 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1726 //You can even chain several calls together in one line!
1727 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1728 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1731 * @param {String} interval A valid date interval enum value
1732 * @param {Number} value The amount to add to the current date
1733 * @return {Date} The new Date instance
1735 Date.prototype.add = function(interval, value){
1736 var d = this.clone();
1737 if (!interval || value === 0) return d;
1738 switch(interval.toLowerCase()){
1740 d.setMilliseconds(this.getMilliseconds() + value);
1743 d.setSeconds(this.getSeconds() + value);
1746 d.setMinutes(this.getMinutes() + value);
1749 d.setHours(this.getHours() + value);
1752 d.setDate(this.getDate() + value);
1755 var day = this.getDate();
1757 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1760 d.setMonth(this.getMonth() + value);
1763 d.setFullYear(this.getFullYear() + value);
1770 * Ext JS Library 1.1.1
1771 * Copyright(c) 2006-2007, Ext JS, LLC.
1773 * Originally Released Under LGPL - original licence link has changed is not relivant.
1776 * <script type="text/javascript">
1780 * @class Roo.lib.Dom
1783 * Dom utils (from YIU afaik)
1788 * Get the view width
1789 * @param {Boolean} full True will get the full document, otherwise it's the view width
1790 * @return {Number} The width
1793 getViewWidth : function(full) {
1794 return full ? this.getDocumentWidth() : this.getViewportWidth();
1797 * Get the view height
1798 * @param {Boolean} full True will get the full document, otherwise it's the view height
1799 * @return {Number} The height
1801 getViewHeight : function(full) {
1802 return full ? this.getDocumentHeight() : this.getViewportHeight();
1805 getDocumentHeight: function() {
1806 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1807 return Math.max(scrollHeight, this.getViewportHeight());
1810 getDocumentWidth: function() {
1811 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1812 return Math.max(scrollWidth, this.getViewportWidth());
1815 getViewportHeight: function() {
1816 var height = self.innerHeight;
1817 var mode = document.compatMode;
1819 if ((mode || Roo.isIE) && !Roo.isOpera) {
1820 height = (mode == "CSS1Compat") ?
1821 document.documentElement.clientHeight :
1822 document.body.clientHeight;
1828 getViewportWidth: function() {
1829 var width = self.innerWidth;
1830 var mode = document.compatMode;
1832 if (mode || Roo.isIE) {
1833 width = (mode == "CSS1Compat") ?
1834 document.documentElement.clientWidth :
1835 document.body.clientWidth;
1840 isAncestor : function(p, c) {
1847 if (p.contains && !Roo.isSafari) {
1848 return p.contains(c);
1849 } else if (p.compareDocumentPosition) {
1850 return !!(p.compareDocumentPosition(c) & 16);
1852 var parent = c.parentNode;
1857 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1860 parent = parent.parentNode;
1866 getRegion : function(el) {
1867 return Roo.lib.Region.getRegion(el);
1870 getY : function(el) {
1871 return this.getXY(el)[1];
1874 getX : function(el) {
1875 return this.getXY(el)[0];
1878 getXY : function(el) {
1879 var p, pe, b, scroll, bd = document.body;
1880 el = Roo.getDom(el);
1881 var fly = Roo.lib.AnimBase.fly;
1882 if (el.getBoundingClientRect) {
1883 b = el.getBoundingClientRect();
1884 scroll = fly(document).getScroll();
1885 return [b.left + scroll.left, b.top + scroll.top];
1891 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1898 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1905 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1906 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1913 if (p != el && pe.getStyle('overflow') != 'visible') {
1921 if (Roo.isSafari && hasAbsolute) {
1926 if (Roo.isGecko && !hasAbsolute) {
1928 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1929 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1933 while (p && p != bd) {
1934 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1946 setXY : function(el, xy) {
1947 el = Roo.fly(el, '_setXY');
1949 var pts = el.translatePoints(xy);
1950 if (xy[0] !== false) {
1951 el.dom.style.left = pts.left + "px";
1953 if (xy[1] !== false) {
1954 el.dom.style.top = pts.top + "px";
1958 setX : function(el, x) {
1959 this.setXY(el, [x, false]);
1962 setY : function(el, y) {
1963 this.setXY(el, [false, y]);
1967 * Portions of this file are based on pieces of Yahoo User Interface Library
1968 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1969 * YUI licensed under the BSD License:
1970 * http://developer.yahoo.net/yui/license.txt
1971 * <script type="text/javascript">
1975 Roo.lib.Event = function() {
1976 var loadComplete = false;
1978 var unloadListeners = [];
1980 var onAvailStack = [];
1982 var lastError = null;
1995 startInterval: function() {
1996 if (!this._interval) {
1998 var callback = function() {
1999 self._tryPreloadAttach();
2001 this._interval = setInterval(callback, this.POLL_INTERVAL);
2006 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2007 onAvailStack.push({ id: p_id,
2010 override: p_override,
2011 checkReady: false });
2013 retryCount = this.POLL_RETRYS;
2014 this.startInterval();
2018 addListener: function(el, eventName, fn) {
2019 el = Roo.getDom(el);
2024 if ("unload" == eventName) {
2025 unloadListeners[unloadListeners.length] =
2026 [el, eventName, fn];
2030 var wrappedFn = function(e) {
2031 return fn(Roo.lib.Event.getEvent(e));
2034 var li = [el, eventName, fn, wrappedFn];
2036 var index = listeners.length;
2037 listeners[index] = li;
2039 this.doAdd(el, eventName, wrappedFn, false);
2045 removeListener: function(el, eventName, fn) {
2048 el = Roo.getDom(el);
2051 return this.purgeElement(el, false, eventName);
2055 if ("unload" == eventName) {
2057 for (i = 0,len = unloadListeners.length; i < len; i++) {
2058 var li = unloadListeners[i];
2061 li[1] == eventName &&
2063 unloadListeners.splice(i, 1);
2071 var cacheItem = null;
2074 var index = arguments[3];
2076 if ("undefined" == typeof index) {
2077 index = this._getCacheIndex(el, eventName, fn);
2081 cacheItem = listeners[index];
2084 if (!el || !cacheItem) {
2088 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2090 delete listeners[index][this.WFN];
2091 delete listeners[index][this.FN];
2092 listeners.splice(index, 1);
2099 getTarget: function(ev, resolveTextNode) {
2100 ev = ev.browserEvent || ev;
2101 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2102 var t = ev.target || ev.srcElement;
2103 return this.resolveTextNode(t);
2107 resolveTextNode: function(node) {
2108 if (Roo.isSafari && node && 3 == node.nodeType) {
2109 return node.parentNode;
2116 getPageX: function(ev) {
2117 ev = ev.browserEvent || ev;
2118 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2120 if (!x && 0 !== x) {
2121 x = ev.clientX || 0;
2124 x += this.getScroll()[1];
2132 getPageY: function(ev) {
2133 ev = ev.browserEvent || ev;
2134 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2136 if (!y && 0 !== y) {
2137 y = ev.clientY || 0;
2140 y += this.getScroll()[0];
2149 getXY: function(ev) {
2150 ev = ev.browserEvent || ev;
2151 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2152 return [this.getPageX(ev), this.getPageY(ev)];
2156 getRelatedTarget: function(ev) {
2157 ev = ev.browserEvent || ev;
2158 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2159 var t = ev.relatedTarget;
2161 if (ev.type == "mouseout") {
2163 } else if (ev.type == "mouseover") {
2168 return this.resolveTextNode(t);
2172 getTime: function(ev) {
2173 ev = ev.browserEvent || ev;
2174 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2176 var t = new Date().getTime();
2180 this.lastError = ex;
2189 stopEvent: function(ev) {
2190 this.stopPropagation(ev);
2191 this.preventDefault(ev);
2195 stopPropagation: function(ev) {
2196 ev = ev.browserEvent || ev;
2197 if (ev.stopPropagation) {
2198 ev.stopPropagation();
2200 ev.cancelBubble = true;
2205 preventDefault: function(ev) {
2206 ev = ev.browserEvent || ev;
2207 if(ev.preventDefault) {
2208 ev.preventDefault();
2210 ev.returnValue = false;
2215 getEvent: function(e) {
2216 var ev = e || window.event;
2218 var c = this.getEvent.caller;
2220 ev = c.arguments[0];
2221 if (ev && Event == ev.constructor) {
2231 getCharCode: function(ev) {
2232 ev = ev.browserEvent || ev;
2233 return ev.charCode || ev.keyCode || 0;
2237 _getCacheIndex: function(el, eventName, fn) {
2238 for (var i = 0,len = listeners.length; i < len; ++i) {
2239 var li = listeners[i];
2241 li[this.FN] == fn &&
2242 li[this.EL] == el &&
2243 li[this.TYPE] == eventName) {
2255 getEl: function(id) {
2256 return document.getElementById(id);
2260 clearCache: function() {
2264 _load: function(e) {
2265 loadComplete = true;
2266 var EU = Roo.lib.Event;
2270 EU.doRemove(window, "load", EU._load);
2275 _tryPreloadAttach: function() {
2284 var tryAgain = !loadComplete;
2286 tryAgain = (retryCount > 0);
2291 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2292 var item = onAvailStack[i];
2294 var el = this.getEl(item.id);
2297 if (!item.checkReady ||
2300 (document && document.body)) {
2303 if (item.override) {
2304 if (item.override === true) {
2307 scope = item.override;
2310 item.fn.call(scope, item.obj);
2311 onAvailStack[i] = null;
2314 notAvail.push(item);
2319 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2323 this.startInterval();
2325 clearInterval(this._interval);
2326 this._interval = null;
2329 this.locked = false;
2336 purgeElement: function(el, recurse, eventName) {
2337 var elListeners = this.getListeners(el, eventName);
2339 for (var i = 0,len = elListeners.length; i < len; ++i) {
2340 var l = elListeners[i];
2341 this.removeListener(el, l.type, l.fn);
2345 if (recurse && el && el.childNodes) {
2346 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2347 this.purgeElement(el.childNodes[i], recurse, eventName);
2353 getListeners: function(el, eventName) {
2354 var results = [], searchLists;
2356 searchLists = [listeners, unloadListeners];
2357 } else if (eventName == "unload") {
2358 searchLists = [unloadListeners];
2360 searchLists = [listeners];
2363 for (var j = 0; j < searchLists.length; ++j) {
2364 var searchList = searchLists[j];
2365 if (searchList && searchList.length > 0) {
2366 for (var i = 0,len = searchList.length; i < len; ++i) {
2367 var l = searchList[i];
2368 if (l && l[this.EL] === el &&
2369 (!eventName || eventName === l[this.TYPE])) {
2374 adjust: l[this.ADJ_SCOPE],
2382 return (results.length) ? results : null;
2386 _unload: function(e) {
2388 var EU = Roo.lib.Event, i, j, l, len, index;
2390 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2391 l = unloadListeners[i];
2394 if (l[EU.ADJ_SCOPE]) {
2395 if (l[EU.ADJ_SCOPE] === true) {
2398 scope = l[EU.ADJ_SCOPE];
2401 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2402 unloadListeners[i] = null;
2408 unloadListeners = null;
2410 if (listeners && listeners.length > 0) {
2411 j = listeners.length;
2414 l = listeners[index];
2416 EU.removeListener(l[EU.EL], l[EU.TYPE],
2426 EU.doRemove(window, "unload", EU._unload);
2431 getScroll: function() {
2432 var dd = document.documentElement, db = document.body;
2433 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2434 return [dd.scrollTop, dd.scrollLeft];
2436 return [db.scrollTop, db.scrollLeft];
2443 doAdd: function () {
2444 if (window.addEventListener) {
2445 return function(el, eventName, fn, capture) {
2446 el.addEventListener(eventName, fn, (capture));
2448 } else if (window.attachEvent) {
2449 return function(el, eventName, fn, capture) {
2450 el.attachEvent("on" + eventName, fn);
2459 doRemove: function() {
2460 if (window.removeEventListener) {
2461 return function (el, eventName, fn, capture) {
2462 el.removeEventListener(eventName, fn, (capture));
2464 } else if (window.detachEvent) {
2465 return function (el, eventName, fn) {
2466 el.detachEvent("on" + eventName, fn);
2478 var E = Roo.lib.Event;
2479 E.on = E.addListener;
2480 E.un = E.removeListener;
2482 if (document && document.body) {
2485 E.doAdd(window, "load", E._load);
2487 E.doAdd(window, "unload", E._unload);
2488 E._tryPreloadAttach();
2492 * Portions of this file are based on pieces of Yahoo User Interface Library
2493 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2494 * YUI licensed under the BSD License:
2495 * http://developer.yahoo.net/yui/license.txt
2496 * <script type="text/javascript">
2502 * @class Roo.lib.Ajax
2509 request : function(method, uri, cb, data, options) {
2511 var hs = options.headers;
2514 if(hs.hasOwnProperty(h)){
2515 this.initHeader(h, hs[h], false);
2519 if(options.xmlData){
2520 this.initHeader('Content-Type', 'text/xml', false);
2522 data = options.xmlData;
2526 return this.asyncRequest(method, uri, cb, data);
2529 serializeForm : function(form) {
2530 if(typeof form == 'string') {
2531 form = (document.getElementById(form) || document.forms[form]);
2534 var el, name, val, disabled, data = '', hasSubmit = false;
2535 for (var i = 0; i < form.elements.length; i++) {
2536 el = form.elements[i];
2537 disabled = form.elements[i].disabled;
2538 name = form.elements[i].name;
2539 val = form.elements[i].value;
2541 if (!disabled && name){
2545 case 'select-multiple':
2546 for (var j = 0; j < el.options.length; j++) {
2547 if (el.options[j].selected) {
2549 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2552 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2560 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2573 if(hasSubmit == false) {
2574 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2579 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2584 data = data.substr(0, data.length - 1);
2592 useDefaultHeader:true,
2594 defaultPostHeader:'application/x-www-form-urlencoded',
2596 useDefaultXhrHeader:true,
2598 defaultXhrHeader:'XMLHttpRequest',
2600 hasDefaultHeaders:true,
2612 setProgId:function(id)
2614 this.activeX.unshift(id);
2617 setDefaultPostHeader:function(b)
2619 this.useDefaultHeader = b;
2622 setDefaultXhrHeader:function(b)
2624 this.useDefaultXhrHeader = b;
2627 setPollingInterval:function(i)
2629 if (typeof i == 'number' && isFinite(i)) {
2630 this.pollInterval = i;
2634 createXhrObject:function(transactionId)
2640 http = new XMLHttpRequest();
2642 obj = { conn:http, tId:transactionId };
2646 for (var i = 0; i < this.activeX.length; ++i) {
2650 http = new ActiveXObject(this.activeX[i]);
2652 obj = { conn:http, tId:transactionId };
2665 getConnectionObject:function()
2668 var tId = this.transactionId;
2672 o = this.createXhrObject(tId);
2674 this.transactionId++;
2685 asyncRequest:function(method, uri, callback, postData)
2687 var o = this.getConnectionObject();
2693 o.conn.open(method, uri, true);
2695 if (this.useDefaultXhrHeader) {
2696 if (!this.defaultHeaders['X-Requested-With']) {
2697 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2701 if(postData && this.useDefaultHeader){
2702 this.initHeader('Content-Type', this.defaultPostHeader);
2705 if (this.hasDefaultHeaders || this.hasHeaders) {
2709 this.handleReadyState(o, callback);
2710 o.conn.send(postData || null);
2716 handleReadyState:function(o, callback)
2720 if (callback && callback.timeout) {
2722 this.timeout[o.tId] = window.setTimeout(function() {
2723 oConn.abort(o, callback, true);
2724 }, callback.timeout);
2727 this.poll[o.tId] = window.setInterval(
2729 if (o.conn && o.conn.readyState == 4) {
2730 window.clearInterval(oConn.poll[o.tId]);
2731 delete oConn.poll[o.tId];
2733 if(callback && callback.timeout) {
2734 window.clearTimeout(oConn.timeout[o.tId]);
2735 delete oConn.timeout[o.tId];
2738 oConn.handleTransactionResponse(o, callback);
2741 , this.pollInterval);
2744 handleTransactionResponse:function(o, callback, isAbort)
2748 this.releaseObject(o);
2752 var httpStatus, responseObject;
2756 if (o.conn.status !== undefined && o.conn.status != 0) {
2757 httpStatus = o.conn.status;
2769 if (httpStatus >= 200 && httpStatus < 300) {
2770 responseObject = this.createResponseObject(o, callback.argument);
2771 if (callback.success) {
2772 if (!callback.scope) {
2773 callback.success(responseObject);
2778 callback.success.apply(callback.scope, [responseObject]);
2783 switch (httpStatus) {
2791 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2792 if (callback.failure) {
2793 if (!callback.scope) {
2794 callback.failure(responseObject);
2797 callback.failure.apply(callback.scope, [responseObject]);
2802 responseObject = this.createResponseObject(o, callback.argument);
2803 if (callback.failure) {
2804 if (!callback.scope) {
2805 callback.failure(responseObject);
2808 callback.failure.apply(callback.scope, [responseObject]);
2814 this.releaseObject(o);
2815 responseObject = null;
2818 createResponseObject:function(o, callbackArg)
2825 var headerStr = o.conn.getAllResponseHeaders();
2826 var header = headerStr.split('\n');
2827 for (var i = 0; i < header.length; i++) {
2828 var delimitPos = header[i].indexOf(':');
2829 if (delimitPos != -1) {
2830 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2838 obj.status = o.conn.status;
2839 obj.statusText = o.conn.statusText;
2840 obj.getResponseHeader = headerObj;
2841 obj.getAllResponseHeaders = headerStr;
2842 obj.responseText = o.conn.responseText;
2843 obj.responseXML = o.conn.responseXML;
2845 if (typeof callbackArg !== undefined) {
2846 obj.argument = callbackArg;
2852 createExceptionObject:function(tId, callbackArg, isAbort)
2855 var COMM_ERROR = 'communication failure';
2856 var ABORT_CODE = -1;
2857 var ABORT_ERROR = 'transaction aborted';
2863 obj.status = ABORT_CODE;
2864 obj.statusText = ABORT_ERROR;
2867 obj.status = COMM_CODE;
2868 obj.statusText = COMM_ERROR;
2872 obj.argument = callbackArg;
2878 initHeader:function(label, value, isDefault)
2880 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2882 if (headerObj[label] === undefined) {
2883 headerObj[label] = value;
2888 headerObj[label] = value + "," + headerObj[label];
2892 this.hasDefaultHeaders = true;
2895 this.hasHeaders = true;
2900 setHeader:function(o)
2902 if (this.hasDefaultHeaders) {
2903 for (var prop in this.defaultHeaders) {
2904 if (this.defaultHeaders.hasOwnProperty(prop)) {
2905 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2910 if (this.hasHeaders) {
2911 for (var prop in this.headers) {
2912 if (this.headers.hasOwnProperty(prop)) {
2913 o.conn.setRequestHeader(prop, this.headers[prop]);
2917 this.hasHeaders = false;
2921 resetDefaultHeaders:function() {
2922 delete this.defaultHeaders;
2923 this.defaultHeaders = {};
2924 this.hasDefaultHeaders = false;
2927 abort:function(o, callback, isTimeout)
2929 if(this.isCallInProgress(o)) {
2931 window.clearInterval(this.poll[o.tId]);
2932 delete this.poll[o.tId];
2934 delete this.timeout[o.tId];
2937 this.handleTransactionResponse(o, callback, true);
2947 isCallInProgress:function(o)
2950 return o.conn.readyState != 4 && o.conn.readyState != 0;
2959 releaseObject:function(o)
2968 'MSXML2.XMLHTTP.3.0',
2976 * Portions of this file are based on pieces of Yahoo User Interface Library
2977 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2978 * YUI licensed under the BSD License:
2979 * http://developer.yahoo.net/yui/license.txt
2980 * <script type="text/javascript">
2984 Roo.lib.Region = function(t, r, b, l) {
2994 Roo.lib.Region.prototype = {
2995 contains : function(region) {
2996 return ( region.left >= this.left &&
2997 region.right <= this.right &&
2998 region.top >= this.top &&
2999 region.bottom <= this.bottom );
3003 getArea : function() {
3004 return ( (this.bottom - this.top) * (this.right - this.left) );
3007 intersect : function(region) {
3008 var t = Math.max(this.top, region.top);
3009 var r = Math.min(this.right, region.right);
3010 var b = Math.min(this.bottom, region.bottom);
3011 var l = Math.max(this.left, region.left);
3013 if (b >= t && r >= l) {
3014 return new Roo.lib.Region(t, r, b, l);
3019 union : function(region) {
3020 var t = Math.min(this.top, region.top);
3021 var r = Math.max(this.right, region.right);
3022 var b = Math.max(this.bottom, region.bottom);
3023 var l = Math.min(this.left, region.left);
3025 return new Roo.lib.Region(t, r, b, l);
3028 adjust : function(t, l, b, r) {
3037 Roo.lib.Region.getRegion = function(el) {
3038 var p = Roo.lib.Dom.getXY(el);
3041 var r = p[0] + el.offsetWidth;
3042 var b = p[1] + el.offsetHeight;
3045 return new Roo.lib.Region(t, r, b, l);
3048 * Portions of this file are based on pieces of Yahoo User Interface Library
3049 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3050 * YUI licensed under the BSD License:
3051 * http://developer.yahoo.net/yui/license.txt
3052 * <script type="text/javascript">
3055 //@@dep Roo.lib.Region
3058 Roo.lib.Point = function(x, y) {
3059 if (x instanceof Array) {
3063 this.x = this.right = this.left = this[0] = x;
3064 this.y = this.top = this.bottom = this[1] = y;
3067 Roo.lib.Point.prototype = new Roo.lib.Region();
3069 * Portions of this file are based on pieces of Yahoo User Interface Library
3070 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3071 * YUI licensed under the BSD License:
3072 * http://developer.yahoo.net/yui/license.txt
3073 * <script type="text/javascript">
3080 scroll : function(el, args, duration, easing, cb, scope) {
3081 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3084 motion : function(el, args, duration, easing, cb, scope) {
3085 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3088 color : function(el, args, duration, easing, cb, scope) {
3089 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3092 run : function(el, args, duration, easing, cb, scope, type) {
3093 type = type || Roo.lib.AnimBase;
3094 if (typeof easing == "string") {
3095 easing = Roo.lib.Easing[easing];
3097 var anim = new type(el, args, duration, easing);
3098 anim.animateX(function() {
3099 Roo.callback(cb, scope);
3105 * Portions of this file are based on pieces of Yahoo User Interface Library
3106 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3107 * YUI licensed under the BSD License:
3108 * http://developer.yahoo.net/yui/license.txt
3109 * <script type="text/javascript">
3117 if (!libFlyweight) {
3118 libFlyweight = new Roo.Element.Flyweight();
3120 libFlyweight.dom = el;
3121 return libFlyweight;
3124 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3128 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3130 this.init(el, attributes, duration, method);
3134 Roo.lib.AnimBase.fly = fly;
3138 Roo.lib.AnimBase.prototype = {
3140 toString: function() {
3141 var el = this.getEl();
3142 var id = el.id || el.tagName;
3143 return ("Anim " + id);
3147 noNegatives: /width|height|opacity|padding/i,
3148 offsetAttribute: /^((width|height)|(top|left))$/,
3149 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3150 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3154 doMethod: function(attr, start, end) {
3155 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3159 setAttribute: function(attr, val, unit) {
3160 if (this.patterns.noNegatives.test(attr)) {
3161 val = (val > 0) ? val : 0;
3164 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3168 getAttribute: function(attr) {
3169 var el = this.getEl();
3170 var val = fly(el).getStyle(attr);
3172 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3173 return parseFloat(val);
3176 var a = this.patterns.offsetAttribute.exec(attr) || [];
3177 var pos = !!( a[3] );
3178 var box = !!( a[2] );
3181 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3182 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3191 getDefaultUnit: function(attr) {
3192 if (this.patterns.defaultUnit.test(attr)) {
3199 animateX : function(callback, scope) {
3200 var f = function() {
3201 this.onComplete.removeListener(f);
3202 if (typeof callback == "function") {
3203 callback.call(scope || this, this);
3206 this.onComplete.addListener(f, this);
3211 setRuntimeAttribute: function(attr) {
3214 var attributes = this.attributes;
3216 this.runtimeAttributes[attr] = {};
3218 var isset = function(prop) {
3219 return (typeof prop !== 'undefined');
3222 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3226 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3229 if (isset(attributes[attr]['to'])) {
3230 end = attributes[attr]['to'];
3231 } else if (isset(attributes[attr]['by'])) {
3232 if (start.constructor == Array) {
3234 for (var i = 0, len = start.length; i < len; ++i) {
3235 end[i] = start[i] + attributes[attr]['by'][i];
3238 end = start + attributes[attr]['by'];
3242 this.runtimeAttributes[attr].start = start;
3243 this.runtimeAttributes[attr].end = end;
3246 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3250 init: function(el, attributes, duration, method) {
3252 var isAnimated = false;
3255 var startTime = null;
3258 var actualFrames = 0;
3261 el = Roo.getDom(el);
3264 this.attributes = attributes || {};
3267 this.duration = duration || 1;
3270 this.method = method || Roo.lib.Easing.easeNone;
3273 this.useSeconds = true;
3276 this.currentFrame = 0;
3279 this.totalFrames = Roo.lib.AnimMgr.fps;
3282 this.getEl = function() {
3287 this.isAnimated = function() {
3292 this.getStartTime = function() {
3296 this.runtimeAttributes = {};
3299 this.animate = function() {
3300 if (this.isAnimated()) {
3304 this.currentFrame = 0;
3306 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3308 Roo.lib.AnimMgr.registerElement(this);
3312 this.stop = function(finish) {
3314 this.currentFrame = this.totalFrames;
3315 this._onTween.fire();
3317 Roo.lib.AnimMgr.stop(this);
3320 var onStart = function() {
3321 this.onStart.fire();
3323 this.runtimeAttributes = {};
3324 for (var attr in this.attributes) {
3325 this.setRuntimeAttribute(attr);
3330 startTime = new Date();
3334 var onTween = function() {
3336 duration: new Date() - this.getStartTime(),
3337 currentFrame: this.currentFrame
3340 data.toString = function() {
3342 'duration: ' + data.duration +
3343 ', currentFrame: ' + data.currentFrame
3347 this.onTween.fire(data);
3349 var runtimeAttributes = this.runtimeAttributes;
3351 for (var attr in runtimeAttributes) {
3352 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3358 var onComplete = function() {
3359 var actual_duration = (new Date() - startTime) / 1000 ;
3362 duration: actual_duration,
3363 frames: actualFrames,
3364 fps: actualFrames / actual_duration
3367 data.toString = function() {
3369 'duration: ' + data.duration +
3370 ', frames: ' + data.frames +
3371 ', fps: ' + data.fps
3377 this.onComplete.fire(data);
3381 this._onStart = new Roo.util.Event(this);
3382 this.onStart = new Roo.util.Event(this);
3383 this.onTween = new Roo.util.Event(this);
3384 this._onTween = new Roo.util.Event(this);
3385 this.onComplete = new Roo.util.Event(this);
3386 this._onComplete = new Roo.util.Event(this);
3387 this._onStart.addListener(onStart);
3388 this._onTween.addListener(onTween);
3389 this._onComplete.addListener(onComplete);
3394 * Portions of this file are based on pieces of Yahoo User Interface Library
3395 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3396 * YUI licensed under the BSD License:
3397 * http://developer.yahoo.net/yui/license.txt
3398 * <script type="text/javascript">
3402 Roo.lib.AnimMgr = new function() {
3419 this.registerElement = function(tween) {
3420 queue[queue.length] = tween;
3422 tween._onStart.fire();
3427 this.unRegister = function(tween, index) {
3428 tween._onComplete.fire();
3429 index = index || getIndex(tween);
3431 queue.splice(index, 1);
3435 if (tweenCount <= 0) {
3441 this.start = function() {
3442 if (thread === null) {
3443 thread = setInterval(this.run, this.delay);
3448 this.stop = function(tween) {
3450 clearInterval(thread);
3452 for (var i = 0, len = queue.length; i < len; ++i) {
3453 if (queue[0].isAnimated()) {
3454 this.unRegister(queue[0], 0);
3463 this.unRegister(tween);
3468 this.run = function() {
3469 for (var i = 0, len = queue.length; i < len; ++i) {
3470 var tween = queue[i];
3471 if (!tween || !tween.isAnimated()) {
3475 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3477 tween.currentFrame += 1;
3479 if (tween.useSeconds) {
3480 correctFrame(tween);
3482 tween._onTween.fire();
3485 Roo.lib.AnimMgr.stop(tween, i);
3490 var getIndex = function(anim) {
3491 for (var i = 0, len = queue.length; i < len; ++i) {
3492 if (queue[i] == anim) {
3500 var correctFrame = function(tween) {
3501 var frames = tween.totalFrames;
3502 var frame = tween.currentFrame;
3503 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3504 var elapsed = (new Date() - tween.getStartTime());
3507 if (elapsed < tween.duration * 1000) {
3508 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3510 tweak = frames - (frame + 1);
3512 if (tweak > 0 && isFinite(tweak)) {
3513 if (tween.currentFrame + tweak >= frames) {
3514 tweak = frames - (frame + 1);
3517 tween.currentFrame += tweak;
3523 * Portions of this file are based on pieces of Yahoo User Interface Library
3524 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3525 * YUI licensed under the BSD License:
3526 * http://developer.yahoo.net/yui/license.txt
3527 * <script type="text/javascript">
3530 Roo.lib.Bezier = new function() {
3532 this.getPosition = function(points, t) {
3533 var n = points.length;
3536 for (var i = 0; i < n; ++i) {
3537 tmp[i] = [points[i][0], points[i][1]];
3540 for (var j = 1; j < n; ++j) {
3541 for (i = 0; i < n - j; ++i) {
3542 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3543 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3547 return [ tmp[0][0], tmp[0][1] ];
3551 * Portions of this file are based on pieces of Yahoo User Interface Library
3552 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3553 * YUI licensed under the BSD License:
3554 * http://developer.yahoo.net/yui/license.txt
3555 * <script type="text/javascript">
3560 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3561 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3564 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3566 var fly = Roo.lib.AnimBase.fly;
3568 var superclass = Y.ColorAnim.superclass;
3569 var proto = Y.ColorAnim.prototype;
3571 proto.toString = function() {
3572 var el = this.getEl();
3573 var id = el.id || el.tagName;
3574 return ("ColorAnim " + id);
3577 proto.patterns.color = /color$/i;
3578 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3579 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3580 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3581 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3584 proto.parseColor = function(s) {
3585 if (s.length == 3) {
3589 var c = this.patterns.hex.exec(s);
3590 if (c && c.length == 4) {
3591 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3594 c = this.patterns.rgb.exec(s);
3595 if (c && c.length == 4) {
3596 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3599 c = this.patterns.hex3.exec(s);
3600 if (c && c.length == 4) {
3601 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3606 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3607 proto.getAttribute = function(attr) {
3608 var el = this.getEl();
3609 if (this.patterns.color.test(attr)) {
3610 var val = fly(el).getStyle(attr);
3612 if (this.patterns.transparent.test(val)) {
3613 var parent = el.parentNode;
3614 val = fly(parent).getStyle(attr);
3616 while (parent && this.patterns.transparent.test(val)) {
3617 parent = parent.parentNode;
3618 val = fly(parent).getStyle(attr);
3619 if (parent.tagName.toUpperCase() == 'HTML') {
3625 val = superclass.getAttribute.call(this, attr);
3630 proto.getAttribute = function(attr) {
3631 var el = this.getEl();
3632 if (this.patterns.color.test(attr)) {
3633 var val = fly(el).getStyle(attr);
3635 if (this.patterns.transparent.test(val)) {
3636 var parent = el.parentNode;
3637 val = fly(parent).getStyle(attr);
3639 while (parent && this.patterns.transparent.test(val)) {
3640 parent = parent.parentNode;
3641 val = fly(parent).getStyle(attr);
3642 if (parent.tagName.toUpperCase() == 'HTML') {
3648 val = superclass.getAttribute.call(this, attr);
3654 proto.doMethod = function(attr, start, end) {
3657 if (this.patterns.color.test(attr)) {
3659 for (var i = 0, len = start.length; i < len; ++i) {
3660 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3663 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3666 val = superclass.doMethod.call(this, attr, start, end);
3672 proto.setRuntimeAttribute = function(attr) {
3673 superclass.setRuntimeAttribute.call(this, attr);
3675 if (this.patterns.color.test(attr)) {
3676 var attributes = this.attributes;
3677 var start = this.parseColor(this.runtimeAttributes[attr].start);
3678 var end = this.parseColor(this.runtimeAttributes[attr].end);
3680 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3681 end = this.parseColor(attributes[attr].by);
3683 for (var i = 0, len = start.length; i < len; ++i) {
3684 end[i] = start[i] + end[i];
3688 this.runtimeAttributes[attr].start = start;
3689 this.runtimeAttributes[attr].end = end;
3695 * Portions of this file are based on pieces of Yahoo User Interface Library
3696 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3697 * YUI licensed under the BSD License:
3698 * http://developer.yahoo.net/yui/license.txt
3699 * <script type="text/javascript">
3705 easeNone: function (t, b, c, d) {
3706 return c * t / d + b;
3710 easeIn: function (t, b, c, d) {
3711 return c * (t /= d) * t + b;
3715 easeOut: function (t, b, c, d) {
3716 return -c * (t /= d) * (t - 2) + b;
3720 easeBoth: function (t, b, c, d) {
3721 if ((t /= d / 2) < 1) {
3722 return c / 2 * t * t + b;
3725 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3729 easeInStrong: function (t, b, c, d) {
3730 return c * (t /= d) * t * t * t + b;
3734 easeOutStrong: function (t, b, c, d) {
3735 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3739 easeBothStrong: function (t, b, c, d) {
3740 if ((t /= d / 2) < 1) {
3741 return c / 2 * t * t * t * t + b;
3744 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3749 elasticIn: function (t, b, c, d, a, p) {
3753 if ((t /= d) == 1) {
3760 if (!a || a < Math.abs(c)) {
3765 var s = p / (2 * Math.PI) * Math.asin(c / a);
3768 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3772 elasticOut: function (t, b, c, d, a, p) {
3776 if ((t /= d) == 1) {
3783 if (!a || a < Math.abs(c)) {
3788 var s = p / (2 * Math.PI) * Math.asin(c / a);
3791 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3795 elasticBoth: function (t, b, c, d, a, p) {
3800 if ((t /= d / 2) == 2) {
3808 if (!a || a < Math.abs(c)) {
3813 var s = p / (2 * Math.PI) * Math.asin(c / a);
3817 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3818 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3820 return a * Math.pow(2, -10 * (t -= 1)) *
3821 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3826 backIn: function (t, b, c, d, s) {
3827 if (typeof s == 'undefined') {
3830 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3834 backOut: function (t, b, c, d, s) {
3835 if (typeof s == 'undefined') {
3838 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3842 backBoth: function (t, b, c, d, s) {
3843 if (typeof s == 'undefined') {
3847 if ((t /= d / 2 ) < 1) {
3848 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3850 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3854 bounceIn: function (t, b, c, d) {
3855 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3859 bounceOut: function (t, b, c, d) {
3860 if ((t /= d) < (1 / 2.75)) {
3861 return c * (7.5625 * t * t) + b;
3862 } else if (t < (2 / 2.75)) {
3863 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3864 } else if (t < (2.5 / 2.75)) {
3865 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3867 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3871 bounceBoth: function (t, b, c, d) {
3873 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3875 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3878 * Portions of this file are based on pieces of Yahoo User Interface Library
3879 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3880 * YUI licensed under the BSD License:
3881 * http://developer.yahoo.net/yui/license.txt
3882 * <script type="text/javascript">
3886 Roo.lib.Motion = function(el, attributes, duration, method) {
3888 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3892 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3896 var superclass = Y.Motion.superclass;
3897 var proto = Y.Motion.prototype;
3899 proto.toString = function() {
3900 var el = this.getEl();
3901 var id = el.id || el.tagName;
3902 return ("Motion " + id);
3905 proto.patterns.points = /^points$/i;
3907 proto.setAttribute = function(attr, val, unit) {
3908 if (this.patterns.points.test(attr)) {
3909 unit = unit || 'px';
3910 superclass.setAttribute.call(this, 'left', val[0], unit);
3911 superclass.setAttribute.call(this, 'top', val[1], unit);
3913 superclass.setAttribute.call(this, attr, val, unit);
3917 proto.getAttribute = function(attr) {
3918 if (this.patterns.points.test(attr)) {
3920 superclass.getAttribute.call(this, 'left'),
3921 superclass.getAttribute.call(this, 'top')
3924 val = superclass.getAttribute.call(this, attr);
3930 proto.doMethod = function(attr, start, end) {
3933 if (this.patterns.points.test(attr)) {
3934 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3935 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3937 val = superclass.doMethod.call(this, attr, start, end);
3942 proto.setRuntimeAttribute = function(attr) {
3943 if (this.patterns.points.test(attr)) {
3944 var el = this.getEl();
3945 var attributes = this.attributes;
3947 var control = attributes['points']['control'] || [];
3951 if (control.length > 0 && !(control[0] instanceof Array)) {
3952 control = [control];
3955 for (i = 0,len = control.length; i < len; ++i) {
3956 tmp[i] = control[i];
3961 Roo.fly(el).position();
3963 if (isset(attributes['points']['from'])) {
3964 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3967 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3970 start = this.getAttribute('points');
3973 if (isset(attributes['points']['to'])) {
3974 end = translateValues.call(this, attributes['points']['to'], start);
3976 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3977 for (i = 0,len = control.length; i < len; ++i) {
3978 control[i] = translateValues.call(this, control[i], start);
3982 } else if (isset(attributes['points']['by'])) {
3983 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3985 for (i = 0,len = control.length; i < len; ++i) {
3986 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3990 this.runtimeAttributes[attr] = [start];
3992 if (control.length > 0) {
3993 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3996 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3999 superclass.setRuntimeAttribute.call(this, attr);
4003 var translateValues = function(val, start) {
4004 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4005 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4010 var isset = function(prop) {
4011 return (typeof prop !== 'undefined');
4015 * Portions of this file are based on pieces of Yahoo User Interface Library
4016 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4017 * YUI licensed under the BSD License:
4018 * http://developer.yahoo.net/yui/license.txt
4019 * <script type="text/javascript">
4023 Roo.lib.Scroll = function(el, attributes, duration, method) {
4025 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4029 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4033 var superclass = Y.Scroll.superclass;
4034 var proto = Y.Scroll.prototype;
4036 proto.toString = function() {
4037 var el = this.getEl();
4038 var id = el.id || el.tagName;
4039 return ("Scroll " + id);
4042 proto.doMethod = function(attr, start, end) {
4045 if (attr == 'scroll') {
4047 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4048 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4052 val = superclass.doMethod.call(this, attr, start, end);
4057 proto.getAttribute = function(attr) {
4059 var el = this.getEl();
4061 if (attr == 'scroll') {
4062 val = [ el.scrollLeft, el.scrollTop ];
4064 val = superclass.getAttribute.call(this, attr);
4070 proto.setAttribute = function(attr, val, unit) {
4071 var el = this.getEl();
4073 if (attr == 'scroll') {
4074 el.scrollLeft = val[0];
4075 el.scrollTop = val[1];
4077 superclass.setAttribute.call(this, attr, val, unit);
4083 * Ext JS Library 1.1.1
4084 * Copyright(c) 2006-2007, Ext JS, LLC.
4086 * Originally Released Under LGPL - original licence link has changed is not relivant.
4089 * <script type="text/javascript">
4093 // nasty IE9 hack - what a pile of crap that is..
4095 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4096 Range.prototype.createContextualFragment = function (html) {
4097 var doc = window.document;
4098 var container = doc.createElement("div");
4099 container.innerHTML = html;
4100 var frag = doc.createDocumentFragment(), n;
4101 while ((n = container.firstChild)) {
4102 frag.appendChild(n);
4109 * @class Roo.DomHelper
4110 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4111 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4114 Roo.DomHelper = function(){
4115 var tempTableEl = null;
4116 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4117 var tableRe = /^table|tbody|tr|td$/i;
4119 // build as innerHTML where available
4121 var createHtml = function(o){
4122 if(typeof o == 'string'){
4131 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4132 if(attr == "style"){
4134 if(typeof s == "function"){
4137 if(typeof s == "string"){
4138 b += ' style="' + s + '"';
4139 }else if(typeof s == "object"){
4142 if(typeof s[key] != "function"){
4143 b += key + ":" + s[key] + ";";
4150 b += ' class="' + o["cls"] + '"';
4151 }else if(attr == "htmlFor"){
4152 b += ' for="' + o["htmlFor"] + '"';
4154 b += " " + attr + '="' + o[attr] + '"';
4158 if(emptyTags.test(o.tag)){
4162 var cn = o.children || o.cn;
4164 //http://bugs.kde.org/show_bug.cgi?id=71506
4165 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4166 for(var i = 0, len = cn.length; i < len; i++) {
4167 b += createHtml(cn[i], b);
4170 b += createHtml(cn, b);
4176 b += "</" + o.tag + ">";
4183 var createDom = function(o, parentNode){
4185 // defininition craeted..
4187 if (o.ns && o.ns != 'html') {
4189 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4190 xmlns[o.ns] = o.xmlns;
4193 if (typeof(xmlns[o.ns]) == 'undefined') {
4194 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4200 if (typeof(o) == 'string') {
4201 return parentNode.appendChild(document.createTextNode(o));
4203 o.tag = o.tag || div;
4204 if (o.ns && Roo.isIE) {
4206 o.tag = o.ns + ':' + o.tag;
4209 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4210 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4213 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4214 attr == "style" || typeof o[attr] == "function") continue;
4216 if(attr=="cls" && Roo.isIE){
4217 el.className = o["cls"];
4219 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4220 else el[attr] = o[attr];
4223 Roo.DomHelper.applyStyles(el, o.style);
4224 var cn = o.children || o.cn;
4226 //http://bugs.kde.org/show_bug.cgi?id=71506
4227 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4228 for(var i = 0, len = cn.length; i < len; i++) {
4229 createDom(cn[i], el);
4236 el.innerHTML = o.html;
4239 parentNode.appendChild(el);
4244 var ieTable = function(depth, s, h, e){
4245 tempTableEl.innerHTML = [s, h, e].join('');
4246 var i = -1, el = tempTableEl;
4253 // kill repeat to save bytes
4257 tbe = '</tbody>'+te,
4263 * Nasty code for IE's broken table implementation
4265 var insertIntoTable = function(tag, where, el, html){
4267 tempTableEl = document.createElement('div');
4272 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4275 if(where == 'beforebegin'){
4279 before = el.nextSibling;
4282 node = ieTable(4, trs, html, tre);
4284 else if(tag == 'tr'){
4285 if(where == 'beforebegin'){
4288 node = ieTable(3, tbs, html, tbe);
4289 } else if(where == 'afterend'){
4290 before = el.nextSibling;
4292 node = ieTable(3, tbs, html, tbe);
4293 } else{ // INTO a TR
4294 if(where == 'afterbegin'){
4295 before = el.firstChild;
4297 node = ieTable(4, trs, html, tre);
4299 } else if(tag == 'tbody'){
4300 if(where == 'beforebegin'){
4303 node = ieTable(2, ts, html, te);
4304 } else if(where == 'afterend'){
4305 before = el.nextSibling;
4307 node = ieTable(2, ts, html, te);
4309 if(where == 'afterbegin'){
4310 before = el.firstChild;
4312 node = ieTable(3, tbs, html, tbe);
4315 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4318 if(where == 'afterbegin'){
4319 before = el.firstChild;
4321 node = ieTable(2, ts, html, te);
4323 el.insertBefore(node, before);
4328 /** True to force the use of DOM instead of html fragments @type Boolean */
4332 * Returns the markup for the passed Element(s) config
4333 * @param {Object} o The Dom object spec (and children)
4336 markup : function(o){
4337 return createHtml(o);
4341 * Applies a style specification to an element
4342 * @param {String/HTMLElement} el The element to apply styles to
4343 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4344 * a function which returns such a specification.
4346 applyStyles : function(el, styles){
4349 if(typeof styles == "string"){
4350 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4352 while ((matches = re.exec(styles)) != null){
4353 el.setStyle(matches[1], matches[2]);
4355 }else if (typeof styles == "object"){
4356 for (var style in styles){
4357 el.setStyle(style, styles[style]);
4359 }else if (typeof styles == "function"){
4360 Roo.DomHelper.applyStyles(el, styles.call());
4366 * Inserts an HTML fragment into the Dom
4367 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4368 * @param {HTMLElement} el The context element
4369 * @param {String} html The HTML fragmenet
4370 * @return {HTMLElement} The new node
4372 insertHtml : function(where, el, html){
4373 where = where.toLowerCase();
4374 if(el.insertAdjacentHTML){
4375 if(tableRe.test(el.tagName)){
4377 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4383 el.insertAdjacentHTML('BeforeBegin', html);
4384 return el.previousSibling;
4386 el.insertAdjacentHTML('AfterBegin', html);
4387 return el.firstChild;
4389 el.insertAdjacentHTML('BeforeEnd', html);
4390 return el.lastChild;
4392 el.insertAdjacentHTML('AfterEnd', html);
4393 return el.nextSibling;
4395 throw 'Illegal insertion point -> "' + where + '"';
4397 var range = el.ownerDocument.createRange();
4401 range.setStartBefore(el);
4402 frag = range.createContextualFragment(html);
4403 el.parentNode.insertBefore(frag, el);
4404 return el.previousSibling;
4407 range.setStartBefore(el.firstChild);
4408 frag = range.createContextualFragment(html);
4409 el.insertBefore(frag, el.firstChild);
4410 return el.firstChild;
4412 el.innerHTML = html;
4413 return el.firstChild;
4417 range.setStartAfter(el.lastChild);
4418 frag = range.createContextualFragment(html);
4419 el.appendChild(frag);
4420 return el.lastChild;
4422 el.innerHTML = html;
4423 return el.lastChild;
4426 range.setStartAfter(el);
4427 frag = range.createContextualFragment(html);
4428 el.parentNode.insertBefore(frag, el.nextSibling);
4429 return el.nextSibling;
4431 throw 'Illegal insertion point -> "' + where + '"';
4435 * Creates new Dom element(s) and inserts them before el
4436 * @param {String/HTMLElement/Element} el The context element
4437 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4438 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4439 * @return {HTMLElement/Roo.Element} The new node
4441 insertBefore : function(el, o, returnElement){
4442 return this.doInsert(el, o, returnElement, "beforeBegin");
4446 * Creates new Dom element(s) and inserts them after el
4447 * @param {String/HTMLElement/Element} el The context element
4448 * @param {Object} o The Dom object spec (and children)
4449 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4450 * @return {HTMLElement/Roo.Element} The new node
4452 insertAfter : function(el, o, returnElement){
4453 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4457 * Creates new Dom element(s) and inserts them as the first child of el
4458 * @param {String/HTMLElement/Element} el The context element
4459 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4460 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4461 * @return {HTMLElement/Roo.Element} The new node
4463 insertFirst : function(el, o, returnElement){
4464 return this.doInsert(el, o, returnElement, "afterBegin");
4468 doInsert : function(el, o, returnElement, pos, sibling){
4469 el = Roo.getDom(el);
4471 if(this.useDom || o.ns){
4472 newNode = createDom(o, null);
4473 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4475 var html = createHtml(o);
4476 newNode = this.insertHtml(pos, el, html);
4478 return returnElement ? Roo.get(newNode, true) : newNode;
4482 * Creates new Dom element(s) and appends them to el
4483 * @param {String/HTMLElement/Element} el The context element
4484 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486 * @return {HTMLElement/Roo.Element} The new node
4488 append : function(el, o, returnElement){
4489 el = Roo.getDom(el);
4491 if(this.useDom || o.ns){
4492 newNode = createDom(o, null);
4493 el.appendChild(newNode);
4495 var html = createHtml(o);
4496 newNode = this.insertHtml("beforeEnd", el, html);
4498 return returnElement ? Roo.get(newNode, true) : newNode;
4502 * Creates new Dom element(s) and overwrites the contents of el with them
4503 * @param {String/HTMLElement/Element} el The context element
4504 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4505 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4506 * @return {HTMLElement/Roo.Element} The new node
4508 overwrite : function(el, o, returnElement){
4509 el = Roo.getDom(el);
4512 while (el.childNodes.length) {
4513 el.removeChild(el.firstChild);
4517 el.innerHTML = createHtml(o);
4520 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4524 * Creates a new Roo.DomHelper.Template from the Dom object spec
4525 * @param {Object} o The Dom object spec (and children)
4526 * @return {Roo.DomHelper.Template} The new template
4528 createTemplate : function(o){
4529 var html = createHtml(o);
4530 return new Roo.Template(html);
4536 * Ext JS Library 1.1.1
4537 * Copyright(c) 2006-2007, Ext JS, LLC.
4539 * Originally Released Under LGPL - original licence link has changed is not relivant.
4542 * <script type="text/javascript">
4546 * @class Roo.Template
4547 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4548 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4551 var t = new Roo.Template({
4552 html : '<div name="{id}">' +
4553 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4555 myformat: function (value, allValues) {
4556 return 'XX' + value;
4559 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4561 * For more information see this blog post with examples:
4562 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4563 - Create Elements using DOM, HTML fragments and Templates</a>.
4565 * @param {Object} cfg - Configuration object.
4567 Roo.Template = function(cfg){
4569 if(cfg instanceof Array){
4571 }else if(arguments.length > 1){
4572 cfg = Array.prototype.join.call(arguments, "");
4576 if (typeof(cfg) == 'object') {
4587 Roo.Template.prototype = {
4590 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4591 * it should be fixed so that template is observable...
4595 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4599 * Returns an HTML fragment of this template with the specified values applied.
4600 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4601 * @return {String} The HTML fragment
4603 applyTemplate : function(values){
4607 return this.compiled(values);
4609 var useF = this.disableFormats !== true;
4610 var fm = Roo.util.Format, tpl = this;
4611 var fn = function(m, name, format, args){
4613 if(format.substr(0, 5) == "this."){
4614 return tpl.call(format.substr(5), values[name], values);
4617 // quoted values are required for strings in compiled templates,
4618 // but for non compiled we need to strip them
4619 // quoted reversed for jsmin
4620 var re = /^\s*['"](.*)["']\s*$/;
4621 args = args.split(',');
4622 for(var i = 0, len = args.length; i < len; i++){
4623 args[i] = args[i].replace(re, "$1");
4625 args = [values[name]].concat(args);
4627 args = [values[name]];
4629 return fm[format].apply(fm, args);
4632 return values[name] !== undefined ? values[name] : "";
4635 return this.html.replace(this.re, fn);
4653 this.loading = true;
4654 this.compiled = false;
4656 var cx = new Roo.data.Connection();
4660 success : function (response) {
4662 _t.html = response.responseText;
4666 failure : function(response) {
4667 Roo.log("Template failed to load from " + _t.url);
4674 * Sets the HTML used as the template and optionally compiles it.
4675 * @param {String} html
4676 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4677 * @return {Roo.Template} this
4679 set : function(html, compile){
4681 this.compiled = null;
4689 * True to disable format functions (defaults to false)
4692 disableFormats : false,
4695 * The regular expression used to match template variables
4699 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4702 * Compiles the template into an internal function, eliminating the RegEx overhead.
4703 * @return {Roo.Template} this
4705 compile : function(){
4706 var fm = Roo.util.Format;
4707 var useF = this.disableFormats !== true;
4708 var sep = Roo.isGecko ? "+" : ",";
4709 var fn = function(m, name, format, args){
4711 args = args ? ',' + args : "";
4712 if(format.substr(0, 5) != "this."){
4713 format = "fm." + format + '(';
4715 format = 'this.call("'+ format.substr(5) + '", ';
4719 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4721 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4724 // branched to use + in gecko and [].join() in others
4726 body = "this.compiled = function(values){ return '" +
4727 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4730 body = ["this.compiled = function(values){ return ['"];
4731 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4732 body.push("'].join('');};");
4733 body = body.join('');
4743 // private function used to call members
4744 call : function(fnName, value, allValues){
4745 return this[fnName](value, allValues);
4749 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4750 * @param {String/HTMLElement/Roo.Element} el The context element
4751 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4752 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4753 * @return {HTMLElement/Roo.Element} The new node or Element
4755 insertFirst: function(el, values, returnElement){
4756 return this.doInsert('afterBegin', el, values, returnElement);
4760 * Applies the supplied values to the template and inserts the new node(s) before el.
4761 * @param {String/HTMLElement/Roo.Element} el The context element
4762 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4763 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4764 * @return {HTMLElement/Roo.Element} The new node or Element
4766 insertBefore: function(el, values, returnElement){
4767 return this.doInsert('beforeBegin', el, values, returnElement);
4771 * Applies the supplied values to the template and inserts the new node(s) after el.
4772 * @param {String/HTMLElement/Roo.Element} el The context element
4773 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4774 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775 * @return {HTMLElement/Roo.Element} The new node or Element
4777 insertAfter : function(el, values, returnElement){
4778 return this.doInsert('afterEnd', el, values, returnElement);
4782 * Applies the supplied values to the template and appends the new node(s) to el.
4783 * @param {String/HTMLElement/Roo.Element} el The context element
4784 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4785 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4786 * @return {HTMLElement/Roo.Element} The new node or Element
4788 append : function(el, values, returnElement){
4789 return this.doInsert('beforeEnd', el, values, returnElement);
4792 doInsert : function(where, el, values, returnEl){
4793 el = Roo.getDom(el);
4794 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4795 return returnEl ? Roo.get(newNode, true) : newNode;
4799 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4800 * @param {String/HTMLElement/Roo.Element} el The context element
4801 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4802 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4803 * @return {HTMLElement/Roo.Element} The new node or Element
4805 overwrite : function(el, values, returnElement){
4806 el = Roo.getDom(el);
4807 el.innerHTML = this.applyTemplate(values);
4808 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4812 * Alias for {@link #applyTemplate}
4815 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4818 Roo.DomHelper.Template = Roo.Template;
4821 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4822 * @param {String/HTMLElement} el A DOM element or its id
4823 * @returns {Roo.Template} The created template
4826 Roo.Template.from = function(el){
4827 el = Roo.getDom(el);
4828 return new Roo.Template(el.value || el.innerHTML);
4831 * Ext JS Library 1.1.1
4832 * Copyright(c) 2006-2007, Ext JS, LLC.
4834 * Originally Released Under LGPL - original licence link has changed is not relivant.
4837 * <script type="text/javascript">
4842 * This is code is also distributed under MIT license for use
4843 * with jQuery and prototype JavaScript libraries.
4846 * @class Roo.DomQuery
4847 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4849 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4852 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4854 <h4>Element Selectors:</h4>
4856 <li> <b>*</b> any element</li>
4857 <li> <b>E</b> an element with the tag E</li>
4858 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4859 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4860 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4861 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4863 <h4>Attribute Selectors:</h4>
4864 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4866 <li> <b>E[foo]</b> has an attribute "foo"</li>
4867 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4868 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4869 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4870 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4871 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4872 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4874 <h4>Pseudo Classes:</h4>
4876 <li> <b>E:first-child</b> E is the first child of its parent</li>
4877 <li> <b>E:last-child</b> E is the last child of its parent</li>
4878 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4879 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4880 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4881 <li> <b>E:only-child</b> E is the only child of its parent</li>
4882 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4883 <li> <b>E:first</b> the first E in the resultset</li>
4884 <li> <b>E:last</b> the last E in the resultset</li>
4885 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4886 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4887 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4888 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4889 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4890 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4891 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4892 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4893 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4895 <h4>CSS Value Selectors:</h4>
4897 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4898 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4899 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4900 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4901 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4902 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4906 Roo.DomQuery = function(){
4907 var cache = {}, simpleCache = {}, valueCache = {};
4908 var nonSpace = /\S/;
4909 var trimRe = /^\s+|\s+$/g;
4910 var tplRe = /\{(\d+)\}/g;
4911 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4912 var tagTokenRe = /^(#)?([\w-\*]+)/;
4913 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4915 function child(p, index){
4917 var n = p.firstChild;
4919 if(n.nodeType == 1){
4930 while((n = n.nextSibling) && n.nodeType != 1);
4935 while((n = n.previousSibling) && n.nodeType != 1);
4939 function children(d){
4940 var n = d.firstChild, ni = -1;
4942 var nx = n.nextSibling;
4943 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4953 function byClassName(c, a, v){
4957 var r = [], ri = -1, cn;
4958 for(var i = 0, ci; ci = c[i]; i++){
4959 if((' '+ci.className+' ').indexOf(v) != -1){
4966 function attrValue(n, attr){
4967 if(!n.tagName && typeof n.length != "undefined"){
4976 if(attr == "class" || attr == "className"){
4979 return n.getAttribute(attr) || n[attr];
4983 function getNodes(ns, mode, tagName){
4984 var result = [], ri = -1, cs;
4988 tagName = tagName || "*";
4989 if(typeof ns.getElementsByTagName != "undefined"){
4993 for(var i = 0, ni; ni = ns[i]; i++){
4994 cs = ni.getElementsByTagName(tagName);
4995 for(var j = 0, ci; ci = cs[j]; j++){
4999 }else if(mode == "/" || mode == ">"){
5000 var utag = tagName.toUpperCase();
5001 for(var i = 0, ni, cn; ni = ns[i]; i++){
5002 cn = ni.children || ni.childNodes;
5003 for(var j = 0, cj; cj = cn[j]; j++){
5004 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5009 }else if(mode == "+"){
5010 var utag = tagName.toUpperCase();
5011 for(var i = 0, n; n = ns[i]; i++){
5012 while((n = n.nextSibling) && n.nodeType != 1);
5013 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5017 }else if(mode == "~"){
5018 for(var i = 0, n; n = ns[i]; i++){
5019 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5028 function concat(a, b){
5032 for(var i = 0, l = b.length; i < l; i++){
5038 function byTag(cs, tagName){
5039 if(cs.tagName || cs == document){
5045 var r = [], ri = -1;
5046 tagName = tagName.toLowerCase();
5047 for(var i = 0, ci; ci = cs[i]; i++){
5048 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5055 function byId(cs, attr, id){
5056 if(cs.tagName || cs == document){
5062 var r = [], ri = -1;
5063 for(var i = 0,ci; ci = cs[i]; i++){
5064 if(ci && ci.id == id){
5072 function byAttribute(cs, attr, value, op, custom){
5073 var r = [], ri = -1, st = custom=="{";
5074 var f = Roo.DomQuery.operators[op];
5075 for(var i = 0, ci; ci = cs[i]; i++){
5078 a = Roo.DomQuery.getStyle(ci, attr);
5080 else if(attr == "class" || attr == "className"){
5082 }else if(attr == "for"){
5084 }else if(attr == "href"){
5085 a = ci.getAttribute("href", 2);
5087 a = ci.getAttribute(attr);
5089 if((f && f(a, value)) || (!f && a)){
5096 function byPseudo(cs, name, value){
5097 return Roo.DomQuery.pseudos[name](cs, value);
5100 // This is for IE MSXML which does not support expandos.
5101 // IE runs the same speed using setAttribute, however FF slows way down
5102 // and Safari completely fails so they need to continue to use expandos.
5103 var isIE = window.ActiveXObject ? true : false;
5105 // this eval is stop the compressor from
5106 // renaming the variable to something shorter
5108 /** eval:var:batch */
5113 function nodupIEXml(cs){
5115 cs[0].setAttribute("_nodup", d);
5117 for(var i = 1, len = cs.length; i < len; i++){
5119 if(!c.getAttribute("_nodup") != d){
5120 c.setAttribute("_nodup", d);
5124 for(var i = 0, len = cs.length; i < len; i++){
5125 cs[i].removeAttribute("_nodup");
5134 var len = cs.length, c, i, r = cs, cj, ri = -1;
5135 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5138 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5139 return nodupIEXml(cs);
5143 for(i = 1; c = cs[i]; i++){
5148 for(var j = 0; j < i; j++){
5151 for(j = i+1; cj = cs[j]; j++){
5163 function quickDiffIEXml(c1, c2){
5165 for(var i = 0, len = c1.length; i < len; i++){
5166 c1[i].setAttribute("_qdiff", d);
5169 for(var i = 0, len = c2.length; i < len; i++){
5170 if(c2[i].getAttribute("_qdiff") != d){
5171 r[r.length] = c2[i];
5174 for(var i = 0, len = c1.length; i < len; i++){
5175 c1[i].removeAttribute("_qdiff");
5180 function quickDiff(c1, c2){
5181 var len1 = c1.length;
5185 if(isIE && c1[0].selectSingleNode){
5186 return quickDiffIEXml(c1, c2);
5189 for(var i = 0; i < len1; i++){
5193 for(var i = 0, len = c2.length; i < len; i++){
5194 if(c2[i]._qdiff != d){
5195 r[r.length] = c2[i];
5201 function quickId(ns, mode, root, id){
5203 var d = root.ownerDocument || root;
5204 return d.getElementById(id);
5206 ns = getNodes(ns, mode, "*");
5207 return byId(ns, null, id);
5211 getStyle : function(el, name){
5212 return Roo.fly(el).getStyle(name);
5215 * Compiles a selector/xpath query into a reusable function. The returned function
5216 * takes one parameter "root" (optional), which is the context node from where the query should start.
5217 * @param {String} selector The selector/xpath query
5218 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5219 * @return {Function}
5221 compile : function(path, type){
5222 type = type || "select";
5224 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5225 var q = path, mode, lq;
5226 var tk = Roo.DomQuery.matchers;
5227 var tklen = tk.length;
5230 // accept leading mode switch
5231 var lmode = q.match(modeRe);
5232 if(lmode && lmode[1]){
5233 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5234 q = q.replace(lmode[1], "");
5236 // strip leading slashes
5237 while(path.substr(0, 1)=="/"){
5238 path = path.substr(1);
5241 while(q && lq != q){
5243 var tm = q.match(tagTokenRe);
5244 if(type == "select"){
5247 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5249 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5251 q = q.replace(tm[0], "");
5252 }else if(q.substr(0, 1) != '@'){
5253 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5258 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5260 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5262 q = q.replace(tm[0], "");
5265 while(!(mm = q.match(modeRe))){
5266 var matched = false;
5267 for(var j = 0; j < tklen; j++){
5269 var m = q.match(t.re);
5271 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5274 q = q.replace(m[0], "");
5279 // prevent infinite loop on bad selector
5281 throw 'Error parsing selector, parsing failed at "' + q + '"';
5285 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5286 q = q.replace(mm[1], "");
5289 fn[fn.length] = "return nodup(n);\n}";
5292 * list of variables that need from compression as they are used by eval.
5302 * eval:var:byClassName
5304 * eval:var:byAttribute
5305 * eval:var:attrValue
5313 * Selects a group of elements.
5314 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5315 * @param {Node} root (optional) The start of the query (defaults to document).
5318 select : function(path, root, type){
5319 if(!root || root == document){
5322 if(typeof root == "string"){
5323 root = document.getElementById(root);
5325 var paths = path.split(",");
5327 for(var i = 0, len = paths.length; i < len; i++){
5328 var p = paths[i].replace(trimRe, "");
5330 cache[p] = Roo.DomQuery.compile(p);
5332 throw p + " is not a valid selector";
5335 var result = cache[p](root);
5336 if(result && result != document){
5337 results = results.concat(result);
5340 if(paths.length > 1){
5341 return nodup(results);
5347 * Selects a single element.
5348 * @param {String} selector The selector/xpath query
5349 * @param {Node} root (optional) The start of the query (defaults to document).
5352 selectNode : function(path, root){
5353 return Roo.DomQuery.select(path, root)[0];
5357 * Selects the value of a node, optionally replacing null with the defaultValue.
5358 * @param {String} selector The selector/xpath query
5359 * @param {Node} root (optional) The start of the query (defaults to document).
5360 * @param {String} defaultValue
5362 selectValue : function(path, root, defaultValue){
5363 path = path.replace(trimRe, "");
5364 if(!valueCache[path]){
5365 valueCache[path] = Roo.DomQuery.compile(path, "select");
5367 var n = valueCache[path](root);
5368 n = n[0] ? n[0] : n;
5369 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5370 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5374 * Selects the value of a node, parsing integers and floats.
5375 * @param {String} selector The selector/xpath query
5376 * @param {Node} root (optional) The start of the query (defaults to document).
5377 * @param {Number} defaultValue
5380 selectNumber : function(path, root, defaultValue){
5381 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5382 return parseFloat(v);
5386 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5387 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5388 * @param {String} selector The simple selector to test
5391 is : function(el, ss){
5392 if(typeof el == "string"){
5393 el = document.getElementById(el);
5395 var isArray = (el instanceof Array);
5396 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5397 return isArray ? (result.length == el.length) : (result.length > 0);
5401 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5402 * @param {Array} el An array of elements to filter
5403 * @param {String} selector The simple selector to test
5404 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5405 * the selector instead of the ones that match
5408 filter : function(els, ss, nonMatches){
5409 ss = ss.replace(trimRe, "");
5410 if(!simpleCache[ss]){
5411 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5413 var result = simpleCache[ss](els);
5414 return nonMatches ? quickDiff(result, els) : result;
5418 * Collection of matching regular expressions and code snippets.
5422 select: 'n = byClassName(n, null, " {1} ");'
5424 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5425 select: 'n = byPseudo(n, "{1}", "{2}");'
5427 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5428 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5431 select: 'n = byId(n, null, "{1}");'
5434 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5439 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5440 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5443 "=" : function(a, v){
5446 "!=" : function(a, v){
5449 "^=" : function(a, v){
5450 return a && a.substr(0, v.length) == v;
5452 "$=" : function(a, v){
5453 return a && a.substr(a.length-v.length) == v;
5455 "*=" : function(a, v){
5456 return a && a.indexOf(v) !== -1;
5458 "%=" : function(a, v){
5459 return (a % v) == 0;
5461 "|=" : function(a, v){
5462 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5464 "~=" : function(a, v){
5465 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5470 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5471 * and the argument (if any) supplied in the selector.
5474 "first-child" : function(c){
5475 var r = [], ri = -1, n;
5476 for(var i = 0, ci; ci = n = c[i]; i++){
5477 while((n = n.previousSibling) && n.nodeType != 1);
5485 "last-child" : function(c){
5486 var r = [], ri = -1, n;
5487 for(var i = 0, ci; ci = n = c[i]; i++){
5488 while((n = n.nextSibling) && n.nodeType != 1);
5496 "nth-child" : function(c, a) {
5497 var r = [], ri = -1;
5498 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5499 var f = (m[1] || 1) - 0, l = m[2] - 0;
5500 for(var i = 0, n; n = c[i]; i++){
5501 var pn = n.parentNode;
5502 if (batch != pn._batch) {
5504 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5505 if(cn.nodeType == 1){
5512 if (l == 0 || n.nodeIndex == l){
5515 } else if ((n.nodeIndex + l) % f == 0){
5523 "only-child" : function(c){
5524 var r = [], ri = -1;;
5525 for(var i = 0, ci; ci = c[i]; i++){
5526 if(!prev(ci) && !next(ci)){
5533 "empty" : function(c){
5534 var r = [], ri = -1;
5535 for(var i = 0, ci; ci = c[i]; i++){
5536 var cns = ci.childNodes, j = 0, cn, empty = true;
5539 if(cn.nodeType == 1 || cn.nodeType == 3){
5551 "contains" : function(c, v){
5552 var r = [], ri = -1;
5553 for(var i = 0, ci; ci = c[i]; i++){
5554 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5561 "nodeValue" : function(c, v){
5562 var r = [], ri = -1;
5563 for(var i = 0, ci; ci = c[i]; i++){
5564 if(ci.firstChild && ci.firstChild.nodeValue == v){
5571 "checked" : function(c){
5572 var r = [], ri = -1;
5573 for(var i = 0, ci; ci = c[i]; i++){
5574 if(ci.checked == true){
5581 "not" : function(c, ss){
5582 return Roo.DomQuery.filter(c, ss, true);
5585 "odd" : function(c){
5586 return this["nth-child"](c, "odd");
5589 "even" : function(c){
5590 return this["nth-child"](c, "even");
5593 "nth" : function(c, a){
5594 return c[a-1] || [];
5597 "first" : function(c){
5601 "last" : function(c){
5602 return c[c.length-1] || [];
5605 "has" : function(c, ss){
5606 var s = Roo.DomQuery.select;
5607 var r = [], ri = -1;
5608 for(var i = 0, ci; ci = c[i]; i++){
5609 if(s(ss, ci).length > 0){
5616 "next" : function(c, ss){
5617 var is = Roo.DomQuery.is;
5618 var r = [], ri = -1;
5619 for(var i = 0, ci; ci = c[i]; i++){
5628 "prev" : function(c, ss){
5629 var is = Roo.DomQuery.is;
5630 var r = [], ri = -1;
5631 for(var i = 0, ci; ci = c[i]; i++){
5644 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5645 * @param {String} path The selector/xpath query
5646 * @param {Node} root (optional) The start of the query (defaults to document).
5651 Roo.query = Roo.DomQuery.select;
5654 * Ext JS Library 1.1.1
5655 * Copyright(c) 2006-2007, Ext JS, LLC.
5657 * Originally Released Under LGPL - original licence link has changed is not relivant.
5660 * <script type="text/javascript">
5664 * @class Roo.util.Observable
5665 * Base class that provides a common interface for publishing events. Subclasses are expected to
5666 * to have a property "events" with all the events defined.<br>
5669 Employee = function(name){
5676 Roo.extend(Employee, Roo.util.Observable);
5678 * @param {Object} config properties to use (incuding events / listeners)
5681 Roo.util.Observable = function(cfg){
5684 this.addEvents(cfg.events || {});
5686 delete cfg.events; // make sure
5689 Roo.apply(this, cfg);
5692 this.on(this.listeners);
5693 delete this.listeners;
5696 Roo.util.Observable.prototype = {
5698 * @cfg {Object} listeners list of events and functions to call for this object,
5702 'click' : function(e) {
5712 * Fires the specified event with the passed parameters (minus the event name).
5713 * @param {String} eventName
5714 * @param {Object...} args Variable number of parameters are passed to handlers
5715 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5717 fireEvent : function(){
5718 var ce = this.events[arguments[0].toLowerCase()];
5719 if(typeof ce == "object"){
5720 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5727 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5730 * Appends an event handler to this component
5731 * @param {String} eventName The type of event to listen for
5732 * @param {Function} handler The method the event invokes
5733 * @param {Object} scope (optional) The scope in which to execute the handler
5734 * function. The handler function's "this" context.
5735 * @param {Object} options (optional) An object containing handler configuration
5736 * properties. This may contain any of the following properties:<ul>
5737 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5738 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5739 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5740 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5741 * by the specified number of milliseconds. If the event fires again within that time, the original
5742 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5745 * <b>Combining Options</b><br>
5746 * Using the options argument, it is possible to combine different types of listeners:<br>
5748 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5750 el.on('click', this.onClick, this, {
5757 * <b>Attaching multiple handlers in 1 call</b><br>
5758 * The method also allows for a single argument to be passed which is a config object containing properties
5759 * which specify multiple handlers.
5768 fn: this.onMouseOver,
5772 fn: this.onMouseOut,
5778 * Or a shorthand syntax which passes the same scope object to all handlers:
5781 'click': this.onClick,
5782 'mouseover': this.onMouseOver,
5783 'mouseout': this.onMouseOut,
5788 addListener : function(eventName, fn, scope, o){
5789 if(typeof eventName == "object"){
5792 if(this.filterOptRe.test(e)){
5795 if(typeof o[e] == "function"){
5797 this.addListener(e, o[e], o.scope, o);
5799 // individual options
5800 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5805 o = (!o || typeof o == "boolean") ? {} : o;
5806 eventName = eventName.toLowerCase();
5807 var ce = this.events[eventName] || true;
5808 if(typeof ce == "boolean"){
5809 ce = new Roo.util.Event(this, eventName);
5810 this.events[eventName] = ce;
5812 ce.addListener(fn, scope, o);
5816 * Removes a listener
5817 * @param {String} eventName The type of event to listen for
5818 * @param {Function} handler The handler to remove
5819 * @param {Object} scope (optional) The scope (this object) for the handler
5821 removeListener : function(eventName, fn, scope){
5822 var ce = this.events[eventName.toLowerCase()];
5823 if(typeof ce == "object"){
5824 ce.removeListener(fn, scope);
5829 * Removes all listeners for this object
5831 purgeListeners : function(){
5832 for(var evt in this.events){
5833 if(typeof this.events[evt] == "object"){
5834 this.events[evt].clearListeners();
5839 relayEvents : function(o, events){
5840 var createHandler = function(ename){
5842 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5845 for(var i = 0, len = events.length; i < len; i++){
5846 var ename = events[i];
5847 if(!this.events[ename]){ this.events[ename] = true; };
5848 o.on(ename, createHandler(ename), this);
5853 * Used to define events on this Observable
5854 * @param {Object} object The object with the events defined
5856 addEvents : function(o){
5860 Roo.applyIf(this.events, o);
5864 * Checks to see if this object has any listeners for a specified event
5865 * @param {String} eventName The name of the event to check for
5866 * @return {Boolean} True if the event is being listened for, else false
5868 hasListener : function(eventName){
5869 var e = this.events[eventName];
5870 return typeof e == "object" && e.listeners.length > 0;
5874 * Appends an event handler to this element (shorthand for addListener)
5875 * @param {String} eventName The type of event to listen for
5876 * @param {Function} handler The method the event invokes
5877 * @param {Object} scope (optional) The scope in which to execute the handler
5878 * function. The handler function's "this" context.
5879 * @param {Object} options (optional)
5882 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5884 * Removes a listener (shorthand for removeListener)
5885 * @param {String} eventName The type of event to listen for
5886 * @param {Function} handler The handler to remove
5887 * @param {Object} scope (optional) The scope (this object) for the handler
5890 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5893 * Starts capture on the specified Observable. All events will be passed
5894 * to the supplied function with the event name + standard signature of the event
5895 * <b>before</b> the event is fired. If the supplied function returns false,
5896 * the event will not fire.
5897 * @param {Observable} o The Observable to capture
5898 * @param {Function} fn The function to call
5899 * @param {Object} scope (optional) The scope (this object) for the fn
5902 Roo.util.Observable.capture = function(o, fn, scope){
5903 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5907 * Removes <b>all</b> added captures from the Observable.
5908 * @param {Observable} o The Observable to release
5911 Roo.util.Observable.releaseCapture = function(o){
5912 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5917 var createBuffered = function(h, o, scope){
5918 var task = new Roo.util.DelayedTask();
5920 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5924 var createSingle = function(h, e, fn, scope){
5926 e.removeListener(fn, scope);
5927 return h.apply(scope, arguments);
5931 var createDelayed = function(h, o, scope){
5933 var args = Array.prototype.slice.call(arguments, 0);
5934 setTimeout(function(){
5935 h.apply(scope, args);
5940 Roo.util.Event = function(obj, name){
5943 this.listeners = [];
5946 Roo.util.Event.prototype = {
5947 addListener : function(fn, scope, options){
5948 var o = options || {};
5949 scope = scope || this.obj;
5950 if(!this.isListening(fn, scope)){
5951 var l = {fn: fn, scope: scope, options: o};
5954 h = createDelayed(h, o, scope);
5957 h = createSingle(h, this, fn, scope);
5960 h = createBuffered(h, o, scope);
5963 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5964 this.listeners.push(l);
5966 this.listeners = this.listeners.slice(0);
5967 this.listeners.push(l);
5972 findListener : function(fn, scope){
5973 scope = scope || this.obj;
5974 var ls = this.listeners;
5975 for(var i = 0, len = ls.length; i < len; i++){
5977 if(l.fn == fn && l.scope == scope){
5984 isListening : function(fn, scope){
5985 return this.findListener(fn, scope) != -1;
5988 removeListener : function(fn, scope){
5990 if((index = this.findListener(fn, scope)) != -1){
5992 this.listeners.splice(index, 1);
5994 this.listeners = this.listeners.slice(0);
5995 this.listeners.splice(index, 1);
6002 clearListeners : function(){
6003 this.listeners = [];
6007 var ls = this.listeners, scope, len = ls.length;
6010 var args = Array.prototype.slice.call(arguments, 0);
6011 for(var i = 0; i < len; i++){
6013 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6014 this.firing = false;
6018 this.firing = false;
6025 * Ext JS Library 1.1.1
6026 * Copyright(c) 2006-2007, Ext JS, LLC.
6028 * Originally Released Under LGPL - original licence link has changed is not relivant.
6031 * <script type="text/javascript">
6035 * @class Roo.EventManager
6036 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6037 * several useful events directly.
6038 * See {@link Roo.EventObject} for more details on normalized event objects.
6041 Roo.EventManager = function(){
6042 var docReadyEvent, docReadyProcId, docReadyState = false;
6043 var resizeEvent, resizeTask, textEvent, textSize;
6044 var E = Roo.lib.Event;
6045 var D = Roo.lib.Dom;
6048 var fireDocReady = function(){
6050 docReadyState = true;
6053 clearInterval(docReadyProcId);
6055 if(Roo.isGecko || Roo.isOpera) {
6056 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6059 var defer = document.getElementById("ie-deferred-loader");
6061 defer.onreadystatechange = null;
6062 defer.parentNode.removeChild(defer);
6066 docReadyEvent.fire();
6067 docReadyEvent.clearListeners();
6072 var initDocReady = function(){
6073 docReadyEvent = new Roo.util.Event();
6074 if(Roo.isGecko || Roo.isOpera) {
6075 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6077 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6078 var defer = document.getElementById("ie-deferred-loader");
6079 defer.onreadystatechange = function(){
6080 if(this.readyState == "complete"){
6084 }else if(Roo.isSafari){
6085 docReadyProcId = setInterval(function(){
6086 var rs = document.readyState;
6087 if(rs == "complete") {
6092 // no matter what, make sure it fires on load
6093 E.on(window, "load", fireDocReady);
6096 var createBuffered = function(h, o){
6097 var task = new Roo.util.DelayedTask(h);
6099 // create new event object impl so new events don't wipe out properties
6100 e = new Roo.EventObjectImpl(e);
6101 task.delay(o.buffer, h, null, [e]);
6105 var createSingle = function(h, el, ename, fn){
6107 Roo.EventManager.removeListener(el, ename, fn);
6112 var createDelayed = function(h, o){
6114 // create new event object impl so new events don't wipe out properties
6115 e = new Roo.EventObjectImpl(e);
6116 setTimeout(function(){
6122 var listen = function(element, ename, opt, fn, scope){
6123 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6124 fn = fn || o.fn; scope = scope || o.scope;
6125 var el = Roo.getDom(element);
6127 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6129 var h = function(e){
6130 e = Roo.EventObject.setEvent(e);
6133 t = e.getTarget(o.delegate, el);
6140 if(o.stopEvent === true){
6143 if(o.preventDefault === true){
6146 if(o.stopPropagation === true){
6147 e.stopPropagation();
6150 if(o.normalized === false){
6154 fn.call(scope || el, e, t, o);
6157 h = createDelayed(h, o);
6160 h = createSingle(h, el, ename, fn);
6163 h = createBuffered(h, o);
6165 fn._handlers = fn._handlers || [];
6166 fn._handlers.push([Roo.id(el), ename, h]);
6169 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6170 el.addEventListener("DOMMouseScroll", h, false);
6171 E.on(window, 'unload', function(){
6172 el.removeEventListener("DOMMouseScroll", h, false);
6175 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6176 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6181 var stopListening = function(el, ename, fn){
6182 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6184 for(var i = 0, len = hds.length; i < len; i++){
6186 if(h[0] == id && h[1] == ename){
6193 E.un(el, ename, hd);
6194 el = Roo.getDom(el);
6195 if(ename == "mousewheel" && el.addEventListener){
6196 el.removeEventListener("DOMMouseScroll", hd, false);
6198 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6199 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6203 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6210 * @scope Roo.EventManager
6215 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6216 * object with a Roo.EventObject
6217 * @param {Function} fn The method the event invokes
6218 * @param {Object} scope An object that becomes the scope of the handler
6219 * @param {boolean} override If true, the obj passed in becomes
6220 * the execution scope of the listener
6221 * @return {Function} The wrapped function
6224 wrap : function(fn, scope, override){
6226 Roo.EventObject.setEvent(e);
6227 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6232 * Appends an event handler to an element (shorthand for addListener)
6233 * @param {String/HTMLElement} element The html element or id to assign the
6234 * @param {String} eventName The type of event to listen for
6235 * @param {Function} handler The method the event invokes
6236 * @param {Object} scope (optional) The scope in which to execute the handler
6237 * function. The handler function's "this" context.
6238 * @param {Object} options (optional) An object containing handler configuration
6239 * properties. This may contain any of the following properties:<ul>
6240 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6241 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6242 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6243 * <li>preventDefault {Boolean} True to prevent the default action</li>
6244 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6245 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6246 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6247 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6248 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6249 * by the specified number of milliseconds. If the event fires again within that time, the original
6250 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6253 * <b>Combining Options</b><br>
6254 * Using the options argument, it is possible to combine different types of listeners:<br>
6256 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6258 el.on('click', this.onClick, this, {
6265 * <b>Attaching multiple handlers in 1 call</b><br>
6266 * The method also allows for a single argument to be passed which is a config object containing properties
6267 * which specify multiple handlers.
6277 fn: this.onMouseOver
6286 * Or a shorthand syntax:<br>
6289 'click' : this.onClick,
6290 'mouseover' : this.onMouseOver,
6291 'mouseout' : this.onMouseOut
6295 addListener : function(element, eventName, fn, scope, options){
6296 if(typeof eventName == "object"){
6302 if(typeof o[e] == "function"){
6304 listen(element, e, o, o[e], o.scope);
6306 // individual options
6307 listen(element, e, o[e]);
6312 return listen(element, eventName, options, fn, scope);
6316 * Removes an event handler
6318 * @param {String/HTMLElement} element The id or html element to remove the
6320 * @param {String} eventName The type of event
6321 * @param {Function} fn
6322 * @return {Boolean} True if a listener was actually removed
6324 removeListener : function(element, eventName, fn){
6325 return stopListening(element, eventName, fn);
6329 * Fires when the document is ready (before onload and before images are loaded). Can be
6330 * accessed shorthanded Roo.onReady().
6331 * @param {Function} fn The method the event invokes
6332 * @param {Object} scope An object that becomes the scope of the handler
6333 * @param {boolean} options
6335 onDocumentReady : function(fn, scope, options){
6336 if(docReadyState){ // if it already fired
6337 docReadyEvent.addListener(fn, scope, options);
6338 docReadyEvent.fire();
6339 docReadyEvent.clearListeners();
6345 docReadyEvent.addListener(fn, scope, options);
6349 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6350 * @param {Function} fn The method the event invokes
6351 * @param {Object} scope An object that becomes the scope of the handler
6352 * @param {boolean} options
6354 onWindowResize : function(fn, scope, options){
6356 resizeEvent = new Roo.util.Event();
6357 resizeTask = new Roo.util.DelayedTask(function(){
6358 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6360 E.on(window, "resize", function(){
6362 resizeTask.delay(50);
6364 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6368 resizeEvent.addListener(fn, scope, options);
6372 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6373 * @param {Function} fn The method the event invokes
6374 * @param {Object} scope An object that becomes the scope of the handler
6375 * @param {boolean} options
6377 onTextResize : function(fn, scope, options){
6379 textEvent = new Roo.util.Event();
6380 var textEl = new Roo.Element(document.createElement('div'));
6381 textEl.dom.className = 'x-text-resize';
6382 textEl.dom.innerHTML = 'X';
6383 textEl.appendTo(document.body);
6384 textSize = textEl.dom.offsetHeight;
6385 setInterval(function(){
6386 if(textEl.dom.offsetHeight != textSize){
6387 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6389 }, this.textResizeInterval);
6391 textEvent.addListener(fn, scope, options);
6395 * Removes the passed window resize listener.
6396 * @param {Function} fn The method the event invokes
6397 * @param {Object} scope The scope of handler
6399 removeResizeListener : function(fn, scope){
6401 resizeEvent.removeListener(fn, scope);
6406 fireResize : function(){
6408 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6412 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6416 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6418 textResizeInterval : 50
6423 * @scopeAlias pub=Roo.EventManager
6427 * Appends an event handler to an element (shorthand for addListener)
6428 * @param {String/HTMLElement} element The html element or id to assign the
6429 * @param {String} eventName The type of event to listen for
6430 * @param {Function} handler The method the event invokes
6431 * @param {Object} scope (optional) The scope in which to execute the handler
6432 * function. The handler function's "this" context.
6433 * @param {Object} options (optional) An object containing handler configuration
6434 * properties. This may contain any of the following properties:<ul>
6435 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6436 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6437 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6438 * <li>preventDefault {Boolean} True to prevent the default action</li>
6439 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6440 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6441 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6442 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6443 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6444 * by the specified number of milliseconds. If the event fires again within that time, the original
6445 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6448 * <b>Combining Options</b><br>
6449 * Using the options argument, it is possible to combine different types of listeners:<br>
6451 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6453 el.on('click', this.onClick, this, {
6460 * <b>Attaching multiple handlers in 1 call</b><br>
6461 * The method also allows for a single argument to be passed which is a config object containing properties
6462 * which specify multiple handlers.
6472 fn: this.onMouseOver
6481 * Or a shorthand syntax:<br>
6484 'click' : this.onClick,
6485 'mouseover' : this.onMouseOver,
6486 'mouseout' : this.onMouseOut
6490 pub.on = pub.addListener;
6491 pub.un = pub.removeListener;
6493 pub.stoppedMouseDownEvent = new Roo.util.Event();
6497 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6498 * @param {Function} fn The method the event invokes
6499 * @param {Object} scope An object that becomes the scope of the handler
6500 * @param {boolean} override If true, the obj passed in becomes
6501 * the execution scope of the listener
6505 Roo.onReady = Roo.EventManager.onDocumentReady;
6507 Roo.onReady(function(){
6508 var bd = Roo.get(document.body);
6513 : Roo.isGecko ? "roo-gecko"
6514 : Roo.isOpera ? "roo-opera"
6515 : Roo.isSafari ? "roo-safari" : ""];
6518 cls.push("roo-mac");
6521 cls.push("roo-linux");
6523 if(Roo.isBorderBox){
6524 cls.push('roo-border-box');
6526 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6527 var p = bd.dom.parentNode;
6529 p.className += ' roo-strict';
6532 bd.addClass(cls.join(' '));
6536 * @class Roo.EventObject
6537 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6538 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6541 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6543 var target = e.getTarget();
6546 var myDiv = Roo.get("myDiv");
6547 myDiv.on("click", handleClick);
6549 Roo.EventManager.on("myDiv", 'click', handleClick);
6550 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6554 Roo.EventObject = function(){
6556 var E = Roo.lib.Event;
6558 // safari keypress events for special keys return bad keycodes
6561 63235 : 39, // right
6564 63276 : 33, // page up
6565 63277 : 34, // page down
6566 63272 : 46, // delete
6571 // normalize button clicks
6572 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6573 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6575 Roo.EventObjectImpl = function(e){
6577 this.setEvent(e.browserEvent || e);
6580 Roo.EventObjectImpl.prototype = {
6582 * Used to fix doc tools.
6583 * @scope Roo.EventObject.prototype
6589 /** The normal browser event */
6590 browserEvent : null,
6591 /** The button pressed in a mouse event */
6593 /** True if the shift key was down during the event */
6595 /** True if the control key was down during the event */
6597 /** True if the alt key was down during the event */
6656 setEvent : function(e){
6657 if(e == this || (e && e.browserEvent)){ // already wrapped
6660 this.browserEvent = e;
6662 // normalize buttons
6663 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6664 if(e.type == 'click' && this.button == -1){
6668 this.shiftKey = e.shiftKey;
6669 // mac metaKey behaves like ctrlKey
6670 this.ctrlKey = e.ctrlKey || e.metaKey;
6671 this.altKey = e.altKey;
6672 // in getKey these will be normalized for the mac
6673 this.keyCode = e.keyCode;
6674 // keyup warnings on firefox.
6675 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6676 // cache the target for the delayed and or buffered events
6677 this.target = E.getTarget(e);
6679 this.xy = E.getXY(e);
6682 this.shiftKey = false;
6683 this.ctrlKey = false;
6684 this.altKey = false;
6694 * Stop the event (preventDefault and stopPropagation)
6696 stopEvent : function(){
6697 if(this.browserEvent){
6698 if(this.browserEvent.type == 'mousedown'){
6699 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6701 E.stopEvent(this.browserEvent);
6706 * Prevents the browsers default handling of the event.
6708 preventDefault : function(){
6709 if(this.browserEvent){
6710 E.preventDefault(this.browserEvent);
6715 isNavKeyPress : function(){
6716 var k = this.keyCode;
6717 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6718 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6721 isSpecialKey : function(){
6722 var k = this.keyCode;
6723 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6724 (k == 16) || (k == 17) ||
6725 (k >= 18 && k <= 20) ||
6726 (k >= 33 && k <= 35) ||
6727 (k >= 36 && k <= 39) ||
6728 (k >= 44 && k <= 45);
6731 * Cancels bubbling of the event.
6733 stopPropagation : function(){
6734 if(this.browserEvent){
6735 if(this.type == 'mousedown'){
6736 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6738 E.stopPropagation(this.browserEvent);
6743 * Gets the key code for the event.
6746 getCharCode : function(){
6747 return this.charCode || this.keyCode;
6751 * Returns a normalized keyCode for the event.
6752 * @return {Number} The key code
6754 getKey : function(){
6755 var k = this.keyCode || this.charCode;
6756 return Roo.isSafari ? (safariKeys[k] || k) : k;
6760 * Gets the x coordinate of the event.
6763 getPageX : function(){
6768 * Gets the y coordinate of the event.
6771 getPageY : function(){
6776 * Gets the time of the event.
6779 getTime : function(){
6780 if(this.browserEvent){
6781 return E.getTime(this.browserEvent);
6787 * Gets the page coordinates of the event.
6788 * @return {Array} The xy values like [x, y]
6795 * Gets the target for the event.
6796 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6797 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6798 search as a number or element (defaults to 10 || document.body)
6799 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6800 * @return {HTMLelement}
6802 getTarget : function(selector, maxDepth, returnEl){
6803 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6806 * Gets the related target.
6807 * @return {HTMLElement}
6809 getRelatedTarget : function(){
6810 if(this.browserEvent){
6811 return E.getRelatedTarget(this.browserEvent);
6817 * Normalizes mouse wheel delta across browsers
6818 * @return {Number} The delta
6820 getWheelDelta : function(){
6821 var e = this.browserEvent;
6823 if(e.wheelDelta){ /* IE/Opera. */
6824 delta = e.wheelDelta/120;
6825 }else if(e.detail){ /* Mozilla case. */
6826 delta = -e.detail/3;
6832 * Returns true if the control, meta, shift or alt key was pressed during this event.
6835 hasModifier : function(){
6836 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6840 * Returns true if the target of this event equals el or is a child of el
6841 * @param {String/HTMLElement/Element} el
6842 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6845 within : function(el, related){
6846 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6847 return t && Roo.fly(el).contains(t);
6850 getPoint : function(){
6851 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6855 return new Roo.EventObjectImpl();
6860 * Ext JS Library 1.1.1
6861 * Copyright(c) 2006-2007, Ext JS, LLC.
6863 * Originally Released Under LGPL - original licence link has changed is not relivant.
6866 * <script type="text/javascript">
6870 // was in Composite Element!??!?!
6873 var D = Roo.lib.Dom;
6874 var E = Roo.lib.Event;
6875 var A = Roo.lib.Anim;
6877 // local style camelizing for speed
6879 var camelRe = /(-[a-z])/gi;
6880 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6881 var view = document.defaultView;
6884 * @class Roo.Element
6885 * Represents an Element in the DOM.<br><br>
6888 var el = Roo.get("my-div");
6891 var el = getEl("my-div");
6893 // or with a DOM element
6894 var el = Roo.get(myDivElement);
6896 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6897 * each call instead of constructing a new one.<br><br>
6898 * <b>Animations</b><br />
6899 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6900 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6902 Option Default Description
6903 --------- -------- ---------------------------------------------
6904 duration .35 The duration of the animation in seconds
6905 easing easeOut The YUI easing method
6906 callback none A function to execute when the anim completes
6907 scope this The scope (this) of the callback function
6909 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6910 * manipulate the animation. Here's an example:
6912 var el = Roo.get("my-div");
6917 // default animation
6918 el.setWidth(100, true);
6920 // animation with some options set
6927 // using the "anim" property to get the Anim object
6933 el.setWidth(100, opt);
6935 if(opt.anim.isAnimated()){
6939 * <b> Composite (Collections of) Elements</b><br />
6940 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6941 * @constructor Create a new Element directly.
6942 * @param {String/HTMLElement} element
6943 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6945 Roo.Element = function(element, forceNew){
6946 var dom = typeof element == "string" ?
6947 document.getElementById(element) : element;
6948 if(!dom){ // invalid id/element
6952 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6953 return Roo.Element.cache[id];
6963 * The DOM element ID
6966 this.id = id || Roo.id(dom);
6969 var El = Roo.Element;
6973 * The element's default display mode (defaults to "")
6976 originalDisplay : "",
6980 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6985 * Sets the element's visibility mode. When setVisible() is called it
6986 * will use this to determine whether to set the visibility or the display property.
6987 * @param visMode Element.VISIBILITY or Element.DISPLAY
6988 * @return {Roo.Element} this
6990 setVisibilityMode : function(visMode){
6991 this.visibilityMode = visMode;
6995 * Convenience method for setVisibilityMode(Element.DISPLAY)
6996 * @param {String} display (optional) What to set display to when visible
6997 * @return {Roo.Element} this
6999 enableDisplayMode : function(display){
7000 this.setVisibilityMode(El.DISPLAY);
7001 if(typeof display != "undefined") this.originalDisplay = display;
7006 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7007 * @param {String} selector The simple selector to test
7008 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7009 search as a number or element (defaults to 10 || document.body)
7010 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7011 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7013 findParent : function(simpleSelector, maxDepth, returnEl){
7014 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7015 maxDepth = maxDepth || 50;
7016 if(typeof maxDepth != "number"){
7017 stopEl = Roo.getDom(maxDepth);
7020 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7021 if(dq.is(p, simpleSelector)){
7022 return returnEl ? Roo.get(p) : p;
7032 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7033 * @param {String} selector The simple selector to test
7034 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7035 search as a number or element (defaults to 10 || document.body)
7036 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7037 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7039 findParentNode : function(simpleSelector, maxDepth, returnEl){
7040 var p = Roo.fly(this.dom.parentNode, '_internal');
7041 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7045 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7046 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7047 * @param {String} selector The simple selector to test
7048 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7049 search as a number or element (defaults to 10 || document.body)
7050 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7052 up : function(simpleSelector, maxDepth){
7053 return this.findParentNode(simpleSelector, maxDepth, true);
7059 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7060 * @param {String} selector The simple selector to test
7061 * @return {Boolean} True if this element matches the selector, else false
7063 is : function(simpleSelector){
7064 return Roo.DomQuery.is(this.dom, simpleSelector);
7068 * Perform animation on this element.
7069 * @param {Object} args The YUI animation control args
7070 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7071 * @param {Function} onComplete (optional) Function to call when animation completes
7072 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7073 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7074 * @return {Roo.Element} this
7076 animate : function(args, duration, onComplete, easing, animType){
7077 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7082 * @private Internal animation call
7084 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7085 animType = animType || 'run';
7087 var anim = Roo.lib.Anim[animType](
7089 (opt.duration || defaultDur) || .35,
7090 (opt.easing || defaultEase) || 'easeOut',
7092 Roo.callback(cb, this);
7093 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7101 // private legacy anim prep
7102 preanim : function(a, i){
7103 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7107 * Removes worthless text nodes
7108 * @param {Boolean} forceReclean (optional) By default the element
7109 * keeps track if it has been cleaned already so
7110 * you can call this over and over. However, if you update the element and
7111 * need to force a reclean, you can pass true.
7113 clean : function(forceReclean){
7114 if(this.isCleaned && forceReclean !== true){
7118 var d = this.dom, n = d.firstChild, ni = -1;
7120 var nx = n.nextSibling;
7121 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7128 this.isCleaned = true;
7133 calcOffsetsTo : function(el){
7136 var restorePos = false;
7137 if(el.getStyle('position') == 'static'){
7138 el.position('relative');
7143 while(op && op != d && op.tagName != 'HTML'){
7146 op = op.offsetParent;
7149 el.position('static');
7155 * Scrolls this element into view within the passed container.
7156 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7157 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7158 * @return {Roo.Element} this
7160 scrollIntoView : function(container, hscroll){
7161 var c = Roo.getDom(container) || document.body;
7164 var o = this.calcOffsetsTo(c),
7167 b = t+el.offsetHeight,
7168 r = l+el.offsetWidth;
7170 var ch = c.clientHeight;
7171 var ct = parseInt(c.scrollTop, 10);
7172 var cl = parseInt(c.scrollLeft, 10);
7174 var cr = cl + c.clientWidth;
7182 if(hscroll !== false){
7186 c.scrollLeft = r-c.clientWidth;
7193 scrollChildIntoView : function(child, hscroll){
7194 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7198 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7199 * the new height may not be available immediately.
7200 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7201 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7202 * @param {Function} onComplete (optional) Function to call when animation completes
7203 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7204 * @return {Roo.Element} this
7206 autoHeight : function(animate, duration, onComplete, easing){
7207 var oldHeight = this.getHeight();
7209 this.setHeight(1); // force clipping
7210 setTimeout(function(){
7211 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7213 this.setHeight(height);
7215 if(typeof onComplete == "function"){
7219 this.setHeight(oldHeight); // restore original height
7220 this.setHeight(height, animate, duration, function(){
7222 if(typeof onComplete == "function") onComplete();
7223 }.createDelegate(this), easing);
7225 }.createDelegate(this), 0);
7230 * Returns true if this element is an ancestor of the passed element
7231 * @param {HTMLElement/String} el The element to check
7232 * @return {Boolean} True if this element is an ancestor of el, else false
7234 contains : function(el){
7235 if(!el){return false;}
7236 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7240 * Checks whether the element is currently visible using both visibility and display properties.
7241 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7242 * @return {Boolean} True if the element is currently visible, else false
7244 isVisible : function(deep) {
7245 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7246 if(deep !== true || !vis){
7249 var p = this.dom.parentNode;
7250 while(p && p.tagName.toLowerCase() != "body"){
7251 if(!Roo.fly(p, '_isVisible').isVisible()){
7260 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7261 * @param {String} selector The CSS selector
7262 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7263 * @return {CompositeElement/CompositeElementLite} The composite element
7265 select : function(selector, unique){
7266 return El.select(selector, unique, this.dom);
7270 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7271 * @param {String} selector The CSS selector
7272 * @return {Array} An array of the matched nodes
7274 query : function(selector, unique){
7275 return Roo.DomQuery.select(selector, this.dom);
7279 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7280 * @param {String} selector The CSS selector
7281 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7282 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7284 child : function(selector, returnDom){
7285 var n = Roo.DomQuery.selectNode(selector, this.dom);
7286 return returnDom ? n : Roo.get(n);
7290 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7291 * @param {String} selector The CSS selector
7292 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7293 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7295 down : function(selector, returnDom){
7296 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7297 return returnDom ? n : Roo.get(n);
7301 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7302 * @param {String} group The group the DD object is member of
7303 * @param {Object} config The DD config object
7304 * @param {Object} overrides An object containing methods to override/implement on the DD object
7305 * @return {Roo.dd.DD} The DD object
7307 initDD : function(group, config, overrides){
7308 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7309 return Roo.apply(dd, overrides);
7313 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7314 * @param {String} group The group the DDProxy object is member of
7315 * @param {Object} config The DDProxy config object
7316 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7317 * @return {Roo.dd.DDProxy} The DDProxy object
7319 initDDProxy : function(group, config, overrides){
7320 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7321 return Roo.apply(dd, overrides);
7325 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7326 * @param {String} group The group the DDTarget object is member of
7327 * @param {Object} config The DDTarget config object
7328 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7329 * @return {Roo.dd.DDTarget} The DDTarget object
7331 initDDTarget : function(group, config, overrides){
7332 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7333 return Roo.apply(dd, overrides);
7337 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7338 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7339 * @param {Boolean} visible Whether the element is visible
7340 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7341 * @return {Roo.Element} this
7343 setVisible : function(visible, animate){
7345 if(this.visibilityMode == El.DISPLAY){
7346 this.setDisplayed(visible);
7349 this.dom.style.visibility = visible ? "visible" : "hidden";
7352 // closure for composites
7354 var visMode = this.visibilityMode;
7356 this.setOpacity(.01);
7357 this.setVisible(true);
7359 this.anim({opacity: { to: (visible?1:0) }},
7360 this.preanim(arguments, 1),
7361 null, .35, 'easeIn', function(){
7363 if(visMode == El.DISPLAY){
7364 dom.style.display = "none";
7366 dom.style.visibility = "hidden";
7368 Roo.get(dom).setOpacity(1);
7376 * Returns true if display is not "none"
7379 isDisplayed : function() {
7380 return this.getStyle("display") != "none";
7384 * Toggles the element's visibility or display, depending on visibility mode.
7385 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7386 * @return {Roo.Element} this
7388 toggle : function(animate){
7389 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7394 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7395 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7396 * @return {Roo.Element} this
7398 setDisplayed : function(value) {
7399 if(typeof value == "boolean"){
7400 value = value ? this.originalDisplay : "none";
7402 this.setStyle("display", value);
7407 * Tries to focus the element. Any exceptions are caught and ignored.
7408 * @return {Roo.Element} this
7410 focus : function() {
7418 * Tries to blur the element. Any exceptions are caught and ignored.
7419 * @return {Roo.Element} this
7429 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7430 * @param {String/Array} className The CSS class to add, or an array of classes
7431 * @return {Roo.Element} this
7433 addClass : function(className){
7434 if(className instanceof Array){
7435 for(var i = 0, len = className.length; i < len; i++) {
7436 this.addClass(className[i]);
7439 if(className && !this.hasClass(className)){
7440 this.dom.className = this.dom.className + " " + className;
7447 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7448 * @param {String/Array} className The CSS class to add, or an array of classes
7449 * @return {Roo.Element} this
7451 radioClass : function(className){
7452 var siblings = this.dom.parentNode.childNodes;
7453 for(var i = 0; i < siblings.length; i++) {
7454 var s = siblings[i];
7455 if(s.nodeType == 1){
7456 Roo.get(s).removeClass(className);
7459 this.addClass(className);
7464 * Removes one or more CSS classes from the element.
7465 * @param {String/Array} className The CSS class to remove, or an array of classes
7466 * @return {Roo.Element} this
7468 removeClass : function(className){
7469 if(!className || !this.dom.className){
7472 if(className instanceof Array){
7473 for(var i = 0, len = className.length; i < len; i++) {
7474 this.removeClass(className[i]);
7477 if(this.hasClass(className)){
7478 var re = this.classReCache[className];
7480 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7481 this.classReCache[className] = re;
7483 this.dom.className =
7484 this.dom.className.replace(re, " ");
7494 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7495 * @param {String} className The CSS class to toggle
7496 * @return {Roo.Element} this
7498 toggleClass : function(className){
7499 if(this.hasClass(className)){
7500 this.removeClass(className);
7502 this.addClass(className);
7508 * Checks if the specified CSS class exists on this element's DOM node.
7509 * @param {String} className The CSS class to check for
7510 * @return {Boolean} True if the class exists, else false
7512 hasClass : function(className){
7513 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7517 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7518 * @param {String} oldClassName The CSS class to replace
7519 * @param {String} newClassName The replacement CSS class
7520 * @return {Roo.Element} this
7522 replaceClass : function(oldClassName, newClassName){
7523 this.removeClass(oldClassName);
7524 this.addClass(newClassName);
7529 * Returns an object with properties matching the styles requested.
7530 * For example, el.getStyles('color', 'font-size', 'width') might return
7531 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7532 * @param {String} style1 A style name
7533 * @param {String} style2 A style name
7534 * @param {String} etc.
7535 * @return {Object} The style object
7537 getStyles : function(){
7538 var a = arguments, len = a.length, r = {};
7539 for(var i = 0; i < len; i++){
7540 r[a[i]] = this.getStyle(a[i]);
7546 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7547 * @param {String} property The style property whose value is returned.
7548 * @return {String} The current value of the style property for this element.
7550 getStyle : function(){
7551 return view && view.getComputedStyle ?
7553 var el = this.dom, v, cs, camel;
7554 if(prop == 'float'){
7557 if(el.style && (v = el.style[prop])){
7560 if(cs = view.getComputedStyle(el, "")){
7561 if(!(camel = propCache[prop])){
7562 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7569 var el = this.dom, v, cs, camel;
7570 if(prop == 'opacity'){
7571 if(typeof el.style.filter == 'string'){
7572 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7574 var fv = parseFloat(m[1]);
7576 return fv ? fv / 100 : 0;
7581 }else if(prop == 'float'){
7582 prop = "styleFloat";
7584 if(!(camel = propCache[prop])){
7585 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7587 if(v = el.style[camel]){
7590 if(cs = el.currentStyle){
7598 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7599 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7600 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7601 * @return {Roo.Element} this
7603 setStyle : function(prop, value){
7604 if(typeof prop == "string"){
7606 if (prop == 'float') {
7607 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7612 if(!(camel = propCache[prop])){
7613 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7616 if(camel == 'opacity') {
7617 this.setOpacity(value);
7619 this.dom.style[camel] = value;
7622 for(var style in prop){
7623 if(typeof prop[style] != "function"){
7624 this.setStyle(style, prop[style]);
7632 * More flexible version of {@link #setStyle} for setting style properties.
7633 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7634 * a function which returns such a specification.
7635 * @return {Roo.Element} this
7637 applyStyles : function(style){
7638 Roo.DomHelper.applyStyles(this.dom, style);
7643 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7644 * @return {Number} The X position of the element
7647 return D.getX(this.dom);
7651 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7652 * @return {Number} The Y position of the element
7655 return D.getY(this.dom);
7659 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7660 * @return {Array} The XY position of the element
7663 return D.getXY(this.dom);
7667 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7668 * @param {Number} The X position of the element
7669 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7670 * @return {Roo.Element} this
7672 setX : function(x, animate){
7674 D.setX(this.dom, x);
7676 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7682 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7683 * @param {Number} The Y position of the element
7684 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7685 * @return {Roo.Element} this
7687 setY : function(y, animate){
7689 D.setY(this.dom, y);
7691 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7697 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7698 * @param {String} left The left CSS property value
7699 * @return {Roo.Element} this
7701 setLeft : function(left){
7702 this.setStyle("left", this.addUnits(left));
7707 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7708 * @param {String} top The top CSS property value
7709 * @return {Roo.Element} this
7711 setTop : function(top){
7712 this.setStyle("top", this.addUnits(top));
7717 * Sets the element's CSS right style.
7718 * @param {String} right The right CSS property value
7719 * @return {Roo.Element} this
7721 setRight : function(right){
7722 this.setStyle("right", this.addUnits(right));
7727 * Sets the element's CSS bottom style.
7728 * @param {String} bottom The bottom CSS property value
7729 * @return {Roo.Element} this
7731 setBottom : function(bottom){
7732 this.setStyle("bottom", this.addUnits(bottom));
7737 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7738 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7739 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7740 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7741 * @return {Roo.Element} this
7743 setXY : function(pos, animate){
7745 D.setXY(this.dom, pos);
7747 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7753 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7754 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7755 * @param {Number} x X value for new position (coordinates are page-based)
7756 * @param {Number} y Y value for new position (coordinates are page-based)
7757 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7758 * @return {Roo.Element} this
7760 setLocation : function(x, y, animate){
7761 this.setXY([x, y], this.preanim(arguments, 2));
7766 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7767 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7768 * @param {Number} x X value for new position (coordinates are page-based)
7769 * @param {Number} y Y value for new position (coordinates are page-based)
7770 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7771 * @return {Roo.Element} this
7773 moveTo : function(x, y, animate){
7774 this.setXY([x, y], this.preanim(arguments, 2));
7779 * Returns the region of the given element.
7780 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7781 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7783 getRegion : function(){
7784 return D.getRegion(this.dom);
7788 * Returns the offset height of the element
7789 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7790 * @return {Number} The element's height
7792 getHeight : function(contentHeight){
7793 var h = this.dom.offsetHeight || 0;
7794 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7798 * Returns the offset width of the element
7799 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7800 * @return {Number} The element's width
7802 getWidth : function(contentWidth){
7803 var w = this.dom.offsetWidth || 0;
7804 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7808 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7809 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7810 * if a height has not been set using CSS.
7813 getComputedHeight : function(){
7814 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7816 h = parseInt(this.getStyle('height'), 10) || 0;
7817 if(!this.isBorderBox()){
7818 h += this.getFrameWidth('tb');
7825 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7826 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7827 * if a width has not been set using CSS.
7830 getComputedWidth : function(){
7831 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7833 w = parseInt(this.getStyle('width'), 10) || 0;
7834 if(!this.isBorderBox()){
7835 w += this.getFrameWidth('lr');
7842 * Returns the size of the element.
7843 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7844 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7846 getSize : function(contentSize){
7847 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7851 * Returns the width and height of the viewport.
7852 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7854 getViewSize : function(){
7855 var d = this.dom, doc = document, aw = 0, ah = 0;
7856 if(d == doc || d == doc.body){
7857 return {width : D.getViewWidth(), height: D.getViewHeight()};
7860 width : d.clientWidth,
7861 height: d.clientHeight
7867 * Returns the value of the "value" attribute
7868 * @param {Boolean} asNumber true to parse the value as a number
7869 * @return {String/Number}
7871 getValue : function(asNumber){
7872 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7876 adjustWidth : function(width){
7877 if(typeof width == "number"){
7878 if(this.autoBoxAdjust && !this.isBorderBox()){
7879 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7889 adjustHeight : function(height){
7890 if(typeof height == "number"){
7891 if(this.autoBoxAdjust && !this.isBorderBox()){
7892 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7902 * Set the width of the element
7903 * @param {Number} width The new width
7904 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7905 * @return {Roo.Element} this
7907 setWidth : function(width, animate){
7908 width = this.adjustWidth(width);
7910 this.dom.style.width = this.addUnits(width);
7912 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7918 * Set the height of the element
7919 * @param {Number} height The new height
7920 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7921 * @return {Roo.Element} this
7923 setHeight : function(height, animate){
7924 height = this.adjustHeight(height);
7926 this.dom.style.height = this.addUnits(height);
7928 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7934 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7935 * @param {Number} width The new width
7936 * @param {Number} height The new height
7937 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7938 * @return {Roo.Element} this
7940 setSize : function(width, height, animate){
7941 if(typeof width == "object"){ // in case of object from getSize()
7942 height = width.height; width = width.width;
7944 width = this.adjustWidth(width); height = this.adjustHeight(height);
7946 this.dom.style.width = this.addUnits(width);
7947 this.dom.style.height = this.addUnits(height);
7949 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7955 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7956 * @param {Number} x X value for new position (coordinates are page-based)
7957 * @param {Number} y Y value for new position (coordinates are page-based)
7958 * @param {Number} width The new width
7959 * @param {Number} height The new height
7960 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961 * @return {Roo.Element} this
7963 setBounds : function(x, y, width, height, animate){
7965 this.setSize(width, height);
7966 this.setLocation(x, y);
7968 width = this.adjustWidth(width); height = this.adjustHeight(height);
7969 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7970 this.preanim(arguments, 4), 'motion');
7976 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7977 * @param {Roo.lib.Region} region The region to fill
7978 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7979 * @return {Roo.Element} this
7981 setRegion : function(region, animate){
7982 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7987 * Appends an event handler
7989 * @param {String} eventName The type of event to append
7990 * @param {Function} fn The method the event invokes
7991 * @param {Object} scope (optional) The scope (this object) of the fn
7992 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7994 addListener : function(eventName, fn, scope, options){
7996 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8001 * Removes an event handler from this element
8002 * @param {String} eventName the type of event to remove
8003 * @param {Function} fn the method the event invokes
8004 * @return {Roo.Element} this
8006 removeListener : function(eventName, fn){
8007 Roo.EventManager.removeListener(this.dom, eventName, fn);
8012 * Removes all previous added listeners from this element
8013 * @return {Roo.Element} this
8015 removeAllListeners : function(){
8016 E.purgeElement(this.dom);
8020 relayEvent : function(eventName, observable){
8021 this.on(eventName, function(e){
8022 observable.fireEvent(eventName, e);
8027 * Set the opacity of the element
8028 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8029 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8030 * @return {Roo.Element} this
8032 setOpacity : function(opacity, animate){
8034 var s = this.dom.style;
8037 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8038 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8040 s.opacity = opacity;
8043 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8049 * Gets the left X coordinate
8050 * @param {Boolean} local True to get the local css position instead of page coordinate
8053 getLeft : function(local){
8057 return parseInt(this.getStyle("left"), 10) || 0;
8062 * Gets the right X coordinate of the element (element X position + element width)
8063 * @param {Boolean} local True to get the local css position instead of page coordinate
8066 getRight : function(local){
8068 return this.getX() + this.getWidth();
8070 return (this.getLeft(true) + this.getWidth()) || 0;
8075 * Gets the top Y coordinate
8076 * @param {Boolean} local True to get the local css position instead of page coordinate
8079 getTop : function(local) {
8083 return parseInt(this.getStyle("top"), 10) || 0;
8088 * Gets the bottom Y coordinate of the element (element Y position + element height)
8089 * @param {Boolean} local True to get the local css position instead of page coordinate
8092 getBottom : function(local){
8094 return this.getY() + this.getHeight();
8096 return (this.getTop(true) + this.getHeight()) || 0;
8101 * Initializes positioning on this element. If a desired position is not passed, it will make the
8102 * the element positioned relative IF it is not already positioned.
8103 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8104 * @param {Number} zIndex (optional) The zIndex to apply
8105 * @param {Number} x (optional) Set the page X position
8106 * @param {Number} y (optional) Set the page Y position
8108 position : function(pos, zIndex, x, y){
8110 if(this.getStyle('position') == 'static'){
8111 this.setStyle('position', 'relative');
8114 this.setStyle("position", pos);
8117 this.setStyle("z-index", zIndex);
8119 if(x !== undefined && y !== undefined){
8121 }else if(x !== undefined){
8123 }else if(y !== undefined){
8129 * Clear positioning back to the default when the document was loaded
8130 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8131 * @return {Roo.Element} this
8133 clearPositioning : function(value){
8141 "position" : "static"
8147 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8148 * snapshot before performing an update and then restoring the element.
8151 getPositioning : function(){
8152 var l = this.getStyle("left");
8153 var t = this.getStyle("top");
8155 "position" : this.getStyle("position"),
8157 "right" : l ? "" : this.getStyle("right"),
8159 "bottom" : t ? "" : this.getStyle("bottom"),
8160 "z-index" : this.getStyle("z-index")
8165 * Gets the width of the border(s) for the specified side(s)
8166 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8167 * passing lr would get the border (l)eft width + the border (r)ight width.
8168 * @return {Number} The width of the sides passed added together
8170 getBorderWidth : function(side){
8171 return this.addStyles(side, El.borders);
8175 * Gets the width of the padding(s) for the specified side(s)
8176 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8177 * passing lr would get the padding (l)eft + the padding (r)ight.
8178 * @return {Number} The padding of the sides passed added together
8180 getPadding : function(side){
8181 return this.addStyles(side, El.paddings);
8185 * Set positioning with an object returned by getPositioning().
8186 * @param {Object} posCfg
8187 * @return {Roo.Element} this
8189 setPositioning : function(pc){
8190 this.applyStyles(pc);
8191 if(pc.right == "auto"){
8192 this.dom.style.right = "";
8194 if(pc.bottom == "auto"){
8195 this.dom.style.bottom = "";
8201 fixDisplay : function(){
8202 if(this.getStyle("display") == "none"){
8203 this.setStyle("visibility", "hidden");
8204 this.setStyle("display", this.originalDisplay); // first try reverting to default
8205 if(this.getStyle("display") == "none"){ // if that fails, default to block
8206 this.setStyle("display", "block");
8212 * Quick set left and top adding default units
8213 * @param {String} left The left CSS property value
8214 * @param {String} top The top CSS property value
8215 * @return {Roo.Element} this
8217 setLeftTop : function(left, top){
8218 this.dom.style.left = this.addUnits(left);
8219 this.dom.style.top = this.addUnits(top);
8224 * Move this element relative to its current position.
8225 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8226 * @param {Number} distance How far to move the element in pixels
8227 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8228 * @return {Roo.Element} this
8230 move : function(direction, distance, animate){
8231 var xy = this.getXY();
8232 direction = direction.toLowerCase();
8236 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8240 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8245 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8250 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8257 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8258 * @return {Roo.Element} this
8261 if(!this.isClipped){
8262 this.isClipped = true;
8263 this.originalClip = {
8264 "o": this.getStyle("overflow"),
8265 "x": this.getStyle("overflow-x"),
8266 "y": this.getStyle("overflow-y")
8268 this.setStyle("overflow", "hidden");
8269 this.setStyle("overflow-x", "hidden");
8270 this.setStyle("overflow-y", "hidden");
8276 * Return clipping (overflow) to original clipping before clip() was called
8277 * @return {Roo.Element} this
8279 unclip : function(){
8281 this.isClipped = false;
8282 var o = this.originalClip;
8283 if(o.o){this.setStyle("overflow", o.o);}
8284 if(o.x){this.setStyle("overflow-x", o.x);}
8285 if(o.y){this.setStyle("overflow-y", o.y);}
8292 * Gets the x,y coordinates specified by the anchor position on the element.
8293 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8294 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8295 * {width: (target width), height: (target height)} (defaults to the element's current size)
8296 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8297 * @return {Array} [x, y] An array containing the element's x and y coordinates
8299 getAnchorXY : function(anchor, local, s){
8300 //Passing a different size is useful for pre-calculating anchors,
8301 //especially for anchored animations that change the el size.
8303 var w, h, vp = false;
8306 if(d == document.body || d == document){
8308 w = D.getViewWidth(); h = D.getViewHeight();
8310 w = this.getWidth(); h = this.getHeight();
8313 w = s.width; h = s.height;
8315 var x = 0, y = 0, r = Math.round;
8316 switch((anchor || "tl").toLowerCase()){
8358 var sc = this.getScroll();
8359 return [x + sc.left, y + sc.top];
8361 //Add the element's offset xy
8362 var o = this.getXY();
8363 return [x+o[0], y+o[1]];
8367 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8368 * supported position values.
8369 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8370 * @param {String} position The position to align to.
8371 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8372 * @return {Array} [x, y]
8374 getAlignToXY : function(el, p, o){
8378 throw "Element.alignTo with an element that doesn't exist";
8380 var c = false; //constrain to viewport
8381 var p1 = "", p2 = "";
8388 }else if(p.indexOf("-") == -1){
8391 p = p.toLowerCase();
8392 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8394 throw "Element.alignTo with an invalid alignment " + p;
8396 p1 = m[1]; p2 = m[2]; c = !!m[3];
8398 //Subtract the aligned el's internal xy from the target's offset xy
8399 //plus custom offset to get the aligned el's new offset xy
8400 var a1 = this.getAnchorXY(p1, true);
8401 var a2 = el.getAnchorXY(p2, false);
8402 var x = a2[0] - a1[0] + o[0];
8403 var y = a2[1] - a1[1] + o[1];
8405 //constrain the aligned el to viewport if necessary
8406 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8407 // 5px of margin for ie
8408 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8410 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8411 //perpendicular to the vp border, allow the aligned el to slide on that border,
8412 //otherwise swap the aligned el to the opposite border of the target.
8413 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8414 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8415 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8416 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8419 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8420 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8422 if((x+w) > dw + scrollX){
8423 x = swapX ? r.left-w : dw+scrollX-w;
8426 x = swapX ? r.right : scrollX;
8428 if((y+h) > dh + scrollY){
8429 y = swapY ? r.top-h : dh+scrollY-h;
8432 y = swapY ? r.bottom : scrollY;
8439 getConstrainToXY : function(){
8440 var os = {top:0, left:0, bottom:0, right: 0};
8442 return function(el, local, offsets, proposedXY){
8444 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8446 var vw, vh, vx = 0, vy = 0;
8447 if(el.dom == document.body || el.dom == document){
8448 vw = Roo.lib.Dom.getViewWidth();
8449 vh = Roo.lib.Dom.getViewHeight();
8451 vw = el.dom.clientWidth;
8452 vh = el.dom.clientHeight;
8454 var vxy = el.getXY();
8460 var s = el.getScroll();
8462 vx += offsets.left + s.left;
8463 vy += offsets.top + s.top;
8465 vw -= offsets.right;
8466 vh -= offsets.bottom;
8471 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8472 var x = xy[0], y = xy[1];
8473 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8475 // only move it if it needs it
8478 // first validate right/bottom
8487 // then make sure top/left isn't negative
8496 return moved ? [x, y] : false;
8501 adjustForConstraints : function(xy, parent, offsets){
8502 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8506 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8507 * document it aligns it to the viewport.
8508 * The position parameter is optional, and can be specified in any one of the following formats:
8510 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8511 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8512 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8513 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8514 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8515 * element's anchor point, and the second value is used as the target's anchor point.</li>
8517 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8518 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8519 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8520 * that specified in order to enforce the viewport constraints.
8521 * Following are all of the supported anchor positions:
8524 ----- -----------------------------
8525 tl The top left corner (default)
8526 t The center of the top edge
8527 tr The top right corner
8528 l The center of the left edge
8529 c In the center of the element
8530 r The center of the right edge
8531 bl The bottom left corner
8532 b The center of the bottom edge
8533 br The bottom right corner
8537 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8538 el.alignTo("other-el");
8540 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8541 el.alignTo("other-el", "tr?");
8543 // align the bottom right corner of el with the center left edge of other-el
8544 el.alignTo("other-el", "br-l?");
8546 // align the center of el with the bottom left corner of other-el and
8547 // adjust the x position by -6 pixels (and the y position by 0)
8548 el.alignTo("other-el", "c-bl", [-6, 0]);
8550 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8551 * @param {String} position The position to align to.
8552 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8553 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8554 * @return {Roo.Element} this
8556 alignTo : function(element, position, offsets, animate){
8557 var xy = this.getAlignToXY(element, position, offsets);
8558 this.setXY(xy, this.preanim(arguments, 3));
8563 * Anchors an element to another element and realigns it when the window is resized.
8564 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8565 * @param {String} position The position to align to.
8566 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8567 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8568 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8569 * is a number, it is used as the buffer delay (defaults to 50ms).
8570 * @param {Function} callback The function to call after the animation finishes
8571 * @return {Roo.Element} this
8573 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8574 var action = function(){
8575 this.alignTo(el, alignment, offsets, animate);
8576 Roo.callback(callback, this);
8578 Roo.EventManager.onWindowResize(action, this);
8579 var tm = typeof monitorScroll;
8580 if(tm != 'undefined'){
8581 Roo.EventManager.on(window, 'scroll', action, this,
8582 {buffer: tm == 'number' ? monitorScroll : 50});
8584 action.call(this); // align immediately
8588 * Clears any opacity settings from this element. Required in some cases for IE.
8589 * @return {Roo.Element} this
8591 clearOpacity : function(){
8592 if (window.ActiveXObject) {
8593 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8594 this.dom.style.filter = "";
8597 this.dom.style.opacity = "";
8598 this.dom.style["-moz-opacity"] = "";
8599 this.dom.style["-khtml-opacity"] = "";
8605 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8606 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8607 * @return {Roo.Element} this
8609 hide : function(animate){
8610 this.setVisible(false, this.preanim(arguments, 0));
8615 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8616 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8617 * @return {Roo.Element} this
8619 show : function(animate){
8620 this.setVisible(true, this.preanim(arguments, 0));
8625 * @private Test if size has a unit, otherwise appends the default
8627 addUnits : function(size){
8628 return Roo.Element.addUnits(size, this.defaultUnit);
8632 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8633 * @return {Roo.Element} this
8635 beginMeasure : function(){
8637 if(el.offsetWidth || el.offsetHeight){
8638 return this; // offsets work already
8641 var p = this.dom, b = document.body; // start with this element
8642 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8643 var pe = Roo.get(p);
8644 if(pe.getStyle('display') == 'none'){
8645 changed.push({el: p, visibility: pe.getStyle("visibility")});
8646 p.style.visibility = "hidden";
8647 p.style.display = "block";
8651 this._measureChanged = changed;
8657 * Restores displays to before beginMeasure was called
8658 * @return {Roo.Element} this
8660 endMeasure : function(){
8661 var changed = this._measureChanged;
8663 for(var i = 0, len = changed.length; i < len; i++) {
8665 r.el.style.visibility = r.visibility;
8666 r.el.style.display = "none";
8668 this._measureChanged = null;
8674 * Update the innerHTML of this element, optionally searching for and processing scripts
8675 * @param {String} html The new HTML
8676 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8677 * @param {Function} callback For async script loading you can be noticed when the update completes
8678 * @return {Roo.Element} this
8680 update : function(html, loadScripts, callback){
8681 if(typeof html == "undefined"){
8684 if(loadScripts !== true){
8685 this.dom.innerHTML = html;
8686 if(typeof callback == "function"){
8694 html += '<span id="' + id + '"></span>';
8696 E.onAvailable(id, function(){
8697 var hd = document.getElementsByTagName("head")[0];
8698 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8699 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8700 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8703 while(match = re.exec(html)){
8704 var attrs = match[1];
8705 var srcMatch = attrs ? attrs.match(srcRe) : false;
8706 if(srcMatch && srcMatch[2]){
8707 var s = document.createElement("script");
8708 s.src = srcMatch[2];
8709 var typeMatch = attrs.match(typeRe);
8710 if(typeMatch && typeMatch[2]){
8711 s.type = typeMatch[2];
8714 }else if(match[2] && match[2].length > 0){
8715 if(window.execScript) {
8716 window.execScript(match[2]);
8724 window.eval(match[2]);
8728 var el = document.getElementById(id);
8729 if(el){el.parentNode.removeChild(el);}
8730 if(typeof callback == "function"){
8734 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8739 * Direct access to the UpdateManager update() method (takes the same parameters).
8740 * @param {String/Function} url The url for this request or a function to call to get the url
8741 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8742 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8743 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8744 * @return {Roo.Element} this
8747 var um = this.getUpdateManager();
8748 um.update.apply(um, arguments);
8753 * Gets this element's UpdateManager
8754 * @return {Roo.UpdateManager} The UpdateManager
8756 getUpdateManager : function(){
8757 if(!this.updateManager){
8758 this.updateManager = new Roo.UpdateManager(this);
8760 return this.updateManager;
8764 * Disables text selection for this element (normalized across browsers)
8765 * @return {Roo.Element} this
8767 unselectable : function(){
8768 this.dom.unselectable = "on";
8769 this.swallowEvent("selectstart", true);
8770 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8771 this.addClass("x-unselectable");
8776 * Calculates the x, y to center this element on the screen
8777 * @return {Array} The x, y values [x, y]
8779 getCenterXY : function(){
8780 return this.getAlignToXY(document, 'c-c');
8784 * Centers the Element in either the viewport, or another Element.
8785 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8787 center : function(centerIn){
8788 this.alignTo(centerIn || document, 'c-c');
8793 * Tests various css rules/browsers to determine if this element uses a border box
8796 isBorderBox : function(){
8797 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8801 * Return a box {x, y, width, height} that can be used to set another elements
8802 * size/location to match this element.
8803 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8804 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8805 * @return {Object} box An object in the format {x, y, width, height}
8807 getBox : function(contentBox, local){
8812 var left = parseInt(this.getStyle("left"), 10) || 0;
8813 var top = parseInt(this.getStyle("top"), 10) || 0;
8816 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8818 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8820 var l = this.getBorderWidth("l")+this.getPadding("l");
8821 var r = this.getBorderWidth("r")+this.getPadding("r");
8822 var t = this.getBorderWidth("t")+this.getPadding("t");
8823 var b = this.getBorderWidth("b")+this.getPadding("b");
8824 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8826 bx.right = bx.x + bx.width;
8827 bx.bottom = bx.y + bx.height;
8832 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8833 for more information about the sides.
8834 * @param {String} sides
8837 getFrameWidth : function(sides, onlyContentBox){
8838 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8842 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8843 * @param {Object} box The box to fill {x, y, width, height}
8844 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8845 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8846 * @return {Roo.Element} this
8848 setBox : function(box, adjust, animate){
8849 var w = box.width, h = box.height;
8850 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8851 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8852 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8854 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8859 * Forces the browser to repaint this element
8860 * @return {Roo.Element} this
8862 repaint : function(){
8864 this.addClass("x-repaint");
8865 setTimeout(function(){
8866 Roo.get(dom).removeClass("x-repaint");
8872 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8873 * then it returns the calculated width of the sides (see getPadding)
8874 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8875 * @return {Object/Number}
8877 getMargins : function(side){
8880 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8881 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8882 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8883 right: parseInt(this.getStyle("margin-right"), 10) || 0
8886 return this.addStyles(side, El.margins);
8891 addStyles : function(sides, styles){
8893 for(var i = 0, len = sides.length; i < len; i++){
8894 v = this.getStyle(styles[sides.charAt(i)]);
8896 w = parseInt(v, 10);
8904 * Creates a proxy element of this element
8905 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8906 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8907 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8908 * @return {Roo.Element} The new proxy element
8910 createProxy : function(config, renderTo, matchBox){
8912 renderTo = Roo.getDom(renderTo);
8914 renderTo = document.body;
8916 config = typeof config == "object" ?
8917 config : {tag : "div", cls: config};
8918 var proxy = Roo.DomHelper.append(renderTo, config, true);
8920 proxy.setBox(this.getBox());
8926 * Puts a mask over this element to disable user interaction. Requires core.css.
8927 * This method can only be applied to elements which accept child nodes.
8928 * @param {String} msg (optional) A message to display in the mask
8929 * @param {String} msgCls (optional) A css class to apply to the msg element
8930 * @return {Element} The mask element
8932 mask : function(msg, msgCls)
8934 if(this.getStyle("position") == "static"){
8935 this.setStyle("position", "relative");
8938 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8940 this.addClass("x-masked");
8941 this._mask.setDisplayed(true);
8946 while (dom && dom.style) {
8947 if (!isNaN(parseInt(dom.style.zIndex))) {
8948 z = Math.max(z, parseInt(dom.style.zIndex));
8950 dom = dom.parentNode;
8952 // if we are masking the body - then it hides everything..
8953 if (this.dom == document.body) {
8955 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8956 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8959 if(typeof msg == 'string'){
8961 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8963 var mm = this._maskMsg;
8964 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8965 mm.dom.firstChild.innerHTML = msg;
8966 mm.setDisplayed(true);
8968 mm.setStyle('z-index', z + 102);
8970 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8971 this._mask.setHeight(this.getHeight());
8973 this._mask.setStyle('z-index', z + 100);
8979 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8980 * it is cached for reuse.
8982 unmask : function(removeEl){
8984 if(removeEl === true){
8985 this._mask.remove();
8988 this._maskMsg.remove();
8989 delete this._maskMsg;
8992 this._mask.setDisplayed(false);
8994 this._maskMsg.setDisplayed(false);
8998 this.removeClass("x-masked");
9002 * Returns true if this element is masked
9005 isMasked : function(){
9006 return this._mask && this._mask.isVisible();
9010 * Creates an iframe shim for this element to keep selects and other windowed objects from
9012 * @return {Roo.Element} The new shim element
9014 createShim : function(){
9015 var el = document.createElement('iframe');
9016 el.frameBorder = 'no';
9017 el.className = 'roo-shim';
9018 if(Roo.isIE && Roo.isSecure){
9019 el.src = Roo.SSL_SECURE_URL;
9021 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9022 shim.autoBoxAdjust = false;
9027 * Removes this element from the DOM and deletes it from the cache
9029 remove : function(){
9030 if(this.dom.parentNode){
9031 this.dom.parentNode.removeChild(this.dom);
9033 delete El.cache[this.dom.id];
9037 * Sets up event handlers to add and remove a css class when the mouse is over this element
9038 * @param {String} className
9039 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9040 * mouseout events for children elements
9041 * @return {Roo.Element} this
9043 addClassOnOver : function(className, preventFlicker){
9044 this.on("mouseover", function(){
9045 Roo.fly(this, '_internal').addClass(className);
9047 var removeFn = function(e){
9048 if(preventFlicker !== true || !e.within(this, true)){
9049 Roo.fly(this, '_internal').removeClass(className);
9052 this.on("mouseout", removeFn, this.dom);
9057 * Sets up event handlers to add and remove a css class when this element has the focus
9058 * @param {String} className
9059 * @return {Roo.Element} this
9061 addClassOnFocus : function(className){
9062 this.on("focus", function(){
9063 Roo.fly(this, '_internal').addClass(className);
9065 this.on("blur", function(){
9066 Roo.fly(this, '_internal').removeClass(className);
9071 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9072 * @param {String} className
9073 * @return {Roo.Element} this
9075 addClassOnClick : function(className){
9077 this.on("mousedown", function(){
9078 Roo.fly(dom, '_internal').addClass(className);
9079 var d = Roo.get(document);
9080 var fn = function(){
9081 Roo.fly(dom, '_internal').removeClass(className);
9082 d.removeListener("mouseup", fn);
9084 d.on("mouseup", fn);
9090 * Stops the specified event from bubbling and optionally prevents the default action
9091 * @param {String} eventName
9092 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9093 * @return {Roo.Element} this
9095 swallowEvent : function(eventName, preventDefault){
9096 var fn = function(e){
9097 e.stopPropagation();
9102 if(eventName instanceof Array){
9103 for(var i = 0, len = eventName.length; i < len; i++){
9104 this.on(eventName[i], fn);
9108 this.on(eventName, fn);
9115 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9118 * Sizes this element to its parent element's dimensions performing
9119 * neccessary box adjustments.
9120 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9121 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9122 * @return {Roo.Element} this
9124 fitToParent : function(monitorResize, targetParent) {
9125 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9126 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9127 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9130 var p = Roo.get(targetParent || this.dom.parentNode);
9131 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9132 if (monitorResize === true) {
9133 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9134 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9140 * Gets the next sibling, skipping text nodes
9141 * @return {HTMLElement} The next sibling or null
9143 getNextSibling : function(){
9144 var n = this.dom.nextSibling;
9145 while(n && n.nodeType != 1){
9152 * Gets the previous sibling, skipping text nodes
9153 * @return {HTMLElement} The previous sibling or null
9155 getPrevSibling : function(){
9156 var n = this.dom.previousSibling;
9157 while(n && n.nodeType != 1){
9158 n = n.previousSibling;
9165 * Appends the passed element(s) to this element
9166 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9167 * @return {Roo.Element} this
9169 appendChild: function(el){
9176 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9177 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9178 * automatically generated with the specified attributes.
9179 * @param {HTMLElement} insertBefore (optional) a child element of this element
9180 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9181 * @return {Roo.Element} The new child element
9183 createChild: function(config, insertBefore, returnDom){
9184 config = config || {tag:'div'};
9186 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9188 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9192 * Appends this element to the passed element
9193 * @param {String/HTMLElement/Element} el The new parent element
9194 * @return {Roo.Element} this
9196 appendTo: function(el){
9197 el = Roo.getDom(el);
9198 el.appendChild(this.dom);
9203 * Inserts this element before the passed element in the DOM
9204 * @param {String/HTMLElement/Element} el The element to insert before
9205 * @return {Roo.Element} this
9207 insertBefore: function(el){
9208 el = Roo.getDom(el);
9209 el.parentNode.insertBefore(this.dom, el);
9214 * Inserts this element after the passed element in the DOM
9215 * @param {String/HTMLElement/Element} el The element to insert after
9216 * @return {Roo.Element} this
9218 insertAfter: function(el){
9219 el = Roo.getDom(el);
9220 el.parentNode.insertBefore(this.dom, el.nextSibling);
9225 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9226 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9227 * @return {Roo.Element} The new child
9229 insertFirst: function(el, returnDom){
9231 if(typeof el == 'object' && !el.nodeType){ // dh config
9232 return this.createChild(el, this.dom.firstChild, returnDom);
9234 el = Roo.getDom(el);
9235 this.dom.insertBefore(el, this.dom.firstChild);
9236 return !returnDom ? Roo.get(el) : el;
9241 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9242 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9243 * @param {String} where (optional) 'before' or 'after' defaults to before
9244 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9245 * @return {Roo.Element} the inserted Element
9247 insertSibling: function(el, where, returnDom){
9248 where = where ? where.toLowerCase() : 'before';
9250 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9252 if(typeof el == 'object' && !el.nodeType){ // dh config
9253 if(where == 'after' && !this.dom.nextSibling){
9254 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9256 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9260 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9261 where == 'before' ? this.dom : this.dom.nextSibling);
9270 * Creates and wraps this element with another element
9271 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9272 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9273 * @return {HTMLElement/Element} The newly created wrapper element
9275 wrap: function(config, returnDom){
9277 config = {tag: "div"};
9279 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9280 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9285 * Replaces the passed element with this element
9286 * @param {String/HTMLElement/Element} el The element to replace
9287 * @return {Roo.Element} this
9289 replace: function(el){
9291 this.insertBefore(el);
9297 * Inserts an html fragment into this element
9298 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9299 * @param {String} html The HTML fragment
9300 * @param {Boolean} returnEl True to return an Roo.Element
9301 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9303 insertHtml : function(where, html, returnEl){
9304 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9305 return returnEl ? Roo.get(el) : el;
9309 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9310 * @param {Object} o The object with the attributes
9311 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9312 * @return {Roo.Element} this
9314 set : function(o, useSet){
9316 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9318 if(attr == "style" || typeof o[attr] == "function") continue;
9320 el.className = o["cls"];
9322 if(useSet) el.setAttribute(attr, o[attr]);
9323 else el[attr] = o[attr];
9327 Roo.DomHelper.applyStyles(el, o.style);
9333 * Convenience method for constructing a KeyMap
9334 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9335 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9336 * @param {Function} fn The function to call
9337 * @param {Object} scope (optional) The scope of the function
9338 * @return {Roo.KeyMap} The KeyMap created
9340 addKeyListener : function(key, fn, scope){
9342 if(typeof key != "object" || key instanceof Array){
9358 return new Roo.KeyMap(this, config);
9362 * Creates a KeyMap for this element
9363 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9364 * @return {Roo.KeyMap} The KeyMap created
9366 addKeyMap : function(config){
9367 return new Roo.KeyMap(this, config);
9371 * Returns true if this element is scrollable.
9374 isScrollable : function(){
9376 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9380 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9381 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9382 * @param {Number} value The new scroll value
9383 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9384 * @return {Element} this
9387 scrollTo : function(side, value, animate){
9388 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9390 this.dom[prop] = value;
9392 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9393 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9399 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9400 * within this element's scrollable range.
9401 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9402 * @param {Number} distance How far to scroll the element in pixels
9403 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9404 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9405 * was scrolled as far as it could go.
9407 scroll : function(direction, distance, animate){
9408 if(!this.isScrollable()){
9412 var l = el.scrollLeft, t = el.scrollTop;
9413 var w = el.scrollWidth, h = el.scrollHeight;
9414 var cw = el.clientWidth, ch = el.clientHeight;
9415 direction = direction.toLowerCase();
9416 var scrolled = false;
9417 var a = this.preanim(arguments, 2);
9422 var v = Math.min(l + distance, w-cw);
9423 this.scrollTo("left", v, a);
9430 var v = Math.max(l - distance, 0);
9431 this.scrollTo("left", v, a);
9439 var v = Math.max(t - distance, 0);
9440 this.scrollTo("top", v, a);
9448 var v = Math.min(t + distance, h-ch);
9449 this.scrollTo("top", v, a);
9458 * Translates the passed page coordinates into left/top css values for this element
9459 * @param {Number/Array} x The page x or an array containing [x, y]
9460 * @param {Number} y The page y
9461 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9463 translatePoints : function(x, y){
9464 if(typeof x == 'object' || x instanceof Array){
9467 var p = this.getStyle('position');
9468 var o = this.getXY();
9470 var l = parseInt(this.getStyle('left'), 10);
9471 var t = parseInt(this.getStyle('top'), 10);
9474 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9477 t = (p == "relative") ? 0 : this.dom.offsetTop;
9480 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9484 * Returns the current scroll position of the element.
9485 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9487 getScroll : function(){
9488 var d = this.dom, doc = document;
9489 if(d == doc || d == doc.body){
9490 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9491 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9492 return {left: l, top: t};
9494 return {left: d.scrollLeft, top: d.scrollTop};
9499 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9500 * are convert to standard 6 digit hex color.
9501 * @param {String} attr The css attribute
9502 * @param {String} defaultValue The default value to use when a valid color isn't found
9503 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9506 getColor : function(attr, defaultValue, prefix){
9507 var v = this.getStyle(attr);
9508 if(!v || v == "transparent" || v == "inherit") {
9509 return defaultValue;
9511 var color = typeof prefix == "undefined" ? "#" : prefix;
9512 if(v.substr(0, 4) == "rgb("){
9513 var rvs = v.slice(4, v.length -1).split(",");
9514 for(var i = 0; i < 3; i++){
9515 var h = parseInt(rvs[i]).toString(16);
9522 if(v.substr(0, 1) == "#"){
9524 for(var i = 1; i < 4; i++){
9525 var c = v.charAt(i);
9528 }else if(v.length == 7){
9529 color += v.substr(1);
9533 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9537 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9538 * gradient background, rounded corners and a 4-way shadow.
9539 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9540 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9541 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9542 * @return {Roo.Element} this
9544 boxWrap : function(cls){
9545 cls = cls || 'x-box';
9546 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9547 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9552 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9553 * @param {String} namespace The namespace in which to look for the attribute
9554 * @param {String} name The attribute name
9555 * @return {String} The attribute value
9557 getAttributeNS : Roo.isIE ? function(ns, name){
9559 var type = typeof d[ns+":"+name];
9560 if(type != 'undefined' && type != 'unknown'){
9561 return d[ns+":"+name];
9564 } : function(ns, name){
9566 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9571 * Sets or Returns the value the dom attribute value
9572 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9573 * @param {String} value (optional) The value to set the attribute to
9574 * @return {String} The attribute value
9576 attr : function(name){
9577 if (arguments.length > 1) {
9578 this.dom.setAttribute(name, arguments[1]);
9579 return arguments[1];
9581 if (typeof(name) == 'object') {
9582 for(var i in name) {
9583 this.attr(i, name[i]);
9589 if (!this.dom.hasAttribute(name)) {
9592 return this.dom.getAttribute(name);
9599 var ep = El.prototype;
9602 * Appends an event handler (Shorthand for addListener)
9603 * @param {String} eventName The type of event to append
9604 * @param {Function} fn The method the event invokes
9605 * @param {Object} scope (optional) The scope (this object) of the fn
9606 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9609 ep.on = ep.addListener;
9611 ep.mon = ep.addListener;
9614 * Removes an event handler from this element (shorthand for removeListener)
9615 * @param {String} eventName the type of event to remove
9616 * @param {Function} fn the method the event invokes
9617 * @return {Roo.Element} this
9620 ep.un = ep.removeListener;
9623 * true to automatically adjust width and height settings for box-model issues (default to true)
9625 ep.autoBoxAdjust = true;
9628 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9631 El.addUnits = function(v, defaultUnit){
9632 if(v === "" || v == "auto"){
9635 if(v === undefined){
9638 if(typeof v == "number" || !El.unitPattern.test(v)){
9639 return v + (defaultUnit || 'px');
9644 // special markup used throughout Roo when box wrapping elements
9645 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>';
9647 * Visibility mode constant - Use visibility to hide element
9653 * Visibility mode constant - Use display to hide element
9659 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9660 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9661 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9673 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9674 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9675 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9676 * @return {Element} The Element object
9679 El.get = function(el){
9681 if(!el){ return null; }
9682 if(typeof el == "string"){ // element id
9683 if(!(elm = document.getElementById(el))){
9686 if(ex = El.cache[el]){
9689 ex = El.cache[el] = new El(elm);
9692 }else if(el.tagName){ // dom element
9696 if(ex = El.cache[id]){
9699 ex = El.cache[id] = new El(el);
9702 }else if(el instanceof El){
9704 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9705 // catch case where it hasn't been appended
9706 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9709 }else if(el.isComposite){
9711 }else if(el instanceof Array){
9712 return El.select(el);
9713 }else if(el == document){
9714 // create a bogus element object representing the document object
9716 var f = function(){};
9717 f.prototype = El.prototype;
9719 docEl.dom = document;
9727 El.uncache = function(el){
9728 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9730 delete El.cache[a[i].id || a[i]];
9736 // Garbage collection - uncache elements/purge listeners on orphaned elements
9737 // so we don't hold a reference and cause the browser to retain them
9738 El.garbageCollect = function(){
9739 if(!Roo.enableGarbageCollector){
9740 clearInterval(El.collectorThread);
9743 for(var eid in El.cache){
9744 var el = El.cache[eid], d = el.dom;
9745 // -------------------------------------------------------
9746 // Determining what is garbage:
9747 // -------------------------------------------------------
9749 // dom node is null, definitely garbage
9750 // -------------------------------------------------------
9752 // no parentNode == direct orphan, definitely garbage
9753 // -------------------------------------------------------
9754 // !d.offsetParent && !document.getElementById(eid)
9755 // display none elements have no offsetParent so we will
9756 // also try to look it up by it's id. However, check
9757 // offsetParent first so we don't do unneeded lookups.
9758 // This enables collection of elements that are not orphans
9759 // directly, but somewhere up the line they have an orphan
9761 // -------------------------------------------------------
9762 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9763 delete El.cache[eid];
9764 if(d && Roo.enableListenerCollection){
9770 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9774 El.Flyweight = function(dom){
9777 El.Flyweight.prototype = El.prototype;
9779 El._flyweights = {};
9781 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9782 * the dom node can be overwritten by other code.
9783 * @param {String/HTMLElement} el The dom node or id
9784 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9785 * prevent conflicts (e.g. internally Roo uses "_internal")
9787 * @return {Element} The shared Element object
9789 El.fly = function(el, named){
9790 named = named || '_global';
9791 el = Roo.getDom(el);
9795 if(!El._flyweights[named]){
9796 El._flyweights[named] = new El.Flyweight();
9798 El._flyweights[named].dom = el;
9799 return El._flyweights[named];
9803 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9804 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9805 * Shorthand of {@link Roo.Element#get}
9806 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9807 * @return {Element} The Element object
9813 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9814 * the dom node can be overwritten by other code.
9815 * Shorthand of {@link Roo.Element#fly}
9816 * @param {String/HTMLElement} el The dom node or id
9817 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9818 * prevent conflicts (e.g. internally Roo uses "_internal")
9820 * @return {Element} The shared Element object
9826 // speedy lookup for elements never to box adjust
9827 var noBoxAdjust = Roo.isStrict ? {
9830 input:1, select:1, textarea:1
9832 if(Roo.isIE || Roo.isGecko){
9833 noBoxAdjust['button'] = 1;
9837 Roo.EventManager.on(window, 'unload', function(){
9839 delete El._flyweights;
9847 Roo.Element.selectorFunction = Roo.DomQuery.select;
9850 Roo.Element.select = function(selector, unique, root){
9852 if(typeof selector == "string"){
9853 els = Roo.Element.selectorFunction(selector, root);
9854 }else if(selector.length !== undefined){
9857 throw "Invalid selector";
9859 if(unique === true){
9860 return new Roo.CompositeElement(els);
9862 return new Roo.CompositeElementLite(els);
9866 * Selects elements based on the passed CSS selector to enable working on them as 1.
9867 * @param {String/Array} selector The CSS selector or an array of elements
9868 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9869 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9870 * @return {CompositeElementLite/CompositeElement}
9874 Roo.select = Roo.Element.select;
9891 * Ext JS Library 1.1.1
9892 * Copyright(c) 2006-2007, Ext JS, LLC.
9894 * Originally Released Under LGPL - original licence link has changed is not relivant.
9897 * <script type="text/javascript">
9902 //Notifies Element that fx methods are available
9903 Roo.enableFx = true;
9907 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9908 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9909 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9910 * Element effects to work.</p><br/>
9912 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9913 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9914 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9915 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9916 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9917 * expected results and should be done with care.</p><br/>
9919 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9920 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9923 ----- -----------------------------
9924 tl The top left corner
9925 t The center of the top edge
9926 tr The top right corner
9927 l The center of the left edge
9928 r The center of the right edge
9929 bl The bottom left corner
9930 b The center of the bottom edge
9931 br The bottom right corner
9933 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9934 * below are common options that can be passed to any Fx method.</b>
9935 * @cfg {Function} callback A function called when the effect is finished
9936 * @cfg {Object} scope The scope of the effect function
9937 * @cfg {String} easing A valid Easing value for the effect
9938 * @cfg {String} afterCls A css class to apply after the effect
9939 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9940 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9941 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9942 * effects that end with the element being visually hidden, ignored otherwise)
9943 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9944 * a function which returns such a specification that will be applied to the Element after the effect finishes
9945 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9946 * @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
9947 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9951 * Slides the element into view. An anchor point can be optionally passed to set the point of
9952 * origin for the slide effect. This function automatically handles wrapping the element with
9953 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9956 // default: slide the element in from the top
9959 // custom: slide the element in from the right with a 2-second duration
9960 el.slideIn('r', { duration: 2 });
9962 // common config options shown with default values
9968 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9969 * @param {Object} options (optional) Object literal with any of the Fx config options
9970 * @return {Roo.Element} The Element
9972 slideIn : function(anchor, o){
9973 var el = this.getFxEl();
9976 el.queueFx(o, function(){
9978 anchor = anchor || "t";
9980 // fix display to visibility
9983 // restore values after effect
9984 var r = this.getFxRestore();
9985 var b = this.getBox();
9986 // fixed size for slide
9990 var wrap = this.fxWrap(r.pos, o, "hidden");
9992 var st = this.dom.style;
9993 st.visibility = "visible";
9994 st.position = "absolute";
9996 // clear out temp styles after slide and unwrap
9997 var after = function(){
9998 el.fxUnwrap(wrap, r.pos, o);
10000 st.height = r.height;
10003 // time to calc the positions
10004 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10006 switch(anchor.toLowerCase()){
10008 wrap.setSize(b.width, 0);
10009 st.left = st.bottom = "0";
10013 wrap.setSize(0, b.height);
10014 st.right = st.top = "0";
10018 wrap.setSize(0, b.height);
10019 wrap.setX(b.right);
10020 st.left = st.top = "0";
10021 a = {width: bw, points: pt};
10024 wrap.setSize(b.width, 0);
10025 wrap.setY(b.bottom);
10026 st.left = st.top = "0";
10027 a = {height: bh, points: pt};
10030 wrap.setSize(0, 0);
10031 st.right = st.bottom = "0";
10032 a = {width: bw, height: bh};
10035 wrap.setSize(0, 0);
10036 wrap.setY(b.y+b.height);
10037 st.right = st.top = "0";
10038 a = {width: bw, height: bh, points: pt};
10041 wrap.setSize(0, 0);
10042 wrap.setXY([b.right, b.bottom]);
10043 st.left = st.top = "0";
10044 a = {width: bw, height: bh, points: pt};
10047 wrap.setSize(0, 0);
10048 wrap.setX(b.x+b.width);
10049 st.left = st.bottom = "0";
10050 a = {width: bw, height: bh, points: pt};
10053 this.dom.style.visibility = "visible";
10056 arguments.callee.anim = wrap.fxanim(a,
10066 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10067 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10068 * 'hidden') but block elements will still take up space in the document. The element must be removed
10069 * from the DOM using the 'remove' config option if desired. This function automatically handles
10070 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10073 // default: slide the element out to the top
10076 // custom: slide the element out to the right with a 2-second duration
10077 el.slideOut('r', { duration: 2 });
10079 // common config options shown with default values
10087 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10088 * @param {Object} options (optional) Object literal with any of the Fx config options
10089 * @return {Roo.Element} The Element
10091 slideOut : function(anchor, o){
10092 var el = this.getFxEl();
10095 el.queueFx(o, function(){
10097 anchor = anchor || "t";
10099 // restore values after effect
10100 var r = this.getFxRestore();
10102 var b = this.getBox();
10103 // fixed size for slide
10107 var wrap = this.fxWrap(r.pos, o, "visible");
10109 var st = this.dom.style;
10110 st.visibility = "visible";
10111 st.position = "absolute";
10115 var after = function(){
10117 el.setDisplayed(false);
10122 el.fxUnwrap(wrap, r.pos, o);
10124 st.width = r.width;
10125 st.height = r.height;
10130 var a, zero = {to: 0};
10131 switch(anchor.toLowerCase()){
10133 st.left = st.bottom = "0";
10134 a = {height: zero};
10137 st.right = st.top = "0";
10141 st.left = st.top = "0";
10142 a = {width: zero, points: {to:[b.right, b.y]}};
10145 st.left = st.top = "0";
10146 a = {height: zero, points: {to:[b.x, b.bottom]}};
10149 st.right = st.bottom = "0";
10150 a = {width: zero, height: zero};
10153 st.right = st.top = "0";
10154 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10157 st.left = st.top = "0";
10158 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10161 st.left = st.bottom = "0";
10162 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10166 arguments.callee.anim = wrap.fxanim(a,
10176 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10177 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10178 * The element must be removed from the DOM using the 'remove' config option if desired.
10184 // common config options shown with default values
10192 * @param {Object} options (optional) Object literal with any of the Fx config options
10193 * @return {Roo.Element} The Element
10195 puff : function(o){
10196 var el = this.getFxEl();
10199 el.queueFx(o, function(){
10200 this.clearOpacity();
10203 // restore values after effect
10204 var r = this.getFxRestore();
10205 var st = this.dom.style;
10207 var after = function(){
10209 el.setDisplayed(false);
10216 el.setPositioning(r.pos);
10217 st.width = r.width;
10218 st.height = r.height;
10223 var width = this.getWidth();
10224 var height = this.getHeight();
10226 arguments.callee.anim = this.fxanim({
10227 width : {to: this.adjustWidth(width * 2)},
10228 height : {to: this.adjustHeight(height * 2)},
10229 points : {by: [-(width * .5), -(height * .5)]},
10231 fontSize: {to:200, unit: "%"}
10242 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10243 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10244 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10250 // all config options shown with default values
10258 * @param {Object} options (optional) Object literal with any of the Fx config options
10259 * @return {Roo.Element} The Element
10261 switchOff : function(o){
10262 var el = this.getFxEl();
10265 el.queueFx(o, function(){
10266 this.clearOpacity();
10269 // restore values after effect
10270 var r = this.getFxRestore();
10271 var st = this.dom.style;
10273 var after = function(){
10275 el.setDisplayed(false);
10281 el.setPositioning(r.pos);
10282 st.width = r.width;
10283 st.height = r.height;
10288 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10289 this.clearOpacity();
10293 points:{by:[0, this.getHeight() * .5]}
10294 }, o, 'motion', 0.3, 'easeIn', after);
10295 }).defer(100, this);
10302 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10303 * changed using the "attr" config option) and then fading back to the original color. If no original
10304 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10307 // default: highlight background to yellow
10310 // custom: highlight foreground text to blue for 2 seconds
10311 el.highlight("0000ff", { attr: 'color', duration: 2 });
10313 // common config options shown with default values
10314 el.highlight("ffff9c", {
10315 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10316 endColor: (current color) or "ffffff",
10321 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10322 * @param {Object} options (optional) Object literal with any of the Fx config options
10323 * @return {Roo.Element} The Element
10325 highlight : function(color, o){
10326 var el = this.getFxEl();
10329 el.queueFx(o, function(){
10330 color = color || "ffff9c";
10331 attr = o.attr || "backgroundColor";
10333 this.clearOpacity();
10336 var origColor = this.getColor(attr);
10337 var restoreColor = this.dom.style[attr];
10338 endColor = (o.endColor || origColor) || "ffffff";
10340 var after = function(){
10341 el.dom.style[attr] = restoreColor;
10346 a[attr] = {from: color, to: endColor};
10347 arguments.callee.anim = this.fxanim(a,
10357 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10360 // default: a single light blue ripple
10363 // custom: 3 red ripples lasting 3 seconds total
10364 el.frame("ff0000", 3, { duration: 3 });
10366 // common config options shown with default values
10367 el.frame("C3DAF9", 1, {
10368 duration: 1 //duration of entire animation (not each individual ripple)
10369 // Note: Easing is not configurable and will be ignored if included
10372 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10373 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10374 * @param {Object} options (optional) Object literal with any of the Fx config options
10375 * @return {Roo.Element} The Element
10377 frame : function(color, count, o){
10378 var el = this.getFxEl();
10381 el.queueFx(o, function(){
10382 color = color || "#C3DAF9";
10383 if(color.length == 6){
10384 color = "#" + color;
10386 count = count || 1;
10387 duration = o.duration || 1;
10390 var b = this.getBox();
10391 var animFn = function(){
10392 var proxy = this.createProxy({
10395 visbility:"hidden",
10396 position:"absolute",
10397 "z-index":"35000", // yee haw
10398 border:"0px solid " + color
10401 var scale = Roo.isBorderBox ? 2 : 1;
10403 top:{from:b.y, to:b.y - 20},
10404 left:{from:b.x, to:b.x - 20},
10405 borderWidth:{from:0, to:10},
10406 opacity:{from:1, to:0},
10407 height:{from:b.height, to:(b.height + (20*scale))},
10408 width:{from:b.width, to:(b.width + (20*scale))}
10409 }, duration, function(){
10413 animFn.defer((duration/2)*1000, this);
10424 * Creates a pause before any subsequent queued effects begin. If there are
10425 * no effects queued after the pause it will have no effect.
10430 * @param {Number} seconds The length of time to pause (in seconds)
10431 * @return {Roo.Element} The Element
10433 pause : function(seconds){
10434 var el = this.getFxEl();
10437 el.queueFx(o, function(){
10438 setTimeout(function(){
10440 }, seconds * 1000);
10446 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10447 * using the "endOpacity" config option.
10450 // default: fade in from opacity 0 to 100%
10453 // custom: fade in from opacity 0 to 75% over 2 seconds
10454 el.fadeIn({ endOpacity: .75, duration: 2});
10456 // common config options shown with default values
10458 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10463 * @param {Object} options (optional) Object literal with any of the Fx config options
10464 * @return {Roo.Element} The Element
10466 fadeIn : function(o){
10467 var el = this.getFxEl();
10469 el.queueFx(o, function(){
10470 this.setOpacity(0);
10472 this.dom.style.visibility = 'visible';
10473 var to = o.endOpacity || 1;
10474 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10475 o, null, .5, "easeOut", function(){
10477 this.clearOpacity();
10486 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10487 * using the "endOpacity" config option.
10490 // default: fade out from the element's current opacity to 0
10493 // custom: fade out from the element's current opacity to 25% over 2 seconds
10494 el.fadeOut({ endOpacity: .25, duration: 2});
10496 // common config options shown with default values
10498 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10505 * @param {Object} options (optional) Object literal with any of the Fx config options
10506 * @return {Roo.Element} The Element
10508 fadeOut : function(o){
10509 var el = this.getFxEl();
10511 el.queueFx(o, function(){
10512 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10513 o, null, .5, "easeOut", function(){
10514 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10515 this.dom.style.display = "none";
10517 this.dom.style.visibility = "hidden";
10519 this.clearOpacity();
10527 * Animates the transition of an element's dimensions from a starting height/width
10528 * to an ending height/width.
10531 // change height and width to 100x100 pixels
10532 el.scale(100, 100);
10534 // common config options shown with default values. The height and width will default to
10535 // the element's existing values if passed as null.
10538 [element's height], {
10543 * @param {Number} width The new width (pass undefined to keep the original width)
10544 * @param {Number} height The new height (pass undefined to keep the original height)
10545 * @param {Object} options (optional) Object literal with any of the Fx config options
10546 * @return {Roo.Element} The Element
10548 scale : function(w, h, o){
10549 this.shift(Roo.apply({}, o, {
10557 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10558 * Any of these properties not specified in the config object will not be changed. This effect
10559 * requires that at least one new dimension, position or opacity setting must be passed in on
10560 * the config object in order for the function to have any effect.
10563 // slide the element horizontally to x position 200 while changing the height and opacity
10564 el.shift({ x: 200, height: 50, opacity: .8 });
10566 // common config options shown with default values.
10568 width: [element's width],
10569 height: [element's height],
10570 x: [element's x position],
10571 y: [element's y position],
10572 opacity: [element's opacity],
10577 * @param {Object} options Object literal with any of the Fx config options
10578 * @return {Roo.Element} The Element
10580 shift : function(o){
10581 var el = this.getFxEl();
10583 el.queueFx(o, function(){
10584 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10585 if(w !== undefined){
10586 a.width = {to: this.adjustWidth(w)};
10588 if(h !== undefined){
10589 a.height = {to: this.adjustHeight(h)};
10591 if(x !== undefined || y !== undefined){
10593 x !== undefined ? x : this.getX(),
10594 y !== undefined ? y : this.getY()
10597 if(op !== undefined){
10598 a.opacity = {to: op};
10600 if(o.xy !== undefined){
10601 a.points = {to: o.xy};
10603 arguments.callee.anim = this.fxanim(a,
10604 o, 'motion', .35, "easeOut", function(){
10612 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10613 * ending point of the effect.
10616 // default: slide the element downward while fading out
10619 // custom: slide the element out to the right with a 2-second duration
10620 el.ghost('r', { duration: 2 });
10622 // common config options shown with default values
10630 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10631 * @param {Object} options (optional) Object literal with any of the Fx config options
10632 * @return {Roo.Element} The Element
10634 ghost : function(anchor, o){
10635 var el = this.getFxEl();
10638 el.queueFx(o, function(){
10639 anchor = anchor || "b";
10641 // restore values after effect
10642 var r = this.getFxRestore();
10643 var w = this.getWidth(),
10644 h = this.getHeight();
10646 var st = this.dom.style;
10648 var after = function(){
10650 el.setDisplayed(false);
10656 el.setPositioning(r.pos);
10657 st.width = r.width;
10658 st.height = r.height;
10663 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10664 switch(anchor.toLowerCase()){
10691 arguments.callee.anim = this.fxanim(a,
10701 * Ensures that all effects queued after syncFx is called on the element are
10702 * run concurrently. This is the opposite of {@link #sequenceFx}.
10703 * @return {Roo.Element} The Element
10705 syncFx : function(){
10706 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10715 * Ensures that all effects queued after sequenceFx is called on the element are
10716 * run in sequence. This is the opposite of {@link #syncFx}.
10717 * @return {Roo.Element} The Element
10719 sequenceFx : function(){
10720 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10722 concurrent : false,
10729 nextFx : function(){
10730 var ef = this.fxQueue[0];
10737 * Returns true if the element has any effects actively running or queued, else returns false.
10738 * @return {Boolean} True if element has active effects, else false
10740 hasActiveFx : function(){
10741 return this.fxQueue && this.fxQueue[0];
10745 * Stops any running effects and clears the element's internal effects queue if it contains
10746 * any additional effects that haven't started yet.
10747 * @return {Roo.Element} The Element
10749 stopFx : function(){
10750 if(this.hasActiveFx()){
10751 var cur = this.fxQueue[0];
10752 if(cur && cur.anim && cur.anim.isAnimated()){
10753 this.fxQueue = [cur]; // clear out others
10754 cur.anim.stop(true);
10761 beforeFx : function(o){
10762 if(this.hasActiveFx() && !o.concurrent){
10773 * Returns true if the element is currently blocking so that no other effect can be queued
10774 * until this effect is finished, else returns false if blocking is not set. This is commonly
10775 * used to ensure that an effect initiated by a user action runs to completion prior to the
10776 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10777 * @return {Boolean} True if blocking, else false
10779 hasFxBlock : function(){
10780 var q = this.fxQueue;
10781 return q && q[0] && q[0].block;
10785 queueFx : function(o, fn){
10789 if(!this.hasFxBlock()){
10790 Roo.applyIf(o, this.fxDefaults);
10792 var run = this.beforeFx(o);
10793 fn.block = o.block;
10794 this.fxQueue.push(fn);
10806 fxWrap : function(pos, o, vis){
10808 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10811 wrapXY = this.getXY();
10813 var div = document.createElement("div");
10814 div.style.visibility = vis;
10815 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10816 wrap.setPositioning(pos);
10817 if(wrap.getStyle("position") == "static"){
10818 wrap.position("relative");
10820 this.clearPositioning('auto');
10822 wrap.dom.appendChild(this.dom);
10824 wrap.setXY(wrapXY);
10831 fxUnwrap : function(wrap, pos, o){
10832 this.clearPositioning();
10833 this.setPositioning(pos);
10835 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10841 getFxRestore : function(){
10842 var st = this.dom.style;
10843 return {pos: this.getPositioning(), width: st.width, height : st.height};
10847 afterFx : function(o){
10849 this.applyStyles(o.afterStyle);
10852 this.addClass(o.afterCls);
10854 if(o.remove === true){
10857 Roo.callback(o.callback, o.scope, [this]);
10859 this.fxQueue.shift();
10865 getFxEl : function(){ // support for composite element fx
10866 return Roo.get(this.dom);
10870 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10871 animType = animType || 'run';
10873 var anim = Roo.lib.Anim[animType](
10875 (opt.duration || defaultDur) || .35,
10876 (opt.easing || defaultEase) || 'easeOut',
10878 Roo.callback(cb, this);
10887 // backwords compat
10888 Roo.Fx.resize = Roo.Fx.scale;
10890 //When included, Roo.Fx is automatically applied to Element so that all basic
10891 //effects are available directly via the Element API
10892 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10894 * Ext JS Library 1.1.1
10895 * Copyright(c) 2006-2007, Ext JS, LLC.
10897 * Originally Released Under LGPL - original licence link has changed is not relivant.
10900 * <script type="text/javascript">
10905 * @class Roo.CompositeElement
10906 * Standard composite class. Creates a Roo.Element for every element in the collection.
10908 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10909 * actions will be performed on all the elements in this collection.</b>
10911 * All methods return <i>this</i> and can be chained.
10913 var els = Roo.select("#some-el div.some-class", true);
10914 // or select directly from an existing element
10915 var el = Roo.get('some-el');
10916 el.select('div.some-class', true);
10918 els.setWidth(100); // all elements become 100 width
10919 els.hide(true); // all elements fade out and hide
10921 els.setWidth(100).hide(true);
10924 Roo.CompositeElement = function(els){
10925 this.elements = [];
10926 this.addElements(els);
10928 Roo.CompositeElement.prototype = {
10930 addElements : function(els){
10931 if(!els) return this;
10932 if(typeof els == "string"){
10933 els = Roo.Element.selectorFunction(els);
10935 var yels = this.elements;
10936 var index = yels.length-1;
10937 for(var i = 0, len = els.length; i < len; i++) {
10938 yels[++index] = Roo.get(els[i]);
10944 * Clears this composite and adds the elements returned by the passed selector.
10945 * @param {String/Array} els A string CSS selector, an array of elements or an element
10946 * @return {CompositeElement} this
10948 fill : function(els){
10949 this.elements = [];
10955 * Filters this composite to only elements that match the passed selector.
10956 * @param {String} selector A string CSS selector
10957 * @param {Boolean} inverse return inverse filter (not matches)
10958 * @return {CompositeElement} this
10960 filter : function(selector, inverse){
10962 inverse = inverse || false;
10963 this.each(function(el){
10964 var match = inverse ? !el.is(selector) : el.is(selector);
10966 els[els.length] = el.dom;
10973 invoke : function(fn, args){
10974 var els = this.elements;
10975 for(var i = 0, len = els.length; i < len; i++) {
10976 Roo.Element.prototype[fn].apply(els[i], args);
10981 * Adds elements to this composite.
10982 * @param {String/Array} els A string CSS selector, an array of elements or an element
10983 * @return {CompositeElement} this
10985 add : function(els){
10986 if(typeof els == "string"){
10987 this.addElements(Roo.Element.selectorFunction(els));
10988 }else if(els.length !== undefined){
10989 this.addElements(els);
10991 this.addElements([els]);
10996 * Calls the passed function passing (el, this, index) for each element in this composite.
10997 * @param {Function} fn The function to call
10998 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10999 * @return {CompositeElement} this
11001 each : function(fn, scope){
11002 var els = this.elements;
11003 for(var i = 0, len = els.length; i < len; i++){
11004 if(fn.call(scope || els[i], els[i], this, i) === false) {
11012 * Returns the Element object at the specified index
11013 * @param {Number} index
11014 * @return {Roo.Element}
11016 item : function(index){
11017 return this.elements[index] || null;
11021 * Returns the first Element
11022 * @return {Roo.Element}
11024 first : function(){
11025 return this.item(0);
11029 * Returns the last Element
11030 * @return {Roo.Element}
11033 return this.item(this.elements.length-1);
11037 * Returns the number of elements in this composite
11040 getCount : function(){
11041 return this.elements.length;
11045 * Returns true if this composite contains the passed element
11048 contains : function(el){
11049 return this.indexOf(el) !== -1;
11053 * Returns true if this composite contains the passed element
11056 indexOf : function(el){
11057 return this.elements.indexOf(Roo.get(el));
11062 * Removes the specified element(s).
11063 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11064 * or an array of any of those.
11065 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11066 * @return {CompositeElement} this
11068 removeElement : function(el, removeDom){
11069 if(el instanceof Array){
11070 for(var i = 0, len = el.length; i < len; i++){
11071 this.removeElement(el[i]);
11075 var index = typeof el == 'number' ? el : this.indexOf(el);
11078 var d = this.elements[index];
11082 d.parentNode.removeChild(d);
11085 this.elements.splice(index, 1);
11091 * Replaces the specified element with the passed element.
11092 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11094 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11095 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11096 * @return {CompositeElement} this
11098 replaceElement : function(el, replacement, domReplace){
11099 var index = typeof el == 'number' ? el : this.indexOf(el);
11102 this.elements[index].replaceWith(replacement);
11104 this.elements.splice(index, 1, Roo.get(replacement))
11111 * Removes all elements.
11113 clear : function(){
11114 this.elements = [];
11118 Roo.CompositeElement.createCall = function(proto, fnName){
11119 if(!proto[fnName]){
11120 proto[fnName] = function(){
11121 return this.invoke(fnName, arguments);
11125 for(var fnName in Roo.Element.prototype){
11126 if(typeof Roo.Element.prototype[fnName] == "function"){
11127 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11133 * Ext JS Library 1.1.1
11134 * Copyright(c) 2006-2007, Ext JS, LLC.
11136 * Originally Released Under LGPL - original licence link has changed is not relivant.
11139 * <script type="text/javascript">
11143 * @class Roo.CompositeElementLite
11144 * @extends Roo.CompositeElement
11145 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11147 var els = Roo.select("#some-el div.some-class");
11148 // or select directly from an existing element
11149 var el = Roo.get('some-el');
11150 el.select('div.some-class');
11152 els.setWidth(100); // all elements become 100 width
11153 els.hide(true); // all elements fade out and hide
11155 els.setWidth(100).hide(true);
11156 </code></pre><br><br>
11157 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11158 * actions will be performed on all the elements in this collection.</b>
11160 Roo.CompositeElementLite = function(els){
11161 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11162 this.el = new Roo.Element.Flyweight();
11164 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11165 addElements : function(els){
11167 if(els instanceof Array){
11168 this.elements = this.elements.concat(els);
11170 var yels = this.elements;
11171 var index = yels.length-1;
11172 for(var i = 0, len = els.length; i < len; i++) {
11173 yels[++index] = els[i];
11179 invoke : function(fn, args){
11180 var els = this.elements;
11182 for(var i = 0, len = els.length; i < len; i++) {
11184 Roo.Element.prototype[fn].apply(el, args);
11189 * Returns a flyweight Element of the dom element object at the specified index
11190 * @param {Number} index
11191 * @return {Roo.Element}
11193 item : function(index){
11194 if(!this.elements[index]){
11197 this.el.dom = this.elements[index];
11201 // fixes scope with flyweight
11202 addListener : function(eventName, handler, scope, opt){
11203 var els = this.elements;
11204 for(var i = 0, len = els.length; i < len; i++) {
11205 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11211 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11212 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11213 * a reference to the dom node, use el.dom.</b>
11214 * @param {Function} fn The function to call
11215 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11216 * @return {CompositeElement} this
11218 each : function(fn, scope){
11219 var els = this.elements;
11221 for(var i = 0, len = els.length; i < len; i++){
11223 if(fn.call(scope || el, el, this, i) === false){
11230 indexOf : function(el){
11231 return this.elements.indexOf(Roo.getDom(el));
11234 replaceElement : function(el, replacement, domReplace){
11235 var index = typeof el == 'number' ? el : this.indexOf(el);
11237 replacement = Roo.getDom(replacement);
11239 var d = this.elements[index];
11240 d.parentNode.insertBefore(replacement, d);
11241 d.parentNode.removeChild(d);
11243 this.elements.splice(index, 1, replacement);
11248 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11252 * Ext JS Library 1.1.1
11253 * Copyright(c) 2006-2007, Ext JS, LLC.
11255 * Originally Released Under LGPL - original licence link has changed is not relivant.
11258 * <script type="text/javascript">
11264 * @class Roo.data.Connection
11265 * @extends Roo.util.Observable
11266 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11267 * either to a configured URL, or to a URL specified at request time.<br><br>
11269 * Requests made by this class are asynchronous, and will return immediately. No data from
11270 * the server will be available to the statement immediately following the {@link #request} call.
11271 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11273 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11274 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11275 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11276 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11277 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11278 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11279 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11280 * standard DOM methods.
11282 * @param {Object} config a configuration object.
11284 Roo.data.Connection = function(config){
11285 Roo.apply(this, config);
11288 * @event beforerequest
11289 * Fires before a network request is made to retrieve a data object.
11290 * @param {Connection} conn This Connection object.
11291 * @param {Object} options The options config object passed to the {@link #request} method.
11293 "beforerequest" : true,
11295 * @event requestcomplete
11296 * Fires if the request was successfully completed.
11297 * @param {Connection} conn This Connection object.
11298 * @param {Object} response The XHR object containing the response data.
11299 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11300 * @param {Object} options The options config object passed to the {@link #request} method.
11302 "requestcomplete" : true,
11304 * @event requestexception
11305 * Fires if an error HTTP status was returned from the server.
11306 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11307 * @param {Connection} conn This Connection object.
11308 * @param {Object} response The XHR object containing the response data.
11309 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11310 * @param {Object} options The options config object passed to the {@link #request} method.
11312 "requestexception" : true
11314 Roo.data.Connection.superclass.constructor.call(this);
11317 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11319 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11322 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11323 * extra parameters to each request made by this object. (defaults to undefined)
11326 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11327 * to each request made by this object. (defaults to undefined)
11330 * @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)
11333 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11337 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11343 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11346 disableCaching: true,
11349 * Sends an HTTP request to a remote server.
11350 * @param {Object} options An object which may contain the following properties:<ul>
11351 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11352 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11353 * request, a url encoded string or a function to call to get either.</li>
11354 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11355 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11356 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11357 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11358 * <li>options {Object} The parameter to the request call.</li>
11359 * <li>success {Boolean} True if the request succeeded.</li>
11360 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11362 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11363 * The callback is passed the following parameters:<ul>
11364 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11365 * <li>options {Object} The parameter to the request call.</li>
11367 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11368 * The callback is passed the following parameters:<ul>
11369 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11370 * <li>options {Object} The parameter to the request call.</li>
11372 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11373 * for the callback function. Defaults to the browser window.</li>
11374 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11375 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11376 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11377 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11378 * params for the post data. Any params will be appended to the URL.</li>
11379 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11381 * @return {Number} transactionId
11383 request : function(o){
11384 if(this.fireEvent("beforerequest", this, o) !== false){
11387 if(typeof p == "function"){
11388 p = p.call(o.scope||window, o);
11390 if(typeof p == "object"){
11391 p = Roo.urlEncode(o.params);
11393 if(this.extraParams){
11394 var extras = Roo.urlEncode(this.extraParams);
11395 p = p ? (p + '&' + extras) : extras;
11398 var url = o.url || this.url;
11399 if(typeof url == 'function'){
11400 url = url.call(o.scope||window, o);
11404 var form = Roo.getDom(o.form);
11405 url = url || form.action;
11407 var enctype = form.getAttribute("enctype");
11408 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11409 return this.doFormUpload(o, p, url);
11411 var f = Roo.lib.Ajax.serializeForm(form);
11412 p = p ? (p + '&' + f) : f;
11415 var hs = o.headers;
11416 if(this.defaultHeaders){
11417 hs = Roo.apply(hs || {}, this.defaultHeaders);
11424 success: this.handleResponse,
11425 failure: this.handleFailure,
11427 argument: {options: o},
11428 timeout : o.timeout || this.timeout
11431 var method = o.method||this.method||(p ? "POST" : "GET");
11433 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11434 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11437 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11441 }else if(this.autoAbort !== false){
11445 if((method == 'GET' && p) || o.xmlData){
11446 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11449 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11450 return this.transId;
11452 Roo.callback(o.callback, o.scope, [o, null, null]);
11458 * Determine whether this object has a request outstanding.
11459 * @param {Number} transactionId (Optional) defaults to the last transaction
11460 * @return {Boolean} True if there is an outstanding request.
11462 isLoading : function(transId){
11464 return Roo.lib.Ajax.isCallInProgress(transId);
11466 return this.transId ? true : false;
11471 * Aborts any outstanding request.
11472 * @param {Number} transactionId (Optional) defaults to the last transaction
11474 abort : function(transId){
11475 if(transId || this.isLoading()){
11476 Roo.lib.Ajax.abort(transId || this.transId);
11481 handleResponse : function(response){
11482 this.transId = false;
11483 var options = response.argument.options;
11484 response.argument = options ? options.argument : null;
11485 this.fireEvent("requestcomplete", this, response, options);
11486 Roo.callback(options.success, options.scope, [response, options]);
11487 Roo.callback(options.callback, options.scope, [options, true, response]);
11491 handleFailure : function(response, e){
11492 this.transId = false;
11493 var options = response.argument.options;
11494 response.argument = options ? options.argument : null;
11495 this.fireEvent("requestexception", this, response, options, e);
11496 Roo.callback(options.failure, options.scope, [response, options]);
11497 Roo.callback(options.callback, options.scope, [options, false, response]);
11501 doFormUpload : function(o, ps, url){
11503 var frame = document.createElement('iframe');
11506 frame.className = 'x-hidden';
11508 frame.src = Roo.SSL_SECURE_URL;
11510 document.body.appendChild(frame);
11513 document.frames[id].name = id;
11516 var form = Roo.getDom(o.form);
11518 form.method = 'POST';
11519 form.enctype = form.encoding = 'multipart/form-data';
11525 if(ps){ // add dynamic params
11527 ps = Roo.urlDecode(ps, false);
11529 if(ps.hasOwnProperty(k)){
11530 hd = document.createElement('input');
11531 hd.type = 'hidden';
11534 form.appendChild(hd);
11541 var r = { // bogus response object
11546 r.argument = o ? o.argument : null;
11551 doc = frame.contentWindow.document;
11553 doc = (frame.contentDocument || window.frames[id].document);
11555 if(doc && doc.body){
11556 r.responseText = doc.body.innerHTML;
11558 if(doc && doc.XMLDocument){
11559 r.responseXML = doc.XMLDocument;
11561 r.responseXML = doc;
11568 Roo.EventManager.removeListener(frame, 'load', cb, this);
11570 this.fireEvent("requestcomplete", this, r, o);
11571 Roo.callback(o.success, o.scope, [r, o]);
11572 Roo.callback(o.callback, o.scope, [o, true, r]);
11574 setTimeout(function(){document.body.removeChild(frame);}, 100);
11577 Roo.EventManager.on(frame, 'load', cb, this);
11580 if(hiddens){ // remove dynamic params
11581 for(var i = 0, len = hiddens.length; i < len; i++){
11582 form.removeChild(hiddens[i]);
11589 * Ext JS Library 1.1.1
11590 * Copyright(c) 2006-2007, Ext JS, LLC.
11592 * Originally Released Under LGPL - original licence link has changed is not relivant.
11595 * <script type="text/javascript">
11599 * Global Ajax request class.
11602 * @extends Roo.data.Connection
11605 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11606 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11607 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11608 * @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)
11609 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11610 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11611 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11613 Roo.Ajax = new Roo.data.Connection({
11622 * Serialize the passed form into a url encoded string
11624 * @param {String/HTMLElement} form
11627 serializeForm : function(form){
11628 return Roo.lib.Ajax.serializeForm(form);
11632 * Ext JS Library 1.1.1
11633 * Copyright(c) 2006-2007, Ext JS, LLC.
11635 * Originally Released Under LGPL - original licence link has changed is not relivant.
11638 * <script type="text/javascript">
11643 * @class Roo.UpdateManager
11644 * @extends Roo.util.Observable
11645 * Provides AJAX-style update for Element object.<br><br>
11648 * // Get it from a Roo.Element object
11649 * var el = Roo.get("foo");
11650 * var mgr = el.getUpdateManager();
11651 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11653 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11655 * // or directly (returns the same UpdateManager instance)
11656 * var mgr = new Roo.UpdateManager("myElementId");
11657 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11658 * mgr.on("update", myFcnNeedsToKnow);
11660 // short handed call directly from the element object
11661 Roo.get("foo").load({
11665 text: "Loading Foo..."
11669 * Create new UpdateManager directly.
11670 * @param {String/HTMLElement/Roo.Element} el The element to update
11671 * @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).
11673 Roo.UpdateManager = function(el, forceNew){
11675 if(!forceNew && el.updateManager){
11676 return el.updateManager;
11679 * The Element object
11680 * @type Roo.Element
11684 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11687 this.defaultUrl = null;
11691 * @event beforeupdate
11692 * Fired before an update is made, return false from your handler and the update is cancelled.
11693 * @param {Roo.Element} el
11694 * @param {String/Object/Function} url
11695 * @param {String/Object} params
11697 "beforeupdate": true,
11700 * Fired after successful update is made.
11701 * @param {Roo.Element} el
11702 * @param {Object} oResponseObject The response Object
11707 * Fired on update failure.
11708 * @param {Roo.Element} el
11709 * @param {Object} oResponseObject The response Object
11713 var d = Roo.UpdateManager.defaults;
11715 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11718 this.sslBlankUrl = d.sslBlankUrl;
11720 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11723 this.disableCaching = d.disableCaching;
11725 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11728 this.indicatorText = d.indicatorText;
11730 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11733 this.showLoadIndicator = d.showLoadIndicator;
11735 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11738 this.timeout = d.timeout;
11741 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11744 this.loadScripts = d.loadScripts;
11747 * Transaction object of current executing transaction
11749 this.transaction = null;
11754 this.autoRefreshProcId = null;
11756 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11759 this.refreshDelegate = this.refresh.createDelegate(this);
11761 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11764 this.updateDelegate = this.update.createDelegate(this);
11766 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11769 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11773 this.successDelegate = this.processSuccess.createDelegate(this);
11777 this.failureDelegate = this.processFailure.createDelegate(this);
11779 if(!this.renderer){
11781 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11783 this.renderer = new Roo.UpdateManager.BasicRenderer();
11786 Roo.UpdateManager.superclass.constructor.call(this);
11789 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11791 * Get the Element this UpdateManager is bound to
11792 * @return {Roo.Element} The element
11794 getEl : function(){
11798 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11799 * @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:
11802 url: "your-url.php",<br/>
11803 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11804 callback: yourFunction,<br/>
11805 scope: yourObject, //(optional scope) <br/>
11806 discardUrl: false, <br/>
11807 nocache: false,<br/>
11808 text: "Loading...",<br/>
11810 scripts: false<br/>
11813 * The only required property is url. The optional properties nocache, text and scripts
11814 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11815 * @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}
11816 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11817 * @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.
11819 update : function(url, params, callback, discardUrl){
11820 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11821 var method = this.method,
11823 if(typeof url == "object"){ // must be config object
11826 params = params || cfg.params;
11827 callback = callback || cfg.callback;
11828 discardUrl = discardUrl || cfg.discardUrl;
11829 if(callback && cfg.scope){
11830 callback = callback.createDelegate(cfg.scope);
11832 if(typeof cfg.method != "undefined"){method = cfg.method;};
11833 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11834 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11835 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11836 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11838 this.showLoading();
11840 this.defaultUrl = url;
11842 if(typeof url == "function"){
11843 url = url.call(this);
11846 method = method || (params ? "POST" : "GET");
11847 if(method == "GET"){
11848 url = this.prepareUrl(url);
11851 var o = Roo.apply(cfg ||{}, {
11854 success: this.successDelegate,
11855 failure: this.failureDelegate,
11856 callback: undefined,
11857 timeout: (this.timeout*1000),
11858 argument: {"url": url, "form": null, "callback": callback, "params": params}
11860 Roo.log("updated manager called with timeout of " + o.timeout);
11861 this.transaction = Roo.Ajax.request(o);
11866 * 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.
11867 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11868 * @param {String/HTMLElement} form The form Id or form element
11869 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11870 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11871 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11873 formUpdate : function(form, url, reset, callback){
11874 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11875 if(typeof url == "function"){
11876 url = url.call(this);
11878 form = Roo.getDom(form);
11879 this.transaction = Roo.Ajax.request({
11882 success: this.successDelegate,
11883 failure: this.failureDelegate,
11884 timeout: (this.timeout*1000),
11885 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11887 this.showLoading.defer(1, this);
11892 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11893 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11895 refresh : function(callback){
11896 if(this.defaultUrl == null){
11899 this.update(this.defaultUrl, null, callback, true);
11903 * Set this element to auto refresh.
11904 * @param {Number} interval How often to update (in seconds).
11905 * @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)
11906 * @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}
11907 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11908 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11910 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11912 this.update(url || this.defaultUrl, params, callback, true);
11914 if(this.autoRefreshProcId){
11915 clearInterval(this.autoRefreshProcId);
11917 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11921 * Stop auto refresh on this element.
11923 stopAutoRefresh : function(){
11924 if(this.autoRefreshProcId){
11925 clearInterval(this.autoRefreshProcId);
11926 delete this.autoRefreshProcId;
11930 isAutoRefreshing : function(){
11931 return this.autoRefreshProcId ? true : false;
11934 * Called to update the element to "Loading" state. Override to perform custom action.
11936 showLoading : function(){
11937 if(this.showLoadIndicator){
11938 this.el.update(this.indicatorText);
11943 * Adds unique parameter to query string if disableCaching = true
11946 prepareUrl : function(url){
11947 if(this.disableCaching){
11948 var append = "_dc=" + (new Date().getTime());
11949 if(url.indexOf("?") !== -1){
11950 url += "&" + append;
11952 url += "?" + append;
11961 processSuccess : function(response){
11962 this.transaction = null;
11963 if(response.argument.form && response.argument.reset){
11964 try{ // put in try/catch since some older FF releases had problems with this
11965 response.argument.form.reset();
11968 if(this.loadScripts){
11969 this.renderer.render(this.el, response, this,
11970 this.updateComplete.createDelegate(this, [response]));
11972 this.renderer.render(this.el, response, this);
11973 this.updateComplete(response);
11977 updateComplete : function(response){
11978 this.fireEvent("update", this.el, response);
11979 if(typeof response.argument.callback == "function"){
11980 response.argument.callback(this.el, true, response);
11987 processFailure : function(response){
11988 this.transaction = null;
11989 this.fireEvent("failure", this.el, response);
11990 if(typeof response.argument.callback == "function"){
11991 response.argument.callback(this.el, false, response);
11996 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11997 * @param {Object} renderer The object implementing the render() method
11999 setRenderer : function(renderer){
12000 this.renderer = renderer;
12003 getRenderer : function(){
12004 return this.renderer;
12008 * Set the defaultUrl used for updates
12009 * @param {String/Function} defaultUrl The url or a function to call to get the url
12011 setDefaultUrl : function(defaultUrl){
12012 this.defaultUrl = defaultUrl;
12016 * Aborts the executing transaction
12018 abort : function(){
12019 if(this.transaction){
12020 Roo.Ajax.abort(this.transaction);
12025 * Returns true if an update is in progress
12026 * @return {Boolean}
12028 isUpdating : function(){
12029 if(this.transaction){
12030 return Roo.Ajax.isLoading(this.transaction);
12037 * @class Roo.UpdateManager.defaults
12038 * @static (not really - but it helps the doc tool)
12039 * The defaults collection enables customizing the default properties of UpdateManager
12041 Roo.UpdateManager.defaults = {
12043 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12049 * True to process scripts by default (Defaults to false).
12052 loadScripts : false,
12055 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12058 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12060 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12063 disableCaching : false,
12065 * Whether to show indicatorText when loading (Defaults to true).
12068 showLoadIndicator : true,
12070 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12073 indicatorText : '<div class="loading-indicator">Loading...</div>'
12077 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12079 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12080 * @param {String/HTMLElement/Roo.Element} el The element to update
12081 * @param {String} url The url
12082 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12083 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12086 * @member Roo.UpdateManager
12088 Roo.UpdateManager.updateElement = function(el, url, params, options){
12089 var um = Roo.get(el, true).getUpdateManager();
12090 Roo.apply(um, options);
12091 um.update(url, params, options ? options.callback : null);
12093 // alias for backwards compat
12094 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12096 * @class Roo.UpdateManager.BasicRenderer
12097 * Default Content renderer. Updates the elements innerHTML with the responseText.
12099 Roo.UpdateManager.BasicRenderer = function(){};
12101 Roo.UpdateManager.BasicRenderer.prototype = {
12103 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12104 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12105 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12106 * @param {Roo.Element} el The element being rendered
12107 * @param {Object} response The YUI Connect response object
12108 * @param {UpdateManager} updateManager The calling update manager
12109 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12111 render : function(el, response, updateManager, callback){
12112 el.update(response.responseText, updateManager.loadScripts, callback);
12118 * (c)) Alan Knowles
12124 * @class Roo.DomTemplate
12125 * @extends Roo.Template
12126 * An effort at a dom based template engine..
12128 * Similar to XTemplate, except it uses dom parsing to create the template..
12130 * Supported features:
12135 {a_variable} - output encoded.
12136 {a_variable.format:("Y-m-d")} - call a method on the variable
12137 {a_variable:raw} - unencoded output
12138 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12139 {a_variable:this.method_on_template(...)} - call a method on the template object.
12144 <div roo-for="a_variable or condition.."></div>
12145 <div roo-if="a_variable or condition"></div>
12146 <div roo-exec="some javascript"></div>
12147 <div roo-name="named_template"></div>
12152 Roo.DomTemplate = function()
12154 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12161 Roo.extend(Roo.DomTemplate, Roo.Template, {
12163 * id counter for sub templates.
12167 * flag to indicate if dom parser is inside a pre,
12168 * it will strip whitespace if not.
12173 * The various sub templates
12181 * basic tag replacing syntax
12184 * // you can fake an object call by doing this
12188 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12189 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12191 iterChild : function (node, method) {
12193 var oldPre = this.inPre;
12194 if (node.tagName == 'PRE') {
12197 for( var i = 0; i < node.childNodes.length; i++) {
12198 method.call(this, node.childNodes[i]);
12200 this.inPre = oldPre;
12206 * compile the template
12208 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12211 compile: function()
12215 // covert the html into DOM...
12219 doc = document.implementation.createHTMLDocument("");
12220 doc.documentElement.innerHTML = this.html ;
12221 div = doc.documentElement;
12223 // old IE... - nasty -- it causes all sorts of issues.. with
12224 // images getting pulled from server..
12225 div = document.createElement('div');
12226 div.innerHTML = this.html;
12228 //doc.documentElement.innerHTML = htmlBody
12234 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12236 var tpls = this.tpls;
12238 // create a top level template from the snippet..
12240 //Roo.log(div.innerHTML);
12247 body : div.innerHTML,
12260 Roo.each(tpls, function(tp){
12261 this.compileTpl(tp);
12262 this.tpls[tp.id] = tp;
12265 this.master = tpls[0];
12271 compileNode : function(node, istop) {
12276 // skip anything not a tag..
12277 if (node.nodeType != 1) {
12278 if (node.nodeType == 3 && !this.inPre) {
12279 // reduce white space..
12280 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12303 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12304 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12305 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12306 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12312 // just itterate children..
12313 this.iterChild(node,this.compileNode);
12316 tpl.uid = this.id++;
12317 tpl.value = node.getAttribute('roo-' + tpl.attr);
12318 node.removeAttribute('roo-'+ tpl.attr);
12319 if (tpl.attr != 'name') {
12320 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12321 node.parentNode.replaceChild(placeholder, node);
12324 var placeholder = document.createElement('span');
12325 placeholder.className = 'roo-tpl-' + tpl.value;
12326 node.parentNode.replaceChild(placeholder, node);
12329 // parent now sees '{domtplXXXX}
12330 this.iterChild(node,this.compileNode);
12332 // we should now have node body...
12333 var div = document.createElement('div');
12334 div.appendChild(node);
12336 // this has the unfortunate side effect of converting tagged attributes
12337 // eg. href="{...}" into %7C...%7D
12338 // this has been fixed by searching for those combo's although it's a bit hacky..
12341 tpl.body = div.innerHTML;
12348 switch (tpl.value) {
12349 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12350 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12351 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12356 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12360 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12364 tpl.id = tpl.value; // replace non characters???
12370 this.tpls.push(tpl);
12380 * Compile a segment of the template into a 'sub-template'
12386 compileTpl : function(tpl)
12388 var fm = Roo.util.Format;
12389 var useF = this.disableFormats !== true;
12391 var sep = Roo.isGecko ? "+\n" : ",\n";
12393 var undef = function(str) {
12394 Roo.debug && Roo.log("Property not found :" + str);
12398 //Roo.log(tpl.body);
12402 var fn = function(m, lbrace, name, format, args)
12405 //Roo.log(arguments);
12406 args = args ? args.replace(/\\'/g,"'") : args;
12407 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12408 if (typeof(format) == 'undefined') {
12409 format = 'htmlEncode';
12411 if (format == 'raw' ) {
12415 if(name.substr(0, 6) == 'domtpl'){
12416 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12419 // build an array of options to determine if value is undefined..
12421 // basically get 'xxxx.yyyy' then do
12422 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12423 // (function () { Roo.log("Property not found"); return ''; })() :
12428 Roo.each(name.split('.'), function(st) {
12429 lookfor += (lookfor.length ? '.': '') + st;
12430 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12433 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12436 if(format && useF){
12438 args = args ? ',' + args : "";
12440 if(format.substr(0, 5) != "this."){
12441 format = "fm." + format + '(';
12443 format = 'this.call("'+ format.substr(5) + '", ';
12447 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12450 if (args && args.length) {
12451 // called with xxyx.yuu:(test,test)
12453 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12455 // raw.. - :raw modifier..
12456 return "'"+ sep + udef_st + name + ")"+sep+"'";
12460 // branched to use + in gecko and [].join() in others
12462 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12463 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12466 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12467 body.push(tpl.body.replace(/(\r\n|\n)/g,
12468 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12469 body.push("'].join('');};};");
12470 body = body.join('');
12473 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12475 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12482 * same as applyTemplate, except it's done to one of the subTemplates
12483 * when using named templates, you can do:
12485 * var str = pl.applySubTemplate('your-name', values);
12488 * @param {Number} id of the template
12489 * @param {Object} values to apply to template
12490 * @param {Object} parent (normaly the instance of this object)
12492 applySubTemplate : function(id, values, parent)
12496 var t = this.tpls[id];
12500 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12501 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12505 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12512 if(t.execCall && t.execCall.call(this, values, parent)){
12516 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12522 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12523 parent = t.target ? values : parent;
12524 if(t.forCall && vs instanceof Array){
12526 for(var i = 0, len = vs.length; i < len; i++){
12528 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12530 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12532 //Roo.log(t.compiled);
12536 return buf.join('');
12539 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12544 return t.compiled.call(this, vs, parent);
12546 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12548 //Roo.log(t.compiled);
12556 applyTemplate : function(values){
12557 return this.master.compiled.call(this, values, {});
12558 //var s = this.subs;
12561 apply : function(){
12562 return this.applyTemplate.apply(this, arguments);
12567 Roo.DomTemplate.from = function(el){
12568 el = Roo.getDom(el);
12569 return new Roo.Domtemplate(el.value || el.innerHTML);
12572 * Ext JS Library 1.1.1
12573 * Copyright(c) 2006-2007, Ext JS, LLC.
12575 * Originally Released Under LGPL - original licence link has changed is not relivant.
12578 * <script type="text/javascript">
12582 * @class Roo.util.DelayedTask
12583 * Provides a convenient method of performing setTimeout where a new
12584 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12585 * You can use this class to buffer
12586 * the keypress events for a certain number of milliseconds, and perform only if they stop
12587 * for that amount of time.
12588 * @constructor The parameters to this constructor serve as defaults and are not required.
12589 * @param {Function} fn (optional) The default function to timeout
12590 * @param {Object} scope (optional) The default scope of that timeout
12591 * @param {Array} args (optional) The default Array of arguments
12593 Roo.util.DelayedTask = function(fn, scope, args){
12594 var id = null, d, t;
12596 var call = function(){
12597 var now = new Date().getTime();
12601 fn.apply(scope, args || []);
12605 * Cancels any pending timeout and queues a new one
12606 * @param {Number} delay The milliseconds to delay
12607 * @param {Function} newFn (optional) Overrides function passed to constructor
12608 * @param {Object} newScope (optional) Overrides scope passed to constructor
12609 * @param {Array} newArgs (optional) Overrides args passed to constructor
12611 this.delay = function(delay, newFn, newScope, newArgs){
12612 if(id && delay != d){
12616 t = new Date().getTime();
12618 scope = newScope || scope;
12619 args = newArgs || args;
12621 id = setInterval(call, d);
12626 * Cancel the last queued timeout
12628 this.cancel = function(){
12636 * Ext JS Library 1.1.1
12637 * Copyright(c) 2006-2007, Ext JS, LLC.
12639 * Originally Released Under LGPL - original licence link has changed is not relivant.
12642 * <script type="text/javascript">
12646 Roo.util.TaskRunner = function(interval){
12647 interval = interval || 10;
12648 var tasks = [], removeQueue = [];
12650 var running = false;
12652 var stopThread = function(){
12658 var startThread = function(){
12661 id = setInterval(runTasks, interval);
12665 var removeTask = function(task){
12666 removeQueue.push(task);
12672 var runTasks = function(){
12673 if(removeQueue.length > 0){
12674 for(var i = 0, len = removeQueue.length; i < len; i++){
12675 tasks.remove(removeQueue[i]);
12678 if(tasks.length < 1){
12683 var now = new Date().getTime();
12684 for(var i = 0, len = tasks.length; i < len; ++i){
12686 var itime = now - t.taskRunTime;
12687 if(t.interval <= itime){
12688 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12689 t.taskRunTime = now;
12690 if(rt === false || t.taskRunCount === t.repeat){
12695 if(t.duration && t.duration <= (now - t.taskStartTime)){
12702 * Queues a new task.
12703 * @param {Object} task
12705 this.start = function(task){
12707 task.taskStartTime = new Date().getTime();
12708 task.taskRunTime = 0;
12709 task.taskRunCount = 0;
12714 this.stop = function(task){
12719 this.stopAll = function(){
12721 for(var i = 0, len = tasks.length; i < len; i++){
12722 if(tasks[i].onStop){
12731 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12733 * Ext JS Library 1.1.1
12734 * Copyright(c) 2006-2007, Ext JS, LLC.
12736 * Originally Released Under LGPL - original licence link has changed is not relivant.
12739 * <script type="text/javascript">
12744 * @class Roo.util.MixedCollection
12745 * @extends Roo.util.Observable
12746 * A Collection class that maintains both numeric indexes and keys and exposes events.
12748 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12749 * collection (defaults to false)
12750 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12751 * and return the key value for that item. This is used when available to look up the key on items that
12752 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12753 * equivalent to providing an implementation for the {@link #getKey} method.
12755 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12763 * Fires when the collection is cleared.
12768 * Fires when an item is added to the collection.
12769 * @param {Number} index The index at which the item was added.
12770 * @param {Object} o The item added.
12771 * @param {String} key The key associated with the added item.
12776 * Fires when an item is replaced in the collection.
12777 * @param {String} key he key associated with the new added.
12778 * @param {Object} old The item being replaced.
12779 * @param {Object} new The new item.
12784 * Fires when an item is removed from the collection.
12785 * @param {Object} o The item being removed.
12786 * @param {String} key (optional) The key associated with the removed item.
12791 this.allowFunctions = allowFunctions === true;
12793 this.getKey = keyFn;
12795 Roo.util.MixedCollection.superclass.constructor.call(this);
12798 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12799 allowFunctions : false,
12802 * Adds an item to the collection.
12803 * @param {String} key The key to associate with the item
12804 * @param {Object} o The item to add.
12805 * @return {Object} The item added.
12807 add : function(key, o){
12808 if(arguments.length == 1){
12810 key = this.getKey(o);
12812 if(typeof key == "undefined" || key === null){
12814 this.items.push(o);
12815 this.keys.push(null);
12817 var old = this.map[key];
12819 return this.replace(key, o);
12822 this.items.push(o);
12824 this.keys.push(key);
12826 this.fireEvent("add", this.length-1, o, key);
12831 * MixedCollection has a generic way to fetch keys if you implement getKey.
12834 var mc = new Roo.util.MixedCollection();
12835 mc.add(someEl.dom.id, someEl);
12836 mc.add(otherEl.dom.id, otherEl);
12840 var mc = new Roo.util.MixedCollection();
12841 mc.getKey = function(el){
12847 // or via the constructor
12848 var mc = new Roo.util.MixedCollection(false, function(el){
12854 * @param o {Object} The item for which to find the key.
12855 * @return {Object} The key for the passed item.
12857 getKey : function(o){
12862 * Replaces an item in the collection.
12863 * @param {String} key The key associated with the item to replace, or the item to replace.
12864 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12865 * @return {Object} The new item.
12867 replace : function(key, o){
12868 if(arguments.length == 1){
12870 key = this.getKey(o);
12872 var old = this.item(key);
12873 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12874 return this.add(key, o);
12876 var index = this.indexOfKey(key);
12877 this.items[index] = o;
12879 this.fireEvent("replace", key, old, o);
12884 * Adds all elements of an Array or an Object to the collection.
12885 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12886 * an Array of values, each of which are added to the collection.
12888 addAll : function(objs){
12889 if(arguments.length > 1 || objs instanceof Array){
12890 var args = arguments.length > 1 ? arguments : objs;
12891 for(var i = 0, len = args.length; i < len; i++){
12895 for(var key in objs){
12896 if(this.allowFunctions || typeof objs[key] != "function"){
12897 this.add(key, objs[key]);
12904 * Executes the specified function once for every item in the collection, passing each
12905 * item as the first and only parameter. returning false from the function will stop the iteration.
12906 * @param {Function} fn The function to execute for each item.
12907 * @param {Object} scope (optional) The scope in which to execute the function.
12909 each : function(fn, scope){
12910 var items = [].concat(this.items); // each safe for removal
12911 for(var i = 0, len = items.length; i < len; i++){
12912 if(fn.call(scope || items[i], items[i], i, len) === false){
12919 * Executes the specified function once for every key in the collection, passing each
12920 * key, and its associated item as the first two parameters.
12921 * @param {Function} fn The function to execute for each item.
12922 * @param {Object} scope (optional) The scope in which to execute the function.
12924 eachKey : function(fn, scope){
12925 for(var i = 0, len = this.keys.length; i < len; i++){
12926 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12931 * Returns the first item in the collection which elicits a true return value from the
12932 * passed selection function.
12933 * @param {Function} fn The selection function to execute for each item.
12934 * @param {Object} scope (optional) The scope in which to execute the function.
12935 * @return {Object} The first item in the collection which returned true from the selection function.
12937 find : function(fn, scope){
12938 for(var i = 0, len = this.items.length; i < len; i++){
12939 if(fn.call(scope || window, this.items[i], this.keys[i])){
12940 return this.items[i];
12947 * Inserts an item at the specified index in the collection.
12948 * @param {Number} index The index to insert the item at.
12949 * @param {String} key The key to associate with the new item, or the item itself.
12950 * @param {Object} o (optional) If the second parameter was a key, the new item.
12951 * @return {Object} The item inserted.
12953 insert : function(index, key, o){
12954 if(arguments.length == 2){
12956 key = this.getKey(o);
12958 if(index >= this.length){
12959 return this.add(key, o);
12962 this.items.splice(index, 0, o);
12963 if(typeof key != "undefined" && key != null){
12966 this.keys.splice(index, 0, key);
12967 this.fireEvent("add", index, o, key);
12972 * Removed an item from the collection.
12973 * @param {Object} o The item to remove.
12974 * @return {Object} The item removed.
12976 remove : function(o){
12977 return this.removeAt(this.indexOf(o));
12981 * Remove an item from a specified index in the collection.
12982 * @param {Number} index The index within the collection of the item to remove.
12984 removeAt : function(index){
12985 if(index < this.length && index >= 0){
12987 var o = this.items[index];
12988 this.items.splice(index, 1);
12989 var key = this.keys[index];
12990 if(typeof key != "undefined"){
12991 delete this.map[key];
12993 this.keys.splice(index, 1);
12994 this.fireEvent("remove", o, key);
12999 * Removed an item associated with the passed key fom the collection.
13000 * @param {String} key The key of the item to remove.
13002 removeKey : function(key){
13003 return this.removeAt(this.indexOfKey(key));
13007 * Returns the number of items in the collection.
13008 * @return {Number} the number of items in the collection.
13010 getCount : function(){
13011 return this.length;
13015 * Returns index within the collection of the passed Object.
13016 * @param {Object} o The item to find the index of.
13017 * @return {Number} index of the item.
13019 indexOf : function(o){
13020 if(!this.items.indexOf){
13021 for(var i = 0, len = this.items.length; i < len; i++){
13022 if(this.items[i] == o) return i;
13026 return this.items.indexOf(o);
13031 * Returns index within the collection of the passed key.
13032 * @param {String} key The key to find the index of.
13033 * @return {Number} index of the key.
13035 indexOfKey : function(key){
13036 if(!this.keys.indexOf){
13037 for(var i = 0, len = this.keys.length; i < len; i++){
13038 if(this.keys[i] == key) return i;
13042 return this.keys.indexOf(key);
13047 * Returns the item associated with the passed key OR index. Key has priority over index.
13048 * @param {String/Number} key The key or index of the item.
13049 * @return {Object} The item associated with the passed key.
13051 item : function(key){
13052 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13053 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13057 * Returns the item at the specified index.
13058 * @param {Number} index The index of the item.
13061 itemAt : function(index){
13062 return this.items[index];
13066 * Returns the item associated with the passed key.
13067 * @param {String/Number} key The key of the item.
13068 * @return {Object} The item associated with the passed key.
13070 key : function(key){
13071 return this.map[key];
13075 * Returns true if the collection contains the passed Object as an item.
13076 * @param {Object} o The Object to look for in the collection.
13077 * @return {Boolean} True if the collection contains the Object as an item.
13079 contains : function(o){
13080 return this.indexOf(o) != -1;
13084 * Returns true if the collection contains the passed Object as a key.
13085 * @param {String} key The key to look for in the collection.
13086 * @return {Boolean} True if the collection contains the Object as a key.
13088 containsKey : function(key){
13089 return typeof this.map[key] != "undefined";
13093 * Removes all items from the collection.
13095 clear : function(){
13100 this.fireEvent("clear");
13104 * Returns the first item in the collection.
13105 * @return {Object} the first item in the collection..
13107 first : function(){
13108 return this.items[0];
13112 * Returns the last item in the collection.
13113 * @return {Object} the last item in the collection..
13116 return this.items[this.length-1];
13119 _sort : function(property, dir, fn){
13120 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13121 fn = fn || function(a, b){
13124 var c = [], k = this.keys, items = this.items;
13125 for(var i = 0, len = items.length; i < len; i++){
13126 c[c.length] = {key: k[i], value: items[i], index: i};
13128 c.sort(function(a, b){
13129 var v = fn(a[property], b[property]) * dsc;
13131 v = (a.index < b.index ? -1 : 1);
13135 for(var i = 0, len = c.length; i < len; i++){
13136 items[i] = c[i].value;
13139 this.fireEvent("sort", this);
13143 * Sorts this collection with the passed comparison function
13144 * @param {String} direction (optional) "ASC" or "DESC"
13145 * @param {Function} fn (optional) comparison function
13147 sort : function(dir, fn){
13148 this._sort("value", dir, fn);
13152 * Sorts this collection by keys
13153 * @param {String} direction (optional) "ASC" or "DESC"
13154 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13156 keySort : function(dir, fn){
13157 this._sort("key", dir, fn || function(a, b){
13158 return String(a).toUpperCase()-String(b).toUpperCase();
13163 * Returns a range of items in this collection
13164 * @param {Number} startIndex (optional) defaults to 0
13165 * @param {Number} endIndex (optional) default to the last item
13166 * @return {Array} An array of items
13168 getRange : function(start, end){
13169 var items = this.items;
13170 if(items.length < 1){
13173 start = start || 0;
13174 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13177 for(var i = start; i <= end; i++) {
13178 r[r.length] = items[i];
13181 for(var i = start; i >= end; i--) {
13182 r[r.length] = items[i];
13189 * Filter the <i>objects</i> in this collection by a specific property.
13190 * Returns a new collection that has been filtered.
13191 * @param {String} property A property on your objects
13192 * @param {String/RegExp} value Either string that the property values
13193 * should start with or a RegExp to test against the property
13194 * @return {MixedCollection} The new filtered collection
13196 filter : function(property, value){
13197 if(!value.exec){ // not a regex
13198 value = String(value);
13199 if(value.length == 0){
13200 return this.clone();
13202 value = new RegExp("^" + Roo.escapeRe(value), "i");
13204 return this.filterBy(function(o){
13205 return o && value.test(o[property]);
13210 * Filter by a function. * Returns a new collection that has been filtered.
13211 * The passed function will be called with each
13212 * object in the collection. If the function returns true, the value is included
13213 * otherwise it is filtered.
13214 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13215 * @param {Object} scope (optional) The scope of the function (defaults to this)
13216 * @return {MixedCollection} The new filtered collection
13218 filterBy : function(fn, scope){
13219 var r = new Roo.util.MixedCollection();
13220 r.getKey = this.getKey;
13221 var k = this.keys, it = this.items;
13222 for(var i = 0, len = it.length; i < len; i++){
13223 if(fn.call(scope||this, it[i], k[i])){
13224 r.add(k[i], it[i]);
13231 * Creates a duplicate of this collection
13232 * @return {MixedCollection}
13234 clone : function(){
13235 var r = new Roo.util.MixedCollection();
13236 var k = this.keys, it = this.items;
13237 for(var i = 0, len = it.length; i < len; i++){
13238 r.add(k[i], it[i]);
13240 r.getKey = this.getKey;
13245 * Returns the item associated with the passed key or index.
13247 * @param {String/Number} key The key or index of the item.
13248 * @return {Object} The item associated with the passed key.
13250 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13252 * Ext JS Library 1.1.1
13253 * Copyright(c) 2006-2007, Ext JS, LLC.
13255 * Originally Released Under LGPL - original licence link has changed is not relivant.
13258 * <script type="text/javascript">
13261 * @class Roo.util.JSON
13262 * Modified version of Douglas Crockford"s json.js that doesn"t
13263 * mess with the Object prototype
13264 * http://www.json.org/js.html
13267 Roo.util.JSON = new (function(){
13268 var useHasOwn = {}.hasOwnProperty ? true : false;
13270 // crashes Safari in some instances
13271 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13273 var pad = function(n) {
13274 return n < 10 ? "0" + n : n;
13287 var encodeString = function(s){
13288 if (/["\\\x00-\x1f]/.test(s)) {
13289 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13294 c = b.charCodeAt();
13296 Math.floor(c / 16).toString(16) +
13297 (c % 16).toString(16);
13300 return '"' + s + '"';
13303 var encodeArray = function(o){
13304 var a = ["["], b, i, l = o.length, v;
13305 for (i = 0; i < l; i += 1) {
13307 switch (typeof v) {
13316 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13324 var encodeDate = function(o){
13325 return '"' + o.getFullYear() + "-" +
13326 pad(o.getMonth() + 1) + "-" +
13327 pad(o.getDate()) + "T" +
13328 pad(o.getHours()) + ":" +
13329 pad(o.getMinutes()) + ":" +
13330 pad(o.getSeconds()) + '"';
13334 * Encodes an Object, Array or other value
13335 * @param {Mixed} o The variable to encode
13336 * @return {String} The JSON string
13338 this.encode = function(o)
13340 // should this be extended to fully wrap stringify..
13342 if(typeof o == "undefined" || o === null){
13344 }else if(o instanceof Array){
13345 return encodeArray(o);
13346 }else if(o instanceof Date){
13347 return encodeDate(o);
13348 }else if(typeof o == "string"){
13349 return encodeString(o);
13350 }else if(typeof o == "number"){
13351 return isFinite(o) ? String(o) : "null";
13352 }else if(typeof o == "boolean"){
13355 var a = ["{"], b, i, v;
13357 if(!useHasOwn || o.hasOwnProperty(i)) {
13359 switch (typeof v) {
13368 a.push(this.encode(i), ":",
13369 v === null ? "null" : this.encode(v));
13380 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13381 * @param {String} json The JSON string
13382 * @return {Object} The resulting object
13384 this.decode = function(json){
13386 return /** eval:var:json */ eval("(" + json + ')');
13390 * Shorthand for {@link Roo.util.JSON#encode}
13391 * @member Roo encode
13393 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13395 * Shorthand for {@link Roo.util.JSON#decode}
13396 * @member Roo decode
13398 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13401 * Ext JS Library 1.1.1
13402 * Copyright(c) 2006-2007, Ext JS, LLC.
13404 * Originally Released Under LGPL - original licence link has changed is not relivant.
13407 * <script type="text/javascript">
13411 * @class Roo.util.Format
13412 * Reusable data formatting functions
13415 Roo.util.Format = function(){
13416 var trimRe = /^\s+|\s+$/g;
13419 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13420 * @param {String} value The string to truncate
13421 * @param {Number} length The maximum length to allow before truncating
13422 * @return {String} The converted text
13424 ellipsis : function(value, len){
13425 if(value && value.length > len){
13426 return value.substr(0, len-3)+"...";
13432 * Checks a reference and converts it to empty string if it is undefined
13433 * @param {Mixed} value Reference to check
13434 * @return {Mixed} Empty string if converted, otherwise the original value
13436 undef : function(value){
13437 return typeof value != "undefined" ? value : "";
13441 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13442 * @param {String} value The string to encode
13443 * @return {String} The encoded text
13445 htmlEncode : function(value){
13446 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13450 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13451 * @param {String} value The string to decode
13452 * @return {String} The decoded text
13454 htmlDecode : function(value){
13455 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13459 * Trims any whitespace from either side of a string
13460 * @param {String} value The text to trim
13461 * @return {String} The trimmed text
13463 trim : function(value){
13464 return String(value).replace(trimRe, "");
13468 * Returns a substring from within an original string
13469 * @param {String} value The original text
13470 * @param {Number} start The start index of the substring
13471 * @param {Number} length The length of the substring
13472 * @return {String} The substring
13474 substr : function(value, start, length){
13475 return String(value).substr(start, length);
13479 * Converts a string to all lower case letters
13480 * @param {String} value The text to convert
13481 * @return {String} The converted text
13483 lowercase : function(value){
13484 return String(value).toLowerCase();
13488 * Converts a string to all upper case letters
13489 * @param {String} value The text to convert
13490 * @return {String} The converted text
13492 uppercase : function(value){
13493 return String(value).toUpperCase();
13497 * Converts the first character only of a string to upper case
13498 * @param {String} value The text to convert
13499 * @return {String} The converted text
13501 capitalize : function(value){
13502 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13506 call : function(value, fn){
13507 if(arguments.length > 2){
13508 var args = Array.prototype.slice.call(arguments, 2);
13509 args.unshift(value);
13511 return /** eval:var:value */ eval(fn).apply(window, args);
13513 /** eval:var:value */
13514 return /** eval:var:value */ eval(fn).call(window, value);
13520 * safer version of Math.toFixed..??/
13521 * @param {Number/String} value The numeric value to format
13522 * @param {Number/String} value Decimal places
13523 * @return {String} The formatted currency string
13525 toFixed : function(v, n)
13527 // why not use to fixed - precision is buggered???
13529 return Math.round(v-0);
13531 var fact = Math.pow(10,n+1);
13532 v = (Math.round((v-0)*fact))/fact;
13533 var z = (''+fact).substring(2);
13534 if (v == Math.floor(v)) {
13535 return Math.floor(v) + '.' + z;
13538 // now just padd decimals..
13539 var ps = String(v).split('.');
13540 var fd = (ps[1] + z);
13541 var r = fd.substring(0,n);
13542 var rm = fd.substring(n);
13544 return ps[0] + '.' + r;
13546 r*=1; // turn it into a number;
13548 if (String(r).length != n) {
13551 r = String(r).substring(1); // chop the end off.
13554 return ps[0] + '.' + r;
13559 * Format a number as US currency
13560 * @param {Number/String} value The numeric value to format
13561 * @return {String} The formatted currency string
13563 usMoney : function(v){
13564 return '$' + Roo.util.Format.number(v);
13569 * eventually this should probably emulate php's number_format
13570 * @param {Number/String} value The numeric value to format
13571 * @param {Number} decimals number of decimal places
13572 * @return {String} The formatted currency string
13574 number : function(v,decimals)
13576 // multiply and round.
13577 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13578 var mul = Math.pow(10, decimals);
13579 var zero = String(mul).substring(1);
13580 v = (Math.round((v-0)*mul))/mul;
13582 // if it's '0' number.. then
13584 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13586 var ps = v.split('.');
13590 var r = /(\d+)(\d{3})/;
13592 while (r.test(whole)) {
13593 whole = whole.replace(r, '$1' + ',' + '$2');
13599 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13600 // does not have decimals
13601 (decimals ? ('.' + zero) : '');
13604 return whole + sub ;
13608 * Parse a value into a formatted date using the specified format pattern.
13609 * @param {Mixed} value The value to format
13610 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13611 * @return {String} The formatted date string
13613 date : function(v, format){
13617 if(!(v instanceof Date)){
13618 v = new Date(Date.parse(v));
13620 return v.dateFormat(format || Roo.util.Format.defaults.date);
13624 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13625 * @param {String} format Any valid date format string
13626 * @return {Function} The date formatting function
13628 dateRenderer : function(format){
13629 return function(v){
13630 return Roo.util.Format.date(v, format);
13635 stripTagsRE : /<\/?[^>]+>/gi,
13638 * Strips all HTML tags
13639 * @param {Mixed} value The text from which to strip tags
13640 * @return {String} The stripped text
13642 stripTags : function(v){
13643 return !v ? v : String(v).replace(this.stripTagsRE, "");
13647 Roo.util.Format.defaults = {
13651 * Ext JS Library 1.1.1
13652 * Copyright(c) 2006-2007, Ext JS, LLC.
13654 * Originally Released Under LGPL - original licence link has changed is not relivant.
13657 * <script type="text/javascript">
13664 * @class Roo.MasterTemplate
13665 * @extends Roo.Template
13666 * Provides a template that can have child templates. The syntax is:
13668 var t = new Roo.MasterTemplate(
13669 '<select name="{name}">',
13670 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13673 t.add('options', {value: 'foo', text: 'bar'});
13674 // or you can add multiple child elements in one shot
13675 t.addAll('options', [
13676 {value: 'foo', text: 'bar'},
13677 {value: 'foo2', text: 'bar2'},
13678 {value: 'foo3', text: 'bar3'}
13680 // then append, applying the master template values
13681 t.append('my-form', {name: 'my-select'});
13683 * A name attribute for the child template is not required if you have only one child
13684 * template or you want to refer to them by index.
13686 Roo.MasterTemplate = function(){
13687 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13688 this.originalHtml = this.html;
13690 var m, re = this.subTemplateRe;
13693 while(m = re.exec(this.html)){
13694 var name = m[1], content = m[2];
13699 tpl : new Roo.Template(content)
13702 st[name] = st[subIndex];
13704 st[subIndex].tpl.compile();
13705 st[subIndex].tpl.call = this.call.createDelegate(this);
13708 this.subCount = subIndex;
13711 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13713 * The regular expression used to match sub templates
13717 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13720 * Applies the passed values to a child template.
13721 * @param {String/Number} name (optional) The name or index of the child template
13722 * @param {Array/Object} values The values to be applied to the template
13723 * @return {MasterTemplate} this
13725 add : function(name, values){
13726 if(arguments.length == 1){
13727 values = arguments[0];
13730 var s = this.subs[name];
13731 s.buffer[s.buffer.length] = s.tpl.apply(values);
13736 * Applies all the passed values to a child template.
13737 * @param {String/Number} name (optional) The name or index of the child template
13738 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13739 * @param {Boolean} reset (optional) True to reset the template first
13740 * @return {MasterTemplate} this
13742 fill : function(name, values, reset){
13744 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13752 for(var i = 0, len = values.length; i < len; i++){
13753 this.add(name, values[i]);
13759 * Resets the template for reuse
13760 * @return {MasterTemplate} this
13762 reset : function(){
13764 for(var i = 0; i < this.subCount; i++){
13770 applyTemplate : function(values){
13772 var replaceIndex = -1;
13773 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13774 return s[++replaceIndex].buffer.join("");
13776 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13779 apply : function(){
13780 return this.applyTemplate.apply(this, arguments);
13783 compile : function(){return this;}
13787 * Alias for fill().
13790 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13792 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13793 * var tpl = Roo.MasterTemplate.from('element-id');
13794 * @param {String/HTMLElement} el
13795 * @param {Object} config
13798 Roo.MasterTemplate.from = function(el, config){
13799 el = Roo.getDom(el);
13800 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13803 * Ext JS Library 1.1.1
13804 * Copyright(c) 2006-2007, Ext JS, LLC.
13806 * Originally Released Under LGPL - original licence link has changed is not relivant.
13809 * <script type="text/javascript">
13814 * @class Roo.util.CSS
13815 * Utility class for manipulating CSS rules
13818 Roo.util.CSS = function(){
13820 var doc = document;
13822 var camelRe = /(-[a-z])/gi;
13823 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13827 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13828 * tag and appended to the HEAD of the document.
13829 * @param {String|Object} cssText The text containing the css rules
13830 * @param {String} id An id to add to the stylesheet for later removal
13831 * @return {StyleSheet}
13833 createStyleSheet : function(cssText, id){
13835 var head = doc.getElementsByTagName("head")[0];
13836 var nrules = doc.createElement("style");
13837 nrules.setAttribute("type", "text/css");
13839 nrules.setAttribute("id", id);
13841 if (typeof(cssText) != 'string') {
13842 // support object maps..
13843 // not sure if this a good idea..
13844 // perhaps it should be merged with the general css handling
13845 // and handle js style props.
13846 var cssTextNew = [];
13847 for(var n in cssText) {
13849 for(var k in cssText[n]) {
13850 citems.push( k + ' : ' +cssText[n][k] + ';' );
13852 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13855 cssText = cssTextNew.join("\n");
13861 head.appendChild(nrules);
13862 ss = nrules.styleSheet;
13863 ss.cssText = cssText;
13866 nrules.appendChild(doc.createTextNode(cssText));
13868 nrules.cssText = cssText;
13870 head.appendChild(nrules);
13871 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13873 this.cacheStyleSheet(ss);
13878 * Removes a style or link tag by id
13879 * @param {String} id The id of the tag
13881 removeStyleSheet : function(id){
13882 var existing = doc.getElementById(id);
13884 existing.parentNode.removeChild(existing);
13889 * Dynamically swaps an existing stylesheet reference for a new one
13890 * @param {String} id The id of an existing link tag to remove
13891 * @param {String} url The href of the new stylesheet to include
13893 swapStyleSheet : function(id, url){
13894 this.removeStyleSheet(id);
13895 var ss = doc.createElement("link");
13896 ss.setAttribute("rel", "stylesheet");
13897 ss.setAttribute("type", "text/css");
13898 ss.setAttribute("id", id);
13899 ss.setAttribute("href", url);
13900 doc.getElementsByTagName("head")[0].appendChild(ss);
13904 * Refresh the rule cache if you have dynamically added stylesheets
13905 * @return {Object} An object (hash) of rules indexed by selector
13907 refreshCache : function(){
13908 return this.getRules(true);
13912 cacheStyleSheet : function(stylesheet){
13916 try{// try catch for cross domain access issue
13917 var ssRules = stylesheet.cssRules || stylesheet.rules;
13918 for(var j = ssRules.length-1; j >= 0; --j){
13919 rules[ssRules[j].selectorText] = ssRules[j];
13925 * Gets all css rules for the document
13926 * @param {Boolean} refreshCache true to refresh the internal cache
13927 * @return {Object} An object (hash) of rules indexed by selector
13929 getRules : function(refreshCache){
13930 if(rules == null || refreshCache){
13932 var ds = doc.styleSheets;
13933 for(var i =0, len = ds.length; i < len; i++){
13935 this.cacheStyleSheet(ds[i]);
13943 * Gets an an individual CSS rule by selector(s)
13944 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13945 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13946 * @return {CSSRule} The CSS rule or null if one is not found
13948 getRule : function(selector, refreshCache){
13949 var rs = this.getRules(refreshCache);
13950 if(!(selector instanceof Array)){
13951 return rs[selector];
13953 for(var i = 0; i < selector.length; i++){
13954 if(rs[selector[i]]){
13955 return rs[selector[i]];
13963 * Updates a rule property
13964 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13965 * @param {String} property The css property
13966 * @param {String} value The new value for the property
13967 * @return {Boolean} true If a rule was found and updated
13969 updateRule : function(selector, property, value){
13970 if(!(selector instanceof Array)){
13971 var rule = this.getRule(selector);
13973 rule.style[property.replace(camelRe, camelFn)] = value;
13977 for(var i = 0; i < selector.length; i++){
13978 if(this.updateRule(selector[i], property, value)){
13988 * Ext JS Library 1.1.1
13989 * Copyright(c) 2006-2007, Ext JS, LLC.
13991 * Originally Released Under LGPL - original licence link has changed is not relivant.
13994 * <script type="text/javascript">
14000 * @class Roo.util.ClickRepeater
14001 * @extends Roo.util.Observable
14003 * A wrapper class which can be applied to any element. Fires a "click" event while the
14004 * mouse is pressed. The interval between firings may be specified in the config but
14005 * defaults to 10 milliseconds.
14007 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14009 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14010 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14011 * Similar to an autorepeat key delay.
14012 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14013 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14014 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14015 * "interval" and "delay" are ignored. "immediate" is honored.
14016 * @cfg {Boolean} preventDefault True to prevent the default click event
14017 * @cfg {Boolean} stopDefault True to stop the default click event
14020 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14021 * 2007-02-02 jvs Renamed to ClickRepeater
14022 * 2007-02-03 jvs Modifications for FF Mac and Safari
14025 * @param {String/HTMLElement/Element} el The element to listen on
14026 * @param {Object} config
14028 Roo.util.ClickRepeater = function(el, config)
14030 this.el = Roo.get(el);
14031 this.el.unselectable();
14033 Roo.apply(this, config);
14038 * Fires when the mouse button is depressed.
14039 * @param {Roo.util.ClickRepeater} this
14041 "mousedown" : true,
14044 * Fires on a specified interval during the time the element is pressed.
14045 * @param {Roo.util.ClickRepeater} this
14050 * Fires when the mouse key is released.
14051 * @param {Roo.util.ClickRepeater} this
14056 this.el.on("mousedown", this.handleMouseDown, this);
14057 if(this.preventDefault || this.stopDefault){
14058 this.el.on("click", function(e){
14059 if(this.preventDefault){
14060 e.preventDefault();
14062 if(this.stopDefault){
14068 // allow inline handler
14070 this.on("click", this.handler, this.scope || this);
14073 Roo.util.ClickRepeater.superclass.constructor.call(this);
14076 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14079 preventDefault : true,
14080 stopDefault : false,
14084 handleMouseDown : function(){
14085 clearTimeout(this.timer);
14087 if(this.pressClass){
14088 this.el.addClass(this.pressClass);
14090 this.mousedownTime = new Date();
14092 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14093 this.el.on("mouseout", this.handleMouseOut, this);
14095 this.fireEvent("mousedown", this);
14096 this.fireEvent("click", this);
14098 this.timer = this.click.defer(this.delay || this.interval, this);
14102 click : function(){
14103 this.fireEvent("click", this);
14104 this.timer = this.click.defer(this.getInterval(), this);
14108 getInterval: function(){
14109 if(!this.accelerate){
14110 return this.interval;
14112 var pressTime = this.mousedownTime.getElapsed();
14113 if(pressTime < 500){
14115 }else if(pressTime < 1700){
14117 }else if(pressTime < 2600){
14119 }else if(pressTime < 3500){
14121 }else if(pressTime < 4400){
14123 }else if(pressTime < 5300){
14125 }else if(pressTime < 6200){
14133 handleMouseOut : function(){
14134 clearTimeout(this.timer);
14135 if(this.pressClass){
14136 this.el.removeClass(this.pressClass);
14138 this.el.on("mouseover", this.handleMouseReturn, this);
14142 handleMouseReturn : function(){
14143 this.el.un("mouseover", this.handleMouseReturn);
14144 if(this.pressClass){
14145 this.el.addClass(this.pressClass);
14151 handleMouseUp : function(){
14152 clearTimeout(this.timer);
14153 this.el.un("mouseover", this.handleMouseReturn);
14154 this.el.un("mouseout", this.handleMouseOut);
14155 Roo.get(document).un("mouseup", this.handleMouseUp);
14156 this.el.removeClass(this.pressClass);
14157 this.fireEvent("mouseup", this);
14161 * Ext JS Library 1.1.1
14162 * Copyright(c) 2006-2007, Ext JS, LLC.
14164 * Originally Released Under LGPL - original licence link has changed is not relivant.
14167 * <script type="text/javascript">
14172 * @class Roo.KeyNav
14173 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14174 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14175 * way to implement custom navigation schemes for any UI component.</p>
14176 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14177 * pageUp, pageDown, del, home, end. Usage:</p>
14179 var nav = new Roo.KeyNav("my-element", {
14180 "left" : function(e){
14181 this.moveLeft(e.ctrlKey);
14183 "right" : function(e){
14184 this.moveRight(e.ctrlKey);
14186 "enter" : function(e){
14193 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14194 * @param {Object} config The config
14196 Roo.KeyNav = function(el, config){
14197 this.el = Roo.get(el);
14198 Roo.apply(this, config);
14199 if(!this.disabled){
14200 this.disabled = true;
14205 Roo.KeyNav.prototype = {
14207 * @cfg {Boolean} disabled
14208 * True to disable this KeyNav instance (defaults to false)
14212 * @cfg {String} defaultEventAction
14213 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14214 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14215 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14217 defaultEventAction: "stopEvent",
14219 * @cfg {Boolean} forceKeyDown
14220 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14221 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14222 * handle keydown instead of keypress.
14224 forceKeyDown : false,
14227 prepareEvent : function(e){
14228 var k = e.getKey();
14229 var h = this.keyToHandler[k];
14230 //if(h && this[h]){
14231 // e.stopPropagation();
14233 if(Roo.isSafari && h && k >= 37 && k <= 40){
14239 relay : function(e){
14240 var k = e.getKey();
14241 var h = this.keyToHandler[k];
14243 if(this.doRelay(e, this[h], h) !== true){
14244 e[this.defaultEventAction]();
14250 doRelay : function(e, h, hname){
14251 return h.call(this.scope || this, e);
14254 // possible handlers
14268 // quick lookup hash
14285 * Enable this KeyNav
14287 enable: function(){
14289 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14290 // the EventObject will normalize Safari automatically
14291 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14292 this.el.on("keydown", this.relay, this);
14294 this.el.on("keydown", this.prepareEvent, this);
14295 this.el.on("keypress", this.relay, this);
14297 this.disabled = false;
14302 * Disable this KeyNav
14304 disable: function(){
14305 if(!this.disabled){
14306 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14307 this.el.un("keydown", this.relay);
14309 this.el.un("keydown", this.prepareEvent);
14310 this.el.un("keypress", this.relay);
14312 this.disabled = true;
14317 * Ext JS Library 1.1.1
14318 * Copyright(c) 2006-2007, Ext JS, LLC.
14320 * Originally Released Under LGPL - original licence link has changed is not relivant.
14323 * <script type="text/javascript">
14328 * @class Roo.KeyMap
14329 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14330 * The constructor accepts the same config object as defined by {@link #addBinding}.
14331 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14332 * combination it will call the function with this signature (if the match is a multi-key
14333 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14334 * A KeyMap can also handle a string representation of keys.<br />
14337 // map one key by key code
14338 var map = new Roo.KeyMap("my-element", {
14339 key: 13, // or Roo.EventObject.ENTER
14344 // map multiple keys to one action by string
14345 var map = new Roo.KeyMap("my-element", {
14351 // map multiple keys to multiple actions by strings and array of codes
14352 var map = new Roo.KeyMap("my-element", [
14355 fn: function(){ alert("Return was pressed"); }
14358 fn: function(){ alert('a, b or c was pressed'); }
14363 fn: function(){ alert('Control + shift + tab was pressed.'); }
14367 * <b>Note: A KeyMap starts enabled</b>
14369 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14370 * @param {Object} config The config (see {@link #addBinding})
14371 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14373 Roo.KeyMap = function(el, config, eventName){
14374 this.el = Roo.get(el);
14375 this.eventName = eventName || "keydown";
14376 this.bindings = [];
14378 this.addBinding(config);
14383 Roo.KeyMap.prototype = {
14385 * True to stop the event from bubbling and prevent the default browser action if the
14386 * key was handled by the KeyMap (defaults to false)
14392 * Add a new binding to this KeyMap. The following config object properties are supported:
14394 Property Type Description
14395 ---------- --------------- ----------------------------------------------------------------------
14396 key String/Array A single keycode or an array of keycodes to handle
14397 shift Boolean True to handle key only when shift is pressed (defaults to false)
14398 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14399 alt Boolean True to handle key only when alt is pressed (defaults to false)
14400 fn Function The function to call when KeyMap finds the expected key combination
14401 scope Object The scope of the callback function
14407 var map = new Roo.KeyMap(document, {
14408 key: Roo.EventObject.ENTER,
14413 //Add a new binding to the existing KeyMap later
14421 * @param {Object/Array} config A single KeyMap config or an array of configs
14423 addBinding : function(config){
14424 if(config instanceof Array){
14425 for(var i = 0, len = config.length; i < len; i++){
14426 this.addBinding(config[i]);
14430 var keyCode = config.key,
14431 shift = config.shift,
14432 ctrl = config.ctrl,
14435 scope = config.scope;
14436 if(typeof keyCode == "string"){
14438 var keyString = keyCode.toUpperCase();
14439 for(var j = 0, len = keyString.length; j < len; j++){
14440 ks.push(keyString.charCodeAt(j));
14444 var keyArray = keyCode instanceof Array;
14445 var handler = function(e){
14446 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14447 var k = e.getKey();
14449 for(var i = 0, len = keyCode.length; i < len; i++){
14450 if(keyCode[i] == k){
14451 if(this.stopEvent){
14454 fn.call(scope || window, k, e);
14460 if(this.stopEvent){
14463 fn.call(scope || window, k, e);
14468 this.bindings.push(handler);
14472 * Shorthand for adding a single key listener
14473 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14474 * following options:
14475 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14476 * @param {Function} fn The function to call
14477 * @param {Object} scope (optional) The scope of the function
14479 on : function(key, fn, scope){
14480 var keyCode, shift, ctrl, alt;
14481 if(typeof key == "object" && !(key instanceof Array)){
14500 handleKeyDown : function(e){
14501 if(this.enabled){ //just in case
14502 var b = this.bindings;
14503 for(var i = 0, len = b.length; i < len; i++){
14504 b[i].call(this, e);
14510 * Returns true if this KeyMap is enabled
14511 * @return {Boolean}
14513 isEnabled : function(){
14514 return this.enabled;
14518 * Enables this KeyMap
14520 enable: function(){
14522 this.el.on(this.eventName, this.handleKeyDown, this);
14523 this.enabled = true;
14528 * Disable this KeyMap
14530 disable: function(){
14532 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14533 this.enabled = false;
14538 * Ext JS Library 1.1.1
14539 * Copyright(c) 2006-2007, Ext JS, LLC.
14541 * Originally Released Under LGPL - original licence link has changed is not relivant.
14544 * <script type="text/javascript">
14549 * @class Roo.util.TextMetrics
14550 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14551 * wide, in pixels, a given block of text will be.
14554 Roo.util.TextMetrics = function(){
14558 * Measures the size of the specified text
14559 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14560 * that can affect the size of the rendered text
14561 * @param {String} text The text to measure
14562 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14563 * in order to accurately measure the text height
14564 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14566 measure : function(el, text, fixedWidth){
14568 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14571 shared.setFixedWidth(fixedWidth || 'auto');
14572 return shared.getSize(text);
14576 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14577 * the overhead of multiple calls to initialize the style properties on each measurement.
14578 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14579 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14580 * in order to accurately measure the text height
14581 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14583 createInstance : function(el, fixedWidth){
14584 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14591 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14592 var ml = new Roo.Element(document.createElement('div'));
14593 document.body.appendChild(ml.dom);
14594 ml.position('absolute');
14595 ml.setLeftTop(-1000, -1000);
14599 ml.setWidth(fixedWidth);
14604 * Returns the size of the specified text based on the internal element's style and width properties
14605 * @memberOf Roo.util.TextMetrics.Instance#
14606 * @param {String} text The text to measure
14607 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14609 getSize : function(text){
14611 var s = ml.getSize();
14617 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14618 * that can affect the size of the rendered text
14619 * @memberOf Roo.util.TextMetrics.Instance#
14620 * @param {String/HTMLElement} el The element, dom node or id
14622 bind : function(el){
14624 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14629 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14630 * to set a fixed width in order to accurately measure the text height.
14631 * @memberOf Roo.util.TextMetrics.Instance#
14632 * @param {Number} width The width to set on the element
14634 setFixedWidth : function(width){
14635 ml.setWidth(width);
14639 * Returns the measured width of the specified text
14640 * @memberOf Roo.util.TextMetrics.Instance#
14641 * @param {String} text The text to measure
14642 * @return {Number} width The width in pixels
14644 getWidth : function(text){
14645 ml.dom.style.width = 'auto';
14646 return this.getSize(text).width;
14650 * Returns the measured height of the specified text. For multiline text, be sure to call
14651 * {@link #setFixedWidth} if necessary.
14652 * @memberOf Roo.util.TextMetrics.Instance#
14653 * @param {String} text The text to measure
14654 * @return {Number} height The height in pixels
14656 getHeight : function(text){
14657 return this.getSize(text).height;
14661 instance.bind(bindTo);
14666 // backwards compat
14667 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14669 * Ext JS Library 1.1.1
14670 * Copyright(c) 2006-2007, Ext JS, LLC.
14672 * Originally Released Under LGPL - original licence link has changed is not relivant.
14675 * <script type="text/javascript">
14679 * @class Roo.state.Provider
14680 * Abstract base class for state provider implementations. This class provides methods
14681 * for encoding and decoding <b>typed</b> variables including dates and defines the
14682 * Provider interface.
14684 Roo.state.Provider = function(){
14686 * @event statechange
14687 * Fires when a state change occurs.
14688 * @param {Provider} this This state provider
14689 * @param {String} key The state key which was changed
14690 * @param {String} value The encoded value for the state
14693 "statechange": true
14696 Roo.state.Provider.superclass.constructor.call(this);
14698 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14700 * Returns the current value for a key
14701 * @param {String} name The key name
14702 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14703 * @return {Mixed} The state data
14705 get : function(name, defaultValue){
14706 return typeof this.state[name] == "undefined" ?
14707 defaultValue : this.state[name];
14711 * Clears a value from the state
14712 * @param {String} name The key name
14714 clear : function(name){
14715 delete this.state[name];
14716 this.fireEvent("statechange", this, name, null);
14720 * Sets the value for a key
14721 * @param {String} name The key name
14722 * @param {Mixed} value The value to set
14724 set : function(name, value){
14725 this.state[name] = value;
14726 this.fireEvent("statechange", this, name, value);
14730 * Decodes a string previously encoded with {@link #encodeValue}.
14731 * @param {String} value The value to decode
14732 * @return {Mixed} The decoded value
14734 decodeValue : function(cookie){
14735 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14736 var matches = re.exec(unescape(cookie));
14737 if(!matches || !matches[1]) return; // non state cookie
14738 var type = matches[1];
14739 var v = matches[2];
14742 return parseFloat(v);
14744 return new Date(Date.parse(v));
14749 var values = v.split("^");
14750 for(var i = 0, len = values.length; i < len; i++){
14751 all.push(this.decodeValue(values[i]));
14756 var values = v.split("^");
14757 for(var i = 0, len = values.length; i < len; i++){
14758 var kv = values[i].split("=");
14759 all[kv[0]] = this.decodeValue(kv[1]);
14768 * Encodes a value including type information. Decode with {@link #decodeValue}.
14769 * @param {Mixed} value The value to encode
14770 * @return {String} The encoded value
14772 encodeValue : function(v){
14774 if(typeof v == "number"){
14776 }else if(typeof v == "boolean"){
14777 enc = "b:" + (v ? "1" : "0");
14778 }else if(v instanceof Date){
14779 enc = "d:" + v.toGMTString();
14780 }else if(v instanceof Array){
14782 for(var i = 0, len = v.length; i < len; i++){
14783 flat += this.encodeValue(v[i]);
14784 if(i != len-1) flat += "^";
14787 }else if(typeof v == "object"){
14790 if(typeof v[key] != "function"){
14791 flat += key + "=" + this.encodeValue(v[key]) + "^";
14794 enc = "o:" + flat.substring(0, flat.length-1);
14798 return escape(enc);
14804 * Ext JS Library 1.1.1
14805 * Copyright(c) 2006-2007, Ext JS, LLC.
14807 * Originally Released Under LGPL - original licence link has changed is not relivant.
14810 * <script type="text/javascript">
14813 * @class Roo.state.Manager
14814 * This is the global state manager. By default all components that are "state aware" check this class
14815 * for state information if you don't pass them a custom state provider. In order for this class
14816 * to be useful, it must be initialized with a provider when your application initializes.
14818 // in your initialization function
14820 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14822 // supposed you have a {@link Roo.BorderLayout}
14823 var layout = new Roo.BorderLayout(...);
14824 layout.restoreState();
14825 // or a {Roo.BasicDialog}
14826 var dialog = new Roo.BasicDialog(...);
14827 dialog.restoreState();
14831 Roo.state.Manager = function(){
14832 var provider = new Roo.state.Provider();
14836 * Configures the default state provider for your application
14837 * @param {Provider} stateProvider The state provider to set
14839 setProvider : function(stateProvider){
14840 provider = stateProvider;
14844 * Returns the current value for a key
14845 * @param {String} name The key name
14846 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14847 * @return {Mixed} The state data
14849 get : function(key, defaultValue){
14850 return provider.get(key, defaultValue);
14854 * Sets the value for a key
14855 * @param {String} name The key name
14856 * @param {Mixed} value The state data
14858 set : function(key, value){
14859 provider.set(key, value);
14863 * Clears a value from the state
14864 * @param {String} name The key name
14866 clear : function(key){
14867 provider.clear(key);
14871 * Gets the currently configured state provider
14872 * @return {Provider} The state provider
14874 getProvider : function(){
14881 * Ext JS Library 1.1.1
14882 * Copyright(c) 2006-2007, Ext JS, LLC.
14884 * Originally Released Under LGPL - original licence link has changed is not relivant.
14887 * <script type="text/javascript">
14890 * @class Roo.state.CookieProvider
14891 * @extends Roo.state.Provider
14892 * The default Provider implementation which saves state via cookies.
14895 var cp = new Roo.state.CookieProvider({
14897 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14898 domain: "roojs.com"
14900 Roo.state.Manager.setProvider(cp);
14902 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14903 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14904 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14905 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14906 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14907 * domain the page is running on including the 'www' like 'www.roojs.com')
14908 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14910 * Create a new CookieProvider
14911 * @param {Object} config The configuration object
14913 Roo.state.CookieProvider = function(config){
14914 Roo.state.CookieProvider.superclass.constructor.call(this);
14916 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14917 this.domain = null;
14918 this.secure = false;
14919 Roo.apply(this, config);
14920 this.state = this.readCookies();
14923 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14925 set : function(name, value){
14926 if(typeof value == "undefined" || value === null){
14930 this.setCookie(name, value);
14931 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14935 clear : function(name){
14936 this.clearCookie(name);
14937 Roo.state.CookieProvider.superclass.clear.call(this, name);
14941 readCookies : function(){
14943 var c = document.cookie + ";";
14944 var re = /\s?(.*?)=(.*?);/g;
14946 while((matches = re.exec(c)) != null){
14947 var name = matches[1];
14948 var value = matches[2];
14949 if(name && name.substring(0,3) == "ys-"){
14950 cookies[name.substr(3)] = this.decodeValue(value);
14957 setCookie : function(name, value){
14958 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14959 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14960 ((this.path == null) ? "" : ("; path=" + this.path)) +
14961 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14962 ((this.secure == true) ? "; secure" : "");
14966 clearCookie : function(name){
14967 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14968 ((this.path == null) ? "" : ("; path=" + this.path)) +
14969 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14970 ((this.secure == true) ? "; secure" : "");
14974 * Ext JS Library 1.1.1
14975 * Copyright(c) 2006-2007, Ext JS, LLC.
14977 * Originally Released Under LGPL - original licence link has changed is not relivant.
14980 * <script type="text/javascript">
14985 * @class Roo.ComponentMgr
14986 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14989 Roo.ComponentMgr = function(){
14990 var all = new Roo.util.MixedCollection();
14994 * Registers a component.
14995 * @param {Roo.Component} c The component
14997 register : function(c){
15002 * Unregisters a component.
15003 * @param {Roo.Component} c The component
15005 unregister : function(c){
15010 * Returns a component by id
15011 * @param {String} id The component id
15013 get : function(id){
15014 return all.get(id);
15018 * Registers a function that will be called when a specified component is added to ComponentMgr
15019 * @param {String} id The component id
15020 * @param {Funtction} fn The callback function
15021 * @param {Object} scope The scope of the callback
15023 onAvailable : function(id, fn, scope){
15024 all.on("add", function(index, o){
15026 fn.call(scope || o, o);
15027 all.un("add", fn, scope);
15034 * Ext JS Library 1.1.1
15035 * Copyright(c) 2006-2007, Ext JS, LLC.
15037 * Originally Released Under LGPL - original licence link has changed is not relivant.
15040 * <script type="text/javascript">
15044 * @class Roo.Component
15045 * @extends Roo.util.Observable
15046 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15047 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15048 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15049 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15050 * All visual components (widgets) that require rendering into a layout should subclass Component.
15052 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15053 * 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
15054 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15056 Roo.Component = function(config){
15057 config = config || {};
15058 if(config.tagName || config.dom || typeof config == "string"){ // element object
15059 config = {el: config, id: config.id || config};
15061 this.initialConfig = config;
15063 Roo.apply(this, config);
15067 * Fires after the component is disabled.
15068 * @param {Roo.Component} this
15073 * Fires after the component is enabled.
15074 * @param {Roo.Component} this
15078 * @event beforeshow
15079 * Fires before the component is shown. Return false to stop the show.
15080 * @param {Roo.Component} this
15085 * Fires after the component is shown.
15086 * @param {Roo.Component} this
15090 * @event beforehide
15091 * Fires before the component is hidden. Return false to stop the hide.
15092 * @param {Roo.Component} this
15097 * Fires after the component is hidden.
15098 * @param {Roo.Component} this
15102 * @event beforerender
15103 * Fires before the component is rendered. Return false to stop the render.
15104 * @param {Roo.Component} this
15106 beforerender : true,
15109 * Fires after the component is rendered.
15110 * @param {Roo.Component} this
15114 * @event beforedestroy
15115 * Fires before the component is destroyed. Return false to stop the destroy.
15116 * @param {Roo.Component} this
15118 beforedestroy : true,
15121 * Fires after the component is destroyed.
15122 * @param {Roo.Component} this
15127 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15129 Roo.ComponentMgr.register(this);
15130 Roo.Component.superclass.constructor.call(this);
15131 this.initComponent();
15132 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15133 this.render(this.renderTo);
15134 delete this.renderTo;
15139 Roo.Component.AUTO_ID = 1000;
15141 Roo.extend(Roo.Component, Roo.util.Observable, {
15143 * @scope Roo.Component.prototype
15145 * true if this component is hidden. Read-only.
15150 * true if this component is disabled. Read-only.
15155 * true if this component has been rendered. Read-only.
15159 /** @cfg {String} disableClass
15160 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15162 disabledClass : "x-item-disabled",
15163 /** @cfg {Boolean} allowDomMove
15164 * Whether the component can move the Dom node when rendering (defaults to true).
15166 allowDomMove : true,
15167 /** @cfg {String} hideMode
15168 * How this component should hidden. Supported values are
15169 * "visibility" (css visibility), "offsets" (negative offset position) and
15170 * "display" (css display) - defaults to "display".
15172 hideMode: 'display',
15175 ctype : "Roo.Component",
15178 * @cfg {String} actionMode
15179 * which property holds the element that used for hide() / show() / disable() / enable()
15185 getActionEl : function(){
15186 return this[this.actionMode];
15189 initComponent : Roo.emptyFn,
15191 * If this is a lazy rendering component, render it to its container element.
15192 * @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.
15194 render : function(container, position){
15195 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15196 if(!container && this.el){
15197 this.el = Roo.get(this.el);
15198 container = this.el.dom.parentNode;
15199 this.allowDomMove = false;
15201 this.container = Roo.get(container);
15202 this.rendered = true;
15203 if(position !== undefined){
15204 if(typeof position == 'number'){
15205 position = this.container.dom.childNodes[position];
15207 position = Roo.getDom(position);
15210 this.onRender(this.container, position || null);
15212 this.el.addClass(this.cls);
15216 this.el.applyStyles(this.style);
15219 this.fireEvent("render", this);
15220 this.afterRender(this.container);
15232 // default function is not really useful
15233 onRender : function(ct, position){
15235 this.el = Roo.get(this.el);
15236 if(this.allowDomMove !== false){
15237 ct.dom.insertBefore(this.el.dom, position);
15243 getAutoCreate : function(){
15244 var cfg = typeof this.autoCreate == "object" ?
15245 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15246 if(this.id && !cfg.id){
15253 afterRender : Roo.emptyFn,
15256 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15257 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15259 destroy : function(){
15260 if(this.fireEvent("beforedestroy", this) !== false){
15261 this.purgeListeners();
15262 this.beforeDestroy();
15264 this.el.removeAllListeners();
15266 if(this.actionMode == "container"){
15267 this.container.remove();
15271 Roo.ComponentMgr.unregister(this);
15272 this.fireEvent("destroy", this);
15277 beforeDestroy : function(){
15282 onDestroy : function(){
15287 * Returns the underlying {@link Roo.Element}.
15288 * @return {Roo.Element} The element
15290 getEl : function(){
15295 * Returns the id of this component.
15298 getId : function(){
15303 * Try to focus this component.
15304 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15305 * @return {Roo.Component} this
15307 focus : function(selectText){
15310 if(selectText === true){
15311 this.el.dom.select();
15326 * Disable this component.
15327 * @return {Roo.Component} this
15329 disable : function(){
15333 this.disabled = true;
15334 this.fireEvent("disable", this);
15339 onDisable : function(){
15340 this.getActionEl().addClass(this.disabledClass);
15341 this.el.dom.disabled = true;
15345 * Enable this component.
15346 * @return {Roo.Component} this
15348 enable : function(){
15352 this.disabled = false;
15353 this.fireEvent("enable", this);
15358 onEnable : function(){
15359 this.getActionEl().removeClass(this.disabledClass);
15360 this.el.dom.disabled = false;
15364 * Convenience function for setting disabled/enabled by boolean.
15365 * @param {Boolean} disabled
15367 setDisabled : function(disabled){
15368 this[disabled ? "disable" : "enable"]();
15372 * Show this component.
15373 * @return {Roo.Component} this
15376 if(this.fireEvent("beforeshow", this) !== false){
15377 this.hidden = false;
15381 this.fireEvent("show", this);
15387 onShow : function(){
15388 var ae = this.getActionEl();
15389 if(this.hideMode == 'visibility'){
15390 ae.dom.style.visibility = "visible";
15391 }else if(this.hideMode == 'offsets'){
15392 ae.removeClass('x-hidden');
15394 ae.dom.style.display = "";
15399 * Hide this component.
15400 * @return {Roo.Component} this
15403 if(this.fireEvent("beforehide", this) !== false){
15404 this.hidden = true;
15408 this.fireEvent("hide", this);
15414 onHide : function(){
15415 var ae = this.getActionEl();
15416 if(this.hideMode == 'visibility'){
15417 ae.dom.style.visibility = "hidden";
15418 }else if(this.hideMode == 'offsets'){
15419 ae.addClass('x-hidden');
15421 ae.dom.style.display = "none";
15426 * Convenience function to hide or show this component by boolean.
15427 * @param {Boolean} visible True to show, false to hide
15428 * @return {Roo.Component} this
15430 setVisible: function(visible){
15440 * Returns true if this component is visible.
15442 isVisible : function(){
15443 return this.getActionEl().isVisible();
15446 cloneConfig : function(overrides){
15447 overrides = overrides || {};
15448 var id = overrides.id || Roo.id();
15449 var cfg = Roo.applyIf(overrides, this.initialConfig);
15450 cfg.id = id; // prevent dup id
15451 return new this.constructor(cfg);
15455 * Ext JS Library 1.1.1
15456 * Copyright(c) 2006-2007, Ext JS, LLC.
15458 * Originally Released Under LGPL - original licence link has changed is not relivant.
15461 * <script type="text/javascript">
15465 * @class Roo.BoxComponent
15466 * @extends Roo.Component
15467 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15468 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15469 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15470 * layout containers.
15472 * @param {Roo.Element/String/Object} config The configuration options.
15474 Roo.BoxComponent = function(config){
15475 Roo.Component.call(this, config);
15479 * Fires after the component is resized.
15480 * @param {Roo.Component} this
15481 * @param {Number} adjWidth The box-adjusted width that was set
15482 * @param {Number} adjHeight The box-adjusted height that was set
15483 * @param {Number} rawWidth The width that was originally specified
15484 * @param {Number} rawHeight The height that was originally specified
15489 * Fires after the component is moved.
15490 * @param {Roo.Component} this
15491 * @param {Number} x The new x position
15492 * @param {Number} y The new y position
15498 Roo.extend(Roo.BoxComponent, Roo.Component, {
15499 // private, set in afterRender to signify that the component has been rendered
15501 // private, used to defer height settings to subclasses
15502 deferHeight: false,
15503 /** @cfg {Number} width
15504 * width (optional) size of component
15506 /** @cfg {Number} height
15507 * height (optional) size of component
15511 * Sets the width and height of the component. This method fires the resize event. This method can accept
15512 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15513 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15514 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15515 * @return {Roo.BoxComponent} this
15517 setSize : function(w, h){
15518 // support for standard size objects
15519 if(typeof w == 'object'){
15524 if(!this.boxReady){
15530 // prevent recalcs when not needed
15531 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15534 this.lastSize = {width: w, height: h};
15536 var adj = this.adjustSize(w, h);
15537 var aw = adj.width, ah = adj.height;
15538 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15539 var rz = this.getResizeEl();
15540 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15541 rz.setSize(aw, ah);
15542 }else if(!this.deferHeight && ah !== undefined){
15544 }else if(aw !== undefined){
15547 this.onResize(aw, ah, w, h);
15548 this.fireEvent('resize', this, aw, ah, w, h);
15554 * Gets the current size of the component's underlying element.
15555 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15557 getSize : function(){
15558 return this.el.getSize();
15562 * Gets the current XY position of the component's underlying element.
15563 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15564 * @return {Array} The XY position of the element (e.g., [100, 200])
15566 getPosition : function(local){
15567 if(local === true){
15568 return [this.el.getLeft(true), this.el.getTop(true)];
15570 return this.xy || this.el.getXY();
15574 * Gets the current box measurements of the component's underlying element.
15575 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15576 * @returns {Object} box An object in the format {x, y, width, height}
15578 getBox : function(local){
15579 var s = this.el.getSize();
15581 s.x = this.el.getLeft(true);
15582 s.y = this.el.getTop(true);
15584 var xy = this.xy || this.el.getXY();
15592 * Sets the current box measurements of the component's underlying element.
15593 * @param {Object} box An object in the format {x, y, width, height}
15594 * @returns {Roo.BoxComponent} this
15596 updateBox : function(box){
15597 this.setSize(box.width, box.height);
15598 this.setPagePosition(box.x, box.y);
15603 getResizeEl : function(){
15604 return this.resizeEl || this.el;
15608 getPositionEl : function(){
15609 return this.positionEl || this.el;
15613 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15614 * This method fires the move event.
15615 * @param {Number} left The new left
15616 * @param {Number} top The new top
15617 * @returns {Roo.BoxComponent} this
15619 setPosition : function(x, y){
15622 if(!this.boxReady){
15625 var adj = this.adjustPosition(x, y);
15626 var ax = adj.x, ay = adj.y;
15628 var el = this.getPositionEl();
15629 if(ax !== undefined || ay !== undefined){
15630 if(ax !== undefined && ay !== undefined){
15631 el.setLeftTop(ax, ay);
15632 }else if(ax !== undefined){
15634 }else if(ay !== undefined){
15637 this.onPosition(ax, ay);
15638 this.fireEvent('move', this, ax, ay);
15644 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15645 * This method fires the move event.
15646 * @param {Number} x The new x position
15647 * @param {Number} y The new y position
15648 * @returns {Roo.BoxComponent} this
15650 setPagePosition : function(x, y){
15653 if(!this.boxReady){
15656 if(x === undefined || y === undefined){ // cannot translate undefined points
15659 var p = this.el.translatePoints(x, y);
15660 this.setPosition(p.left, p.top);
15665 onRender : function(ct, position){
15666 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15668 this.resizeEl = Roo.get(this.resizeEl);
15670 if(this.positionEl){
15671 this.positionEl = Roo.get(this.positionEl);
15676 afterRender : function(){
15677 Roo.BoxComponent.superclass.afterRender.call(this);
15678 this.boxReady = true;
15679 this.setSize(this.width, this.height);
15680 if(this.x || this.y){
15681 this.setPosition(this.x, this.y);
15683 if(this.pageX || this.pageY){
15684 this.setPagePosition(this.pageX, this.pageY);
15689 * Force the component's size to recalculate based on the underlying element's current height and width.
15690 * @returns {Roo.BoxComponent} this
15692 syncSize : function(){
15693 delete this.lastSize;
15694 this.setSize(this.el.getWidth(), this.el.getHeight());
15699 * Called after the component is resized, this method is empty by default but can be implemented by any
15700 * subclass that needs to perform custom logic after a resize occurs.
15701 * @param {Number} adjWidth The box-adjusted width that was set
15702 * @param {Number} adjHeight The box-adjusted height that was set
15703 * @param {Number} rawWidth The width that was originally specified
15704 * @param {Number} rawHeight The height that was originally specified
15706 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15711 * Called after the component is moved, this method is empty by default but can be implemented by any
15712 * subclass that needs to perform custom logic after a move occurs.
15713 * @param {Number} x The new x position
15714 * @param {Number} y The new y position
15716 onPosition : function(x, y){
15721 adjustSize : function(w, h){
15722 if(this.autoWidth){
15725 if(this.autoHeight){
15728 return {width : w, height: h};
15732 adjustPosition : function(x, y){
15733 return {x : x, y: y};
15736 * Original code for Roojs - LGPL
15737 * <script type="text/javascript">
15741 * @class Roo.XComponent
15742 * A delayed Element creator...
15743 * Or a way to group chunks of interface together.
15744 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15745 * used in conjunction with XComponent.build() it will create an instance of each element,
15746 * then call addxtype() to build the User interface.
15748 * Mypart.xyx = new Roo.XComponent({
15750 parent : 'Mypart.xyz', // empty == document.element.!!
15754 disabled : function() {}
15756 tree : function() { // return an tree of xtype declared components
15760 xtype : 'NestedLayoutPanel',
15767 * It can be used to build a big heiracy, with parent etc.
15768 * or you can just use this to render a single compoent to a dom element
15769 * MYPART.render(Roo.Element | String(id) | dom_element )
15776 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15777 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15779 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15781 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15782 * - if mulitple topModules exist, the last one is defined as the top module.
15786 * When the top level or multiple modules are to embedded into a existing HTML page,
15787 * the parent element can container '#id' of the element where the module will be drawn.
15791 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15792 * it relies more on a include mechanism, where sub modules are included into an outer page.
15793 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15795 * Bootstrap Roo Included elements
15797 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15798 * hence confusing the component builder as it thinks there are multiple top level elements.
15802 * @extends Roo.util.Observable
15804 * @param cfg {Object} configuration of component
15807 Roo.XComponent = function(cfg) {
15808 Roo.apply(this, cfg);
15812 * Fires when this the componnt is built
15813 * @param {Roo.XComponent} c the component
15818 this.region = this.region || 'center'; // default..
15819 Roo.XComponent.register(this);
15820 this.modules = false;
15821 this.el = false; // where the layout goes..
15825 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15828 * The created element (with Roo.factory())
15829 * @type {Roo.Layout}
15835 * for BC - use el in new code
15836 * @type {Roo.Layout}
15842 * for BC - use el in new code
15843 * @type {Roo.Layout}
15848 * @cfg {Function|boolean} disabled
15849 * If this module is disabled by some rule, return true from the funtion
15854 * @cfg {String} parent
15855 * Name of parent element which it get xtype added to..
15860 * @cfg {String} order
15861 * Used to set the order in which elements are created (usefull for multiple tabs)
15866 * @cfg {String} name
15867 * String to display while loading.
15871 * @cfg {String} region
15872 * Region to render component to (defaults to center)
15877 * @cfg {Array} items
15878 * A single item array - the first element is the root of the tree..
15879 * It's done this way to stay compatible with the Xtype system...
15885 * The method that retuns the tree of parts that make up this compoennt
15892 * render element to dom or tree
15893 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15896 render : function(el)
15900 var hp = this.parent ? 1 : 0;
15903 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15904 // if parent is a '#.....' string, then let's use that..
15905 var ename = this.parent.substr(1);
15906 this.parent = false;
15909 case 'bootstrap-body' :
15910 if (typeof(Roo.bootstrap.Body) != 'undefined') {
15911 this.parent = { el : new Roo.bootstrap.Body() };
15912 Roo.log("setting el to doc body");
15915 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15919 this.parent = { el : true};
15922 el = Roo.get(ename);
15927 if (!el && !this.parent) {
15928 Roo.log("Warning - element can not be found :#" + ename );
15932 Roo.log("EL:");Roo.log(el);
15933 Roo.log("this.parent.el:");Roo.log(this.parent.el);
15935 var tree = this._tree ? this._tree() : this.tree();
15937 // altertive root elements ??? - we need a better way to indicate these.
15938 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15939 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15941 if (!this.parent && is_alt) {
15942 //el = Roo.get(document.body);
15943 this.parent = { el : true };
15948 if (!this.parent) {
15950 Roo.log("no parent - creating one");
15952 el = el ? Roo.get(el) : false;
15954 // it's a top level one..
15956 el : new Roo.BorderLayout(el || document.body, {
15962 tabPosition: 'top',
15963 //resizeTabs: true,
15964 alwaysShowTabs: el && hp? false : true,
15965 hideTabs: el || !hp ? true : false,
15972 if (!this.parent.el) {
15973 // probably an old style ctor, which has been disabled.
15977 // The 'tree' method is '_tree now'
15979 tree.region = tree.region || this.region;
15981 if (this.parent.el === true) {
15982 // bootstrap... - body..
15983 this.parent.el = Roo.factory(tree);
15986 this.el = this.parent.el.addxtype(tree);
15987 this.fireEvent('built', this);
15989 this.panel = this.el;
15990 this.layout = this.panel.layout;
15991 this.parentLayout = this.parent.layout || false;
15997 Roo.apply(Roo.XComponent, {
15999 * @property hideProgress
16000 * true to disable the building progress bar.. usefull on single page renders.
16003 hideProgress : false,
16005 * @property buildCompleted
16006 * True when the builder has completed building the interface.
16009 buildCompleted : false,
16012 * @property topModule
16013 * the upper most module - uses document.element as it's constructor.
16020 * @property modules
16021 * array of modules to be created by registration system.
16022 * @type {Array} of Roo.XComponent
16027 * @property elmodules
16028 * array of modules to be created by which use #ID
16029 * @type {Array} of Roo.XComponent
16035 * @property build_from_html
16036 * Build elements from html - used by bootstrap HTML stuff
16037 * - this is cleared after build is completed
16038 * @type {boolean} true (default false)
16041 build_from_html : false,
16044 * Register components to be built later.
16046 * This solves the following issues
16047 * - Building is not done on page load, but after an authentication process has occured.
16048 * - Interface elements are registered on page load
16049 * - Parent Interface elements may not be loaded before child, so this handles that..
16056 module : 'Pman.Tab.projectMgr',
16058 parent : 'Pman.layout',
16059 disabled : false, // or use a function..
16062 * * @param {Object} details about module
16064 register : function(obj) {
16066 Roo.XComponent.event.fireEvent('register', obj);
16067 switch(typeof(obj.disabled) ) {
16073 if ( obj.disabled() ) {
16079 if (obj.disabled) {
16085 this.modules.push(obj);
16089 * convert a string to an object..
16090 * eg. 'AAA.BBB' -> finds AAA.BBB
16094 toObject : function(str)
16096 if (!str || typeof(str) == 'object') {
16099 if (str.substring(0,1) == '#') {
16103 var ar = str.split('.');
16108 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16110 throw "Module not found : " + str;
16114 throw "Module not found : " + str;
16116 Roo.each(ar, function(e) {
16117 if (typeof(o[e]) == 'undefined') {
16118 throw "Module not found : " + str;
16129 * move modules into their correct place in the tree..
16132 preBuild : function ()
16135 Roo.each(this.modules , function (obj)
16137 Roo.XComponent.event.fireEvent('beforebuild', obj);
16139 var opar = obj.parent;
16141 obj.parent = this.toObject(opar);
16143 Roo.log("parent:toObject failed: " + e.toString());
16148 Roo.debug && Roo.log("GOT top level module");
16149 Roo.debug && Roo.log(obj);
16150 obj.modules = new Roo.util.MixedCollection(false,
16151 function(o) { return o.order + '' }
16153 this.topModule = obj;
16156 // parent is a string (usually a dom element name..)
16157 if (typeof(obj.parent) == 'string') {
16158 this.elmodules.push(obj);
16161 if (obj.parent.constructor != Roo.XComponent) {
16162 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16164 if (!obj.parent.modules) {
16165 obj.parent.modules = new Roo.util.MixedCollection(false,
16166 function(o) { return o.order + '' }
16169 if (obj.parent.disabled) {
16170 obj.disabled = true;
16172 obj.parent.modules.add(obj);
16177 * make a list of modules to build.
16178 * @return {Array} list of modules.
16181 buildOrder : function()
16184 var cmp = function(a,b) {
16185 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16187 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16188 throw "No top level modules to build";
16191 // make a flat list in order of modules to build.
16192 var mods = this.topModule ? [ this.topModule ] : [];
16195 // elmodules (is a list of DOM based modules )
16196 Roo.each(this.elmodules, function(e) {
16198 if (!this.topModule &&
16199 typeof(e.parent) == 'string' &&
16200 e.parent.substring(0,1) == '#' &&
16201 Roo.get(e.parent.substr(1))
16204 _this.topModule = e;
16210 // add modules to their parents..
16211 var addMod = function(m) {
16212 Roo.debug && Roo.log("build Order: add: " + m.name);
16215 if (m.modules && !m.disabled) {
16216 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16217 m.modules.keySort('ASC', cmp );
16218 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16220 m.modules.each(addMod);
16222 Roo.debug && Roo.log("build Order: no child modules");
16224 // not sure if this is used any more..
16226 m.finalize.name = m.name + " (clean up) ";
16227 mods.push(m.finalize);
16231 if (this.topModule && this.topModule.modules) {
16232 this.topModule.modules.keySort('ASC', cmp );
16233 this.topModule.modules.each(addMod);
16239 * Build the registered modules.
16240 * @param {Object} parent element.
16241 * @param {Function} optional method to call after module has been added.
16245 build : function(opts)
16248 if (typeof(opts) != 'undefined') {
16249 Roo.apply(this,opts);
16253 var mods = this.buildOrder();
16255 //this.allmods = mods;
16256 //Roo.debug && Roo.log(mods);
16258 if (!mods.length) { // should not happen
16259 throw "NO modules!!!";
16263 var msg = "Building Interface...";
16264 // flash it up as modal - so we store the mask!?
16265 if (!this.hideProgress && Roo.MessageBox) {
16266 Roo.MessageBox.show({ title: 'loading' });
16267 Roo.MessageBox.show({
16268 title: "Please wait...",
16277 var total = mods.length;
16280 var progressRun = function() {
16281 if (!mods.length) {
16282 Roo.debug && Roo.log('hide?');
16283 if (!this.hideProgress && Roo.MessageBox) {
16284 Roo.MessageBox.hide();
16286 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16288 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16294 var m = mods.shift();
16297 Roo.debug && Roo.log(m);
16298 // not sure if this is supported any more.. - modules that are are just function
16299 if (typeof(m) == 'function') {
16301 return progressRun.defer(10, _this);
16305 msg = "Building Interface " + (total - mods.length) +
16307 (m.name ? (' - ' + m.name) : '');
16308 Roo.debug && Roo.log(msg);
16309 if (!this.hideProgress && Roo.MessageBox) {
16310 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16314 // is the module disabled?
16315 var disabled = (typeof(m.disabled) == 'function') ?
16316 m.disabled.call(m.module.disabled) : m.disabled;
16320 return progressRun(); // we do not update the display!
16328 // it's 10 on top level, and 1 on others??? why...
16329 return progressRun.defer(10, _this);
16332 progressRun.defer(1, _this);
16346 * wrapper for event.on - aliased later..
16347 * Typically use to register a event handler for register:
16349 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16358 Roo.XComponent.event = new Roo.util.Observable({
16362 * Fires when an Component is registered,
16363 * set the disable property on the Component to stop registration.
16364 * @param {Roo.XComponent} c the component being registerd.
16369 * @event beforebuild
16370 * Fires before each Component is built
16371 * can be used to apply permissions.
16372 * @param {Roo.XComponent} c the component being registerd.
16375 'beforebuild' : true,
16377 * @event buildcomplete
16378 * Fires on the top level element when all elements have been built
16379 * @param {Roo.XComponent} the top level component.
16381 'buildcomplete' : true
16386 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16389 * Ext JS Library 1.1.1
16390 * Copyright(c) 2006-2007, Ext JS, LLC.
16392 * Originally Released Under LGPL - original licence link has changed is not relivant.
16395 * <script type="text/javascript">
16401 * These classes are derivatives of the similarly named classes in the YUI Library.
16402 * The original license:
16403 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16404 * Code licensed under the BSD License:
16405 * http://developer.yahoo.net/yui/license.txt
16410 var Event=Roo.EventManager;
16411 var Dom=Roo.lib.Dom;
16414 * @class Roo.dd.DragDrop
16415 * @extends Roo.util.Observable
16416 * Defines the interface and base operation of items that that can be
16417 * dragged or can be drop targets. It was designed to be extended, overriding
16418 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16419 * Up to three html elements can be associated with a DragDrop instance:
16421 * <li>linked element: the element that is passed into the constructor.
16422 * This is the element which defines the boundaries for interaction with
16423 * other DragDrop objects.</li>
16424 * <li>handle element(s): The drag operation only occurs if the element that
16425 * was clicked matches a handle element. By default this is the linked
16426 * element, but there are times that you will want only a portion of the
16427 * linked element to initiate the drag operation, and the setHandleElId()
16428 * method provides a way to define this.</li>
16429 * <li>drag element: this represents the element that would be moved along
16430 * with the cursor during a drag operation. By default, this is the linked
16431 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16432 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16435 * This class should not be instantiated until the onload event to ensure that
16436 * the associated elements are available.
16437 * The following would define a DragDrop obj that would interact with any
16438 * other DragDrop obj in the "group1" group:
16440 * dd = new Roo.dd.DragDrop("div1", "group1");
16442 * Since none of the event handlers have been implemented, nothing would
16443 * actually happen if you were to run the code above. Normally you would
16444 * override this class or one of the default implementations, but you can
16445 * also override the methods you want on an instance of the class...
16447 * dd.onDragDrop = function(e, id) {
16448 * alert("dd was dropped on " + id);
16452 * @param {String} id of the element that is linked to this instance
16453 * @param {String} sGroup the group of related DragDrop objects
16454 * @param {object} config an object containing configurable attributes
16455 * Valid properties for DragDrop:
16456 * padding, isTarget, maintainOffset, primaryButtonOnly
16458 Roo.dd.DragDrop = function(id, sGroup, config) {
16460 this.init(id, sGroup, config);
16465 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16468 * The id of the element associated with this object. This is what we
16469 * refer to as the "linked element" because the size and position of
16470 * this element is used to determine when the drag and drop objects have
16478 * Configuration attributes passed into the constructor
16485 * The id of the element that will be dragged. By default this is same
16486 * as the linked element , but could be changed to another element. Ex:
16488 * @property dragElId
16495 * the id of the element that initiates the drag operation. By default
16496 * this is the linked element, but could be changed to be a child of this
16497 * element. This lets us do things like only starting the drag when the
16498 * header element within the linked html element is clicked.
16499 * @property handleElId
16506 * An associative array of HTML tags that will be ignored if clicked.
16507 * @property invalidHandleTypes
16508 * @type {string: string}
16510 invalidHandleTypes: null,
16513 * An associative array of ids for elements that will be ignored if clicked
16514 * @property invalidHandleIds
16515 * @type {string: string}
16517 invalidHandleIds: null,
16520 * An indexted array of css class names for elements that will be ignored
16522 * @property invalidHandleClasses
16525 invalidHandleClasses: null,
16528 * The linked element's absolute X position at the time the drag was
16530 * @property startPageX
16537 * The linked element's absolute X position at the time the drag was
16539 * @property startPageY
16546 * The group defines a logical collection of DragDrop objects that are
16547 * related. Instances only get events when interacting with other
16548 * DragDrop object in the same group. This lets us define multiple
16549 * groups using a single DragDrop subclass if we want.
16551 * @type {string: string}
16556 * Individual drag/drop instances can be locked. This will prevent
16557 * onmousedown start drag.
16565 * Lock this instance
16568 lock: function() { this.locked = true; },
16571 * Unlock this instace
16574 unlock: function() { this.locked = false; },
16577 * By default, all insances can be a drop target. This can be disabled by
16578 * setting isTarget to false.
16585 * The padding configured for this drag and drop object for calculating
16586 * the drop zone intersection with this object.
16593 * Cached reference to the linked element
16594 * @property _domRef
16600 * Internal typeof flag
16601 * @property __ygDragDrop
16604 __ygDragDrop: true,
16607 * Set to true when horizontal contraints are applied
16608 * @property constrainX
16615 * Set to true when vertical contraints are applied
16616 * @property constrainY
16623 * The left constraint
16631 * The right constraint
16639 * The up constraint
16648 * The down constraint
16656 * Maintain offsets when we resetconstraints. Set to true when you want
16657 * the position of the element relative to its parent to stay the same
16658 * when the page changes
16660 * @property maintainOffset
16663 maintainOffset: false,
16666 * Array of pixel locations the element will snap to if we specified a
16667 * horizontal graduation/interval. This array is generated automatically
16668 * when you define a tick interval.
16675 * Array of pixel locations the element will snap to if we specified a
16676 * vertical graduation/interval. This array is generated automatically
16677 * when you define a tick interval.
16684 * By default the drag and drop instance will only respond to the primary
16685 * button click (left button for a right-handed mouse). Set to true to
16686 * allow drag and drop to start with any mouse click that is propogated
16688 * @property primaryButtonOnly
16691 primaryButtonOnly: true,
16694 * The availabe property is false until the linked dom element is accessible.
16695 * @property available
16701 * By default, drags can only be initiated if the mousedown occurs in the
16702 * region the linked element is. This is done in part to work around a
16703 * bug in some browsers that mis-report the mousedown if the previous
16704 * mouseup happened outside of the window. This property is set to true
16705 * if outer handles are defined.
16707 * @property hasOuterHandles
16711 hasOuterHandles: false,
16714 * Code that executes immediately before the startDrag event
16715 * @method b4StartDrag
16718 b4StartDrag: function(x, y) { },
16721 * Abstract method called after a drag/drop object is clicked
16722 * and the drag or mousedown time thresholds have beeen met.
16723 * @method startDrag
16724 * @param {int} X click location
16725 * @param {int} Y click location
16727 startDrag: function(x, y) { /* override this */ },
16730 * Code that executes immediately before the onDrag event
16734 b4Drag: function(e) { },
16737 * Abstract method called during the onMouseMove event while dragging an
16740 * @param {Event} e the mousemove event
16742 onDrag: function(e) { /* override this */ },
16745 * Abstract method called when this element fist begins hovering over
16746 * another DragDrop obj
16747 * @method onDragEnter
16748 * @param {Event} e the mousemove event
16749 * @param {String|DragDrop[]} id In POINT mode, the element
16750 * id this is hovering over. In INTERSECT mode, an array of one or more
16751 * dragdrop items being hovered over.
16753 onDragEnter: function(e, id) { /* override this */ },
16756 * Code that executes immediately before the onDragOver event
16757 * @method b4DragOver
16760 b4DragOver: function(e) { },
16763 * Abstract method called when this element is hovering over another
16765 * @method onDragOver
16766 * @param {Event} e the mousemove event
16767 * @param {String|DragDrop[]} id In POINT mode, the element
16768 * id this is hovering over. In INTERSECT mode, an array of dd items
16769 * being hovered over.
16771 onDragOver: function(e, id) { /* override this */ },
16774 * Code that executes immediately before the onDragOut event
16775 * @method b4DragOut
16778 b4DragOut: function(e) { },
16781 * Abstract method called when we are no longer hovering over an element
16782 * @method onDragOut
16783 * @param {Event} e the mousemove event
16784 * @param {String|DragDrop[]} id In POINT mode, the element
16785 * id this was hovering over. In INTERSECT mode, an array of dd items
16786 * that the mouse is no longer over.
16788 onDragOut: function(e, id) { /* override this */ },
16791 * Code that executes immediately before the onDragDrop event
16792 * @method b4DragDrop
16795 b4DragDrop: function(e) { },
16798 * Abstract method called when this item is dropped on another DragDrop
16800 * @method onDragDrop
16801 * @param {Event} e the mouseup event
16802 * @param {String|DragDrop[]} id In POINT mode, the element
16803 * id this was dropped on. In INTERSECT mode, an array of dd items this
16806 onDragDrop: function(e, id) { /* override this */ },
16809 * Abstract method called when this item is dropped on an area with no
16811 * @method onInvalidDrop
16812 * @param {Event} e the mouseup event
16814 onInvalidDrop: function(e) { /* override this */ },
16817 * Code that executes immediately before the endDrag event
16818 * @method b4EndDrag
16821 b4EndDrag: function(e) { },
16824 * Fired when we are done dragging the object
16826 * @param {Event} e the mouseup event
16828 endDrag: function(e) { /* override this */ },
16831 * Code executed immediately before the onMouseDown event
16832 * @method b4MouseDown
16833 * @param {Event} e the mousedown event
16836 b4MouseDown: function(e) { },
16839 * Event handler that fires when a drag/drop obj gets a mousedown
16840 * @method onMouseDown
16841 * @param {Event} e the mousedown event
16843 onMouseDown: function(e) { /* override this */ },
16846 * Event handler that fires when a drag/drop obj gets a mouseup
16847 * @method onMouseUp
16848 * @param {Event} e the mouseup event
16850 onMouseUp: function(e) { /* override this */ },
16853 * Override the onAvailable method to do what is needed after the initial
16854 * position was determined.
16855 * @method onAvailable
16857 onAvailable: function () {
16861 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16864 defaultPadding : {left:0, right:0, top:0, bottom:0},
16867 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16871 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16872 { dragElId: "existingProxyDiv" });
16873 dd.startDrag = function(){
16874 this.constrainTo("parent-id");
16877 * Or you can initalize it using the {@link Roo.Element} object:
16879 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16880 startDrag : function(){
16881 this.constrainTo("parent-id");
16885 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16886 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16887 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16888 * an object containing the sides to pad. For example: {right:10, bottom:10}
16889 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16891 constrainTo : function(constrainTo, pad, inContent){
16892 if(typeof pad == "number"){
16893 pad = {left: pad, right:pad, top:pad, bottom:pad};
16895 pad = pad || this.defaultPadding;
16896 var b = Roo.get(this.getEl()).getBox();
16897 var ce = Roo.get(constrainTo);
16898 var s = ce.getScroll();
16899 var c, cd = ce.dom;
16900 if(cd == document.body){
16901 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16904 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16908 var topSpace = b.y - c.y;
16909 var leftSpace = b.x - c.x;
16911 this.resetConstraints();
16912 this.setXConstraint(leftSpace - (pad.left||0), // left
16913 c.width - leftSpace - b.width - (pad.right||0) //right
16915 this.setYConstraint(topSpace - (pad.top||0), //top
16916 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16921 * Returns a reference to the linked element
16923 * @return {HTMLElement} the html element
16925 getEl: function() {
16926 if (!this._domRef) {
16927 this._domRef = Roo.getDom(this.id);
16930 return this._domRef;
16934 * Returns a reference to the actual element to drag. By default this is
16935 * the same as the html element, but it can be assigned to another
16936 * element. An example of this can be found in Roo.dd.DDProxy
16937 * @method getDragEl
16938 * @return {HTMLElement} the html element
16940 getDragEl: function() {
16941 return Roo.getDom(this.dragElId);
16945 * Sets up the DragDrop object. Must be called in the constructor of any
16946 * Roo.dd.DragDrop subclass
16948 * @param id the id of the linked element
16949 * @param {String} sGroup the group of related items
16950 * @param {object} config configuration attributes
16952 init: function(id, sGroup, config) {
16953 this.initTarget(id, sGroup, config);
16954 if (!Roo.isTouch) {
16955 Event.on(this.id, "mousedown", this.handleMouseDown, this);
16957 Event.on(this.id, "touchstart", this.handleMouseDown, this);
16958 // Event.on(this.id, "selectstart", Event.preventDefault);
16962 * Initializes Targeting functionality only... the object does not
16963 * get a mousedown handler.
16964 * @method initTarget
16965 * @param id the id of the linked element
16966 * @param {String} sGroup the group of related items
16967 * @param {object} config configuration attributes
16969 initTarget: function(id, sGroup, config) {
16971 // configuration attributes
16972 this.config = config || {};
16974 // create a local reference to the drag and drop manager
16975 this.DDM = Roo.dd.DDM;
16976 // initialize the groups array
16979 // assume that we have an element reference instead of an id if the
16980 // parameter is not a string
16981 if (typeof id !== "string") {
16988 // add to an interaction group
16989 this.addToGroup((sGroup) ? sGroup : "default");
16991 // We don't want to register this as the handle with the manager
16992 // so we just set the id rather than calling the setter.
16993 this.handleElId = id;
16995 // the linked element is the element that gets dragged by default
16996 this.setDragElId(id);
16998 // by default, clicked anchors will not start drag operations.
16999 this.invalidHandleTypes = { A: "A" };
17000 this.invalidHandleIds = {};
17001 this.invalidHandleClasses = [];
17003 this.applyConfig();
17005 this.handleOnAvailable();
17009 * Applies the configuration parameters that were passed into the constructor.
17010 * This is supposed to happen at each level through the inheritance chain. So
17011 * a DDProxy implentation will execute apply config on DDProxy, DD, and
17012 * DragDrop in order to get all of the parameters that are available in
17014 * @method applyConfig
17016 applyConfig: function() {
17018 // configurable properties:
17019 // padding, isTarget, maintainOffset, primaryButtonOnly
17020 this.padding = this.config.padding || [0, 0, 0, 0];
17021 this.isTarget = (this.config.isTarget !== false);
17022 this.maintainOffset = (this.config.maintainOffset);
17023 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
17028 * Executed when the linked element is available
17029 * @method handleOnAvailable
17032 handleOnAvailable: function() {
17033 this.available = true;
17034 this.resetConstraints();
17035 this.onAvailable();
17039 * Configures the padding for the target zone in px. Effectively expands
17040 * (or reduces) the virtual object size for targeting calculations.
17041 * Supports css-style shorthand; if only one parameter is passed, all sides
17042 * will have that padding, and if only two are passed, the top and bottom
17043 * will have the first param, the left and right the second.
17044 * @method setPadding
17045 * @param {int} iTop Top pad
17046 * @param {int} iRight Right pad
17047 * @param {int} iBot Bot pad
17048 * @param {int} iLeft Left pad
17050 setPadding: function(iTop, iRight, iBot, iLeft) {
17051 // this.padding = [iLeft, iRight, iTop, iBot];
17052 if (!iRight && 0 !== iRight) {
17053 this.padding = [iTop, iTop, iTop, iTop];
17054 } else if (!iBot && 0 !== iBot) {
17055 this.padding = [iTop, iRight, iTop, iRight];
17057 this.padding = [iTop, iRight, iBot, iLeft];
17062 * Stores the initial placement of the linked element.
17063 * @method setInitialPosition
17064 * @param {int} diffX the X offset, default 0
17065 * @param {int} diffY the Y offset, default 0
17067 setInitPosition: function(diffX, diffY) {
17068 var el = this.getEl();
17070 if (!this.DDM.verifyEl(el)) {
17074 var dx = diffX || 0;
17075 var dy = diffY || 0;
17077 var p = Dom.getXY( el );
17079 this.initPageX = p[0] - dx;
17080 this.initPageY = p[1] - dy;
17082 this.lastPageX = p[0];
17083 this.lastPageY = p[1];
17086 this.setStartPosition(p);
17090 * Sets the start position of the element. This is set when the obj
17091 * is initialized, the reset when a drag is started.
17092 * @method setStartPosition
17093 * @param pos current position (from previous lookup)
17096 setStartPosition: function(pos) {
17097 var p = pos || Dom.getXY( this.getEl() );
17098 this.deltaSetXY = null;
17100 this.startPageX = p[0];
17101 this.startPageY = p[1];
17105 * Add this instance to a group of related drag/drop objects. All
17106 * instances belong to at least one group, and can belong to as many
17107 * groups as needed.
17108 * @method addToGroup
17109 * @param sGroup {string} the name of the group
17111 addToGroup: function(sGroup) {
17112 this.groups[sGroup] = true;
17113 this.DDM.regDragDrop(this, sGroup);
17117 * Remove's this instance from the supplied interaction group
17118 * @method removeFromGroup
17119 * @param {string} sGroup The group to drop
17121 removeFromGroup: function(sGroup) {
17122 if (this.groups[sGroup]) {
17123 delete this.groups[sGroup];
17126 this.DDM.removeDDFromGroup(this, sGroup);
17130 * Allows you to specify that an element other than the linked element
17131 * will be moved with the cursor during a drag
17132 * @method setDragElId
17133 * @param id {string} the id of the element that will be used to initiate the drag
17135 setDragElId: function(id) {
17136 this.dragElId = id;
17140 * Allows you to specify a child of the linked element that should be
17141 * used to initiate the drag operation. An example of this would be if
17142 * you have a content div with text and links. Clicking anywhere in the
17143 * content area would normally start the drag operation. Use this method
17144 * to specify that an element inside of the content div is the element
17145 * that starts the drag operation.
17146 * @method setHandleElId
17147 * @param id {string} the id of the element that will be used to
17148 * initiate the drag.
17150 setHandleElId: function(id) {
17151 if (typeof id !== "string") {
17154 this.handleElId = id;
17155 this.DDM.regHandle(this.id, id);
17159 * Allows you to set an element outside of the linked element as a drag
17161 * @method setOuterHandleElId
17162 * @param id the id of the element that will be used to initiate the drag
17164 setOuterHandleElId: function(id) {
17165 if (typeof id !== "string") {
17168 Event.on(id, "mousedown",
17169 this.handleMouseDown, this);
17170 this.setHandleElId(id);
17172 this.hasOuterHandles = true;
17176 * Remove all drag and drop hooks for this element
17179 unreg: function() {
17180 Event.un(this.id, "mousedown",
17181 this.handleMouseDown);
17182 Event.un(this.id, "touchstart",
17183 this.handleMouseDown);
17184 this._domRef = null;
17185 this.DDM._remove(this);
17188 destroy : function(){
17193 * Returns true if this instance is locked, or the drag drop mgr is locked
17194 * (meaning that all drag/drop is disabled on the page.)
17196 * @return {boolean} true if this obj or all drag/drop is locked, else
17199 isLocked: function() {
17200 return (this.DDM.isLocked() || this.locked);
17204 * Fired when this object is clicked
17205 * @method handleMouseDown
17207 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17210 handleMouseDown: function(e, oDD){
17212 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17213 //Roo.log('not touch/ button !=0');
17216 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17217 return; // double touch..
17221 if (this.isLocked()) {
17222 //Roo.log('locked');
17226 this.DDM.refreshCache(this.groups);
17227 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17228 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17229 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17230 //Roo.log('no outer handes or not over target');
17233 // Roo.log('check validator');
17234 if (this.clickValidator(e)) {
17235 // Roo.log('validate success');
17236 // set the initial element position
17237 this.setStartPosition();
17240 this.b4MouseDown(e);
17241 this.onMouseDown(e);
17243 this.DDM.handleMouseDown(e, this);
17245 this.DDM.stopEvent(e);
17253 clickValidator: function(e) {
17254 var target = e.getTarget();
17255 return ( this.isValidHandleChild(target) &&
17256 (this.id == this.handleElId ||
17257 this.DDM.handleWasClicked(target, this.id)) );
17261 * Allows you to specify a tag name that should not start a drag operation
17262 * when clicked. This is designed to facilitate embedding links within a
17263 * drag handle that do something other than start the drag.
17264 * @method addInvalidHandleType
17265 * @param {string} tagName the type of element to exclude
17267 addInvalidHandleType: function(tagName) {
17268 var type = tagName.toUpperCase();
17269 this.invalidHandleTypes[type] = type;
17273 * Lets you to specify an element id for a child of a drag handle
17274 * that should not initiate a drag
17275 * @method addInvalidHandleId
17276 * @param {string} id the element id of the element you wish to ignore
17278 addInvalidHandleId: function(id) {
17279 if (typeof id !== "string") {
17282 this.invalidHandleIds[id] = id;
17286 * Lets you specify a css class of elements that will not initiate a drag
17287 * @method addInvalidHandleClass
17288 * @param {string} cssClass the class of the elements you wish to ignore
17290 addInvalidHandleClass: function(cssClass) {
17291 this.invalidHandleClasses.push(cssClass);
17295 * Unsets an excluded tag name set by addInvalidHandleType
17296 * @method removeInvalidHandleType
17297 * @param {string} tagName the type of element to unexclude
17299 removeInvalidHandleType: function(tagName) {
17300 var type = tagName.toUpperCase();
17301 // this.invalidHandleTypes[type] = null;
17302 delete this.invalidHandleTypes[type];
17306 * Unsets an invalid handle id
17307 * @method removeInvalidHandleId
17308 * @param {string} id the id of the element to re-enable
17310 removeInvalidHandleId: function(id) {
17311 if (typeof id !== "string") {
17314 delete this.invalidHandleIds[id];
17318 * Unsets an invalid css class
17319 * @method removeInvalidHandleClass
17320 * @param {string} cssClass the class of the element(s) you wish to
17323 removeInvalidHandleClass: function(cssClass) {
17324 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17325 if (this.invalidHandleClasses[i] == cssClass) {
17326 delete this.invalidHandleClasses[i];
17332 * Checks the tag exclusion list to see if this click should be ignored
17333 * @method isValidHandleChild
17334 * @param {HTMLElement} node the HTMLElement to evaluate
17335 * @return {boolean} true if this is a valid tag type, false if not
17337 isValidHandleChild: function(node) {
17340 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17343 nodeName = node.nodeName.toUpperCase();
17345 nodeName = node.nodeName;
17347 valid = valid && !this.invalidHandleTypes[nodeName];
17348 valid = valid && !this.invalidHandleIds[node.id];
17350 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17351 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17360 * Create the array of horizontal tick marks if an interval was specified
17361 * in setXConstraint().
17362 * @method setXTicks
17365 setXTicks: function(iStartX, iTickSize) {
17367 this.xTickSize = iTickSize;
17371 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17373 this.xTicks[this.xTicks.length] = i;
17378 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17380 this.xTicks[this.xTicks.length] = i;
17385 this.xTicks.sort(this.DDM.numericSort) ;
17389 * Create the array of vertical tick marks if an interval was specified in
17390 * setYConstraint().
17391 * @method setYTicks
17394 setYTicks: function(iStartY, iTickSize) {
17396 this.yTickSize = iTickSize;
17400 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17402 this.yTicks[this.yTicks.length] = i;
17407 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17409 this.yTicks[this.yTicks.length] = i;
17414 this.yTicks.sort(this.DDM.numericSort) ;
17418 * By default, the element can be dragged any place on the screen. Use
17419 * this method to limit the horizontal travel of the element. Pass in
17420 * 0,0 for the parameters if you want to lock the drag to the y axis.
17421 * @method setXConstraint
17422 * @param {int} iLeft the number of pixels the element can move to the left
17423 * @param {int} iRight the number of pixels the element can move to the
17425 * @param {int} iTickSize optional parameter for specifying that the
17427 * should move iTickSize pixels at a time.
17429 setXConstraint: function(iLeft, iRight, iTickSize) {
17430 this.leftConstraint = iLeft;
17431 this.rightConstraint = iRight;
17433 this.minX = this.initPageX - iLeft;
17434 this.maxX = this.initPageX + iRight;
17435 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17437 this.constrainX = true;
17441 * Clears any constraints applied to this instance. Also clears ticks
17442 * since they can't exist independent of a constraint at this time.
17443 * @method clearConstraints
17445 clearConstraints: function() {
17446 this.constrainX = false;
17447 this.constrainY = false;
17452 * Clears any tick interval defined for this instance
17453 * @method clearTicks
17455 clearTicks: function() {
17456 this.xTicks = null;
17457 this.yTicks = null;
17458 this.xTickSize = 0;
17459 this.yTickSize = 0;
17463 * By default, the element can be dragged any place on the screen. Set
17464 * this to limit the vertical travel of the element. Pass in 0,0 for the
17465 * parameters if you want to lock the drag to the x axis.
17466 * @method setYConstraint
17467 * @param {int} iUp the number of pixels the element can move up
17468 * @param {int} iDown the number of pixels the element can move down
17469 * @param {int} iTickSize optional parameter for specifying that the
17470 * element should move iTickSize pixels at a time.
17472 setYConstraint: function(iUp, iDown, iTickSize) {
17473 this.topConstraint = iUp;
17474 this.bottomConstraint = iDown;
17476 this.minY = this.initPageY - iUp;
17477 this.maxY = this.initPageY + iDown;
17478 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17480 this.constrainY = true;
17485 * resetConstraints must be called if you manually reposition a dd element.
17486 * @method resetConstraints
17487 * @param {boolean} maintainOffset
17489 resetConstraints: function() {
17492 // Maintain offsets if necessary
17493 if (this.initPageX || this.initPageX === 0) {
17494 // figure out how much this thing has moved
17495 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17496 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17498 this.setInitPosition(dx, dy);
17500 // This is the first time we have detected the element's position
17502 this.setInitPosition();
17505 if (this.constrainX) {
17506 this.setXConstraint( this.leftConstraint,
17507 this.rightConstraint,
17511 if (this.constrainY) {
17512 this.setYConstraint( this.topConstraint,
17513 this.bottomConstraint,
17519 * Normally the drag element is moved pixel by pixel, but we can specify
17520 * that it move a number of pixels at a time. This method resolves the
17521 * location when we have it set up like this.
17523 * @param {int} val where we want to place the object
17524 * @param {int[]} tickArray sorted array of valid points
17525 * @return {int} the closest tick
17528 getTick: function(val, tickArray) {
17531 // If tick interval is not defined, it is effectively 1 pixel,
17532 // so we return the value passed to us.
17534 } else if (tickArray[0] >= val) {
17535 // The value is lower than the first tick, so we return the first
17537 return tickArray[0];
17539 for (var i=0, len=tickArray.length; i<len; ++i) {
17541 if (tickArray[next] && tickArray[next] >= val) {
17542 var diff1 = val - tickArray[i];
17543 var diff2 = tickArray[next] - val;
17544 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17548 // The value is larger than the last tick, so we return the last
17550 return tickArray[tickArray.length - 1];
17557 * @return {string} string representation of the dd obj
17559 toString: function() {
17560 return ("DragDrop " + this.id);
17568 * Ext JS Library 1.1.1
17569 * Copyright(c) 2006-2007, Ext JS, LLC.
17571 * Originally Released Under LGPL - original licence link has changed is not relivant.
17574 * <script type="text/javascript">
17579 * The drag and drop utility provides a framework for building drag and drop
17580 * applications. In addition to enabling drag and drop for specific elements,
17581 * the drag and drop elements are tracked by the manager class, and the
17582 * interactions between the various elements are tracked during the drag and
17583 * the implementing code is notified about these important moments.
17586 // Only load the library once. Rewriting the manager class would orphan
17587 // existing drag and drop instances.
17588 if (!Roo.dd.DragDropMgr) {
17591 * @class Roo.dd.DragDropMgr
17592 * DragDropMgr is a singleton that tracks the element interaction for
17593 * all DragDrop items in the window. Generally, you will not call
17594 * this class directly, but it does have helper methods that could
17595 * be useful in your DragDrop implementations.
17598 Roo.dd.DragDropMgr = function() {
17600 var Event = Roo.EventManager;
17605 * Two dimensional Array of registered DragDrop objects. The first
17606 * dimension is the DragDrop item group, the second the DragDrop
17609 * @type {string: string}
17616 * Array of element ids defined as drag handles. Used to determine
17617 * if the element that generated the mousedown event is actually the
17618 * handle and not the html element itself.
17619 * @property handleIds
17620 * @type {string: string}
17627 * the DragDrop object that is currently being dragged
17628 * @property dragCurrent
17636 * the DragDrop object(s) that are being hovered over
17637 * @property dragOvers
17645 * the X distance between the cursor and the object being dragged
17654 * the Y distance between the cursor and the object being dragged
17663 * Flag to determine if we should prevent the default behavior of the
17664 * events we define. By default this is true, but this can be set to
17665 * false if you need the default behavior (not recommended)
17666 * @property preventDefault
17670 preventDefault: true,
17673 * Flag to determine if we should stop the propagation of the events
17674 * we generate. This is true by default but you may want to set it to
17675 * false if the html element contains other features that require the
17677 * @property stopPropagation
17681 stopPropagation: true,
17684 * Internal flag that is set to true when drag and drop has been
17686 * @property initialized
17693 * All drag and drop can be disabled.
17701 * Called the first time an element is registered.
17707 this.initialized = true;
17711 * In point mode, drag and drop interaction is defined by the
17712 * location of the cursor during the drag/drop
17720 * In intersect mode, drag and drop interactio nis defined by the
17721 * overlap of two or more drag and drop objects.
17722 * @property INTERSECT
17729 * The current drag and drop mode. Default: POINT
17737 * Runs method on all drag and drop objects
17738 * @method _execOnAll
17742 _execOnAll: function(sMethod, args) {
17743 for (var i in this.ids) {
17744 for (var j in this.ids[i]) {
17745 var oDD = this.ids[i][j];
17746 if (! this.isTypeOfDD(oDD)) {
17749 oDD[sMethod].apply(oDD, args);
17755 * Drag and drop initialization. Sets up the global event handlers
17760 _onLoad: function() {
17764 if (!Roo.isTouch) {
17765 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17766 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17768 Event.on(document, "touchend", this.handleMouseUp, this, true);
17769 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17771 Event.on(window, "unload", this._onUnload, this, true);
17772 Event.on(window, "resize", this._onResize, this, true);
17773 // Event.on(window, "mouseout", this._test);
17778 * Reset constraints on all drag and drop objs
17779 * @method _onResize
17783 _onResize: function(e) {
17784 this._execOnAll("resetConstraints", []);
17788 * Lock all drag and drop functionality
17792 lock: function() { this.locked = true; },
17795 * Unlock all drag and drop functionality
17799 unlock: function() { this.locked = false; },
17802 * Is drag and drop locked?
17804 * @return {boolean} True if drag and drop is locked, false otherwise.
17807 isLocked: function() { return this.locked; },
17810 * Location cache that is set for all drag drop objects when a drag is
17811 * initiated, cleared when the drag is finished.
17812 * @property locationCache
17819 * Set useCache to false if you want to force object the lookup of each
17820 * drag and drop linked element constantly during a drag.
17821 * @property useCache
17828 * The number of pixels that the mouse needs to move after the
17829 * mousedown before the drag is initiated. Default=3;
17830 * @property clickPixelThresh
17834 clickPixelThresh: 3,
17837 * The number of milliseconds after the mousedown event to initiate the
17838 * drag if we don't get a mouseup event. Default=1000
17839 * @property clickTimeThresh
17843 clickTimeThresh: 350,
17846 * Flag that indicates that either the drag pixel threshold or the
17847 * mousdown time threshold has been met
17848 * @property dragThreshMet
17853 dragThreshMet: false,
17856 * Timeout used for the click time threshold
17857 * @property clickTimeout
17862 clickTimeout: null,
17865 * The X position of the mousedown event stored for later use when a
17866 * drag threshold is met.
17875 * The Y position of the mousedown event stored for later use when a
17876 * drag threshold is met.
17885 * Each DragDrop instance must be registered with the DragDropMgr.
17886 * This is executed in DragDrop.init()
17887 * @method regDragDrop
17888 * @param {DragDrop} oDD the DragDrop object to register
17889 * @param {String} sGroup the name of the group this element belongs to
17892 regDragDrop: function(oDD, sGroup) {
17893 if (!this.initialized) { this.init(); }
17895 if (!this.ids[sGroup]) {
17896 this.ids[sGroup] = {};
17898 this.ids[sGroup][oDD.id] = oDD;
17902 * Removes the supplied dd instance from the supplied group. Executed
17903 * by DragDrop.removeFromGroup, so don't call this function directly.
17904 * @method removeDDFromGroup
17908 removeDDFromGroup: function(oDD, sGroup) {
17909 if (!this.ids[sGroup]) {
17910 this.ids[sGroup] = {};
17913 var obj = this.ids[sGroup];
17914 if (obj && obj[oDD.id]) {
17915 delete obj[oDD.id];
17920 * Unregisters a drag and drop item. This is executed in
17921 * DragDrop.unreg, use that method instead of calling this directly.
17926 _remove: function(oDD) {
17927 for (var g in oDD.groups) {
17928 if (g && this.ids[g][oDD.id]) {
17929 delete this.ids[g][oDD.id];
17932 delete this.handleIds[oDD.id];
17936 * Each DragDrop handle element must be registered. This is done
17937 * automatically when executing DragDrop.setHandleElId()
17938 * @method regHandle
17939 * @param {String} sDDId the DragDrop id this element is a handle for
17940 * @param {String} sHandleId the id of the element that is the drag
17944 regHandle: function(sDDId, sHandleId) {
17945 if (!this.handleIds[sDDId]) {
17946 this.handleIds[sDDId] = {};
17948 this.handleIds[sDDId][sHandleId] = sHandleId;
17952 * Utility function to determine if a given element has been
17953 * registered as a drag drop item.
17954 * @method isDragDrop
17955 * @param {String} id the element id to check
17956 * @return {boolean} true if this element is a DragDrop item,
17960 isDragDrop: function(id) {
17961 return ( this.getDDById(id) ) ? true : false;
17965 * Returns the drag and drop instances that are in all groups the
17966 * passed in instance belongs to.
17967 * @method getRelated
17968 * @param {DragDrop} p_oDD the obj to get related data for
17969 * @param {boolean} bTargetsOnly if true, only return targetable objs
17970 * @return {DragDrop[]} the related instances
17973 getRelated: function(p_oDD, bTargetsOnly) {
17975 for (var i in p_oDD.groups) {
17976 for (j in this.ids[i]) {
17977 var dd = this.ids[i][j];
17978 if (! this.isTypeOfDD(dd)) {
17981 if (!bTargetsOnly || dd.isTarget) {
17982 oDDs[oDDs.length] = dd;
17991 * Returns true if the specified dd target is a legal target for
17992 * the specifice drag obj
17993 * @method isLegalTarget
17994 * @param {DragDrop} the drag obj
17995 * @param {DragDrop} the target
17996 * @return {boolean} true if the target is a legal target for the
18000 isLegalTarget: function (oDD, oTargetDD) {
18001 var targets = this.getRelated(oDD, true);
18002 for (var i=0, len=targets.length;i<len;++i) {
18003 if (targets[i].id == oTargetDD.id) {
18012 * My goal is to be able to transparently determine if an object is
18013 * typeof DragDrop, and the exact subclass of DragDrop. typeof
18014 * returns "object", oDD.constructor.toString() always returns
18015 * "DragDrop" and not the name of the subclass. So for now it just
18016 * evaluates a well-known variable in DragDrop.
18017 * @method isTypeOfDD
18018 * @param {Object} the object to evaluate
18019 * @return {boolean} true if typeof oDD = DragDrop
18022 isTypeOfDD: function (oDD) {
18023 return (oDD && oDD.__ygDragDrop);
18027 * Utility function to determine if a given element has been
18028 * registered as a drag drop handle for the given Drag Drop object.
18030 * @param {String} id the element id to check
18031 * @return {boolean} true if this element is a DragDrop handle, false
18035 isHandle: function(sDDId, sHandleId) {
18036 return ( this.handleIds[sDDId] &&
18037 this.handleIds[sDDId][sHandleId] );
18041 * Returns the DragDrop instance for a given id
18042 * @method getDDById
18043 * @param {String} id the id of the DragDrop object
18044 * @return {DragDrop} the drag drop object, null if it is not found
18047 getDDById: function(id) {
18048 for (var i in this.ids) {
18049 if (this.ids[i][id]) {
18050 return this.ids[i][id];
18057 * Fired after a registered DragDrop object gets the mousedown event.
18058 * Sets up the events required to track the object being dragged
18059 * @method handleMouseDown
18060 * @param {Event} e the event
18061 * @param oDD the DragDrop object being dragged
18065 handleMouseDown: function(e, oDD) {
18067 Roo.QuickTips.disable();
18069 this.currentTarget = e.getTarget();
18071 this.dragCurrent = oDD;
18073 var el = oDD.getEl();
18075 // track start position
18076 this.startX = e.getPageX();
18077 this.startY = e.getPageY();
18079 this.deltaX = this.startX - el.offsetLeft;
18080 this.deltaY = this.startY - el.offsetTop;
18082 this.dragThreshMet = false;
18084 this.clickTimeout = setTimeout(
18086 var DDM = Roo.dd.DDM;
18087 DDM.startDrag(DDM.startX, DDM.startY);
18089 this.clickTimeThresh );
18093 * Fired when either the drag pixel threshol or the mousedown hold
18094 * time threshold has been met.
18095 * @method startDrag
18096 * @param x {int} the X position of the original mousedown
18097 * @param y {int} the Y position of the original mousedown
18100 startDrag: function(x, y) {
18101 clearTimeout(this.clickTimeout);
18102 if (this.dragCurrent) {
18103 this.dragCurrent.b4StartDrag(x, y);
18104 this.dragCurrent.startDrag(x, y);
18106 this.dragThreshMet = true;
18110 * Internal function to handle the mouseup event. Will be invoked
18111 * from the context of the document.
18112 * @method handleMouseUp
18113 * @param {Event} e the event
18117 handleMouseUp: function(e) {
18120 Roo.QuickTips.enable();
18122 if (! this.dragCurrent) {
18126 clearTimeout(this.clickTimeout);
18128 if (this.dragThreshMet) {
18129 this.fireEvents(e, true);
18139 * Utility to stop event propagation and event default, if these
18140 * features are turned on.
18141 * @method stopEvent
18142 * @param {Event} e the event as returned by this.getEvent()
18145 stopEvent: function(e){
18146 if(this.stopPropagation) {
18147 e.stopPropagation();
18150 if (this.preventDefault) {
18151 e.preventDefault();
18156 * Internal function to clean up event handlers after the drag
18157 * operation is complete
18159 * @param {Event} e the event
18163 stopDrag: function(e) {
18164 // Fire the drag end event for the item that was dragged
18165 if (this.dragCurrent) {
18166 if (this.dragThreshMet) {
18167 this.dragCurrent.b4EndDrag(e);
18168 this.dragCurrent.endDrag(e);
18171 this.dragCurrent.onMouseUp(e);
18174 this.dragCurrent = null;
18175 this.dragOvers = {};
18179 * Internal function to handle the mousemove event. Will be invoked
18180 * from the context of the html element.
18182 * @TODO figure out what we can do about mouse events lost when the
18183 * user drags objects beyond the window boundary. Currently we can
18184 * detect this in internet explorer by verifying that the mouse is
18185 * down during the mousemove event. Firefox doesn't give us the
18186 * button state on the mousemove event.
18187 * @method handleMouseMove
18188 * @param {Event} e the event
18192 handleMouseMove: function(e) {
18193 if (! this.dragCurrent) {
18197 // var button = e.which || e.button;
18199 // check for IE mouseup outside of page boundary
18200 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18202 return this.handleMouseUp(e);
18205 if (!this.dragThreshMet) {
18206 var diffX = Math.abs(this.startX - e.getPageX());
18207 var diffY = Math.abs(this.startY - e.getPageY());
18208 if (diffX > this.clickPixelThresh ||
18209 diffY > this.clickPixelThresh) {
18210 this.startDrag(this.startX, this.startY);
18214 if (this.dragThreshMet) {
18215 this.dragCurrent.b4Drag(e);
18216 this.dragCurrent.onDrag(e);
18217 if(!this.dragCurrent.moveOnly){
18218 this.fireEvents(e, false);
18228 * Iterates over all of the DragDrop elements to find ones we are
18229 * hovering over or dropping on
18230 * @method fireEvents
18231 * @param {Event} e the event
18232 * @param {boolean} isDrop is this a drop op or a mouseover op?
18236 fireEvents: function(e, isDrop) {
18237 var dc = this.dragCurrent;
18239 // If the user did the mouse up outside of the window, we could
18240 // get here even though we have ended the drag.
18241 if (!dc || dc.isLocked()) {
18245 var pt = e.getPoint();
18247 // cache the previous dragOver array
18253 var enterEvts = [];
18255 // Check to see if the object(s) we were hovering over is no longer
18256 // being hovered over so we can fire the onDragOut event
18257 for (var i in this.dragOvers) {
18259 var ddo = this.dragOvers[i];
18261 if (! this.isTypeOfDD(ddo)) {
18265 if (! this.isOverTarget(pt, ddo, this.mode)) {
18266 outEvts.push( ddo );
18269 oldOvers[i] = true;
18270 delete this.dragOvers[i];
18273 for (var sGroup in dc.groups) {
18275 if ("string" != typeof sGroup) {
18279 for (i in this.ids[sGroup]) {
18280 var oDD = this.ids[sGroup][i];
18281 if (! this.isTypeOfDD(oDD)) {
18285 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18286 if (this.isOverTarget(pt, oDD, this.mode)) {
18287 // look for drop interactions
18289 dropEvts.push( oDD );
18290 // look for drag enter and drag over interactions
18293 // initial drag over: dragEnter fires
18294 if (!oldOvers[oDD.id]) {
18295 enterEvts.push( oDD );
18296 // subsequent drag overs: dragOver fires
18298 overEvts.push( oDD );
18301 this.dragOvers[oDD.id] = oDD;
18309 if (outEvts.length) {
18310 dc.b4DragOut(e, outEvts);
18311 dc.onDragOut(e, outEvts);
18314 if (enterEvts.length) {
18315 dc.onDragEnter(e, enterEvts);
18318 if (overEvts.length) {
18319 dc.b4DragOver(e, overEvts);
18320 dc.onDragOver(e, overEvts);
18323 if (dropEvts.length) {
18324 dc.b4DragDrop(e, dropEvts);
18325 dc.onDragDrop(e, dropEvts);
18329 // fire dragout events
18331 for (i=0, len=outEvts.length; i<len; ++i) {
18332 dc.b4DragOut(e, outEvts[i].id);
18333 dc.onDragOut(e, outEvts[i].id);
18336 // fire enter events
18337 for (i=0,len=enterEvts.length; i<len; ++i) {
18338 // dc.b4DragEnter(e, oDD.id);
18339 dc.onDragEnter(e, enterEvts[i].id);
18342 // fire over events
18343 for (i=0,len=overEvts.length; i<len; ++i) {
18344 dc.b4DragOver(e, overEvts[i].id);
18345 dc.onDragOver(e, overEvts[i].id);
18348 // fire drop events
18349 for (i=0, len=dropEvts.length; i<len; ++i) {
18350 dc.b4DragDrop(e, dropEvts[i].id);
18351 dc.onDragDrop(e, dropEvts[i].id);
18356 // notify about a drop that did not find a target
18357 if (isDrop && !dropEvts.length) {
18358 dc.onInvalidDrop(e);
18364 * Helper function for getting the best match from the list of drag
18365 * and drop objects returned by the drag and drop events when we are
18366 * in INTERSECT mode. It returns either the first object that the
18367 * cursor is over, or the object that has the greatest overlap with
18368 * the dragged element.
18369 * @method getBestMatch
18370 * @param {DragDrop[]} dds The array of drag and drop objects
18372 * @return {DragDrop} The best single match
18375 getBestMatch: function(dds) {
18377 // Return null if the input is not what we expect
18378 //if (!dds || !dds.length || dds.length == 0) {
18380 // If there is only one item, it wins
18381 //} else if (dds.length == 1) {
18383 var len = dds.length;
18388 // Loop through the targeted items
18389 for (var i=0; i<len; ++i) {
18391 // If the cursor is over the object, it wins. If the
18392 // cursor is over multiple matches, the first one we come
18394 if (dd.cursorIsOver) {
18397 // Otherwise the object with the most overlap wins
18400 winner.overlap.getArea() < dd.overlap.getArea()) {
18411 * Refreshes the cache of the top-left and bottom-right points of the
18412 * drag and drop objects in the specified group(s). This is in the
18413 * format that is stored in the drag and drop instance, so typical
18416 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18420 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18422 * @TODO this really should be an indexed array. Alternatively this
18423 * method could accept both.
18424 * @method refreshCache
18425 * @param {Object} groups an associative array of groups to refresh
18428 refreshCache: function(groups) {
18429 for (var sGroup in groups) {
18430 if ("string" != typeof sGroup) {
18433 for (var i in this.ids[sGroup]) {
18434 var oDD = this.ids[sGroup][i];
18436 if (this.isTypeOfDD(oDD)) {
18437 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18438 var loc = this.getLocation(oDD);
18440 this.locationCache[oDD.id] = loc;
18442 delete this.locationCache[oDD.id];
18443 // this will unregister the drag and drop object if
18444 // the element is not in a usable state
18453 * This checks to make sure an element exists and is in the DOM. The
18454 * main purpose is to handle cases where innerHTML is used to remove
18455 * drag and drop objects from the DOM. IE provides an 'unspecified
18456 * error' when trying to access the offsetParent of such an element
18458 * @param {HTMLElement} el the element to check
18459 * @return {boolean} true if the element looks usable
18462 verifyEl: function(el) {
18467 parent = el.offsetParent;
18470 parent = el.offsetParent;
18481 * Returns a Region object containing the drag and drop element's position
18482 * and size, including the padding configured for it
18483 * @method getLocation
18484 * @param {DragDrop} oDD the drag and drop object to get the
18486 * @return {Roo.lib.Region} a Region object representing the total area
18487 * the element occupies, including any padding
18488 * the instance is configured for.
18491 getLocation: function(oDD) {
18492 if (! this.isTypeOfDD(oDD)) {
18496 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18499 pos= Roo.lib.Dom.getXY(el);
18507 x2 = x1 + el.offsetWidth;
18509 y2 = y1 + el.offsetHeight;
18511 t = y1 - oDD.padding[0];
18512 r = x2 + oDD.padding[1];
18513 b = y2 + oDD.padding[2];
18514 l = x1 - oDD.padding[3];
18516 return new Roo.lib.Region( t, r, b, l );
18520 * Checks the cursor location to see if it over the target
18521 * @method isOverTarget
18522 * @param {Roo.lib.Point} pt The point to evaluate
18523 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18524 * @return {boolean} true if the mouse is over the target
18528 isOverTarget: function(pt, oTarget, intersect) {
18529 // use cache if available
18530 var loc = this.locationCache[oTarget.id];
18531 if (!loc || !this.useCache) {
18532 loc = this.getLocation(oTarget);
18533 this.locationCache[oTarget.id] = loc;
18541 oTarget.cursorIsOver = loc.contains( pt );
18543 // DragDrop is using this as a sanity check for the initial mousedown
18544 // in this case we are done. In POINT mode, if the drag obj has no
18545 // contraints, we are also done. Otherwise we need to evaluate the
18546 // location of the target as related to the actual location of the
18547 // dragged element.
18548 var dc = this.dragCurrent;
18549 if (!dc || !dc.getTargetCoord ||
18550 (!intersect && !dc.constrainX && !dc.constrainY)) {
18551 return oTarget.cursorIsOver;
18554 oTarget.overlap = null;
18556 // Get the current location of the drag element, this is the
18557 // location of the mouse event less the delta that represents
18558 // where the original mousedown happened on the element. We
18559 // need to consider constraints and ticks as well.
18560 var pos = dc.getTargetCoord(pt.x, pt.y);
18562 var el = dc.getDragEl();
18563 var curRegion = new Roo.lib.Region( pos.y,
18564 pos.x + el.offsetWidth,
18565 pos.y + el.offsetHeight,
18568 var overlap = curRegion.intersect(loc);
18571 oTarget.overlap = overlap;
18572 return (intersect) ? true : oTarget.cursorIsOver;
18579 * unload event handler
18580 * @method _onUnload
18584 _onUnload: function(e, me) {
18585 Roo.dd.DragDropMgr.unregAll();
18589 * Cleans up the drag and drop events and objects.
18594 unregAll: function() {
18596 if (this.dragCurrent) {
18598 this.dragCurrent = null;
18601 this._execOnAll("unreg", []);
18603 for (i in this.elementCache) {
18604 delete this.elementCache[i];
18607 this.elementCache = {};
18612 * A cache of DOM elements
18613 * @property elementCache
18620 * Get the wrapper for the DOM element specified
18621 * @method getElWrapper
18622 * @param {String} id the id of the element to get
18623 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18625 * @deprecated This wrapper isn't that useful
18628 getElWrapper: function(id) {
18629 var oWrapper = this.elementCache[id];
18630 if (!oWrapper || !oWrapper.el) {
18631 oWrapper = this.elementCache[id] =
18632 new this.ElementWrapper(Roo.getDom(id));
18638 * Returns the actual DOM element
18639 * @method getElement
18640 * @param {String} id the id of the elment to get
18641 * @return {Object} The element
18642 * @deprecated use Roo.getDom instead
18645 getElement: function(id) {
18646 return Roo.getDom(id);
18650 * Returns the style property for the DOM element (i.e.,
18651 * document.getElById(id).style)
18653 * @param {String} id the id of the elment to get
18654 * @return {Object} The style property of the element
18655 * @deprecated use Roo.getDom instead
18658 getCss: function(id) {
18659 var el = Roo.getDom(id);
18660 return (el) ? el.style : null;
18664 * Inner class for cached elements
18665 * @class DragDropMgr.ElementWrapper
18670 ElementWrapper: function(el) {
18675 this.el = el || null;
18680 this.id = this.el && el.id;
18682 * A reference to the style property
18685 this.css = this.el && el.style;
18689 * Returns the X position of an html element
18691 * @param el the element for which to get the position
18692 * @return {int} the X coordinate
18694 * @deprecated use Roo.lib.Dom.getX instead
18697 getPosX: function(el) {
18698 return Roo.lib.Dom.getX(el);
18702 * Returns the Y position of an html element
18704 * @param el the element for which to get the position
18705 * @return {int} the Y coordinate
18706 * @deprecated use Roo.lib.Dom.getY instead
18709 getPosY: function(el) {
18710 return Roo.lib.Dom.getY(el);
18714 * Swap two nodes. In IE, we use the native method, for others we
18715 * emulate the IE behavior
18717 * @param n1 the first node to swap
18718 * @param n2 the other node to swap
18721 swapNode: function(n1, n2) {
18725 var p = n2.parentNode;
18726 var s = n2.nextSibling;
18729 p.insertBefore(n1, n2);
18730 } else if (n2 == n1.nextSibling) {
18731 p.insertBefore(n2, n1);
18733 n1.parentNode.replaceChild(n2, n1);
18734 p.insertBefore(n1, s);
18740 * Returns the current scroll position
18741 * @method getScroll
18745 getScroll: function () {
18746 var t, l, dde=document.documentElement, db=document.body;
18747 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18749 l = dde.scrollLeft;
18756 return { top: t, left: l };
18760 * Returns the specified element style property
18762 * @param {HTMLElement} el the element
18763 * @param {string} styleProp the style property
18764 * @return {string} The value of the style property
18765 * @deprecated use Roo.lib.Dom.getStyle
18768 getStyle: function(el, styleProp) {
18769 return Roo.fly(el).getStyle(styleProp);
18773 * Gets the scrollTop
18774 * @method getScrollTop
18775 * @return {int} the document's scrollTop
18778 getScrollTop: function () { return this.getScroll().top; },
18781 * Gets the scrollLeft
18782 * @method getScrollLeft
18783 * @return {int} the document's scrollTop
18786 getScrollLeft: function () { return this.getScroll().left; },
18789 * Sets the x/y position of an element to the location of the
18792 * @param {HTMLElement} moveEl The element to move
18793 * @param {HTMLElement} targetEl The position reference element
18796 moveToEl: function (moveEl, targetEl) {
18797 var aCoord = Roo.lib.Dom.getXY(targetEl);
18798 Roo.lib.Dom.setXY(moveEl, aCoord);
18802 * Numeric array sort function
18803 * @method numericSort
18806 numericSort: function(a, b) { return (a - b); },
18810 * @property _timeoutCount
18817 * Trying to make the load order less important. Without this we get
18818 * an error if this file is loaded before the Event Utility.
18819 * @method _addListeners
18823 _addListeners: function() {
18824 var DDM = Roo.dd.DDM;
18825 if ( Roo.lib.Event && document ) {
18828 if (DDM._timeoutCount > 2000) {
18830 setTimeout(DDM._addListeners, 10);
18831 if (document && document.body) {
18832 DDM._timeoutCount += 1;
18839 * Recursively searches the immediate parent and all child nodes for
18840 * the handle element in order to determine wheter or not it was
18842 * @method handleWasClicked
18843 * @param node the html element to inspect
18846 handleWasClicked: function(node, id) {
18847 if (this.isHandle(id, node.id)) {
18850 // check to see if this is a text node child of the one we want
18851 var p = node.parentNode;
18854 if (this.isHandle(id, p.id)) {
18869 // shorter alias, save a few bytes
18870 Roo.dd.DDM = Roo.dd.DragDropMgr;
18871 Roo.dd.DDM._addListeners();
18875 * Ext JS Library 1.1.1
18876 * Copyright(c) 2006-2007, Ext JS, LLC.
18878 * Originally Released Under LGPL - original licence link has changed is not relivant.
18881 * <script type="text/javascript">
18886 * A DragDrop implementation where the linked element follows the
18887 * mouse cursor during a drag.
18888 * @extends Roo.dd.DragDrop
18890 * @param {String} id the id of the linked element
18891 * @param {String} sGroup the group of related DragDrop items
18892 * @param {object} config an object containing configurable attributes
18893 * Valid properties for DD:
18896 Roo.dd.DD = function(id, sGroup, config) {
18898 this.init(id, sGroup, config);
18902 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18905 * When set to true, the utility automatically tries to scroll the browser
18906 * window wehn a drag and drop element is dragged near the viewport boundary.
18907 * Defaults to true.
18914 * Sets the pointer offset to the distance between the linked element's top
18915 * left corner and the location the element was clicked
18916 * @method autoOffset
18917 * @param {int} iPageX the X coordinate of the click
18918 * @param {int} iPageY the Y coordinate of the click
18920 autoOffset: function(iPageX, iPageY) {
18921 var x = iPageX - this.startPageX;
18922 var y = iPageY - this.startPageY;
18923 this.setDelta(x, y);
18927 * Sets the pointer offset. You can call this directly to force the
18928 * offset to be in a particular location (e.g., pass in 0,0 to set it
18929 * to the center of the object)
18931 * @param {int} iDeltaX the distance from the left
18932 * @param {int} iDeltaY the distance from the top
18934 setDelta: function(iDeltaX, iDeltaY) {
18935 this.deltaX = iDeltaX;
18936 this.deltaY = iDeltaY;
18940 * Sets the drag element to the location of the mousedown or click event,
18941 * maintaining the cursor location relative to the location on the element
18942 * that was clicked. Override this if you want to place the element in a
18943 * location other than where the cursor is.
18944 * @method setDragElPos
18945 * @param {int} iPageX the X coordinate of the mousedown or drag event
18946 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18948 setDragElPos: function(iPageX, iPageY) {
18949 // the first time we do this, we are going to check to make sure
18950 // the element has css positioning
18952 var el = this.getDragEl();
18953 this.alignElWithMouse(el, iPageX, iPageY);
18957 * Sets the element to the location of the mousedown or click event,
18958 * maintaining the cursor location relative to the location on the element
18959 * that was clicked. Override this if you want to place the element in a
18960 * location other than where the cursor is.
18961 * @method alignElWithMouse
18962 * @param {HTMLElement} el the element to move
18963 * @param {int} iPageX the X coordinate of the mousedown or drag event
18964 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18966 alignElWithMouse: function(el, iPageX, iPageY) {
18967 var oCoord = this.getTargetCoord(iPageX, iPageY);
18968 var fly = el.dom ? el : Roo.fly(el);
18969 if (!this.deltaSetXY) {
18970 var aCoord = [oCoord.x, oCoord.y];
18972 var newLeft = fly.getLeft(true);
18973 var newTop = fly.getTop(true);
18974 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
18976 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
18979 this.cachePosition(oCoord.x, oCoord.y);
18980 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
18985 * Saves the most recent position so that we can reset the constraints and
18986 * tick marks on-demand. We need to know this so that we can calculate the
18987 * number of pixels the element is offset from its original position.
18988 * @method cachePosition
18989 * @param iPageX the current x position (optional, this just makes it so we
18990 * don't have to look it up again)
18991 * @param iPageY the current y position (optional, this just makes it so we
18992 * don't have to look it up again)
18994 cachePosition: function(iPageX, iPageY) {
18996 this.lastPageX = iPageX;
18997 this.lastPageY = iPageY;
18999 var aCoord = Roo.lib.Dom.getXY(this.getEl());
19000 this.lastPageX = aCoord[0];
19001 this.lastPageY = aCoord[1];
19006 * Auto-scroll the window if the dragged object has been moved beyond the
19007 * visible window boundary.
19008 * @method autoScroll
19009 * @param {int} x the drag element's x position
19010 * @param {int} y the drag element's y position
19011 * @param {int} h the height of the drag element
19012 * @param {int} w the width of the drag element
19015 autoScroll: function(x, y, h, w) {
19018 // The client height
19019 var clientH = Roo.lib.Dom.getViewWidth();
19021 // The client width
19022 var clientW = Roo.lib.Dom.getViewHeight();
19024 // The amt scrolled down
19025 var st = this.DDM.getScrollTop();
19027 // The amt scrolled right
19028 var sl = this.DDM.getScrollLeft();
19030 // Location of the bottom of the element
19033 // Location of the right of the element
19036 // The distance from the cursor to the bottom of the visible area,
19037 // adjusted so that we don't scroll if the cursor is beyond the
19038 // element drag constraints
19039 var toBot = (clientH + st - y - this.deltaY);
19041 // The distance from the cursor to the right of the visible area
19042 var toRight = (clientW + sl - x - this.deltaX);
19045 // How close to the edge the cursor must be before we scroll
19046 // var thresh = (document.all) ? 100 : 40;
19049 // How many pixels to scroll per autoscroll op. This helps to reduce
19050 // clunky scrolling. IE is more sensitive about this ... it needs this
19051 // value to be higher.
19052 var scrAmt = (document.all) ? 80 : 30;
19054 // Scroll down if we are near the bottom of the visible page and the
19055 // obj extends below the crease
19056 if ( bot > clientH && toBot < thresh ) {
19057 window.scrollTo(sl, st + scrAmt);
19060 // Scroll up if the window is scrolled down and the top of the object
19061 // goes above the top border
19062 if ( y < st && st > 0 && y - st < thresh ) {
19063 window.scrollTo(sl, st - scrAmt);
19066 // Scroll right if the obj is beyond the right border and the cursor is
19067 // near the border.
19068 if ( right > clientW && toRight < thresh ) {
19069 window.scrollTo(sl + scrAmt, st);
19072 // Scroll left if the window has been scrolled to the right and the obj
19073 // extends past the left border
19074 if ( x < sl && sl > 0 && x - sl < thresh ) {
19075 window.scrollTo(sl - scrAmt, st);
19081 * Finds the location the element should be placed if we want to move
19082 * it to where the mouse location less the click offset would place us.
19083 * @method getTargetCoord
19084 * @param {int} iPageX the X coordinate of the click
19085 * @param {int} iPageY the Y coordinate of the click
19086 * @return an object that contains the coordinates (Object.x and Object.y)
19089 getTargetCoord: function(iPageX, iPageY) {
19092 var x = iPageX - this.deltaX;
19093 var y = iPageY - this.deltaY;
19095 if (this.constrainX) {
19096 if (x < this.minX) { x = this.minX; }
19097 if (x > this.maxX) { x = this.maxX; }
19100 if (this.constrainY) {
19101 if (y < this.minY) { y = this.minY; }
19102 if (y > this.maxY) { y = this.maxY; }
19105 x = this.getTick(x, this.xTicks);
19106 y = this.getTick(y, this.yTicks);
19113 * Sets up config options specific to this class. Overrides
19114 * Roo.dd.DragDrop, but all versions of this method through the
19115 * inheritance chain are called
19117 applyConfig: function() {
19118 Roo.dd.DD.superclass.applyConfig.call(this);
19119 this.scroll = (this.config.scroll !== false);
19123 * Event that fires prior to the onMouseDown event. Overrides
19126 b4MouseDown: function(e) {
19127 // this.resetConstraints();
19128 this.autoOffset(e.getPageX(),
19133 * Event that fires prior to the onDrag event. Overrides
19136 b4Drag: function(e) {
19137 this.setDragElPos(e.getPageX(),
19141 toString: function() {
19142 return ("DD " + this.id);
19145 //////////////////////////////////////////////////////////////////////////
19146 // Debugging ygDragDrop events that can be overridden
19147 //////////////////////////////////////////////////////////////////////////
19149 startDrag: function(x, y) {
19152 onDrag: function(e) {
19155 onDragEnter: function(e, id) {
19158 onDragOver: function(e, id) {
19161 onDragOut: function(e, id) {
19164 onDragDrop: function(e, id) {
19167 endDrag: function(e) {
19174 * Ext JS Library 1.1.1
19175 * Copyright(c) 2006-2007, Ext JS, LLC.
19177 * Originally Released Under LGPL - original licence link has changed is not relivant.
19180 * <script type="text/javascript">
19184 * @class Roo.dd.DDProxy
19185 * A DragDrop implementation that inserts an empty, bordered div into
19186 * the document that follows the cursor during drag operations. At the time of
19187 * the click, the frame div is resized to the dimensions of the linked html
19188 * element, and moved to the exact location of the linked element.
19190 * References to the "frame" element refer to the single proxy element that
19191 * was created to be dragged in place of all DDProxy elements on the
19194 * @extends Roo.dd.DD
19196 * @param {String} id the id of the linked html element
19197 * @param {String} sGroup the group of related DragDrop objects
19198 * @param {object} config an object containing configurable attributes
19199 * Valid properties for DDProxy in addition to those in DragDrop:
19200 * resizeFrame, centerFrame, dragElId
19202 Roo.dd.DDProxy = function(id, sGroup, config) {
19204 this.init(id, sGroup, config);
19210 * The default drag frame div id
19211 * @property Roo.dd.DDProxy.dragElId
19215 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19217 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19220 * By default we resize the drag frame to be the same size as the element
19221 * we want to drag (this is to get the frame effect). We can turn it off
19222 * if we want a different behavior.
19223 * @property resizeFrame
19229 * By default the frame is positioned exactly where the drag element is, so
19230 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19231 * you do not have constraints on the obj is to have the drag frame centered
19232 * around the cursor. Set centerFrame to true for this effect.
19233 * @property centerFrame
19236 centerFrame: false,
19239 * Creates the proxy element if it does not yet exist
19240 * @method createFrame
19242 createFrame: function() {
19244 var body = document.body;
19246 if (!body || !body.firstChild) {
19247 setTimeout( function() { self.createFrame(); }, 50 );
19251 var div = this.getDragEl();
19254 div = document.createElement("div");
19255 div.id = this.dragElId;
19258 s.position = "absolute";
19259 s.visibility = "hidden";
19261 s.border = "2px solid #aaa";
19264 // appendChild can blow up IE if invoked prior to the window load event
19265 // while rendering a table. It is possible there are other scenarios
19266 // that would cause this to happen as well.
19267 body.insertBefore(div, body.firstChild);
19272 * Initialization for the drag frame element. Must be called in the
19273 * constructor of all subclasses
19274 * @method initFrame
19276 initFrame: function() {
19277 this.createFrame();
19280 applyConfig: function() {
19281 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19283 this.resizeFrame = (this.config.resizeFrame !== false);
19284 this.centerFrame = (this.config.centerFrame);
19285 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19289 * Resizes the drag frame to the dimensions of the clicked object, positions
19290 * it over the object, and finally displays it
19291 * @method showFrame
19292 * @param {int} iPageX X click position
19293 * @param {int} iPageY Y click position
19296 showFrame: function(iPageX, iPageY) {
19297 var el = this.getEl();
19298 var dragEl = this.getDragEl();
19299 var s = dragEl.style;
19301 this._resizeProxy();
19303 if (this.centerFrame) {
19304 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19305 Math.round(parseInt(s.height, 10)/2) );
19308 this.setDragElPos(iPageX, iPageY);
19310 Roo.fly(dragEl).show();
19314 * The proxy is automatically resized to the dimensions of the linked
19315 * element when a drag is initiated, unless resizeFrame is set to false
19316 * @method _resizeProxy
19319 _resizeProxy: function() {
19320 if (this.resizeFrame) {
19321 var el = this.getEl();
19322 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19326 // overrides Roo.dd.DragDrop
19327 b4MouseDown: function(e) {
19328 var x = e.getPageX();
19329 var y = e.getPageY();
19330 this.autoOffset(x, y);
19331 this.setDragElPos(x, y);
19334 // overrides Roo.dd.DragDrop
19335 b4StartDrag: function(x, y) {
19336 // show the drag frame
19337 this.showFrame(x, y);
19340 // overrides Roo.dd.DragDrop
19341 b4EndDrag: function(e) {
19342 Roo.fly(this.getDragEl()).hide();
19345 // overrides Roo.dd.DragDrop
19346 // By default we try to move the element to the last location of the frame.
19347 // This is so that the default behavior mirrors that of Roo.dd.DD.
19348 endDrag: function(e) {
19350 var lel = this.getEl();
19351 var del = this.getDragEl();
19353 // Show the drag frame briefly so we can get its position
19354 del.style.visibility = "";
19357 // Hide the linked element before the move to get around a Safari
19359 lel.style.visibility = "hidden";
19360 Roo.dd.DDM.moveToEl(lel, del);
19361 del.style.visibility = "hidden";
19362 lel.style.visibility = "";
19367 beforeMove : function(){
19371 afterDrag : function(){
19375 toString: function() {
19376 return ("DDProxy " + this.id);
19382 * Ext JS Library 1.1.1
19383 * Copyright(c) 2006-2007, Ext JS, LLC.
19385 * Originally Released Under LGPL - original licence link has changed is not relivant.
19388 * <script type="text/javascript">
19392 * @class Roo.dd.DDTarget
19393 * A DragDrop implementation that does not move, but can be a drop
19394 * target. You would get the same result by simply omitting implementation
19395 * for the event callbacks, but this way we reduce the processing cost of the
19396 * event listener and the callbacks.
19397 * @extends Roo.dd.DragDrop
19399 * @param {String} id the id of the element that is a drop target
19400 * @param {String} sGroup the group of related DragDrop objects
19401 * @param {object} config an object containing configurable attributes
19402 * Valid properties for DDTarget in addition to those in
19406 Roo.dd.DDTarget = function(id, sGroup, config) {
19408 this.initTarget(id, sGroup, config);
19410 if (config.listeners || config.events) {
19411 Roo.dd.DragDrop.superclass.constructor.call(this, {
19412 listeners : config.listeners || {},
19413 events : config.events || {}
19418 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19419 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19420 toString: function() {
19421 return ("DDTarget " + this.id);
19426 * Ext JS Library 1.1.1
19427 * Copyright(c) 2006-2007, Ext JS, LLC.
19429 * Originally Released Under LGPL - original licence link has changed is not relivant.
19432 * <script type="text/javascript">
19437 * @class Roo.dd.ScrollManager
19438 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19439 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19442 Roo.dd.ScrollManager = function(){
19443 var ddm = Roo.dd.DragDropMgr;
19450 var onStop = function(e){
19455 var triggerRefresh = function(){
19456 if(ddm.dragCurrent){
19457 ddm.refreshCache(ddm.dragCurrent.groups);
19461 var doScroll = function(){
19462 if(ddm.dragCurrent){
19463 var dds = Roo.dd.ScrollManager;
19465 if(proc.el.scroll(proc.dir, dds.increment)){
19469 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19474 var clearProc = function(){
19476 clearInterval(proc.id);
19483 var startProc = function(el, dir){
19484 Roo.log('scroll startproc');
19488 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19491 var onFire = function(e, isDrop){
19493 if(isDrop || !ddm.dragCurrent){ return; }
19494 var dds = Roo.dd.ScrollManager;
19495 if(!dragEl || dragEl != ddm.dragCurrent){
19496 dragEl = ddm.dragCurrent;
19497 // refresh regions on drag start
19498 dds.refreshCache();
19501 var xy = Roo.lib.Event.getXY(e);
19502 var pt = new Roo.lib.Point(xy[0], xy[1]);
19503 for(var id in els){
19504 var el = els[id], r = el._region;
19505 if(r && r.contains(pt) && el.isScrollable()){
19506 if(r.bottom - pt.y <= dds.thresh){
19508 startProc(el, "down");
19511 }else if(r.right - pt.x <= dds.thresh){
19513 startProc(el, "left");
19516 }else if(pt.y - r.top <= dds.thresh){
19518 startProc(el, "up");
19521 }else if(pt.x - r.left <= dds.thresh){
19523 startProc(el, "right");
19532 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19533 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19537 * Registers new overflow element(s) to auto scroll
19538 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19540 register : function(el){
19541 if(el instanceof Array){
19542 for(var i = 0, len = el.length; i < len; i++) {
19543 this.register(el[i]);
19549 Roo.dd.ScrollManager.els = els;
19553 * Unregisters overflow element(s) so they are no longer scrolled
19554 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19556 unregister : function(el){
19557 if(el instanceof Array){
19558 for(var i = 0, len = el.length; i < len; i++) {
19559 this.unregister(el[i]);
19568 * The number of pixels from the edge of a container the pointer needs to be to
19569 * trigger scrolling (defaults to 25)
19575 * The number of pixels to scroll in each scroll increment (defaults to 50)
19581 * The frequency of scrolls in milliseconds (defaults to 500)
19587 * True to animate the scroll (defaults to true)
19593 * The animation duration in seconds -
19594 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19600 * Manually trigger a cache refresh.
19602 refreshCache : function(){
19603 for(var id in els){
19604 if(typeof els[id] == 'object'){ // for people extending the object prototype
19605 els[id]._region = els[id].getRegion();
19612 * Ext JS Library 1.1.1
19613 * Copyright(c) 2006-2007, Ext JS, LLC.
19615 * Originally Released Under LGPL - original licence link has changed is not relivant.
19618 * <script type="text/javascript">
19623 * @class Roo.dd.Registry
19624 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19625 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19628 Roo.dd.Registry = function(){
19631 var autoIdSeed = 0;
19633 var getId = function(el, autogen){
19634 if(typeof el == "string"){
19638 if(!id && autogen !== false){
19639 id = "roodd-" + (++autoIdSeed);
19647 * Register a drag drop element
19648 * @param {String|HTMLElement} element The id or DOM node to register
19649 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19650 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19651 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19652 * populated in the data object (if applicable):
19654 Value Description<br />
19655 --------- ------------------------------------------<br />
19656 handles Array of DOM nodes that trigger dragging<br />
19657 for the element being registered<br />
19658 isHandle True if the element passed in triggers<br />
19659 dragging itself, else false
19662 register : function(el, data){
19664 if(typeof el == "string"){
19665 el = document.getElementById(el);
19668 elements[getId(el)] = data;
19669 if(data.isHandle !== false){
19670 handles[data.ddel.id] = data;
19673 var hs = data.handles;
19674 for(var i = 0, len = hs.length; i < len; i++){
19675 handles[getId(hs[i])] = data;
19681 * Unregister a drag drop element
19682 * @param {String|HTMLElement} element The id or DOM node to unregister
19684 unregister : function(el){
19685 var id = getId(el, false);
19686 var data = elements[id];
19688 delete elements[id];
19690 var hs = data.handles;
19691 for(var i = 0, len = hs.length; i < len; i++){
19692 delete handles[getId(hs[i], false)];
19699 * Returns the handle registered for a DOM Node by id
19700 * @param {String|HTMLElement} id The DOM node or id to look up
19701 * @return {Object} handle The custom handle data
19703 getHandle : function(id){
19704 if(typeof id != "string"){ // must be element?
19707 return handles[id];
19711 * Returns the handle that is registered for the DOM node that is the target of the event
19712 * @param {Event} e The event
19713 * @return {Object} handle The custom handle data
19715 getHandleFromEvent : function(e){
19716 var t = Roo.lib.Event.getTarget(e);
19717 return t ? handles[t.id] : null;
19721 * Returns a custom data object that is registered for a DOM node by id
19722 * @param {String|HTMLElement} id The DOM node or id to look up
19723 * @return {Object} data The custom data
19725 getTarget : function(id){
19726 if(typeof id != "string"){ // must be element?
19729 return elements[id];
19733 * Returns a custom data object that is registered for the DOM node that is the target of the event
19734 * @param {Event} e The event
19735 * @return {Object} data The custom data
19737 getTargetFromEvent : function(e){
19738 var t = Roo.lib.Event.getTarget(e);
19739 return t ? elements[t.id] || handles[t.id] : null;
19744 * Ext JS Library 1.1.1
19745 * Copyright(c) 2006-2007, Ext JS, LLC.
19747 * Originally Released Under LGPL - original licence link has changed is not relivant.
19750 * <script type="text/javascript">
19755 * @class Roo.dd.StatusProxy
19756 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19757 * default drag proxy used by all Roo.dd components.
19759 * @param {Object} config
19761 Roo.dd.StatusProxy = function(config){
19762 Roo.apply(this, config);
19763 this.id = this.id || Roo.id();
19764 this.el = new Roo.Layer({
19766 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19767 {tag: "div", cls: "x-dd-drop-icon"},
19768 {tag: "div", cls: "x-dd-drag-ghost"}
19771 shadow: !config || config.shadow !== false
19773 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19774 this.dropStatus = this.dropNotAllowed;
19777 Roo.dd.StatusProxy.prototype = {
19779 * @cfg {String} dropAllowed
19780 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19782 dropAllowed : "x-dd-drop-ok",
19784 * @cfg {String} dropNotAllowed
19785 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19787 dropNotAllowed : "x-dd-drop-nodrop",
19790 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19791 * over the current target element.
19792 * @param {String} cssClass The css class for the new drop status indicator image
19794 setStatus : function(cssClass){
19795 cssClass = cssClass || this.dropNotAllowed;
19796 if(this.dropStatus != cssClass){
19797 this.el.replaceClass(this.dropStatus, cssClass);
19798 this.dropStatus = cssClass;
19803 * Resets the status indicator to the default dropNotAllowed value
19804 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19806 reset : function(clearGhost){
19807 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19808 this.dropStatus = this.dropNotAllowed;
19810 this.ghost.update("");
19815 * Updates the contents of the ghost element
19816 * @param {String} html The html that will replace the current innerHTML of the ghost element
19818 update : function(html){
19819 if(typeof html == "string"){
19820 this.ghost.update(html);
19822 this.ghost.update("");
19823 html.style.margin = "0";
19824 this.ghost.dom.appendChild(html);
19826 // ensure float = none set?? cant remember why though.
19827 var el = this.ghost.dom.firstChild;
19829 Roo.fly(el).setStyle('float', 'none');
19834 * Returns the underlying proxy {@link Roo.Layer}
19835 * @return {Roo.Layer} el
19837 getEl : function(){
19842 * Returns the ghost element
19843 * @return {Roo.Element} el
19845 getGhost : function(){
19851 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19853 hide : function(clear){
19861 * Stops the repair animation if it's currently running
19864 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19870 * Displays this proxy
19877 * Force the Layer to sync its shadow and shim positions to the element
19884 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19885 * invalid drop operation by the item being dragged.
19886 * @param {Array} xy The XY position of the element ([x, y])
19887 * @param {Function} callback The function to call after the repair is complete
19888 * @param {Object} scope The scope in which to execute the callback
19890 repair : function(xy, callback, scope){
19891 this.callback = callback;
19892 this.scope = scope;
19893 if(xy && this.animRepair !== false){
19894 this.el.addClass("x-dd-drag-repair");
19895 this.el.hideUnders(true);
19896 this.anim = this.el.shift({
19897 duration: this.repairDuration || .5,
19901 callback: this.afterRepair,
19905 this.afterRepair();
19910 afterRepair : function(){
19912 if(typeof this.callback == "function"){
19913 this.callback.call(this.scope || this);
19915 this.callback = null;
19920 * Ext JS Library 1.1.1
19921 * Copyright(c) 2006-2007, Ext JS, LLC.
19923 * Originally Released Under LGPL - original licence link has changed is not relivant.
19926 * <script type="text/javascript">
19930 * @class Roo.dd.DragSource
19931 * @extends Roo.dd.DDProxy
19932 * A simple class that provides the basic implementation needed to make any element draggable.
19934 * @param {String/HTMLElement/Element} el The container element
19935 * @param {Object} config
19937 Roo.dd.DragSource = function(el, config){
19938 this.el = Roo.get(el);
19939 this.dragData = {};
19941 Roo.apply(this, config);
19944 this.proxy = new Roo.dd.StatusProxy();
19947 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
19948 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
19950 this.dragging = false;
19953 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
19955 * @cfg {String} dropAllowed
19956 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
19958 dropAllowed : "x-dd-drop-ok",
19960 * @cfg {String} dropNotAllowed
19961 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
19963 dropNotAllowed : "x-dd-drop-nodrop",
19966 * Returns the data object associated with this drag source
19967 * @return {Object} data An object containing arbitrary data
19969 getDragData : function(e){
19970 return this.dragData;
19974 onDragEnter : function(e, id){
19975 var target = Roo.dd.DragDropMgr.getDDById(id);
19976 this.cachedTarget = target;
19977 if(this.beforeDragEnter(target, e, id) !== false){
19978 if(target.isNotifyTarget){
19979 var status = target.notifyEnter(this, e, this.dragData);
19980 this.proxy.setStatus(status);
19982 this.proxy.setStatus(this.dropAllowed);
19985 if(this.afterDragEnter){
19987 * An empty function by default, but provided so that you can perform a custom action
19988 * when the dragged item enters the drop target by providing an implementation.
19989 * @param {Roo.dd.DragDrop} target The drop target
19990 * @param {Event} e The event object
19991 * @param {String} id The id of the dragged element
19992 * @method afterDragEnter
19994 this.afterDragEnter(target, e, id);
20000 * An empty function by default, but provided so that you can perform a custom action
20001 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
20002 * @param {Roo.dd.DragDrop} target The drop target
20003 * @param {Event} e The event object
20004 * @param {String} id The id of the dragged element
20005 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20007 beforeDragEnter : function(target, e, id){
20012 alignElWithMouse: function() {
20013 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
20018 onDragOver : function(e, id){
20019 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20020 if(this.beforeDragOver(target, e, id) !== false){
20021 if(target.isNotifyTarget){
20022 var status = target.notifyOver(this, e, this.dragData);
20023 this.proxy.setStatus(status);
20026 if(this.afterDragOver){
20028 * An empty function by default, but provided so that you can perform a custom action
20029 * while the dragged item is over the drop target by providing an implementation.
20030 * @param {Roo.dd.DragDrop} target The drop target
20031 * @param {Event} e The event object
20032 * @param {String} id The id of the dragged element
20033 * @method afterDragOver
20035 this.afterDragOver(target, e, id);
20041 * An empty function by default, but provided so that you can perform a custom action
20042 * while the dragged item is over the drop target and optionally cancel the onDragOver.
20043 * @param {Roo.dd.DragDrop} target The drop target
20044 * @param {Event} e The event object
20045 * @param {String} id The id of the dragged element
20046 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20048 beforeDragOver : function(target, e, id){
20053 onDragOut : function(e, id){
20054 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20055 if(this.beforeDragOut(target, e, id) !== false){
20056 if(target.isNotifyTarget){
20057 target.notifyOut(this, e, this.dragData);
20059 this.proxy.reset();
20060 if(this.afterDragOut){
20062 * An empty function by default, but provided so that you can perform a custom action
20063 * after the dragged item is dragged out of the target without dropping.
20064 * @param {Roo.dd.DragDrop} target The drop target
20065 * @param {Event} e The event object
20066 * @param {String} id The id of the dragged element
20067 * @method afterDragOut
20069 this.afterDragOut(target, e, id);
20072 this.cachedTarget = null;
20076 * An empty function by default, but provided so that you can perform a custom action before the dragged
20077 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20078 * @param {Roo.dd.DragDrop} target The drop target
20079 * @param {Event} e The event object
20080 * @param {String} id The id of the dragged element
20081 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20083 beforeDragOut : function(target, e, id){
20088 onDragDrop : function(e, id){
20089 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20090 if(this.beforeDragDrop(target, e, id) !== false){
20091 if(target.isNotifyTarget){
20092 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20093 this.onValidDrop(target, e, id);
20095 this.onInvalidDrop(target, e, id);
20098 this.onValidDrop(target, e, id);
20101 if(this.afterDragDrop){
20103 * An empty function by default, but provided so that you can perform a custom action
20104 * after a valid drag drop has occurred by providing an implementation.
20105 * @param {Roo.dd.DragDrop} target The drop target
20106 * @param {Event} e The event object
20107 * @param {String} id The id of the dropped element
20108 * @method afterDragDrop
20110 this.afterDragDrop(target, e, id);
20113 delete this.cachedTarget;
20117 * An empty function by default, but provided so that you can perform a custom action before the dragged
20118 * item is dropped onto the target and optionally cancel the onDragDrop.
20119 * @param {Roo.dd.DragDrop} target The drop target
20120 * @param {Event} e The event object
20121 * @param {String} id The id of the dragged element
20122 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20124 beforeDragDrop : function(target, e, id){
20129 onValidDrop : function(target, e, id){
20131 if(this.afterValidDrop){
20133 * An empty function by default, but provided so that you can perform a custom action
20134 * after a valid drop has occurred by providing an implementation.
20135 * @param {Object} target The target DD
20136 * @param {Event} e The event object
20137 * @param {String} id The id of the dropped element
20138 * @method afterInvalidDrop
20140 this.afterValidDrop(target, e, id);
20145 getRepairXY : function(e, data){
20146 return this.el.getXY();
20150 onInvalidDrop : function(target, e, id){
20151 this.beforeInvalidDrop(target, e, id);
20152 if(this.cachedTarget){
20153 if(this.cachedTarget.isNotifyTarget){
20154 this.cachedTarget.notifyOut(this, e, this.dragData);
20156 this.cacheTarget = null;
20158 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20160 if(this.afterInvalidDrop){
20162 * An empty function by default, but provided so that you can perform a custom action
20163 * after an invalid drop has occurred by providing an implementation.
20164 * @param {Event} e The event object
20165 * @param {String} id The id of the dropped element
20166 * @method afterInvalidDrop
20168 this.afterInvalidDrop(e, id);
20173 afterRepair : function(){
20175 this.el.highlight(this.hlColor || "c3daf9");
20177 this.dragging = false;
20181 * An empty function by default, but provided so that you can perform a custom action after an invalid
20182 * drop has occurred.
20183 * @param {Roo.dd.DragDrop} target The drop target
20184 * @param {Event} e The event object
20185 * @param {String} id The id of the dragged element
20186 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20188 beforeInvalidDrop : function(target, e, id){
20193 handleMouseDown : function(e){
20194 if(this.dragging) {
20197 var data = this.getDragData(e);
20198 if(data && this.onBeforeDrag(data, e) !== false){
20199 this.dragData = data;
20201 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20206 * An empty function by default, but provided so that you can perform a custom action before the initial
20207 * drag event begins and optionally cancel it.
20208 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20209 * @param {Event} e The event object
20210 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20212 onBeforeDrag : function(data, e){
20217 * An empty function by default, but provided so that you can perform a custom action once the initial
20218 * drag event has begun. The drag cannot be canceled from this function.
20219 * @param {Number} x The x position of the click on the dragged object
20220 * @param {Number} y The y position of the click on the dragged object
20222 onStartDrag : Roo.emptyFn,
20224 // private - YUI override
20225 startDrag : function(x, y){
20226 this.proxy.reset();
20227 this.dragging = true;
20228 this.proxy.update("");
20229 this.onInitDrag(x, y);
20234 onInitDrag : function(x, y){
20235 var clone = this.el.dom.cloneNode(true);
20236 clone.id = Roo.id(); // prevent duplicate ids
20237 this.proxy.update(clone);
20238 this.onStartDrag(x, y);
20243 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20244 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20246 getProxy : function(){
20251 * Hides the drag source's {@link Roo.dd.StatusProxy}
20253 hideProxy : function(){
20255 this.proxy.reset(true);
20256 this.dragging = false;
20260 triggerCacheRefresh : function(){
20261 Roo.dd.DDM.refreshCache(this.groups);
20264 // private - override to prevent hiding
20265 b4EndDrag: function(e) {
20268 // private - override to prevent moving
20269 endDrag : function(e){
20270 this.onEndDrag(this.dragData, e);
20274 onEndDrag : function(data, e){
20277 // private - pin to cursor
20278 autoOffset : function(x, y) {
20279 this.setDelta(-12, -20);
20283 * Ext JS Library 1.1.1
20284 * Copyright(c) 2006-2007, Ext JS, LLC.
20286 * Originally Released Under LGPL - original licence link has changed is not relivant.
20289 * <script type="text/javascript">
20294 * @class Roo.dd.DropTarget
20295 * @extends Roo.dd.DDTarget
20296 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20297 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20299 * @param {String/HTMLElement/Element} el The container element
20300 * @param {Object} config
20302 Roo.dd.DropTarget = function(el, config){
20303 this.el = Roo.get(el);
20305 var listeners = false; ;
20306 if (config && config.listeners) {
20307 listeners= config.listeners;
20308 delete config.listeners;
20310 Roo.apply(this, config);
20312 if(this.containerScroll){
20313 Roo.dd.ScrollManager.register(this.el);
20317 * @scope Roo.dd.DropTarget
20322 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20323 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20324 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20326 * IMPORTANT : it should set this.overClass and this.dropAllowed
20328 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20329 * @param {Event} e The event
20330 * @param {Object} data An object containing arbitrary data supplied by the drag source
20336 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20337 * This method will be called on every mouse movement while the drag source is over the drop target.
20338 * This default implementation simply returns the dropAllowed config value.
20340 * IMPORTANT : it should set this.dropAllowed
20342 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20343 * @param {Event} e The event
20344 * @param {Object} data An object containing arbitrary data supplied by the drag source
20350 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20351 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20352 * overClass (if any) from the drop element.
20354 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20355 * @param {Event} e The event
20356 * @param {Object} data An object containing arbitrary data supplied by the drag source
20362 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20363 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20364 * implementation that does something to process the drop event and returns true so that the drag source's
20365 * repair action does not run.
20367 * IMPORTANT : it should set this.success
20369 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20370 * @param {Event} e The event
20371 * @param {Object} data An object containing arbitrary data supplied by the drag source
20377 Roo.dd.DropTarget.superclass.constructor.call( this,
20379 this.ddGroup || this.group,
20382 listeners : listeners || {}
20390 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20392 * @cfg {String} overClass
20393 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20396 * @cfg {String} ddGroup
20397 * The drag drop group to handle drop events for
20401 * @cfg {String} dropAllowed
20402 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20404 dropAllowed : "x-dd-drop-ok",
20406 * @cfg {String} dropNotAllowed
20407 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20409 dropNotAllowed : "x-dd-drop-nodrop",
20411 * @cfg {boolean} success
20412 * set this after drop listener..
20416 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20417 * if the drop point is valid for over/enter..
20424 isNotifyTarget : true,
20429 notifyEnter : function(dd, e, data)
20432 this.fireEvent('enter', dd, e, data);
20433 if(this.overClass){
20434 this.el.addClass(this.overClass);
20436 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20437 this.valid ? this.dropAllowed : this.dropNotAllowed
20444 notifyOver : function(dd, e, data)
20447 this.fireEvent('over', dd, e, data);
20448 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20449 this.valid ? this.dropAllowed : this.dropNotAllowed
20456 notifyOut : function(dd, e, data)
20458 this.fireEvent('out', dd, e, data);
20459 if(this.overClass){
20460 this.el.removeClass(this.overClass);
20467 notifyDrop : function(dd, e, data)
20469 this.success = false;
20470 this.fireEvent('drop', dd, e, data);
20471 return this.success;
20475 * Ext JS Library 1.1.1
20476 * Copyright(c) 2006-2007, Ext JS, LLC.
20478 * Originally Released Under LGPL - original licence link has changed is not relivant.
20481 * <script type="text/javascript">
20486 * @class Roo.dd.DragZone
20487 * @extends Roo.dd.DragSource
20488 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20489 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20491 * @param {String/HTMLElement/Element} el The container element
20492 * @param {Object} config
20494 Roo.dd.DragZone = function(el, config){
20495 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20496 if(this.containerScroll){
20497 Roo.dd.ScrollManager.register(this.el);
20501 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20503 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20504 * for auto scrolling during drag operations.
20507 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20508 * method after a failed drop (defaults to "c3daf9" - light blue)
20512 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20513 * for a valid target to drag based on the mouse down. Override this method
20514 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20515 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20516 * @param {EventObject} e The mouse down event
20517 * @return {Object} The dragData
20519 getDragData : function(e){
20520 return Roo.dd.Registry.getHandleFromEvent(e);
20524 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20525 * this.dragData.ddel
20526 * @param {Number} x The x position of the click on the dragged object
20527 * @param {Number} y The y position of the click on the dragged object
20528 * @return {Boolean} true to continue the drag, false to cancel
20530 onInitDrag : function(x, y){
20531 this.proxy.update(this.dragData.ddel.cloneNode(true));
20532 this.onStartDrag(x, y);
20537 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20539 afterRepair : function(){
20541 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20543 this.dragging = false;
20547 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20548 * the XY of this.dragData.ddel
20549 * @param {EventObject} e The mouse up event
20550 * @return {Array} The xy location (e.g. [100, 200])
20552 getRepairXY : function(e){
20553 return Roo.Element.fly(this.dragData.ddel).getXY();
20557 * Ext JS Library 1.1.1
20558 * Copyright(c) 2006-2007, Ext JS, LLC.
20560 * Originally Released Under LGPL - original licence link has changed is not relivant.
20563 * <script type="text/javascript">
20566 * @class Roo.dd.DropZone
20567 * @extends Roo.dd.DropTarget
20568 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20569 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20571 * @param {String/HTMLElement/Element} el The container element
20572 * @param {Object} config
20574 Roo.dd.DropZone = function(el, config){
20575 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20578 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20580 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20581 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20582 * provide your own custom lookup.
20583 * @param {Event} e The event
20584 * @return {Object} data The custom data
20586 getTargetFromEvent : function(e){
20587 return Roo.dd.Registry.getTargetFromEvent(e);
20591 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20592 * that it has registered. This method has no default implementation and should be overridden to provide
20593 * node-specific processing if necessary.
20594 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20595 * {@link #getTargetFromEvent} for this node)
20596 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20597 * @param {Event} e The event
20598 * @param {Object} data An object containing arbitrary data supplied by the drag source
20600 onNodeEnter : function(n, dd, e, data){
20605 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20606 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20607 * overridden to provide the proper feedback.
20608 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20609 * {@link #getTargetFromEvent} for this node)
20610 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20611 * @param {Event} e The event
20612 * @param {Object} data An object containing arbitrary data supplied by the drag source
20613 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20614 * underlying {@link Roo.dd.StatusProxy} can be updated
20616 onNodeOver : function(n, dd, e, data){
20617 return this.dropAllowed;
20621 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20622 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20623 * node-specific processing if necessary.
20624 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20625 * {@link #getTargetFromEvent} for this node)
20626 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20627 * @param {Event} e The event
20628 * @param {Object} data An object containing arbitrary data supplied by the drag source
20630 onNodeOut : function(n, dd, e, data){
20635 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20636 * the drop node. The default implementation returns false, so it should be overridden to provide the
20637 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20638 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20639 * {@link #getTargetFromEvent} for this node)
20640 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20641 * @param {Event} e The event
20642 * @param {Object} data An object containing arbitrary data supplied by the drag source
20643 * @return {Boolean} True if the drop was valid, else false
20645 onNodeDrop : function(n, dd, e, data){
20650 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20651 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20652 * it should be overridden to provide the proper feedback if necessary.
20653 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20654 * @param {Event} e The event
20655 * @param {Object} data An object containing arbitrary data supplied by the drag source
20656 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20657 * underlying {@link Roo.dd.StatusProxy} can be updated
20659 onContainerOver : function(dd, e, data){
20660 return this.dropNotAllowed;
20664 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20665 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20666 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20667 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20668 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20669 * @param {Event} e The event
20670 * @param {Object} data An object containing arbitrary data supplied by the drag source
20671 * @return {Boolean} True if the drop was valid, else false
20673 onContainerDrop : function(dd, e, data){
20678 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20679 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20680 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20681 * you should override this method and provide a custom implementation.
20682 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20683 * @param {Event} e The event
20684 * @param {Object} data An object containing arbitrary data supplied by the drag source
20685 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20686 * underlying {@link Roo.dd.StatusProxy} can be updated
20688 notifyEnter : function(dd, e, data){
20689 return this.dropNotAllowed;
20693 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20694 * This method will be called on every mouse movement while the drag source is over the drop zone.
20695 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20696 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20697 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20698 * registered node, it will call {@link #onContainerOver}.
20699 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20700 * @param {Event} e The event
20701 * @param {Object} data An object containing arbitrary data supplied by the drag source
20702 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20703 * underlying {@link Roo.dd.StatusProxy} can be updated
20705 notifyOver : function(dd, e, data){
20706 var n = this.getTargetFromEvent(e);
20707 if(!n){ // not over valid drop target
20708 if(this.lastOverNode){
20709 this.onNodeOut(this.lastOverNode, dd, e, data);
20710 this.lastOverNode = null;
20712 return this.onContainerOver(dd, e, data);
20714 if(this.lastOverNode != n){
20715 if(this.lastOverNode){
20716 this.onNodeOut(this.lastOverNode, dd, e, data);
20718 this.onNodeEnter(n, dd, e, data);
20719 this.lastOverNode = n;
20721 return this.onNodeOver(n, dd, e, data);
20725 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20726 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20727 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20728 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20729 * @param {Event} e The event
20730 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20732 notifyOut : function(dd, e, data){
20733 if(this.lastOverNode){
20734 this.onNodeOut(this.lastOverNode, dd, e, data);
20735 this.lastOverNode = null;
20740 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20741 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20742 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20743 * otherwise it will call {@link #onContainerDrop}.
20744 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20745 * @param {Event} e The event
20746 * @param {Object} data An object containing arbitrary data supplied by the drag source
20747 * @return {Boolean} True if the drop was valid, else false
20749 notifyDrop : function(dd, e, data){
20750 if(this.lastOverNode){
20751 this.onNodeOut(this.lastOverNode, dd, e, data);
20752 this.lastOverNode = null;
20754 var n = this.getTargetFromEvent(e);
20756 this.onNodeDrop(n, dd, e, data) :
20757 this.onContainerDrop(dd, e, data);
20761 triggerCacheRefresh : function(){
20762 Roo.dd.DDM.refreshCache(this.groups);
20766 * Ext JS Library 1.1.1
20767 * Copyright(c) 2006-2007, Ext JS, LLC.
20769 * Originally Released Under LGPL - original licence link has changed is not relivant.
20772 * <script type="text/javascript">
20777 * @class Roo.data.SortTypes
20779 * Defines the default sorting (casting?) comparison functions used when sorting data.
20781 Roo.data.SortTypes = {
20783 * Default sort that does nothing
20784 * @param {Mixed} s The value being converted
20785 * @return {Mixed} The comparison value
20787 none : function(s){
20792 * The regular expression used to strip tags
20796 stripTagsRE : /<\/?[^>]+>/gi,
20799 * Strips all HTML tags to sort on text only
20800 * @param {Mixed} s The value being converted
20801 * @return {String} The comparison value
20803 asText : function(s){
20804 return String(s).replace(this.stripTagsRE, "");
20808 * Strips all HTML tags to sort on text only - Case insensitive
20809 * @param {Mixed} s The value being converted
20810 * @return {String} The comparison value
20812 asUCText : function(s){
20813 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20817 * Case insensitive string
20818 * @param {Mixed} s The value being converted
20819 * @return {String} The comparison value
20821 asUCString : function(s) {
20822 return String(s).toUpperCase();
20827 * @param {Mixed} s The value being converted
20828 * @return {Number} The comparison value
20830 asDate : function(s) {
20834 if(s instanceof Date){
20835 return s.getTime();
20837 return Date.parse(String(s));
20842 * @param {Mixed} s The value being converted
20843 * @return {Float} The comparison value
20845 asFloat : function(s) {
20846 var val = parseFloat(String(s).replace(/,/g, ""));
20847 if(isNaN(val)) val = 0;
20853 * @param {Mixed} s The value being converted
20854 * @return {Number} The comparison value
20856 asInt : function(s) {
20857 var val = parseInt(String(s).replace(/,/g, ""));
20858 if(isNaN(val)) val = 0;
20863 * Ext JS Library 1.1.1
20864 * Copyright(c) 2006-2007, Ext JS, LLC.
20866 * Originally Released Under LGPL - original licence link has changed is not relivant.
20869 * <script type="text/javascript">
20873 * @class Roo.data.Record
20874 * Instances of this class encapsulate both record <em>definition</em> information, and record
20875 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20876 * to access Records cached in an {@link Roo.data.Store} object.<br>
20878 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20879 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20882 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20884 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20885 * {@link #create}. The parameters are the same.
20886 * @param {Array} data An associative Array of data values keyed by the field name.
20887 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20888 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20889 * not specified an integer id is generated.
20891 Roo.data.Record = function(data, id){
20892 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20897 * Generate a constructor for a specific record layout.
20898 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20899 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20900 * Each field definition object may contain the following properties: <ul>
20901 * <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,
20902 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20903 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20904 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20905 * is being used, then this is a string containing the javascript expression to reference the data relative to
20906 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20907 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20908 * this may be omitted.</p></li>
20909 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20910 * <ul><li>auto (Default, implies no conversion)</li>
20915 * <li>date</li></ul></p></li>
20916 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20917 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20918 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20919 * by the Reader into an object that will be stored in the Record. It is passed the
20920 * following parameters:<ul>
20921 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20923 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20925 * <br>usage:<br><pre><code>
20926 var TopicRecord = Roo.data.Record.create(
20927 {name: 'title', mapping: 'topic_title'},
20928 {name: 'author', mapping: 'username'},
20929 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20930 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20931 {name: 'lastPoster', mapping: 'user2'},
20932 {name: 'excerpt', mapping: 'post_text'}
20935 var myNewRecord = new TopicRecord({
20936 title: 'Do my job please',
20939 lastPost: new Date(),
20940 lastPoster: 'Animal',
20941 excerpt: 'No way dude!'
20943 myStore.add(myNewRecord);
20948 Roo.data.Record.create = function(o){
20949 var f = function(){
20950 f.superclass.constructor.apply(this, arguments);
20952 Roo.extend(f, Roo.data.Record);
20953 var p = f.prototype;
20954 p.fields = new Roo.util.MixedCollection(false, function(field){
20957 for(var i = 0, len = o.length; i < len; i++){
20958 p.fields.add(new Roo.data.Field(o[i]));
20960 f.getField = function(name){
20961 return p.fields.get(name);
20966 Roo.data.Record.AUTO_ID = 1000;
20967 Roo.data.Record.EDIT = 'edit';
20968 Roo.data.Record.REJECT = 'reject';
20969 Roo.data.Record.COMMIT = 'commit';
20971 Roo.data.Record.prototype = {
20973 * Readonly flag - true if this record has been modified.
20982 join : function(store){
20983 this.store = store;
20987 * Set the named field to the specified value.
20988 * @param {String} name The name of the field to set.
20989 * @param {Object} value The value to set the field to.
20991 set : function(name, value){
20992 if(this.data[name] == value){
20996 if(!this.modified){
20997 this.modified = {};
20999 if(typeof this.modified[name] == 'undefined'){
21000 this.modified[name] = this.data[name];
21002 this.data[name] = value;
21003 if(!this.editing && this.store){
21004 this.store.afterEdit(this);
21009 * Get the value of the named field.
21010 * @param {String} name The name of the field to get the value of.
21011 * @return {Object} The value of the field.
21013 get : function(name){
21014 return this.data[name];
21018 beginEdit : function(){
21019 this.editing = true;
21020 this.modified = {};
21024 cancelEdit : function(){
21025 this.editing = false;
21026 delete this.modified;
21030 endEdit : function(){
21031 this.editing = false;
21032 if(this.dirty && this.store){
21033 this.store.afterEdit(this);
21038 * Usually called by the {@link Roo.data.Store} which owns the Record.
21039 * Rejects all changes made to the Record since either creation, or the last commit operation.
21040 * Modified fields are reverted to their original values.
21042 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21043 * of reject operations.
21045 reject : function(){
21046 var m = this.modified;
21048 if(typeof m[n] != "function"){
21049 this.data[n] = m[n];
21052 this.dirty = false;
21053 delete this.modified;
21054 this.editing = false;
21056 this.store.afterReject(this);
21061 * Usually called by the {@link Roo.data.Store} which owns the Record.
21062 * Commits all changes made to the Record since either creation, or the last commit operation.
21064 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21065 * of commit operations.
21067 commit : function(){
21068 this.dirty = false;
21069 delete this.modified;
21070 this.editing = false;
21072 this.store.afterCommit(this);
21077 hasError : function(){
21078 return this.error != null;
21082 clearError : function(){
21087 * Creates a copy of this record.
21088 * @param {String} id (optional) A new record id if you don't want to use this record's id
21091 copy : function(newId) {
21092 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21096 * Ext JS Library 1.1.1
21097 * Copyright(c) 2006-2007, Ext JS, LLC.
21099 * Originally Released Under LGPL - original licence link has changed is not relivant.
21102 * <script type="text/javascript">
21108 * @class Roo.data.Store
21109 * @extends Roo.util.Observable
21110 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21111 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21113 * 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
21114 * has no knowledge of the format of the data returned by the Proxy.<br>
21116 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21117 * instances from the data object. These records are cached and made available through accessor functions.
21119 * Creates a new Store.
21120 * @param {Object} config A config object containing the objects needed for the Store to access data,
21121 * and read the data into Records.
21123 Roo.data.Store = function(config){
21124 this.data = new Roo.util.MixedCollection(false);
21125 this.data.getKey = function(o){
21128 this.baseParams = {};
21130 this.paramNames = {
21135 "multisort" : "_multisort"
21138 if(config && config.data){
21139 this.inlineData = config.data;
21140 delete config.data;
21143 Roo.apply(this, config);
21145 if(this.reader){ // reader passed
21146 this.reader = Roo.factory(this.reader, Roo.data);
21147 this.reader.xmodule = this.xmodule || false;
21148 if(!this.recordType){
21149 this.recordType = this.reader.recordType;
21151 if(this.reader.onMetaChange){
21152 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21156 if(this.recordType){
21157 this.fields = this.recordType.prototype.fields;
21159 this.modified = [];
21163 * @event datachanged
21164 * Fires when the data cache has changed, and a widget which is using this Store
21165 * as a Record cache should refresh its view.
21166 * @param {Store} this
21168 datachanged : true,
21170 * @event metachange
21171 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21172 * @param {Store} this
21173 * @param {Object} meta The JSON metadata
21178 * Fires when Records have been added to the Store
21179 * @param {Store} this
21180 * @param {Roo.data.Record[]} records The array of Records added
21181 * @param {Number} index The index at which the record(s) were added
21186 * Fires when a Record has been removed from the Store
21187 * @param {Store} this
21188 * @param {Roo.data.Record} record The Record that was removed
21189 * @param {Number} index The index at which the record was removed
21194 * Fires when a Record has been updated
21195 * @param {Store} this
21196 * @param {Roo.data.Record} record The Record that was updated
21197 * @param {String} operation The update operation being performed. Value may be one of:
21199 Roo.data.Record.EDIT
21200 Roo.data.Record.REJECT
21201 Roo.data.Record.COMMIT
21207 * Fires when the data cache has been cleared.
21208 * @param {Store} this
21212 * @event beforeload
21213 * Fires before a request is made for a new data object. If the beforeload handler returns false
21214 * the load action will be canceled.
21215 * @param {Store} this
21216 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21220 * @event beforeloadadd
21221 * Fires after a new set of Records has been loaded.
21222 * @param {Store} this
21223 * @param {Roo.data.Record[]} records The Records that were loaded
21224 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21226 beforeloadadd : true,
21229 * Fires after a new set of Records has been loaded, before they are added to the store.
21230 * @param {Store} this
21231 * @param {Roo.data.Record[]} records The Records that were loaded
21232 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21233 * @params {Object} return from reader
21237 * @event loadexception
21238 * Fires if an exception occurs in the Proxy during loading.
21239 * Called with the signature of the Proxy's "loadexception" event.
21240 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21243 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21244 * @param {Object} load options
21245 * @param {Object} jsonData from your request (normally this contains the Exception)
21247 loadexception : true
21251 this.proxy = Roo.factory(this.proxy, Roo.data);
21252 this.proxy.xmodule = this.xmodule || false;
21253 this.relayEvents(this.proxy, ["loadexception"]);
21255 this.sortToggle = {};
21256 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21258 Roo.data.Store.superclass.constructor.call(this);
21260 if(this.inlineData){
21261 this.loadData(this.inlineData);
21262 delete this.inlineData;
21266 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21268 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21269 * without a remote query - used by combo/forms at present.
21273 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21276 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21279 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21280 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21283 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21284 * on any HTTP request
21287 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21290 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21294 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21295 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21297 remoteSort : false,
21300 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21301 * loaded or when a record is removed. (defaults to false).
21303 pruneModifiedRecords : false,
21306 lastOptions : null,
21309 * Add Records to the Store and fires the add event.
21310 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21312 add : function(records){
21313 records = [].concat(records);
21314 for(var i = 0, len = records.length; i < len; i++){
21315 records[i].join(this);
21317 var index = this.data.length;
21318 this.data.addAll(records);
21319 this.fireEvent("add", this, records, index);
21323 * Remove a Record from the Store and fires the remove event.
21324 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21326 remove : function(record){
21327 var index = this.data.indexOf(record);
21328 this.data.removeAt(index);
21329 if(this.pruneModifiedRecords){
21330 this.modified.remove(record);
21332 this.fireEvent("remove", this, record, index);
21336 * Remove all Records from the Store and fires the clear event.
21338 removeAll : function(){
21340 if(this.pruneModifiedRecords){
21341 this.modified = [];
21343 this.fireEvent("clear", this);
21347 * Inserts Records to the Store at the given index and fires the add event.
21348 * @param {Number} index The start index at which to insert the passed Records.
21349 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21351 insert : function(index, records){
21352 records = [].concat(records);
21353 for(var i = 0, len = records.length; i < len; i++){
21354 this.data.insert(index, records[i]);
21355 records[i].join(this);
21357 this.fireEvent("add", this, records, index);
21361 * Get the index within the cache of the passed Record.
21362 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21363 * @return {Number} The index of the passed Record. Returns -1 if not found.
21365 indexOf : function(record){
21366 return this.data.indexOf(record);
21370 * Get the index within the cache of the Record with the passed id.
21371 * @param {String} id The id of the Record to find.
21372 * @return {Number} The index of the Record. Returns -1 if not found.
21374 indexOfId : function(id){
21375 return this.data.indexOfKey(id);
21379 * Get the Record with the specified id.
21380 * @param {String} id The id of the Record to find.
21381 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21383 getById : function(id){
21384 return this.data.key(id);
21388 * Get the Record at the specified index.
21389 * @param {Number} index The index of the Record to find.
21390 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21392 getAt : function(index){
21393 return this.data.itemAt(index);
21397 * Returns a range of Records between specified indices.
21398 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21399 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21400 * @return {Roo.data.Record[]} An array of Records
21402 getRange : function(start, end){
21403 return this.data.getRange(start, end);
21407 storeOptions : function(o){
21408 o = Roo.apply({}, o);
21411 this.lastOptions = o;
21415 * Loads the Record cache from the configured Proxy using the configured Reader.
21417 * If using remote paging, then the first load call must specify the <em>start</em>
21418 * and <em>limit</em> properties in the options.params property to establish the initial
21419 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21421 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21422 * and this call will return before the new data has been loaded. Perform any post-processing
21423 * in a callback function, or in a "load" event handler.</strong>
21425 * @param {Object} options An object containing properties which control loading options:<ul>
21426 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21427 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21428 * passed the following arguments:<ul>
21429 * <li>r : Roo.data.Record[]</li>
21430 * <li>options: Options object from the load call</li>
21431 * <li>success: Boolean success indicator</li></ul></li>
21432 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21433 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21436 load : function(options){
21437 options = options || {};
21438 if(this.fireEvent("beforeload", this, options) !== false){
21439 this.storeOptions(options);
21440 var p = Roo.apply(options.params || {}, this.baseParams);
21441 // if meta was not loaded from remote source.. try requesting it.
21442 if (!this.reader.metaFromRemote) {
21443 p._requestMeta = 1;
21445 if(this.sortInfo && this.remoteSort){
21446 var pn = this.paramNames;
21447 p[pn["sort"]] = this.sortInfo.field;
21448 p[pn["dir"]] = this.sortInfo.direction;
21450 if (this.multiSort) {
21451 var pn = this.paramNames;
21452 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21455 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21460 * Reloads the Record cache from the configured Proxy using the configured Reader and
21461 * the options from the last load operation performed.
21462 * @param {Object} options (optional) An object containing properties which may override the options
21463 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21464 * the most recently used options are reused).
21466 reload : function(options){
21467 this.load(Roo.applyIf(options||{}, this.lastOptions));
21471 // Called as a callback by the Reader during a load operation.
21472 loadRecords : function(o, options, success){
21473 if(!o || success === false){
21474 if(success !== false){
21475 this.fireEvent("load", this, [], options, o);
21477 if(options.callback){
21478 options.callback.call(options.scope || this, [], options, false);
21482 // if data returned failure - throw an exception.
21483 if (o.success === false) {
21484 // show a message if no listener is registered.
21485 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21486 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21488 // loadmask wil be hooked into this..
21489 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21492 var r = o.records, t = o.totalRecords || r.length;
21494 this.fireEvent("beforeloadadd", this, r, options, o);
21496 if(!options || options.add !== true){
21497 if(this.pruneModifiedRecords){
21498 this.modified = [];
21500 for(var i = 0, len = r.length; i < len; i++){
21504 this.data = this.snapshot;
21505 delete this.snapshot;
21508 this.data.addAll(r);
21509 this.totalLength = t;
21511 this.fireEvent("datachanged", this);
21513 this.totalLength = Math.max(t, this.data.length+r.length);
21516 this.fireEvent("load", this, r, options, o);
21517 if(options.callback){
21518 options.callback.call(options.scope || this, r, options, true);
21524 * Loads data from a passed data block. A Reader which understands the format of the data
21525 * must have been configured in the constructor.
21526 * @param {Object} data The data block from which to read the Records. The format of the data expected
21527 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21528 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21530 loadData : function(o, append){
21531 var r = this.reader.readRecords(o);
21532 this.loadRecords(r, {add: append}, true);
21536 * Gets the number of cached records.
21538 * <em>If using paging, this may not be the total size of the dataset. If the data object
21539 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21540 * the data set size</em>
21542 getCount : function(){
21543 return this.data.length || 0;
21547 * Gets the total number of records in the dataset as returned by the server.
21549 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21550 * the dataset size</em>
21552 getTotalCount : function(){
21553 return this.totalLength || 0;
21557 * Returns the sort state of the Store as an object with two properties:
21559 field {String} The name of the field by which the Records are sorted
21560 direction {String} The sort order, "ASC" or "DESC"
21563 getSortState : function(){
21564 return this.sortInfo;
21568 applySort : function(){
21569 if(this.sortInfo && !this.remoteSort){
21570 var s = this.sortInfo, f = s.field;
21571 var st = this.fields.get(f).sortType;
21572 var fn = function(r1, r2){
21573 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21574 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21576 this.data.sort(s.direction, fn);
21577 if(this.snapshot && this.snapshot != this.data){
21578 this.snapshot.sort(s.direction, fn);
21584 * Sets the default sort column and order to be used by the next load operation.
21585 * @param {String} fieldName The name of the field to sort by.
21586 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21588 setDefaultSort : function(field, dir){
21589 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21593 * Sort the Records.
21594 * If remote sorting is used, the sort is performed on the server, and the cache is
21595 * reloaded. If local sorting is used, the cache is sorted internally.
21596 * @param {String} fieldName The name of the field to sort by.
21597 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21599 sort : function(fieldName, dir){
21600 var f = this.fields.get(fieldName);
21602 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21604 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21605 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21610 this.sortToggle[f.name] = dir;
21611 this.sortInfo = {field: f.name, direction: dir};
21612 if(!this.remoteSort){
21614 this.fireEvent("datachanged", this);
21616 this.load(this.lastOptions);
21621 * Calls the specified function for each of the Records in the cache.
21622 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21623 * Returning <em>false</em> aborts and exits the iteration.
21624 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21626 each : function(fn, scope){
21627 this.data.each(fn, scope);
21631 * Gets all records modified since the last commit. Modified records are persisted across load operations
21632 * (e.g., during paging).
21633 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21635 getModifiedRecords : function(){
21636 return this.modified;
21640 createFilterFn : function(property, value, anyMatch){
21641 if(!value.exec){ // not a regex
21642 value = String(value);
21643 if(value.length == 0){
21646 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21648 return function(r){
21649 return value.test(r.data[property]);
21654 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21655 * @param {String} property A field on your records
21656 * @param {Number} start The record index to start at (defaults to 0)
21657 * @param {Number} end The last record index to include (defaults to length - 1)
21658 * @return {Number} The sum
21660 sum : function(property, start, end){
21661 var rs = this.data.items, v = 0;
21662 start = start || 0;
21663 end = (end || end === 0) ? end : rs.length-1;
21665 for(var i = start; i <= end; i++){
21666 v += (rs[i].data[property] || 0);
21672 * Filter the records by a specified property.
21673 * @param {String} field A field on your records
21674 * @param {String/RegExp} value Either a string that the field
21675 * should start with or a RegExp to test against the field
21676 * @param {Boolean} anyMatch True to match any part not just the beginning
21678 filter : function(property, value, anyMatch){
21679 var fn = this.createFilterFn(property, value, anyMatch);
21680 return fn ? this.filterBy(fn) : this.clearFilter();
21684 * Filter by a function. The specified function will be called with each
21685 * record in this data source. If the function returns true the record is included,
21686 * otherwise it is filtered.
21687 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21688 * @param {Object} scope (optional) The scope of the function (defaults to this)
21690 filterBy : function(fn, scope){
21691 this.snapshot = this.snapshot || this.data;
21692 this.data = this.queryBy(fn, scope||this);
21693 this.fireEvent("datachanged", this);
21697 * Query the records by a specified property.
21698 * @param {String} field A field on your records
21699 * @param {String/RegExp} value Either a string that the field
21700 * should start with or a RegExp to test against the field
21701 * @param {Boolean} anyMatch True to match any part not just the beginning
21702 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21704 query : function(property, value, anyMatch){
21705 var fn = this.createFilterFn(property, value, anyMatch);
21706 return fn ? this.queryBy(fn) : this.data.clone();
21710 * Query by a function. The specified function will be called with each
21711 * record in this data source. If the function returns true the record is included
21713 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21714 * @param {Object} scope (optional) The scope of the function (defaults to this)
21715 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21717 queryBy : function(fn, scope){
21718 var data = this.snapshot || this.data;
21719 return data.filterBy(fn, scope||this);
21723 * Collects unique values for a particular dataIndex from this store.
21724 * @param {String} dataIndex The property to collect
21725 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21726 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21727 * @return {Array} An array of the unique values
21729 collect : function(dataIndex, allowNull, bypassFilter){
21730 var d = (bypassFilter === true && this.snapshot) ?
21731 this.snapshot.items : this.data.items;
21732 var v, sv, r = [], l = {};
21733 for(var i = 0, len = d.length; i < len; i++){
21734 v = d[i].data[dataIndex];
21736 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21745 * Revert to a view of the Record cache with no filtering applied.
21746 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21748 clearFilter : function(suppressEvent){
21749 if(this.snapshot && this.snapshot != this.data){
21750 this.data = this.snapshot;
21751 delete this.snapshot;
21752 if(suppressEvent !== true){
21753 this.fireEvent("datachanged", this);
21759 afterEdit : function(record){
21760 if(this.modified.indexOf(record) == -1){
21761 this.modified.push(record);
21763 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21767 afterReject : function(record){
21768 this.modified.remove(record);
21769 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21773 afterCommit : function(record){
21774 this.modified.remove(record);
21775 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21779 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21780 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21782 commitChanges : function(){
21783 var m = this.modified.slice(0);
21784 this.modified = [];
21785 for(var i = 0, len = m.length; i < len; i++){
21791 * Cancel outstanding changes on all changed records.
21793 rejectChanges : function(){
21794 var m = this.modified.slice(0);
21795 this.modified = [];
21796 for(var i = 0, len = m.length; i < len; i++){
21801 onMetaChange : function(meta, rtype, o){
21802 this.recordType = rtype;
21803 this.fields = rtype.prototype.fields;
21804 delete this.snapshot;
21805 this.sortInfo = meta.sortInfo || this.sortInfo;
21806 this.modified = [];
21807 this.fireEvent('metachange', this, this.reader.meta);
21810 moveIndex : function(data, type)
21812 var index = this.indexOf(data);
21814 var newIndex = index + type;
21818 this.insert(newIndex, data);
21823 * Ext JS Library 1.1.1
21824 * Copyright(c) 2006-2007, Ext JS, LLC.
21826 * Originally Released Under LGPL - original licence link has changed is not relivant.
21829 * <script type="text/javascript">
21833 * @class Roo.data.SimpleStore
21834 * @extends Roo.data.Store
21835 * Small helper class to make creating Stores from Array data easier.
21836 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21837 * @cfg {Array} fields An array of field definition objects, or field name strings.
21838 * @cfg {Array} data The multi-dimensional array of data
21840 * @param {Object} config
21842 Roo.data.SimpleStore = function(config){
21843 Roo.data.SimpleStore.superclass.constructor.call(this, {
21845 reader: new Roo.data.ArrayReader({
21848 Roo.data.Record.create(config.fields)
21850 proxy : new Roo.data.MemoryProxy(config.data)
21854 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21856 * Ext JS Library 1.1.1
21857 * Copyright(c) 2006-2007, Ext JS, LLC.
21859 * Originally Released Under LGPL - original licence link has changed is not relivant.
21862 * <script type="text/javascript">
21867 * @extends Roo.data.Store
21868 * @class Roo.data.JsonStore
21869 * Small helper class to make creating Stores for JSON data easier. <br/>
21871 var store = new Roo.data.JsonStore({
21872 url: 'get-images.php',
21874 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21877 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21878 * JsonReader and HttpProxy (unless inline data is provided).</b>
21879 * @cfg {Array} fields An array of field definition objects, or field name strings.
21881 * @param {Object} config
21883 Roo.data.JsonStore = function(c){
21884 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21885 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21886 reader: new Roo.data.JsonReader(c, c.fields)
21889 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21891 * Ext JS Library 1.1.1
21892 * Copyright(c) 2006-2007, Ext JS, LLC.
21894 * Originally Released Under LGPL - original licence link has changed is not relivant.
21897 * <script type="text/javascript">
21901 Roo.data.Field = function(config){
21902 if(typeof config == "string"){
21903 config = {name: config};
21905 Roo.apply(this, config);
21908 this.type = "auto";
21911 var st = Roo.data.SortTypes;
21912 // named sortTypes are supported, here we look them up
21913 if(typeof this.sortType == "string"){
21914 this.sortType = st[this.sortType];
21917 // set default sortType for strings and dates
21918 if(!this.sortType){
21921 this.sortType = st.asUCString;
21924 this.sortType = st.asDate;
21927 this.sortType = st.none;
21932 var stripRe = /[\$,%]/g;
21934 // prebuilt conversion function for this field, instead of
21935 // switching every time we're reading a value
21937 var cv, dateFormat = this.dateFormat;
21942 cv = function(v){ return v; };
21945 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
21949 return v !== undefined && v !== null && v !== '' ?
21950 parseInt(String(v).replace(stripRe, ""), 10) : '';
21955 return v !== undefined && v !== null && v !== '' ?
21956 parseFloat(String(v).replace(stripRe, ""), 10) : '';
21961 cv = function(v){ return v === true || v === "true" || v == 1; };
21968 if(v instanceof Date){
21972 if(dateFormat == "timestamp"){
21973 return new Date(v*1000);
21975 return Date.parseDate(v, dateFormat);
21977 var parsed = Date.parse(v);
21978 return parsed ? new Date(parsed) : null;
21987 Roo.data.Field.prototype = {
21995 * Ext JS Library 1.1.1
21996 * Copyright(c) 2006-2007, Ext JS, LLC.
21998 * Originally Released Under LGPL - original licence link has changed is not relivant.
22001 * <script type="text/javascript">
22004 // Base class for reading structured data from a data source. This class is intended to be
22005 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
22008 * @class Roo.data.DataReader
22009 * Base class for reading structured data from a data source. This class is intended to be
22010 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
22013 Roo.data.DataReader = function(meta, recordType){
22017 this.recordType = recordType instanceof Array ?
22018 Roo.data.Record.create(recordType) : recordType;
22021 Roo.data.DataReader.prototype = {
22023 * Create an empty record
22024 * @param {Object} data (optional) - overlay some values
22025 * @return {Roo.data.Record} record created.
22027 newRow : function(d) {
22029 this.recordType.prototype.fields.each(function(c) {
22031 case 'int' : da[c.name] = 0; break;
22032 case 'date' : da[c.name] = new Date(); break;
22033 case 'float' : da[c.name] = 0.0; break;
22034 case 'boolean' : da[c.name] = false; break;
22035 case 'array' : da[c.name] = []; break;
22036 default : da[c.name] = ""; break;
22040 return new this.recordType(Roo.apply(da, d));
22045 * Ext JS Library 1.1.1
22046 * Copyright(c) 2006-2007, Ext JS, LLC.
22048 * Originally Released Under LGPL - original licence link has changed is not relivant.
22051 * <script type="text/javascript">
22055 * @class Roo.data.DataProxy
22056 * @extends Roo.data.Observable
22057 * This class is an abstract base class for implementations which provide retrieval of
22058 * unformatted data objects.<br>
22060 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22061 * (of the appropriate type which knows how to parse the data object) to provide a block of
22062 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22064 * Custom implementations must implement the load method as described in
22065 * {@link Roo.data.HttpProxy#load}.
22067 Roo.data.DataProxy = function(){
22070 * @event beforeload
22071 * Fires before a network request is made to retrieve a data object.
22072 * @param {Object} This DataProxy object.
22073 * @param {Object} params The params parameter to the load function.
22078 * Fires before the load method's callback is called.
22079 * @param {Object} This DataProxy object.
22080 * @param {Object} o The data object.
22081 * @param {Object} arg The callback argument object passed to the load function.
22085 * @event loadexception
22086 * Fires if an Exception occurs during data retrieval.
22087 * @param {Object} This DataProxy object.
22088 * @param {Object} o The data object.
22089 * @param {Object} arg The callback argument object passed to the load function.
22090 * @param {Object} e The Exception.
22092 loadexception : true
22094 Roo.data.DataProxy.superclass.constructor.call(this);
22097 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22100 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22104 * Ext JS Library 1.1.1
22105 * Copyright(c) 2006-2007, Ext JS, LLC.
22107 * Originally Released Under LGPL - original licence link has changed is not relivant.
22110 * <script type="text/javascript">
22113 * @class Roo.data.MemoryProxy
22114 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22115 * to the Reader when its load method is called.
22117 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22119 Roo.data.MemoryProxy = function(data){
22123 Roo.data.MemoryProxy.superclass.constructor.call(this);
22127 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22129 * Load data from the requested source (in this case an in-memory
22130 * data object passed to the constructor), read the data object into
22131 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22132 * process that block using the passed callback.
22133 * @param {Object} params This parameter is not used by the MemoryProxy class.
22134 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22135 * object into a block of Roo.data.Records.
22136 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22137 * The function must be passed <ul>
22138 * <li>The Record block object</li>
22139 * <li>The "arg" argument from the load function</li>
22140 * <li>A boolean success indicator</li>
22142 * @param {Object} scope The scope in which to call the callback
22143 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22145 load : function(params, reader, callback, scope, arg){
22146 params = params || {};
22149 result = reader.readRecords(this.data);
22151 this.fireEvent("loadexception", this, arg, null, e);
22152 callback.call(scope, null, arg, false);
22155 callback.call(scope, result, arg, true);
22159 update : function(params, records){
22164 * Ext JS Library 1.1.1
22165 * Copyright(c) 2006-2007, Ext JS, LLC.
22167 * Originally Released Under LGPL - original licence link has changed is not relivant.
22170 * <script type="text/javascript">
22173 * @class Roo.data.HttpProxy
22174 * @extends Roo.data.DataProxy
22175 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22176 * configured to reference a certain URL.<br><br>
22178 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22179 * from which the running page was served.<br><br>
22181 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22183 * Be aware that to enable the browser to parse an XML document, the server must set
22184 * the Content-Type header in the HTTP response to "text/xml".
22186 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22187 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22188 * will be used to make the request.
22190 Roo.data.HttpProxy = function(conn){
22191 Roo.data.HttpProxy.superclass.constructor.call(this);
22192 // is conn a conn config or a real conn?
22194 this.useAjax = !conn || !conn.events;
22198 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22199 // thse are take from connection...
22202 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22205 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22206 * extra parameters to each request made by this object. (defaults to undefined)
22209 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22210 * to each request made by this object. (defaults to undefined)
22213 * @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)
22216 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22219 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22225 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22229 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22230 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22231 * a finer-grained basis than the DataProxy events.
22233 getConnection : function(){
22234 return this.useAjax ? Roo.Ajax : this.conn;
22238 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22239 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22240 * process that block using the passed callback.
22241 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22242 * for the request to the remote server.
22243 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22244 * object into a block of Roo.data.Records.
22245 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22246 * The function must be passed <ul>
22247 * <li>The Record block object</li>
22248 * <li>The "arg" argument from the load function</li>
22249 * <li>A boolean success indicator</li>
22251 * @param {Object} scope The scope in which to call the callback
22252 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22254 load : function(params, reader, callback, scope, arg){
22255 if(this.fireEvent("beforeload", this, params) !== false){
22257 params : params || {},
22259 callback : callback,
22264 callback : this.loadResponse,
22268 Roo.applyIf(o, this.conn);
22269 if(this.activeRequest){
22270 Roo.Ajax.abort(this.activeRequest);
22272 this.activeRequest = Roo.Ajax.request(o);
22274 this.conn.request(o);
22277 callback.call(scope||this, null, arg, false);
22282 loadResponse : function(o, success, response){
22283 delete this.activeRequest;
22285 this.fireEvent("loadexception", this, o, response);
22286 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22291 result = o.reader.read(response);
22293 this.fireEvent("loadexception", this, o, response, e);
22294 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22298 this.fireEvent("load", this, o, o.request.arg);
22299 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22303 update : function(dataSet){
22308 updateResponse : function(dataSet){
22313 * Ext JS Library 1.1.1
22314 * Copyright(c) 2006-2007, Ext JS, LLC.
22316 * Originally Released Under LGPL - original licence link has changed is not relivant.
22319 * <script type="text/javascript">
22323 * @class Roo.data.ScriptTagProxy
22324 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22325 * other than the originating domain of the running page.<br><br>
22327 * <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
22328 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22330 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22331 * source code that is used as the source inside a <script> tag.<br><br>
22333 * In order for the browser to process the returned data, the server must wrap the data object
22334 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22335 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22336 * depending on whether the callback name was passed:
22339 boolean scriptTag = false;
22340 String cb = request.getParameter("callback");
22343 response.setContentType("text/javascript");
22345 response.setContentType("application/x-json");
22347 Writer out = response.getWriter();
22349 out.write(cb + "(");
22351 out.print(dataBlock.toJsonString());
22358 * @param {Object} config A configuration object.
22360 Roo.data.ScriptTagProxy = function(config){
22361 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22362 Roo.apply(this, config);
22363 this.head = document.getElementsByTagName("head")[0];
22366 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22368 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22370 * @cfg {String} url The URL from which to request the data object.
22373 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22377 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22378 * the server the name of the callback function set up by the load call to process the returned data object.
22379 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22380 * javascript output which calls this named function passing the data object as its only parameter.
22382 callbackParam : "callback",
22384 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22385 * name to the request.
22390 * Load data from the configured URL, read the data object into
22391 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22392 * process that block using the passed callback.
22393 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22394 * for the request to the remote server.
22395 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22396 * object into a block of Roo.data.Records.
22397 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22398 * The function must be passed <ul>
22399 * <li>The Record block object</li>
22400 * <li>The "arg" argument from the load function</li>
22401 * <li>A boolean success indicator</li>
22403 * @param {Object} scope The scope in which to call the callback
22404 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22406 load : function(params, reader, callback, scope, arg){
22407 if(this.fireEvent("beforeload", this, params) !== false){
22409 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22411 var url = this.url;
22412 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22414 url += "&_dc=" + (new Date().getTime());
22416 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22419 cb : "stcCallback"+transId,
22420 scriptId : "stcScript"+transId,
22424 callback : callback,
22430 window[trans.cb] = function(o){
22431 conn.handleResponse(o, trans);
22434 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22436 if(this.autoAbort !== false){
22440 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22442 var script = document.createElement("script");
22443 script.setAttribute("src", url);
22444 script.setAttribute("type", "text/javascript");
22445 script.setAttribute("id", trans.scriptId);
22446 this.head.appendChild(script);
22448 this.trans = trans;
22450 callback.call(scope||this, null, arg, false);
22455 isLoading : function(){
22456 return this.trans ? true : false;
22460 * Abort the current server request.
22462 abort : function(){
22463 if(this.isLoading()){
22464 this.destroyTrans(this.trans);
22469 destroyTrans : function(trans, isLoaded){
22470 this.head.removeChild(document.getElementById(trans.scriptId));
22471 clearTimeout(trans.timeoutId);
22473 window[trans.cb] = undefined;
22475 delete window[trans.cb];
22478 // if hasn't been loaded, wait for load to remove it to prevent script error
22479 window[trans.cb] = function(){
22480 window[trans.cb] = undefined;
22482 delete window[trans.cb];
22489 handleResponse : function(o, trans){
22490 this.trans = false;
22491 this.destroyTrans(trans, true);
22494 result = trans.reader.readRecords(o);
22496 this.fireEvent("loadexception", this, o, trans.arg, e);
22497 trans.callback.call(trans.scope||window, null, trans.arg, false);
22500 this.fireEvent("load", this, o, trans.arg);
22501 trans.callback.call(trans.scope||window, result, trans.arg, true);
22505 handleFailure : function(trans){
22506 this.trans = false;
22507 this.destroyTrans(trans, false);
22508 this.fireEvent("loadexception", this, null, trans.arg);
22509 trans.callback.call(trans.scope||window, null, trans.arg, false);
22513 * Ext JS Library 1.1.1
22514 * Copyright(c) 2006-2007, Ext JS, LLC.
22516 * Originally Released Under LGPL - original licence link has changed is not relivant.
22519 * <script type="text/javascript">
22523 * @class Roo.data.JsonReader
22524 * @extends Roo.data.DataReader
22525 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22526 * based on mappings in a provided Roo.data.Record constructor.
22528 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22529 * in the reply previously.
22534 var RecordDef = Roo.data.Record.create([
22535 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22536 {name: 'occupation'} // This field will use "occupation" as the mapping.
22538 var myReader = new Roo.data.JsonReader({
22539 totalProperty: "results", // The property which contains the total dataset size (optional)
22540 root: "rows", // The property which contains an Array of row objects
22541 id: "id" // The property within each row object that provides an ID for the record (optional)
22545 * This would consume a JSON file like this:
22547 { 'results': 2, 'rows': [
22548 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22549 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22552 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22553 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22554 * paged from the remote server.
22555 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22556 * @cfg {String} root name of the property which contains the Array of row objects.
22557 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22559 * Create a new JsonReader
22560 * @param {Object} meta Metadata configuration options
22561 * @param {Object} recordType Either an Array of field definition objects,
22562 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22564 Roo.data.JsonReader = function(meta, recordType){
22567 // set some defaults:
22568 Roo.applyIf(meta, {
22569 totalProperty: 'total',
22570 successProperty : 'success',
22575 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22577 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22580 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22581 * Used by Store query builder to append _requestMeta to params.
22584 metaFromRemote : false,
22586 * This method is only used by a DataProxy which has retrieved data from a remote server.
22587 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22588 * @return {Object} data A data block which is used by an Roo.data.Store object as
22589 * a cache of Roo.data.Records.
22591 read : function(response){
22592 var json = response.responseText;
22594 var o = /* eval:var:o */ eval("("+json+")");
22596 throw {message: "JsonReader.read: Json object not found"};
22602 this.metaFromRemote = true;
22603 this.meta = o.metaData;
22604 this.recordType = Roo.data.Record.create(o.metaData.fields);
22605 this.onMetaChange(this.meta, this.recordType, o);
22607 return this.readRecords(o);
22610 // private function a store will implement
22611 onMetaChange : function(meta, recordType, o){
22618 simpleAccess: function(obj, subsc) {
22625 getJsonAccessor: function(){
22627 return function(expr) {
22629 return(re.test(expr))
22630 ? new Function("obj", "return obj." + expr)
22635 return Roo.emptyFn;
22640 * Create a data block containing Roo.data.Records from an XML document.
22641 * @param {Object} o An object which contains an Array of row objects in the property specified
22642 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22643 * which contains the total size of the dataset.
22644 * @return {Object} data A data block which is used by an Roo.data.Store object as
22645 * a cache of Roo.data.Records.
22647 readRecords : function(o){
22649 * After any data loads, the raw JSON data is available for further custom processing.
22653 var s = this.meta, Record = this.recordType,
22654 f = Record.prototype.fields, fi = f.items, fl = f.length;
22656 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22658 if(s.totalProperty) {
22659 this.getTotal = this.getJsonAccessor(s.totalProperty);
22661 if(s.successProperty) {
22662 this.getSuccess = this.getJsonAccessor(s.successProperty);
22664 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22666 var g = this.getJsonAccessor(s.id);
22667 this.getId = function(rec) {
22669 return (r === undefined || r === "") ? null : r;
22672 this.getId = function(){return null;};
22675 for(var jj = 0; jj < fl; jj++){
22677 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22678 this.ef[jj] = this.getJsonAccessor(map);
22682 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22683 if(s.totalProperty){
22684 var vt = parseInt(this.getTotal(o), 10);
22689 if(s.successProperty){
22690 var vs = this.getSuccess(o);
22691 if(vs === false || vs === 'false'){
22696 for(var i = 0; i < c; i++){
22699 var id = this.getId(n);
22700 for(var j = 0; j < fl; j++){
22702 var v = this.ef[j](n);
22704 Roo.log('missing convert for ' + f.name);
22708 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22710 var record = new Record(values, id);
22712 records[i] = record;
22718 totalRecords : totalRecords
22723 * Ext JS Library 1.1.1
22724 * Copyright(c) 2006-2007, Ext JS, LLC.
22726 * Originally Released Under LGPL - original licence link has changed is not relivant.
22729 * <script type="text/javascript">
22733 * @class Roo.data.XmlReader
22734 * @extends Roo.data.DataReader
22735 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22736 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22738 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22739 * header in the HTTP response must be set to "text/xml".</em>
22743 var RecordDef = Roo.data.Record.create([
22744 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22745 {name: 'occupation'} // This field will use "occupation" as the mapping.
22747 var myReader = new Roo.data.XmlReader({
22748 totalRecords: "results", // The element which contains the total dataset size (optional)
22749 record: "row", // The repeated element which contains row information
22750 id: "id" // The element within the row that provides an ID for the record (optional)
22754 * This would consume an XML file like this:
22758 <results>2</results>
22761 <name>Bill</name>
22762 <occupation>Gardener</occupation>
22766 <name>Ben</name>
22767 <occupation>Horticulturalist</occupation>
22771 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22772 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22773 * paged from the remote server.
22774 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22775 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22776 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22777 * a record identifier value.
22779 * Create a new XmlReader
22780 * @param {Object} meta Metadata configuration options
22781 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22782 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22783 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22785 Roo.data.XmlReader = function(meta, recordType){
22787 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22789 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22791 * This method is only used by a DataProxy which has retrieved data from a remote server.
22792 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22793 * to contain a method called 'responseXML' that returns an XML document object.
22794 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22795 * a cache of Roo.data.Records.
22797 read : function(response){
22798 var doc = response.responseXML;
22800 throw {message: "XmlReader.read: XML Document not available"};
22802 return this.readRecords(doc);
22806 * Create a data block containing Roo.data.Records from an XML document.
22807 * @param {Object} doc A parsed XML document.
22808 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22809 * a cache of Roo.data.Records.
22811 readRecords : function(doc){
22813 * After any data loads/reads, the raw XML Document is available for further custom processing.
22814 * @type XMLDocument
22816 this.xmlData = doc;
22817 var root = doc.documentElement || doc;
22818 var q = Roo.DomQuery;
22819 var recordType = this.recordType, fields = recordType.prototype.fields;
22820 var sid = this.meta.id;
22821 var totalRecords = 0, success = true;
22822 if(this.meta.totalRecords){
22823 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22826 if(this.meta.success){
22827 var sv = q.selectValue(this.meta.success, root, true);
22828 success = sv !== false && sv !== 'false';
22831 var ns = q.select(this.meta.record, root);
22832 for(var i = 0, len = ns.length; i < len; i++) {
22835 var id = sid ? q.selectValue(sid, n) : undefined;
22836 for(var j = 0, jlen = fields.length; j < jlen; j++){
22837 var f = fields.items[j];
22838 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22840 values[f.name] = v;
22842 var record = new recordType(values, id);
22844 records[records.length] = record;
22850 totalRecords : totalRecords || records.length
22855 * Ext JS Library 1.1.1
22856 * Copyright(c) 2006-2007, Ext JS, LLC.
22858 * Originally Released Under LGPL - original licence link has changed is not relivant.
22861 * <script type="text/javascript">
22865 * @class Roo.data.ArrayReader
22866 * @extends Roo.data.DataReader
22867 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22868 * Each element of that Array represents a row of data fields. The
22869 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22870 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22874 var RecordDef = Roo.data.Record.create([
22875 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22876 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22878 var myReader = new Roo.data.ArrayReader({
22879 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22883 * This would consume an Array like this:
22885 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22887 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22889 * Create a new JsonReader
22890 * @param {Object} meta Metadata configuration options.
22891 * @param {Object} recordType Either an Array of field definition objects
22892 * as specified to {@link Roo.data.Record#create},
22893 * or an {@link Roo.data.Record} object
22894 * created using {@link Roo.data.Record#create}.
22896 Roo.data.ArrayReader = function(meta, recordType){
22897 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22900 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22902 * Create a data block containing Roo.data.Records from an XML document.
22903 * @param {Object} o An Array of row objects which represents the dataset.
22904 * @return {Object} data A data block which is used by an Roo.data.Store object as
22905 * a cache of Roo.data.Records.
22907 readRecords : function(o){
22908 var sid = this.meta ? this.meta.id : null;
22909 var recordType = this.recordType, fields = recordType.prototype.fields;
22912 for(var i = 0; i < root.length; i++){
22915 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22916 for(var j = 0, jlen = fields.length; j < jlen; j++){
22917 var f = fields.items[j];
22918 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22919 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22921 values[f.name] = v;
22923 var record = new recordType(values, id);
22925 records[records.length] = record;
22929 totalRecords : records.length
22934 * Ext JS Library 1.1.1
22935 * Copyright(c) 2006-2007, Ext JS, LLC.
22937 * Originally Released Under LGPL - original licence link has changed is not relivant.
22940 * <script type="text/javascript">
22945 * @class Roo.data.Tree
22946 * @extends Roo.util.Observable
22947 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
22948 * in the tree have most standard DOM functionality.
22950 * @param {Node} root (optional) The root node
22952 Roo.data.Tree = function(root){
22953 this.nodeHash = {};
22955 * The root node for this tree
22960 this.setRootNode(root);
22965 * Fires when a new child node is appended to a node in this tree.
22966 * @param {Tree} tree The owner tree
22967 * @param {Node} parent The parent node
22968 * @param {Node} node The newly appended node
22969 * @param {Number} index The index of the newly appended node
22974 * Fires when a child node is removed from a node in this tree.
22975 * @param {Tree} tree The owner tree
22976 * @param {Node} parent The parent node
22977 * @param {Node} node The child node removed
22982 * Fires when a node is moved to a new location in the tree
22983 * @param {Tree} tree The owner tree
22984 * @param {Node} node The node moved
22985 * @param {Node} oldParent The old parent of this node
22986 * @param {Node} newParent The new parent of this node
22987 * @param {Number} index The index it was moved to
22992 * Fires when a new child node is inserted in a node in this tree.
22993 * @param {Tree} tree The owner tree
22994 * @param {Node} parent The parent node
22995 * @param {Node} node The child node inserted
22996 * @param {Node} refNode The child node the node was inserted before
23000 * @event beforeappend
23001 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
23002 * @param {Tree} tree The owner tree
23003 * @param {Node} parent The parent node
23004 * @param {Node} node The child node to be appended
23006 "beforeappend" : true,
23008 * @event beforeremove
23009 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
23010 * @param {Tree} tree The owner tree
23011 * @param {Node} parent The parent node
23012 * @param {Node} node The child node to be removed
23014 "beforeremove" : true,
23016 * @event beforemove
23017 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
23018 * @param {Tree} tree The owner tree
23019 * @param {Node} node The node being moved
23020 * @param {Node} oldParent The parent of the node
23021 * @param {Node} newParent The new parent the node is moving to
23022 * @param {Number} index The index it is being moved to
23024 "beforemove" : true,
23026 * @event beforeinsert
23027 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
23028 * @param {Tree} tree The owner tree
23029 * @param {Node} parent The parent node
23030 * @param {Node} node The child node to be inserted
23031 * @param {Node} refNode The child node the node is being inserted before
23033 "beforeinsert" : true
23036 Roo.data.Tree.superclass.constructor.call(this);
23039 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
23040 pathSeparator: "/",
23042 proxyNodeEvent : function(){
23043 return this.fireEvent.apply(this, arguments);
23047 * Returns the root node for this tree.
23050 getRootNode : function(){
23055 * Sets the root node for this tree.
23056 * @param {Node} node
23059 setRootNode : function(node){
23061 node.ownerTree = this;
23062 node.isRoot = true;
23063 this.registerNode(node);
23068 * Gets a node in this tree by its id.
23069 * @param {String} id
23072 getNodeById : function(id){
23073 return this.nodeHash[id];
23076 registerNode : function(node){
23077 this.nodeHash[node.id] = node;
23080 unregisterNode : function(node){
23081 delete this.nodeHash[node.id];
23084 toString : function(){
23085 return "[Tree"+(this.id?" "+this.id:"")+"]";
23090 * @class Roo.data.Node
23091 * @extends Roo.util.Observable
23092 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23093 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23095 * @param {Object} attributes The attributes/config for the node
23097 Roo.data.Node = function(attributes){
23099 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23102 this.attributes = attributes || {};
23103 this.leaf = this.attributes.leaf;
23105 * The node id. @type String
23107 this.id = this.attributes.id;
23109 this.id = Roo.id(null, "ynode-");
23110 this.attributes.id = this.id;
23115 * All child nodes of this node. @type Array
23117 this.childNodes = [];
23118 if(!this.childNodes.indexOf){ // indexOf is a must
23119 this.childNodes.indexOf = function(o){
23120 for(var i = 0, len = this.length; i < len; i++){
23129 * The parent node for this node. @type Node
23131 this.parentNode = null;
23133 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23135 this.firstChild = null;
23137 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23139 this.lastChild = null;
23141 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23143 this.previousSibling = null;
23145 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23147 this.nextSibling = null;
23152 * Fires when a new child node is appended
23153 * @param {Tree} tree The owner tree
23154 * @param {Node} this This node
23155 * @param {Node} node The newly appended node
23156 * @param {Number} index The index of the newly appended node
23161 * Fires when a child node is removed
23162 * @param {Tree} tree The owner tree
23163 * @param {Node} this This node
23164 * @param {Node} node The removed node
23169 * Fires when this node is moved to a new location in the tree
23170 * @param {Tree} tree The owner tree
23171 * @param {Node} this This node
23172 * @param {Node} oldParent The old parent of this node
23173 * @param {Node} newParent The new parent of this node
23174 * @param {Number} index The index it was moved to
23179 * Fires when a new child node is inserted.
23180 * @param {Tree} tree The owner tree
23181 * @param {Node} this This node
23182 * @param {Node} node The child node inserted
23183 * @param {Node} refNode The child node the node was inserted before
23187 * @event beforeappend
23188 * Fires before a new child is appended, return false to cancel the append.
23189 * @param {Tree} tree The owner tree
23190 * @param {Node} this This node
23191 * @param {Node} node The child node to be appended
23193 "beforeappend" : true,
23195 * @event beforeremove
23196 * Fires before a child is removed, return false to cancel the remove.
23197 * @param {Tree} tree The owner tree
23198 * @param {Node} this This node
23199 * @param {Node} node The child node to be removed
23201 "beforeremove" : true,
23203 * @event beforemove
23204 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23205 * @param {Tree} tree The owner tree
23206 * @param {Node} this This node
23207 * @param {Node} oldParent The parent of this node
23208 * @param {Node} newParent The new parent this node is moving to
23209 * @param {Number} index The index it is being moved to
23211 "beforemove" : true,
23213 * @event beforeinsert
23214 * Fires before a new child is inserted, return false to cancel the insert.
23215 * @param {Tree} tree The owner tree
23216 * @param {Node} this This node
23217 * @param {Node} node The child node to be inserted
23218 * @param {Node} refNode The child node the node is being inserted before
23220 "beforeinsert" : true
23222 this.listeners = this.attributes.listeners;
23223 Roo.data.Node.superclass.constructor.call(this);
23226 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23227 fireEvent : function(evtName){
23228 // first do standard event for this node
23229 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23232 // then bubble it up to the tree if the event wasn't cancelled
23233 var ot = this.getOwnerTree();
23235 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23243 * Returns true if this node is a leaf
23244 * @return {Boolean}
23246 isLeaf : function(){
23247 return this.leaf === true;
23251 setFirstChild : function(node){
23252 this.firstChild = node;
23256 setLastChild : function(node){
23257 this.lastChild = node;
23262 * Returns true if this node is the last child of its parent
23263 * @return {Boolean}
23265 isLast : function(){
23266 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23270 * Returns true if this node is the first child of its parent
23271 * @return {Boolean}
23273 isFirst : function(){
23274 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23277 hasChildNodes : function(){
23278 return !this.isLeaf() && this.childNodes.length > 0;
23282 * Insert node(s) as the last child node of this node.
23283 * @param {Node/Array} node The node or Array of nodes to append
23284 * @return {Node} The appended node if single append, or null if an array was passed
23286 appendChild : function(node){
23288 if(node instanceof Array){
23290 }else if(arguments.length > 1){
23293 // if passed an array or multiple args do them one by one
23295 for(var i = 0, len = multi.length; i < len; i++) {
23296 this.appendChild(multi[i]);
23299 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23302 var index = this.childNodes.length;
23303 var oldParent = node.parentNode;
23304 // it's a move, make sure we move it cleanly
23306 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23309 oldParent.removeChild(node);
23311 index = this.childNodes.length;
23313 this.setFirstChild(node);
23315 this.childNodes.push(node);
23316 node.parentNode = this;
23317 var ps = this.childNodes[index-1];
23319 node.previousSibling = ps;
23320 ps.nextSibling = node;
23322 node.previousSibling = null;
23324 node.nextSibling = null;
23325 this.setLastChild(node);
23326 node.setOwnerTree(this.getOwnerTree());
23327 this.fireEvent("append", this.ownerTree, this, node, index);
23329 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23336 * Removes a child node from this node.
23337 * @param {Node} node The node to remove
23338 * @return {Node} The removed node
23340 removeChild : function(node){
23341 var index = this.childNodes.indexOf(node);
23345 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23349 // remove it from childNodes collection
23350 this.childNodes.splice(index, 1);
23353 if(node.previousSibling){
23354 node.previousSibling.nextSibling = node.nextSibling;
23356 if(node.nextSibling){
23357 node.nextSibling.previousSibling = node.previousSibling;
23360 // update child refs
23361 if(this.firstChild == node){
23362 this.setFirstChild(node.nextSibling);
23364 if(this.lastChild == node){
23365 this.setLastChild(node.previousSibling);
23368 node.setOwnerTree(null);
23369 // clear any references from the node
23370 node.parentNode = null;
23371 node.previousSibling = null;
23372 node.nextSibling = null;
23373 this.fireEvent("remove", this.ownerTree, this, node);
23378 * Inserts the first node before the second node in this nodes childNodes collection.
23379 * @param {Node} node The node to insert
23380 * @param {Node} refNode The node to insert before (if null the node is appended)
23381 * @return {Node} The inserted node
23383 insertBefore : function(node, refNode){
23384 if(!refNode){ // like standard Dom, refNode can be null for append
23385 return this.appendChild(node);
23388 if(node == refNode){
23392 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23395 var index = this.childNodes.indexOf(refNode);
23396 var oldParent = node.parentNode;
23397 var refIndex = index;
23399 // when moving internally, indexes will change after remove
23400 if(oldParent == this && this.childNodes.indexOf(node) < index){
23404 // it's a move, make sure we move it cleanly
23406 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23409 oldParent.removeChild(node);
23412 this.setFirstChild(node);
23414 this.childNodes.splice(refIndex, 0, node);
23415 node.parentNode = this;
23416 var ps = this.childNodes[refIndex-1];
23418 node.previousSibling = ps;
23419 ps.nextSibling = node;
23421 node.previousSibling = null;
23423 node.nextSibling = refNode;
23424 refNode.previousSibling = node;
23425 node.setOwnerTree(this.getOwnerTree());
23426 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23428 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23434 * Returns the child node at the specified index.
23435 * @param {Number} index
23438 item : function(index){
23439 return this.childNodes[index];
23443 * Replaces one child node in this node with another.
23444 * @param {Node} newChild The replacement node
23445 * @param {Node} oldChild The node to replace
23446 * @return {Node} The replaced node
23448 replaceChild : function(newChild, oldChild){
23449 this.insertBefore(newChild, oldChild);
23450 this.removeChild(oldChild);
23455 * Returns the index of a child node
23456 * @param {Node} node
23457 * @return {Number} The index of the node or -1 if it was not found
23459 indexOf : function(child){
23460 return this.childNodes.indexOf(child);
23464 * Returns the tree this node is in.
23467 getOwnerTree : function(){
23468 // if it doesn't have one, look for one
23469 if(!this.ownerTree){
23473 this.ownerTree = p.ownerTree;
23479 return this.ownerTree;
23483 * Returns depth of this node (the root node has a depth of 0)
23486 getDepth : function(){
23489 while(p.parentNode){
23497 setOwnerTree : function(tree){
23498 // if it's move, we need to update everyone
23499 if(tree != this.ownerTree){
23500 if(this.ownerTree){
23501 this.ownerTree.unregisterNode(this);
23503 this.ownerTree = tree;
23504 var cs = this.childNodes;
23505 for(var i = 0, len = cs.length; i < len; i++) {
23506 cs[i].setOwnerTree(tree);
23509 tree.registerNode(this);
23515 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23516 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23517 * @return {String} The path
23519 getPath : function(attr){
23520 attr = attr || "id";
23521 var p = this.parentNode;
23522 var b = [this.attributes[attr]];
23524 b.unshift(p.attributes[attr]);
23527 var sep = this.getOwnerTree().pathSeparator;
23528 return sep + b.join(sep);
23532 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23533 * function call will be the scope provided or the current node. The arguments to the function
23534 * will be the args provided or the current node. If the function returns false at any point,
23535 * the bubble is stopped.
23536 * @param {Function} fn The function to call
23537 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23538 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23540 bubble : function(fn, scope, args){
23543 if(fn.call(scope || p, args || p) === false){
23551 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23552 * function call will be the scope provided or the current node. The arguments to the function
23553 * will be the args provided or the current node. If the function returns false at any point,
23554 * the cascade is stopped on that branch.
23555 * @param {Function} fn The function to call
23556 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23557 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23559 cascade : function(fn, scope, args){
23560 if(fn.call(scope || this, args || this) !== false){
23561 var cs = this.childNodes;
23562 for(var i = 0, len = cs.length; i < len; i++) {
23563 cs[i].cascade(fn, scope, args);
23569 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23570 * function call will be the scope provided or the current node. The arguments to the function
23571 * will be the args provided or the current node. If the function returns false at any point,
23572 * the iteration stops.
23573 * @param {Function} fn The function to call
23574 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23575 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23577 eachChild : function(fn, scope, args){
23578 var cs = this.childNodes;
23579 for(var i = 0, len = cs.length; i < len; i++) {
23580 if(fn.call(scope || this, args || cs[i]) === false){
23587 * Finds the first child that has the attribute with the specified value.
23588 * @param {String} attribute The attribute name
23589 * @param {Mixed} value The value to search for
23590 * @return {Node} The found child or null if none was found
23592 findChild : function(attribute, value){
23593 var cs = this.childNodes;
23594 for(var i = 0, len = cs.length; i < len; i++) {
23595 if(cs[i].attributes[attribute] == value){
23603 * Finds the first child by a custom function. The child matches if the function passed
23605 * @param {Function} fn
23606 * @param {Object} scope (optional)
23607 * @return {Node} The found child or null if none was found
23609 findChildBy : function(fn, scope){
23610 var cs = this.childNodes;
23611 for(var i = 0, len = cs.length; i < len; i++) {
23612 if(fn.call(scope||cs[i], cs[i]) === true){
23620 * Sorts this nodes children using the supplied sort function
23621 * @param {Function} fn
23622 * @param {Object} scope (optional)
23624 sort : function(fn, scope){
23625 var cs = this.childNodes;
23626 var len = cs.length;
23628 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23630 for(var i = 0; i < len; i++){
23632 n.previousSibling = cs[i-1];
23633 n.nextSibling = cs[i+1];
23635 this.setFirstChild(n);
23638 this.setLastChild(n);
23645 * Returns true if this node is an ancestor (at any point) of the passed node.
23646 * @param {Node} node
23647 * @return {Boolean}
23649 contains : function(node){
23650 return node.isAncestor(this);
23654 * Returns true if the passed node is an ancestor (at any point) of this node.
23655 * @param {Node} node
23656 * @return {Boolean}
23658 isAncestor : function(node){
23659 var p = this.parentNode;
23669 toString : function(){
23670 return "[Node"+(this.id?" "+this.id:"")+"]";
23674 * Ext JS Library 1.1.1
23675 * Copyright(c) 2006-2007, Ext JS, LLC.
23677 * Originally Released Under LGPL - original licence link has changed is not relivant.
23680 * <script type="text/javascript">
23685 * @extends Roo.Element
23686 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23687 * automatic maintaining of shadow/shim positions.
23688 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23689 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23690 * you can pass a string with a CSS class name. False turns off the shadow.
23691 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23692 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23693 * @cfg {String} cls CSS class to add to the element
23694 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23695 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23697 * @param {Object} config An object with config options.
23698 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23701 Roo.Layer = function(config, existingEl){
23702 config = config || {};
23703 var dh = Roo.DomHelper;
23704 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23706 this.dom = Roo.getDom(existingEl);
23709 var o = config.dh || {tag: "div", cls: "x-layer"};
23710 this.dom = dh.append(pel, o);
23713 this.addClass(config.cls);
23715 this.constrain = config.constrain !== false;
23716 this.visibilityMode = Roo.Element.VISIBILITY;
23718 this.id = this.dom.id = config.id;
23720 this.id = Roo.id(this.dom);
23722 this.zindex = config.zindex || this.getZIndex();
23723 this.position("absolute", this.zindex);
23725 this.shadowOffset = config.shadowOffset || 4;
23726 this.shadow = new Roo.Shadow({
23727 offset : this.shadowOffset,
23728 mode : config.shadow
23731 this.shadowOffset = 0;
23733 this.useShim = config.shim !== false && Roo.useShims;
23734 this.useDisplay = config.useDisplay;
23738 var supr = Roo.Element.prototype;
23740 // shims are shared among layer to keep from having 100 iframes
23743 Roo.extend(Roo.Layer, Roo.Element, {
23745 getZIndex : function(){
23746 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23749 getShim : function(){
23756 var shim = shims.shift();
23758 shim = this.createShim();
23759 shim.enableDisplayMode('block');
23760 shim.dom.style.display = 'none';
23761 shim.dom.style.visibility = 'visible';
23763 var pn = this.dom.parentNode;
23764 if(shim.dom.parentNode != pn){
23765 pn.insertBefore(shim.dom, this.dom);
23767 shim.setStyle('z-index', this.getZIndex()-2);
23772 hideShim : function(){
23774 this.shim.setDisplayed(false);
23775 shims.push(this.shim);
23780 disableShadow : function(){
23782 this.shadowDisabled = true;
23783 this.shadow.hide();
23784 this.lastShadowOffset = this.shadowOffset;
23785 this.shadowOffset = 0;
23789 enableShadow : function(show){
23791 this.shadowDisabled = false;
23792 this.shadowOffset = this.lastShadowOffset;
23793 delete this.lastShadowOffset;
23801 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23802 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23803 sync : function(doShow){
23804 var sw = this.shadow;
23805 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23806 var sh = this.getShim();
23808 var w = this.getWidth(),
23809 h = this.getHeight();
23811 var l = this.getLeft(true),
23812 t = this.getTop(true);
23814 if(sw && !this.shadowDisabled){
23815 if(doShow && !sw.isVisible()){
23818 sw.realign(l, t, w, h);
23824 // fit the shim behind the shadow, so it is shimmed too
23825 var a = sw.adjusts, s = sh.dom.style;
23826 s.left = (Math.min(l, l+a.l))+"px";
23827 s.top = (Math.min(t, t+a.t))+"px";
23828 s.width = (w+a.w)+"px";
23829 s.height = (h+a.h)+"px";
23836 sh.setLeftTop(l, t);
23843 destroy : function(){
23846 this.shadow.hide();
23848 this.removeAllListeners();
23849 var pn = this.dom.parentNode;
23851 pn.removeChild(this.dom);
23853 Roo.Element.uncache(this.id);
23856 remove : function(){
23861 beginUpdate : function(){
23862 this.updating = true;
23866 endUpdate : function(){
23867 this.updating = false;
23872 hideUnders : function(negOffset){
23874 this.shadow.hide();
23880 constrainXY : function(){
23881 if(this.constrain){
23882 var vw = Roo.lib.Dom.getViewWidth(),
23883 vh = Roo.lib.Dom.getViewHeight();
23884 var s = Roo.get(document).getScroll();
23886 var xy = this.getXY();
23887 var x = xy[0], y = xy[1];
23888 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23889 // only move it if it needs it
23891 // first validate right/bottom
23892 if((x + w) > vw+s.left){
23893 x = vw - w - this.shadowOffset;
23896 if((y + h) > vh+s.top){
23897 y = vh - h - this.shadowOffset;
23900 // then make sure top/left isn't negative
23911 var ay = this.avoidY;
23912 if(y <= ay && (y+h) >= ay){
23918 supr.setXY.call(this, xy);
23924 isVisible : function(){
23925 return this.visible;
23929 showAction : function(){
23930 this.visible = true; // track visibility to prevent getStyle calls
23931 if(this.useDisplay === true){
23932 this.setDisplayed("");
23933 }else if(this.lastXY){
23934 supr.setXY.call(this, this.lastXY);
23935 }else if(this.lastLT){
23936 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23941 hideAction : function(){
23942 this.visible = false;
23943 if(this.useDisplay === true){
23944 this.setDisplayed(false);
23946 this.setLeftTop(-10000,-10000);
23950 // overridden Element method
23951 setVisible : function(v, a, d, c, e){
23956 var cb = function(){
23961 }.createDelegate(this);
23962 supr.setVisible.call(this, true, true, d, cb, e);
23965 this.hideUnders(true);
23974 }.createDelegate(this);
23976 supr.setVisible.call(this, v, a, d, cb, e);
23985 storeXY : function(xy){
23986 delete this.lastLT;
23990 storeLeftTop : function(left, top){
23991 delete this.lastXY;
23992 this.lastLT = [left, top];
23996 beforeFx : function(){
23997 this.beforeAction();
23998 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
24002 afterFx : function(){
24003 Roo.Layer.superclass.afterFx.apply(this, arguments);
24004 this.sync(this.isVisible());
24008 beforeAction : function(){
24009 if(!this.updating && this.shadow){
24010 this.shadow.hide();
24014 // overridden Element method
24015 setLeft : function(left){
24016 this.storeLeftTop(left, this.getTop(true));
24017 supr.setLeft.apply(this, arguments);
24021 setTop : function(top){
24022 this.storeLeftTop(this.getLeft(true), top);
24023 supr.setTop.apply(this, arguments);
24027 setLeftTop : function(left, top){
24028 this.storeLeftTop(left, top);
24029 supr.setLeftTop.apply(this, arguments);
24033 setXY : function(xy, a, d, c, e){
24035 this.beforeAction();
24037 var cb = this.createCB(c);
24038 supr.setXY.call(this, xy, a, d, cb, e);
24045 createCB : function(c){
24056 // overridden Element method
24057 setX : function(x, a, d, c, e){
24058 this.setXY([x, this.getY()], a, d, c, e);
24061 // overridden Element method
24062 setY : function(y, a, d, c, e){
24063 this.setXY([this.getX(), y], a, d, c, e);
24066 // overridden Element method
24067 setSize : function(w, h, a, d, c, e){
24068 this.beforeAction();
24069 var cb = this.createCB(c);
24070 supr.setSize.call(this, w, h, a, d, cb, e);
24076 // overridden Element method
24077 setWidth : function(w, a, d, c, e){
24078 this.beforeAction();
24079 var cb = this.createCB(c);
24080 supr.setWidth.call(this, w, a, d, cb, e);
24086 // overridden Element method
24087 setHeight : function(h, a, d, c, e){
24088 this.beforeAction();
24089 var cb = this.createCB(c);
24090 supr.setHeight.call(this, h, a, d, cb, e);
24096 // overridden Element method
24097 setBounds : function(x, y, w, h, a, d, c, e){
24098 this.beforeAction();
24099 var cb = this.createCB(c);
24101 this.storeXY([x, y]);
24102 supr.setXY.call(this, [x, y]);
24103 supr.setSize.call(this, w, h, a, d, cb, e);
24106 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24112 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24113 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24114 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24115 * @param {Number} zindex The new z-index to set
24116 * @return {this} The Layer
24118 setZIndex : function(zindex){
24119 this.zindex = zindex;
24120 this.setStyle("z-index", zindex + 2);
24122 this.shadow.setZIndex(zindex + 1);
24125 this.shim.setStyle("z-index", zindex);
24131 * Ext JS Library 1.1.1
24132 * Copyright(c) 2006-2007, Ext JS, LLC.
24134 * Originally Released Under LGPL - original licence link has changed is not relivant.
24137 * <script type="text/javascript">
24142 * @class Roo.Shadow
24143 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24144 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24145 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24147 * Create a new Shadow
24148 * @param {Object} config The config object
24150 Roo.Shadow = function(config){
24151 Roo.apply(this, config);
24152 if(typeof this.mode != "string"){
24153 this.mode = this.defaultMode;
24155 var o = this.offset, a = {h: 0};
24156 var rad = Math.floor(this.offset/2);
24157 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24163 a.l -= this.offset + rad;
24164 a.t -= this.offset + rad;
24175 a.l -= (this.offset - rad);
24176 a.t -= this.offset + rad;
24178 a.w -= (this.offset - rad)*2;
24189 a.l -= (this.offset - rad);
24190 a.t -= (this.offset - rad);
24192 a.w -= (this.offset + rad + 1);
24193 a.h -= (this.offset + rad);
24202 Roo.Shadow.prototype = {
24204 * @cfg {String} mode
24205 * The shadow display mode. Supports the following options:<br />
24206 * sides: Shadow displays on both sides and bottom only<br />
24207 * frame: Shadow displays equally on all four sides<br />
24208 * drop: Traditional bottom-right drop shadow (default)
24211 * @cfg {String} offset
24212 * The number of pixels to offset the shadow from the element (defaults to 4)
24217 defaultMode: "drop",
24220 * Displays the shadow under the target element
24221 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24223 show : function(target){
24224 target = Roo.get(target);
24226 this.el = Roo.Shadow.Pool.pull();
24227 if(this.el.dom.nextSibling != target.dom){
24228 this.el.insertBefore(target);
24231 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24233 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24236 target.getLeft(true),
24237 target.getTop(true),
24241 this.el.dom.style.display = "block";
24245 * Returns true if the shadow is visible, else false
24247 isVisible : function(){
24248 return this.el ? true : false;
24252 * Direct alignment when values are already available. Show must be called at least once before
24253 * calling this method to ensure it is initialized.
24254 * @param {Number} left The target element left position
24255 * @param {Number} top The target element top position
24256 * @param {Number} width The target element width
24257 * @param {Number} height The target element height
24259 realign : function(l, t, w, h){
24263 var a = this.adjusts, d = this.el.dom, s = d.style;
24265 s.left = (l+a.l)+"px";
24266 s.top = (t+a.t)+"px";
24267 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24269 if(s.width != sws || s.height != shs){
24273 var cn = d.childNodes;
24274 var sww = Math.max(0, (sw-12))+"px";
24275 cn[0].childNodes[1].style.width = sww;
24276 cn[1].childNodes[1].style.width = sww;
24277 cn[2].childNodes[1].style.width = sww;
24278 cn[1].style.height = Math.max(0, (sh-12))+"px";
24284 * Hides this shadow
24288 this.el.dom.style.display = "none";
24289 Roo.Shadow.Pool.push(this.el);
24295 * Adjust the z-index of this shadow
24296 * @param {Number} zindex The new z-index
24298 setZIndex : function(z){
24301 this.el.setStyle("z-index", z);
24306 // Private utility class that manages the internal Shadow cache
24307 Roo.Shadow.Pool = function(){
24309 var markup = Roo.isIE ?
24310 '<div class="x-ie-shadow"></div>' :
24311 '<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>';
24314 var sh = p.shift();
24316 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24317 sh.autoBoxAdjust = false;
24322 push : function(sh){
24328 * Ext JS Library 1.1.1
24329 * Copyright(c) 2006-2007, Ext JS, LLC.
24331 * Originally Released Under LGPL - original licence link has changed is not relivant.
24334 * <script type="text/javascript">
24339 * @class Roo.SplitBar
24340 * @extends Roo.util.Observable
24341 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24345 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24346 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24347 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24348 split.minSize = 100;
24349 split.maxSize = 600;
24350 split.animate = true;
24351 split.on('moved', splitterMoved);
24354 * Create a new SplitBar
24355 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24356 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24357 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24358 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24359 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24360 position of the SplitBar).
24362 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24365 this.el = Roo.get(dragElement, true);
24366 this.el.dom.unselectable = "on";
24368 this.resizingEl = Roo.get(resizingElement, true);
24372 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24373 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24376 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24379 * The minimum size of the resizing element. (Defaults to 0)
24385 * The maximum size of the resizing element. (Defaults to 2000)
24388 this.maxSize = 2000;
24391 * Whether to animate the transition to the new size
24394 this.animate = false;
24397 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24400 this.useShim = false;
24405 if(!existingProxy){
24407 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24409 this.proxy = Roo.get(existingProxy).dom;
24412 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24415 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24418 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24421 this.dragSpecs = {};
24424 * @private The adapter to use to positon and resize elements
24426 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24427 this.adapter.init(this);
24429 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24431 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24432 this.el.addClass("x-splitbar-h");
24435 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24436 this.el.addClass("x-splitbar-v");
24442 * Fires when the splitter is moved (alias for {@link #event-moved})
24443 * @param {Roo.SplitBar} this
24444 * @param {Number} newSize the new width or height
24449 * Fires when the splitter is moved
24450 * @param {Roo.SplitBar} this
24451 * @param {Number} newSize the new width or height
24455 * @event beforeresize
24456 * Fires before the splitter is dragged
24457 * @param {Roo.SplitBar} this
24459 "beforeresize" : true,
24461 "beforeapply" : true
24464 Roo.util.Observable.call(this);
24467 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24468 onStartProxyDrag : function(x, y){
24469 this.fireEvent("beforeresize", this);
24471 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24473 o.enableDisplayMode("block");
24474 // all splitbars share the same overlay
24475 Roo.SplitBar.prototype.overlay = o;
24477 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24478 this.overlay.show();
24479 Roo.get(this.proxy).setDisplayed("block");
24480 var size = this.adapter.getElementSize(this);
24481 this.activeMinSize = this.getMinimumSize();;
24482 this.activeMaxSize = this.getMaximumSize();;
24483 var c1 = size - this.activeMinSize;
24484 var c2 = Math.max(this.activeMaxSize - size, 0);
24485 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24486 this.dd.resetConstraints();
24487 this.dd.setXConstraint(
24488 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24489 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24491 this.dd.setYConstraint(0, 0);
24493 this.dd.resetConstraints();
24494 this.dd.setXConstraint(0, 0);
24495 this.dd.setYConstraint(
24496 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24497 this.placement == Roo.SplitBar.TOP ? c2 : c1
24500 this.dragSpecs.startSize = size;
24501 this.dragSpecs.startPoint = [x, y];
24502 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24506 * @private Called after the drag operation by the DDProxy
24508 onEndProxyDrag : function(e){
24509 Roo.get(this.proxy).setDisplayed(false);
24510 var endPoint = Roo.lib.Event.getXY(e);
24512 this.overlay.hide();
24515 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24516 newSize = this.dragSpecs.startSize +
24517 (this.placement == Roo.SplitBar.LEFT ?
24518 endPoint[0] - this.dragSpecs.startPoint[0] :
24519 this.dragSpecs.startPoint[0] - endPoint[0]
24522 newSize = this.dragSpecs.startSize +
24523 (this.placement == Roo.SplitBar.TOP ?
24524 endPoint[1] - this.dragSpecs.startPoint[1] :
24525 this.dragSpecs.startPoint[1] - endPoint[1]
24528 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24529 if(newSize != this.dragSpecs.startSize){
24530 if(this.fireEvent('beforeapply', this, newSize) !== false){
24531 this.adapter.setElementSize(this, newSize);
24532 this.fireEvent("moved", this, newSize);
24533 this.fireEvent("resize", this, newSize);
24539 * Get the adapter this SplitBar uses
24540 * @return The adapter object
24542 getAdapter : function(){
24543 return this.adapter;
24547 * Set the adapter this SplitBar uses
24548 * @param {Object} adapter A SplitBar adapter object
24550 setAdapter : function(adapter){
24551 this.adapter = adapter;
24552 this.adapter.init(this);
24556 * Gets the minimum size for the resizing element
24557 * @return {Number} The minimum size
24559 getMinimumSize : function(){
24560 return this.minSize;
24564 * Sets the minimum size for the resizing element
24565 * @param {Number} minSize The minimum size
24567 setMinimumSize : function(minSize){
24568 this.minSize = minSize;
24572 * Gets the maximum size for the resizing element
24573 * @return {Number} The maximum size
24575 getMaximumSize : function(){
24576 return this.maxSize;
24580 * Sets the maximum size for the resizing element
24581 * @param {Number} maxSize The maximum size
24583 setMaximumSize : function(maxSize){
24584 this.maxSize = maxSize;
24588 * Sets the initialize size for the resizing element
24589 * @param {Number} size The initial size
24591 setCurrentSize : function(size){
24592 var oldAnimate = this.animate;
24593 this.animate = false;
24594 this.adapter.setElementSize(this, size);
24595 this.animate = oldAnimate;
24599 * Destroy this splitbar.
24600 * @param {Boolean} removeEl True to remove the element
24602 destroy : function(removeEl){
24604 this.shim.remove();
24607 this.proxy.parentNode.removeChild(this.proxy);
24615 * @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.
24617 Roo.SplitBar.createProxy = function(dir){
24618 var proxy = new Roo.Element(document.createElement("div"));
24619 proxy.unselectable();
24620 var cls = 'x-splitbar-proxy';
24621 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24622 document.body.appendChild(proxy.dom);
24627 * @class Roo.SplitBar.BasicLayoutAdapter
24628 * Default Adapter. It assumes the splitter and resizing element are not positioned
24629 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24631 Roo.SplitBar.BasicLayoutAdapter = function(){
24634 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24635 // do nothing for now
24636 init : function(s){
24640 * Called before drag operations to get the current size of the resizing element.
24641 * @param {Roo.SplitBar} s The SplitBar using this adapter
24643 getElementSize : function(s){
24644 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24645 return s.resizingEl.getWidth();
24647 return s.resizingEl.getHeight();
24652 * Called after drag operations to set the size of the resizing element.
24653 * @param {Roo.SplitBar} s The SplitBar using this adapter
24654 * @param {Number} newSize The new size to set
24655 * @param {Function} onComplete A function to be invoked when resizing is complete
24657 setElementSize : function(s, newSize, onComplete){
24658 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24660 s.resizingEl.setWidth(newSize);
24662 onComplete(s, newSize);
24665 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24670 s.resizingEl.setHeight(newSize);
24672 onComplete(s, newSize);
24675 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24682 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24683 * @extends Roo.SplitBar.BasicLayoutAdapter
24684 * Adapter that moves the splitter element to align with the resized sizing element.
24685 * Used with an absolute positioned SplitBar.
24686 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24687 * document.body, make sure you assign an id to the body element.
24689 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24690 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24691 this.container = Roo.get(container);
24694 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24695 init : function(s){
24696 this.basic.init(s);
24699 getElementSize : function(s){
24700 return this.basic.getElementSize(s);
24703 setElementSize : function(s, newSize, onComplete){
24704 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24707 moveSplitter : function(s){
24708 var yes = Roo.SplitBar;
24709 switch(s.placement){
24711 s.el.setX(s.resizingEl.getRight());
24714 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24717 s.el.setY(s.resizingEl.getBottom());
24720 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24727 * Orientation constant - Create a vertical SplitBar
24731 Roo.SplitBar.VERTICAL = 1;
24734 * Orientation constant - Create a horizontal SplitBar
24738 Roo.SplitBar.HORIZONTAL = 2;
24741 * Placement constant - The resizing element is to the left of the splitter element
24745 Roo.SplitBar.LEFT = 1;
24748 * Placement constant - The resizing element is to the right of the splitter element
24752 Roo.SplitBar.RIGHT = 2;
24755 * Placement constant - The resizing element is positioned above the splitter element
24759 Roo.SplitBar.TOP = 3;
24762 * Placement constant - The resizing element is positioned under splitter element
24766 Roo.SplitBar.BOTTOM = 4;
24769 * Ext JS Library 1.1.1
24770 * Copyright(c) 2006-2007, Ext JS, LLC.
24772 * Originally Released Under LGPL - original licence link has changed is not relivant.
24775 * <script type="text/javascript">
24780 * @extends Roo.util.Observable
24781 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24782 * This class also supports single and multi selection modes. <br>
24783 * Create a data model bound view:
24785 var store = new Roo.data.Store(...);
24787 var view = new Roo.View({
24789 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24791 singleSelect: true,
24792 selectedClass: "ydataview-selected",
24796 // listen for node click?
24797 view.on("click", function(vw, index, node, e){
24798 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24802 dataModel.load("foobar.xml");
24804 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24806 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24807 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24809 * Note: old style constructor is still suported (container, template, config)
24812 * Create a new View
24813 * @param {Object} config The config object
24816 Roo.View = function(config, depreciated_tpl, depreciated_config){
24818 if (typeof(depreciated_tpl) == 'undefined') {
24819 // new way.. - universal constructor.
24820 Roo.apply(this, config);
24821 this.el = Roo.get(this.el);
24824 this.el = Roo.get(config);
24825 this.tpl = depreciated_tpl;
24826 Roo.apply(this, depreciated_config);
24828 this.wrapEl = this.el.wrap().wrap();
24829 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24832 if(typeof(this.tpl) == "string"){
24833 this.tpl = new Roo.Template(this.tpl);
24835 // support xtype ctors..
24836 this.tpl = new Roo.factory(this.tpl, Roo);
24840 this.tpl.compile();
24848 * @event beforeclick
24849 * Fires before a click is processed. Returns false to cancel the default action.
24850 * @param {Roo.View} this
24851 * @param {Number} index The index of the target node
24852 * @param {HTMLElement} node The target node
24853 * @param {Roo.EventObject} e The raw event object
24855 "beforeclick" : true,
24858 * Fires when a template node is clicked.
24859 * @param {Roo.View} this
24860 * @param {Number} index The index of the target node
24861 * @param {HTMLElement} node The target node
24862 * @param {Roo.EventObject} e The raw event object
24867 * Fires when a template node is double clicked.
24868 * @param {Roo.View} this
24869 * @param {Number} index The index of the target node
24870 * @param {HTMLElement} node The target node
24871 * @param {Roo.EventObject} e The raw event object
24875 * @event contextmenu
24876 * Fires when a template node is right clicked.
24877 * @param {Roo.View} this
24878 * @param {Number} index The index of the target node
24879 * @param {HTMLElement} node The target node
24880 * @param {Roo.EventObject} e The raw event object
24882 "contextmenu" : true,
24884 * @event selectionchange
24885 * Fires when the selected nodes change.
24886 * @param {Roo.View} this
24887 * @param {Array} selections Array of the selected nodes
24889 "selectionchange" : true,
24892 * @event beforeselect
24893 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24894 * @param {Roo.View} this
24895 * @param {HTMLElement} node The node to be selected
24896 * @param {Array} selections Array of currently selected nodes
24898 "beforeselect" : true,
24900 * @event preparedata
24901 * Fires on every row to render, to allow you to change the data.
24902 * @param {Roo.View} this
24903 * @param {Object} data to be rendered (change this)
24905 "preparedata" : true
24913 "click": this.onClick,
24914 "dblclick": this.onDblClick,
24915 "contextmenu": this.onContextMenu,
24919 this.selections = [];
24921 this.cmp = new Roo.CompositeElementLite([]);
24923 this.store = Roo.factory(this.store, Roo.data);
24924 this.setStore(this.store, true);
24927 if ( this.footer && this.footer.xtype) {
24929 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24931 this.footer.dataSource = this.store
24932 this.footer.container = fctr;
24933 this.footer = Roo.factory(this.footer, Roo);
24934 fctr.insertFirst(this.el);
24936 // this is a bit insane - as the paging toolbar seems to detach the el..
24937 // dom.parentNode.parentNode.parentNode
24938 // they get detached?
24942 Roo.View.superclass.constructor.call(this);
24947 Roo.extend(Roo.View, Roo.util.Observable, {
24950 * @cfg {Roo.data.Store} store Data store to load data from.
24955 * @cfg {String|Roo.Element} el The container element.
24960 * @cfg {String|Roo.Template} tpl The template used by this View
24964 * @cfg {String} dataName the named area of the template to use as the data area
24965 * Works with domtemplates roo-name="name"
24969 * @cfg {String} selectedClass The css class to add to selected nodes
24971 selectedClass : "x-view-selected",
24973 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24978 * @cfg {String} text to display on mask (default Loading)
24982 * @cfg {Boolean} multiSelect Allow multiple selection
24984 multiSelect : false,
24986 * @cfg {Boolean} singleSelect Allow single selection
24988 singleSelect: false,
24991 * @cfg {Boolean} toggleSelect - selecting
24993 toggleSelect : false,
24996 * Returns the element this view is bound to.
24997 * @return {Roo.Element}
24999 getEl : function(){
25000 return this.wrapEl;
25006 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25008 refresh : function(){
25009 Roo.log('refresh');
25012 // if we are using something like 'domtemplate', then
25013 // the what gets used is:
25014 // t.applySubtemplate(NAME, data, wrapping data..)
25015 // the outer template then get' applied with
25016 // the store 'extra data'
25017 // and the body get's added to the
25018 // roo-name="data" node?
25019 // <span class='roo-tpl-{name}'></span> ?????
25023 this.clearSelections();
25024 this.el.update("");
25026 var records = this.store.getRange();
25027 if(records.length < 1) {
25029 // is this valid?? = should it render a template??
25031 this.el.update(this.emptyText);
25035 if (this.dataName) {
25036 this.el.update(t.apply(this.store.meta)); //????
25037 el = this.el.child('.roo-tpl-' + this.dataName);
25040 for(var i = 0, len = records.length; i < len; i++){
25041 var data = this.prepareData(records[i].data, i, records[i]);
25042 this.fireEvent("preparedata", this, data, i, records[i]);
25043 html[html.length] = Roo.util.Format.trim(
25045 t.applySubtemplate(this.dataName, data, this.store.meta) :
25052 el.update(html.join(""));
25053 this.nodes = el.dom.childNodes;
25054 this.updateIndexes(0);
25059 * Function to override to reformat the data that is sent to
25060 * the template for each node.
25061 * DEPRICATED - use the preparedata event handler.
25062 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25063 * a JSON object for an UpdateManager bound view).
25065 prepareData : function(data, index, record)
25067 this.fireEvent("preparedata", this, data, index, record);
25071 onUpdate : function(ds, record){
25072 Roo.log('on update');
25073 this.clearSelections();
25074 var index = this.store.indexOf(record);
25075 var n = this.nodes[index];
25076 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25077 n.parentNode.removeChild(n);
25078 this.updateIndexes(index, index);
25084 onAdd : function(ds, records, index)
25086 Roo.log(['on Add', ds, records, index] );
25087 this.clearSelections();
25088 if(this.nodes.length == 0){
25092 var n = this.nodes[index];
25093 for(var i = 0, len = records.length; i < len; i++){
25094 var d = this.prepareData(records[i].data, i, records[i]);
25096 this.tpl.insertBefore(n, d);
25099 this.tpl.append(this.el, d);
25102 this.updateIndexes(index);
25105 onRemove : function(ds, record, index){
25106 Roo.log('onRemove');
25107 this.clearSelections();
25108 var el = this.dataName ?
25109 this.el.child('.roo-tpl-' + this.dataName) :
25112 el.dom.removeChild(this.nodes[index]);
25113 this.updateIndexes(index);
25117 * Refresh an individual node.
25118 * @param {Number} index
25120 refreshNode : function(index){
25121 this.onUpdate(this.store, this.store.getAt(index));
25124 updateIndexes : function(startIndex, endIndex){
25125 var ns = this.nodes;
25126 startIndex = startIndex || 0;
25127 endIndex = endIndex || ns.length - 1;
25128 for(var i = startIndex; i <= endIndex; i++){
25129 ns[i].nodeIndex = i;
25134 * Changes the data store this view uses and refresh the view.
25135 * @param {Store} store
25137 setStore : function(store, initial){
25138 if(!initial && this.store){
25139 this.store.un("datachanged", this.refresh);
25140 this.store.un("add", this.onAdd);
25141 this.store.un("remove", this.onRemove);
25142 this.store.un("update", this.onUpdate);
25143 this.store.un("clear", this.refresh);
25144 this.store.un("beforeload", this.onBeforeLoad);
25145 this.store.un("load", this.onLoad);
25146 this.store.un("loadexception", this.onLoad);
25150 store.on("datachanged", this.refresh, this);
25151 store.on("add", this.onAdd, this);
25152 store.on("remove", this.onRemove, this);
25153 store.on("update", this.onUpdate, this);
25154 store.on("clear", this.refresh, this);
25155 store.on("beforeload", this.onBeforeLoad, this);
25156 store.on("load", this.onLoad, this);
25157 store.on("loadexception", this.onLoad, this);
25165 * onbeforeLoad - masks the loading area.
25168 onBeforeLoad : function(store,opts)
25170 Roo.log('onBeforeLoad');
25172 this.el.update("");
25174 this.el.mask(this.mask ? this.mask : "Loading" );
25176 onLoad : function ()
25183 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25184 * @param {HTMLElement} node
25185 * @return {HTMLElement} The template node
25187 findItemFromChild : function(node){
25188 var el = this.dataName ?
25189 this.el.child('.roo-tpl-' + this.dataName,true) :
25192 if(!node || node.parentNode == el){
25195 var p = node.parentNode;
25196 while(p && p != el){
25197 if(p.parentNode == el){
25206 onClick : function(e){
25207 var item = this.findItemFromChild(e.getTarget());
25209 var index = this.indexOf(item);
25210 if(this.onItemClick(item, index, e) !== false){
25211 this.fireEvent("click", this, index, item, e);
25214 this.clearSelections();
25219 onContextMenu : function(e){
25220 var item = this.findItemFromChild(e.getTarget());
25222 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25227 onDblClick : function(e){
25228 var item = this.findItemFromChild(e.getTarget());
25230 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25234 onItemClick : function(item, index, e)
25236 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25239 if (this.toggleSelect) {
25240 var m = this.isSelected(item) ? 'unselect' : 'select';
25243 _t[m](item, true, false);
25246 if(this.multiSelect || this.singleSelect){
25247 if(this.multiSelect && e.shiftKey && this.lastSelection){
25248 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25250 this.select(item, this.multiSelect && e.ctrlKey);
25251 this.lastSelection = item;
25253 e.preventDefault();
25259 * Get the number of selected nodes.
25262 getSelectionCount : function(){
25263 return this.selections.length;
25267 * Get the currently selected nodes.
25268 * @return {Array} An array of HTMLElements
25270 getSelectedNodes : function(){
25271 return this.selections;
25275 * Get the indexes of the selected nodes.
25278 getSelectedIndexes : function(){
25279 var indexes = [], s = this.selections;
25280 for(var i = 0, len = s.length; i < len; i++){
25281 indexes.push(s[i].nodeIndex);
25287 * Clear all selections
25288 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25290 clearSelections : function(suppressEvent){
25291 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25292 this.cmp.elements = this.selections;
25293 this.cmp.removeClass(this.selectedClass);
25294 this.selections = [];
25295 if(!suppressEvent){
25296 this.fireEvent("selectionchange", this, this.selections);
25302 * Returns true if the passed node is selected
25303 * @param {HTMLElement/Number} node The node or node index
25304 * @return {Boolean}
25306 isSelected : function(node){
25307 var s = this.selections;
25311 node = this.getNode(node);
25312 return s.indexOf(node) !== -1;
25317 * @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
25318 * @param {Boolean} keepExisting (optional) true to keep existing selections
25319 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25321 select : function(nodeInfo, keepExisting, suppressEvent){
25322 if(nodeInfo instanceof Array){
25324 this.clearSelections(true);
25326 for(var i = 0, len = nodeInfo.length; i < len; i++){
25327 this.select(nodeInfo[i], true, true);
25331 var node = this.getNode(nodeInfo);
25332 if(!node || this.isSelected(node)){
25333 return; // already selected.
25336 this.clearSelections(true);
25338 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25339 Roo.fly(node).addClass(this.selectedClass);
25340 this.selections.push(node);
25341 if(!suppressEvent){
25342 this.fireEvent("selectionchange", this, this.selections);
25350 * @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
25351 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25352 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25354 unselect : function(nodeInfo, keepExisting, suppressEvent)
25356 if(nodeInfo instanceof Array){
25357 Roo.each(this.selections, function(s) {
25358 this.unselect(s, nodeInfo);
25362 var node = this.getNode(nodeInfo);
25363 if(!node || !this.isSelected(node)){
25364 Roo.log("not selected");
25365 return; // not selected.
25369 Roo.each(this.selections, function(s) {
25371 Roo.fly(node).removeClass(this.selectedClass);
25378 this.selections= ns;
25379 this.fireEvent("selectionchange", this, this.selections);
25383 * Gets a template node.
25384 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25385 * @return {HTMLElement} The node or null if it wasn't found
25387 getNode : function(nodeInfo){
25388 if(typeof nodeInfo == "string"){
25389 return document.getElementById(nodeInfo);
25390 }else if(typeof nodeInfo == "number"){
25391 return this.nodes[nodeInfo];
25397 * Gets a range template nodes.
25398 * @param {Number} startIndex
25399 * @param {Number} endIndex
25400 * @return {Array} An array of nodes
25402 getNodes : function(start, end){
25403 var ns = this.nodes;
25404 start = start || 0;
25405 end = typeof end == "undefined" ? ns.length - 1 : end;
25408 for(var i = start; i <= end; i++){
25412 for(var i = start; i >= end; i--){
25420 * Finds the index of the passed node
25421 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25422 * @return {Number} The index of the node or -1
25424 indexOf : function(node){
25425 node = this.getNode(node);
25426 if(typeof node.nodeIndex == "number"){
25427 return node.nodeIndex;
25429 var ns = this.nodes;
25430 for(var i = 0, len = ns.length; i < len; i++){
25440 * Ext JS Library 1.1.1
25441 * Copyright(c) 2006-2007, Ext JS, LLC.
25443 * Originally Released Under LGPL - original licence link has changed is not relivant.
25446 * <script type="text/javascript">
25450 * @class Roo.JsonView
25451 * @extends Roo.View
25452 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25454 var view = new Roo.JsonView({
25455 container: "my-element",
25456 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25461 // listen for node click?
25462 view.on("click", function(vw, index, node, e){
25463 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25466 // direct load of JSON data
25467 view.load("foobar.php");
25469 // Example from my blog list
25470 var tpl = new Roo.Template(
25471 '<div class="entry">' +
25472 '<a class="entry-title" href="{link}">{title}</a>' +
25473 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25474 "</div><hr />"
25477 var moreView = new Roo.JsonView({
25478 container : "entry-list",
25482 moreView.on("beforerender", this.sortEntries, this);
25484 url: "/blog/get-posts.php",
25485 params: "allposts=true",
25486 text: "Loading Blog Entries..."
25490 * Note: old code is supported with arguments : (container, template, config)
25494 * Create a new JsonView
25496 * @param {Object} config The config object
25499 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25502 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25504 var um = this.el.getUpdateManager();
25505 um.setRenderer(this);
25506 um.on("update", this.onLoad, this);
25507 um.on("failure", this.onLoadException, this);
25510 * @event beforerender
25511 * Fires before rendering of the downloaded JSON data.
25512 * @param {Roo.JsonView} this
25513 * @param {Object} data The JSON data loaded
25517 * Fires when data is loaded.
25518 * @param {Roo.JsonView} this
25519 * @param {Object} data The JSON data loaded
25520 * @param {Object} response The raw Connect response object
25523 * @event loadexception
25524 * Fires when loading fails.
25525 * @param {Roo.JsonView} this
25526 * @param {Object} response The raw Connect response object
25529 'beforerender' : true,
25531 'loadexception' : true
25534 Roo.extend(Roo.JsonView, Roo.View, {
25536 * @type {String} The root property in the loaded JSON object that contains the data
25541 * Refreshes the view.
25543 refresh : function(){
25544 this.clearSelections();
25545 this.el.update("");
25547 var o = this.jsonData;
25548 if(o && o.length > 0){
25549 for(var i = 0, len = o.length; i < len; i++){
25550 var data = this.prepareData(o[i], i, o);
25551 html[html.length] = this.tpl.apply(data);
25554 html.push(this.emptyText);
25556 this.el.update(html.join(""));
25557 this.nodes = this.el.dom.childNodes;
25558 this.updateIndexes(0);
25562 * 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.
25563 * @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:
25566 url: "your-url.php",
25567 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25568 callback: yourFunction,
25569 scope: yourObject, //(optional scope)
25572 text: "Loading...",
25577 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25578 * 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.
25579 * @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}
25580 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25581 * @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.
25584 var um = this.el.getUpdateManager();
25585 um.update.apply(um, arguments);
25588 render : function(el, response){
25589 this.clearSelections();
25590 this.el.update("");
25593 o = Roo.util.JSON.decode(response.responseText);
25596 o = o[this.jsonRoot];
25601 * The current JSON data or null
25604 this.beforeRender();
25609 * Get the number of records in the current JSON dataset
25612 getCount : function(){
25613 return this.jsonData ? this.jsonData.length : 0;
25617 * Returns the JSON object for the specified node(s)
25618 * @param {HTMLElement/Array} node The node or an array of nodes
25619 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25620 * you get the JSON object for the node
25622 getNodeData : function(node){
25623 if(node instanceof Array){
25625 for(var i = 0, len = node.length; i < len; i++){
25626 data.push(this.getNodeData(node[i]));
25630 return this.jsonData[this.indexOf(node)] || null;
25633 beforeRender : function(){
25634 this.snapshot = this.jsonData;
25636 this.sort.apply(this, this.sortInfo);
25638 this.fireEvent("beforerender", this, this.jsonData);
25641 onLoad : function(el, o){
25642 this.fireEvent("load", this, this.jsonData, o);
25645 onLoadException : function(el, o){
25646 this.fireEvent("loadexception", this, o);
25650 * Filter the data by a specific property.
25651 * @param {String} property A property on your JSON objects
25652 * @param {String/RegExp} value Either string that the property values
25653 * should start with, or a RegExp to test against the property
25655 filter : function(property, value){
25658 var ss = this.snapshot;
25659 if(typeof value == "string"){
25660 var vlen = value.length;
25662 this.clearFilter();
25665 value = value.toLowerCase();
25666 for(var i = 0, len = ss.length; i < len; i++){
25668 if(o[property].substr(0, vlen).toLowerCase() == value){
25672 } else if(value.exec){ // regex?
25673 for(var i = 0, len = ss.length; i < len; i++){
25675 if(value.test(o[property])){
25682 this.jsonData = data;
25688 * Filter by a function. The passed function will be called with each
25689 * object in the current dataset. If the function returns true the value is kept,
25690 * otherwise it is filtered.
25691 * @param {Function} fn
25692 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25694 filterBy : function(fn, scope){
25697 var ss = this.snapshot;
25698 for(var i = 0, len = ss.length; i < len; i++){
25700 if(fn.call(scope || this, o)){
25704 this.jsonData = data;
25710 * Clears the current filter.
25712 clearFilter : function(){
25713 if(this.snapshot && this.jsonData != this.snapshot){
25714 this.jsonData = this.snapshot;
25721 * Sorts the data for this view and refreshes it.
25722 * @param {String} property A property on your JSON objects to sort on
25723 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25724 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25726 sort : function(property, dir, sortType){
25727 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25730 var dsc = dir && dir.toLowerCase() == "desc";
25731 var f = function(o1, o2){
25732 var v1 = sortType ? sortType(o1[p]) : o1[p];
25733 var v2 = sortType ? sortType(o2[p]) : o2[p];
25736 return dsc ? +1 : -1;
25737 } else if(v1 > v2){
25738 return dsc ? -1 : +1;
25743 this.jsonData.sort(f);
25745 if(this.jsonData != this.snapshot){
25746 this.snapshot.sort(f);
25752 * Ext JS Library 1.1.1
25753 * Copyright(c) 2006-2007, Ext JS, LLC.
25755 * Originally Released Under LGPL - original licence link has changed is not relivant.
25758 * <script type="text/javascript">
25763 * @class Roo.ColorPalette
25764 * @extends Roo.Component
25765 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25766 * Here's an example of typical usage:
25768 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25769 cp.render('my-div');
25771 cp.on('select', function(palette, selColor){
25772 // do something with selColor
25776 * Create a new ColorPalette
25777 * @param {Object} config The config object
25779 Roo.ColorPalette = function(config){
25780 Roo.ColorPalette.superclass.constructor.call(this, config);
25784 * Fires when a color is selected
25785 * @param {ColorPalette} this
25786 * @param {String} color The 6-digit color hex code (without the # symbol)
25792 this.on("select", this.handler, this.scope, true);
25795 Roo.extend(Roo.ColorPalette, Roo.Component, {
25797 * @cfg {String} itemCls
25798 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25800 itemCls : "x-color-palette",
25802 * @cfg {String} value
25803 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25804 * the hex codes are case-sensitive.
25807 clickEvent:'click',
25809 ctype: "Roo.ColorPalette",
25812 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25814 allowReselect : false,
25817 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25818 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25819 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25820 * of colors with the width setting until the box is symmetrical.</p>
25821 * <p>You can override individual colors if needed:</p>
25823 var cp = new Roo.ColorPalette();
25824 cp.colors[0] = "FF0000"; // change the first box to red
25827 Or you can provide a custom array of your own for complete control:
25829 var cp = new Roo.ColorPalette();
25830 cp.colors = ["000000", "993300", "333300"];
25835 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25836 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25837 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25838 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25839 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25843 onRender : function(container, position){
25844 var t = new Roo.MasterTemplate(
25845 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25847 var c = this.colors;
25848 for(var i = 0, len = c.length; i < len; i++){
25851 var el = document.createElement("div");
25852 el.className = this.itemCls;
25854 container.dom.insertBefore(el, position);
25855 this.el = Roo.get(el);
25856 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25857 if(this.clickEvent != 'click'){
25858 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25863 afterRender : function(){
25864 Roo.ColorPalette.superclass.afterRender.call(this);
25866 var s = this.value;
25873 handleClick : function(e, t){
25874 e.preventDefault();
25875 if(!this.disabled){
25876 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25877 this.select(c.toUpperCase());
25882 * Selects the specified color in the palette (fires the select event)
25883 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25885 select : function(color){
25886 color = color.replace("#", "");
25887 if(color != this.value || this.allowReselect){
25890 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25892 el.child("a.color-"+color).addClass("x-color-palette-sel");
25893 this.value = color;
25894 this.fireEvent("select", this, color);
25899 * Ext JS Library 1.1.1
25900 * Copyright(c) 2006-2007, Ext JS, LLC.
25902 * Originally Released Under LGPL - original licence link has changed is not relivant.
25905 * <script type="text/javascript">
25909 * @class Roo.DatePicker
25910 * @extends Roo.Component
25911 * Simple date picker class.
25913 * Create a new DatePicker
25914 * @param {Object} config The config object
25916 Roo.DatePicker = function(config){
25917 Roo.DatePicker.superclass.constructor.call(this, config);
25919 this.value = config && config.value ?
25920 config.value.clearTime() : new Date().clearTime();
25925 * Fires when a date is selected
25926 * @param {DatePicker} this
25927 * @param {Date} date The selected date
25931 * @event monthchange
25932 * Fires when the displayed month changes
25933 * @param {DatePicker} this
25934 * @param {Date} date The selected month
25936 'monthchange': true
25940 this.on("select", this.handler, this.scope || this);
25942 // build the disabledDatesRE
25943 if(!this.disabledDatesRE && this.disabledDates){
25944 var dd = this.disabledDates;
25946 for(var i = 0; i < dd.length; i++){
25948 if(i != dd.length-1) re += "|";
25950 this.disabledDatesRE = new RegExp(re + ")");
25954 Roo.extend(Roo.DatePicker, Roo.Component, {
25956 * @cfg {String} todayText
25957 * The text to display on the button that selects the current date (defaults to "Today")
25959 todayText : "Today",
25961 * @cfg {String} okText
25962 * The text to display on the ok button
25964 okText : " OK ", //   to give the user extra clicking room
25966 * @cfg {String} cancelText
25967 * The text to display on the cancel button
25969 cancelText : "Cancel",
25971 * @cfg {String} todayTip
25972 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25974 todayTip : "{0} (Spacebar)",
25976 * @cfg {Date} minDate
25977 * Minimum allowable date (JavaScript date object, defaults to null)
25981 * @cfg {Date} maxDate
25982 * Maximum allowable date (JavaScript date object, defaults to null)
25986 * @cfg {String} minText
25987 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25989 minText : "This date is before the minimum date",
25991 * @cfg {String} maxText
25992 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25994 maxText : "This date is after the maximum date",
25996 * @cfg {String} format
25997 * The default date format string which can be overriden for localization support. The format must be
25998 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26002 * @cfg {Array} disabledDays
26003 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26005 disabledDays : null,
26007 * @cfg {String} disabledDaysText
26008 * The tooltip to display when the date falls on a disabled day (defaults to "")
26010 disabledDaysText : "",
26012 * @cfg {RegExp} disabledDatesRE
26013 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26015 disabledDatesRE : null,
26017 * @cfg {String} disabledDatesText
26018 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26020 disabledDatesText : "",
26022 * @cfg {Boolean} constrainToViewport
26023 * True to constrain the date picker to the viewport (defaults to true)
26025 constrainToViewport : true,
26027 * @cfg {Array} monthNames
26028 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26030 monthNames : Date.monthNames,
26032 * @cfg {Array} dayNames
26033 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26035 dayNames : Date.dayNames,
26037 * @cfg {String} nextText
26038 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26040 nextText: 'Next Month (Control+Right)',
26042 * @cfg {String} prevText
26043 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26045 prevText: 'Previous Month (Control+Left)',
26047 * @cfg {String} monthYearText
26048 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26050 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26052 * @cfg {Number} startDay
26053 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26057 * @cfg {Bool} showClear
26058 * Show a clear button (usefull for date form elements that can be blank.)
26064 * Sets the value of the date field
26065 * @param {Date} value The date to set
26067 setValue : function(value){
26068 var old = this.value;
26070 if (typeof(value) == 'string') {
26072 value = Date.parseDate(value, this.format);
26075 value = new Date();
26078 this.value = value.clearTime(true);
26080 this.update(this.value);
26085 * Gets the current selected value of the date field
26086 * @return {Date} The selected date
26088 getValue : function(){
26093 focus : function(){
26095 this.update(this.activeDate);
26100 onRender : function(container, position){
26103 '<table cellspacing="0">',
26104 '<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>',
26105 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26106 var dn = this.dayNames;
26107 for(var i = 0; i < 7; i++){
26108 var d = this.startDay+i;
26112 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26114 m[m.length] = "</tr></thead><tbody><tr>";
26115 for(var i = 0; i < 42; i++) {
26116 if(i % 7 == 0 && i != 0){
26117 m[m.length] = "</tr><tr>";
26119 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26121 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26122 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26124 var el = document.createElement("div");
26125 el.className = "x-date-picker";
26126 el.innerHTML = m.join("");
26128 container.dom.insertBefore(el, position);
26130 this.el = Roo.get(el);
26131 this.eventEl = Roo.get(el.firstChild);
26133 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26134 handler: this.showPrevMonth,
26136 preventDefault:true,
26140 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26141 handler: this.showNextMonth,
26143 preventDefault:true,
26147 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26149 this.monthPicker = this.el.down('div.x-date-mp');
26150 this.monthPicker.enableDisplayMode('block');
26152 var kn = new Roo.KeyNav(this.eventEl, {
26153 "left" : function(e){
26155 this.showPrevMonth() :
26156 this.update(this.activeDate.add("d", -1));
26159 "right" : function(e){
26161 this.showNextMonth() :
26162 this.update(this.activeDate.add("d", 1));
26165 "up" : function(e){
26167 this.showNextYear() :
26168 this.update(this.activeDate.add("d", -7));
26171 "down" : function(e){
26173 this.showPrevYear() :
26174 this.update(this.activeDate.add("d", 7));
26177 "pageUp" : function(e){
26178 this.showNextMonth();
26181 "pageDown" : function(e){
26182 this.showPrevMonth();
26185 "enter" : function(e){
26186 e.stopPropagation();
26193 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26195 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26197 this.el.unselectable();
26199 this.cells = this.el.select("table.x-date-inner tbody td");
26200 this.textNodes = this.el.query("table.x-date-inner tbody span");
26202 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26204 tooltip: this.monthYearText
26207 this.mbtn.on('click', this.showMonthPicker, this);
26208 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26211 var today = (new Date()).dateFormat(this.format);
26213 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26214 if (this.showClear) {
26215 baseTb.add( new Roo.Toolbar.Fill());
26218 text: String.format(this.todayText, today),
26219 tooltip: String.format(this.todayTip, today),
26220 handler: this.selectToday,
26224 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26227 if (this.showClear) {
26229 baseTb.add( new Roo.Toolbar.Fill());
26232 cls: 'x-btn-icon x-btn-clear',
26233 handler: function() {
26235 this.fireEvent("select", this, '');
26245 this.update(this.value);
26248 createMonthPicker : function(){
26249 if(!this.monthPicker.dom.firstChild){
26250 var buf = ['<table border="0" cellspacing="0">'];
26251 for(var i = 0; i < 6; i++){
26253 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26254 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26256 '<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>' :
26257 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26261 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26263 '</button><button type="button" class="x-date-mp-cancel">',
26265 '</button></td></tr>',
26268 this.monthPicker.update(buf.join(''));
26269 this.monthPicker.on('click', this.onMonthClick, this);
26270 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26272 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26273 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26275 this.mpMonths.each(function(m, a, i){
26278 m.dom.xmonth = 5 + Math.round(i * .5);
26280 m.dom.xmonth = Math.round((i-1) * .5);
26286 showMonthPicker : function(){
26287 this.createMonthPicker();
26288 var size = this.el.getSize();
26289 this.monthPicker.setSize(size);
26290 this.monthPicker.child('table').setSize(size);
26292 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26293 this.updateMPMonth(this.mpSelMonth);
26294 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26295 this.updateMPYear(this.mpSelYear);
26297 this.monthPicker.slideIn('t', {duration:.2});
26300 updateMPYear : function(y){
26302 var ys = this.mpYears.elements;
26303 for(var i = 1; i <= 10; i++){
26304 var td = ys[i-1], y2;
26306 y2 = y + Math.round(i * .5);
26307 td.firstChild.innerHTML = y2;
26310 y2 = y - (5-Math.round(i * .5));
26311 td.firstChild.innerHTML = y2;
26314 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26318 updateMPMonth : function(sm){
26319 this.mpMonths.each(function(m, a, i){
26320 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26324 selectMPMonth: function(m){
26328 onMonthClick : function(e, t){
26330 var el = new Roo.Element(t), pn;
26331 if(el.is('button.x-date-mp-cancel')){
26332 this.hideMonthPicker();
26334 else if(el.is('button.x-date-mp-ok')){
26335 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26336 this.hideMonthPicker();
26338 else if(pn = el.up('td.x-date-mp-month', 2)){
26339 this.mpMonths.removeClass('x-date-mp-sel');
26340 pn.addClass('x-date-mp-sel');
26341 this.mpSelMonth = pn.dom.xmonth;
26343 else if(pn = el.up('td.x-date-mp-year', 2)){
26344 this.mpYears.removeClass('x-date-mp-sel');
26345 pn.addClass('x-date-mp-sel');
26346 this.mpSelYear = pn.dom.xyear;
26348 else if(el.is('a.x-date-mp-prev')){
26349 this.updateMPYear(this.mpyear-10);
26351 else if(el.is('a.x-date-mp-next')){
26352 this.updateMPYear(this.mpyear+10);
26356 onMonthDblClick : function(e, t){
26358 var el = new Roo.Element(t), pn;
26359 if(pn = el.up('td.x-date-mp-month', 2)){
26360 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26361 this.hideMonthPicker();
26363 else if(pn = el.up('td.x-date-mp-year', 2)){
26364 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26365 this.hideMonthPicker();
26369 hideMonthPicker : function(disableAnim){
26370 if(this.monthPicker){
26371 if(disableAnim === true){
26372 this.monthPicker.hide();
26374 this.monthPicker.slideOut('t', {duration:.2});
26380 showPrevMonth : function(e){
26381 this.update(this.activeDate.add("mo", -1));
26385 showNextMonth : function(e){
26386 this.update(this.activeDate.add("mo", 1));
26390 showPrevYear : function(){
26391 this.update(this.activeDate.add("y", -1));
26395 showNextYear : function(){
26396 this.update(this.activeDate.add("y", 1));
26400 handleMouseWheel : function(e){
26401 var delta = e.getWheelDelta();
26403 this.showPrevMonth();
26405 } else if(delta < 0){
26406 this.showNextMonth();
26412 handleDateClick : function(e, t){
26414 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26415 this.setValue(new Date(t.dateValue));
26416 this.fireEvent("select", this, this.value);
26421 selectToday : function(){
26422 this.setValue(new Date().clearTime());
26423 this.fireEvent("select", this, this.value);
26427 update : function(date)
26429 var vd = this.activeDate;
26430 this.activeDate = date;
26432 var t = date.getTime();
26433 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26434 this.cells.removeClass("x-date-selected");
26435 this.cells.each(function(c){
26436 if(c.dom.firstChild.dateValue == t){
26437 c.addClass("x-date-selected");
26438 setTimeout(function(){
26439 try{c.dom.firstChild.focus();}catch(e){}
26448 var days = date.getDaysInMonth();
26449 var firstOfMonth = date.getFirstDateOfMonth();
26450 var startingPos = firstOfMonth.getDay()-this.startDay;
26452 if(startingPos <= this.startDay){
26456 var pm = date.add("mo", -1);
26457 var prevStart = pm.getDaysInMonth()-startingPos;
26459 var cells = this.cells.elements;
26460 var textEls = this.textNodes;
26461 days += startingPos;
26463 // convert everything to numbers so it's fast
26464 var day = 86400000;
26465 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26466 var today = new Date().clearTime().getTime();
26467 var sel = date.clearTime().getTime();
26468 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26469 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26470 var ddMatch = this.disabledDatesRE;
26471 var ddText = this.disabledDatesText;
26472 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26473 var ddaysText = this.disabledDaysText;
26474 var format = this.format;
26476 var setCellClass = function(cal, cell){
26478 var t = d.getTime();
26479 cell.firstChild.dateValue = t;
26481 cell.className += " x-date-today";
26482 cell.title = cal.todayText;
26485 cell.className += " x-date-selected";
26486 setTimeout(function(){
26487 try{cell.firstChild.focus();}catch(e){}
26492 cell.className = " x-date-disabled";
26493 cell.title = cal.minText;
26497 cell.className = " x-date-disabled";
26498 cell.title = cal.maxText;
26502 if(ddays.indexOf(d.getDay()) != -1){
26503 cell.title = ddaysText;
26504 cell.className = " x-date-disabled";
26507 if(ddMatch && format){
26508 var fvalue = d.dateFormat(format);
26509 if(ddMatch.test(fvalue)){
26510 cell.title = ddText.replace("%0", fvalue);
26511 cell.className = " x-date-disabled";
26517 for(; i < startingPos; i++) {
26518 textEls[i].innerHTML = (++prevStart);
26519 d.setDate(d.getDate()+1);
26520 cells[i].className = "x-date-prevday";
26521 setCellClass(this, cells[i]);
26523 for(; i < days; i++){
26524 intDay = i - startingPos + 1;
26525 textEls[i].innerHTML = (intDay);
26526 d.setDate(d.getDate()+1);
26527 cells[i].className = "x-date-active";
26528 setCellClass(this, cells[i]);
26531 for(; i < 42; i++) {
26532 textEls[i].innerHTML = (++extraDays);
26533 d.setDate(d.getDate()+1);
26534 cells[i].className = "x-date-nextday";
26535 setCellClass(this, cells[i]);
26538 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26539 this.fireEvent('monthchange', this, date);
26541 if(!this.internalRender){
26542 var main = this.el.dom.firstChild;
26543 var w = main.offsetWidth;
26544 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26545 Roo.fly(main).setWidth(w);
26546 this.internalRender = true;
26547 // opera does not respect the auto grow header center column
26548 // then, after it gets a width opera refuses to recalculate
26549 // without a second pass
26550 if(Roo.isOpera && !this.secondPass){
26551 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26552 this.secondPass = true;
26553 this.update.defer(10, this, [date]);
26561 * Ext JS Library 1.1.1
26562 * Copyright(c) 2006-2007, Ext JS, LLC.
26564 * Originally Released Under LGPL - original licence link has changed is not relivant.
26567 * <script type="text/javascript">
26570 * @class Roo.TabPanel
26571 * @extends Roo.util.Observable
26572 * A lightweight tab container.
26576 // basic tabs 1, built from existing content
26577 var tabs = new Roo.TabPanel("tabs1");
26578 tabs.addTab("script", "View Script");
26579 tabs.addTab("markup", "View Markup");
26580 tabs.activate("script");
26582 // more advanced tabs, built from javascript
26583 var jtabs = new Roo.TabPanel("jtabs");
26584 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26586 // set up the UpdateManager
26587 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26588 var updater = tab2.getUpdateManager();
26589 updater.setDefaultUrl("ajax1.htm");
26590 tab2.on('activate', updater.refresh, updater, true);
26592 // Use setUrl for Ajax loading
26593 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26594 tab3.setUrl("ajax2.htm", null, true);
26597 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26600 jtabs.activate("jtabs-1");
26603 * Create a new TabPanel.
26604 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26605 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26607 Roo.TabPanel = function(container, config){
26609 * The container element for this TabPanel.
26610 * @type Roo.Element
26612 this.el = Roo.get(container, true);
26614 if(typeof config == "boolean"){
26615 this.tabPosition = config ? "bottom" : "top";
26617 Roo.apply(this, config);
26620 if(this.tabPosition == "bottom"){
26621 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26622 this.el.addClass("x-tabs-bottom");
26624 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26625 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26626 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26628 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26630 if(this.tabPosition != "bottom"){
26631 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26632 * @type Roo.Element
26634 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26635 this.el.addClass("x-tabs-top");
26639 this.bodyEl.setStyle("position", "relative");
26641 this.active = null;
26642 this.activateDelegate = this.activate.createDelegate(this);
26647 * Fires when the active tab changes
26648 * @param {Roo.TabPanel} this
26649 * @param {Roo.TabPanelItem} activePanel The new active tab
26653 * @event beforetabchange
26654 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26655 * @param {Roo.TabPanel} this
26656 * @param {Object} e Set cancel to true on this object to cancel the tab change
26657 * @param {Roo.TabPanelItem} tab The tab being changed to
26659 "beforetabchange" : true
26662 Roo.EventManager.onWindowResize(this.onResize, this);
26663 this.cpad = this.el.getPadding("lr");
26664 this.hiddenCount = 0;
26667 // toolbar on the tabbar support...
26668 if (this.toolbar) {
26669 var tcfg = this.toolbar;
26670 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26671 this.toolbar = new Roo.Toolbar(tcfg);
26672 if (Roo.isSafari) {
26673 var tbl = tcfg.container.child('table', true);
26674 tbl.setAttribute('width', '100%');
26681 Roo.TabPanel.superclass.constructor.call(this);
26684 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26686 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26688 tabPosition : "top",
26690 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26692 currentTabWidth : 0,
26694 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26698 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26702 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26704 preferredTabWidth : 175,
26706 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26708 resizeTabs : false,
26710 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26712 monitorResize : true,
26714 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26719 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26720 * @param {String} id The id of the div to use <b>or create</b>
26721 * @param {String} text The text for the tab
26722 * @param {String} content (optional) Content to put in the TabPanelItem body
26723 * @param {Boolean} closable (optional) True to create a close icon on the tab
26724 * @return {Roo.TabPanelItem} The created TabPanelItem
26726 addTab : function(id, text, content, closable){
26727 var item = new Roo.TabPanelItem(this, id, text, closable);
26728 this.addTabItem(item);
26730 item.setContent(content);
26736 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26737 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26738 * @return {Roo.TabPanelItem}
26740 getTab : function(id){
26741 return this.items[id];
26745 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26746 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26748 hideTab : function(id){
26749 var t = this.items[id];
26752 this.hiddenCount++;
26753 this.autoSizeTabs();
26758 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26759 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26761 unhideTab : function(id){
26762 var t = this.items[id];
26764 t.setHidden(false);
26765 this.hiddenCount--;
26766 this.autoSizeTabs();
26771 * Adds an existing {@link Roo.TabPanelItem}.
26772 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26774 addTabItem : function(item){
26775 this.items[item.id] = item;
26776 this.items.push(item);
26777 if(this.resizeTabs){
26778 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26779 this.autoSizeTabs();
26786 * Removes a {@link Roo.TabPanelItem}.
26787 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26789 removeTab : function(id){
26790 var items = this.items;
26791 var tab = items[id];
26792 if(!tab) { return; }
26793 var index = items.indexOf(tab);
26794 if(this.active == tab && items.length > 1){
26795 var newTab = this.getNextAvailable(index);
26800 this.stripEl.dom.removeChild(tab.pnode.dom);
26801 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26802 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26804 items.splice(index, 1);
26805 delete this.items[tab.id];
26806 tab.fireEvent("close", tab);
26807 tab.purgeListeners();
26808 this.autoSizeTabs();
26811 getNextAvailable : function(start){
26812 var items = this.items;
26814 // look for a next tab that will slide over to
26815 // replace the one being removed
26816 while(index < items.length){
26817 var item = items[++index];
26818 if(item && !item.isHidden()){
26822 // if one isn't found select the previous tab (on the left)
26825 var item = items[--index];
26826 if(item && !item.isHidden()){
26834 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26835 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26837 disableTab : function(id){
26838 var tab = this.items[id];
26839 if(tab && this.active != tab){
26845 * Enables a {@link Roo.TabPanelItem} that is disabled.
26846 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26848 enableTab : function(id){
26849 var tab = this.items[id];
26854 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26855 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26856 * @return {Roo.TabPanelItem} The TabPanelItem.
26858 activate : function(id){
26859 var tab = this.items[id];
26863 if(tab == this.active || tab.disabled){
26867 this.fireEvent("beforetabchange", this, e, tab);
26868 if(e.cancel !== true && !tab.disabled){
26870 this.active.hide();
26872 this.active = this.items[id];
26873 this.active.show();
26874 this.fireEvent("tabchange", this, this.active);
26880 * Gets the active {@link Roo.TabPanelItem}.
26881 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26883 getActiveTab : function(){
26884 return this.active;
26888 * Updates the tab body element to fit the height of the container element
26889 * for overflow scrolling
26890 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26892 syncHeight : function(targetHeight){
26893 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26894 var bm = this.bodyEl.getMargins();
26895 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26896 this.bodyEl.setHeight(newHeight);
26900 onResize : function(){
26901 if(this.monitorResize){
26902 this.autoSizeTabs();
26907 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26909 beginUpdate : function(){
26910 this.updating = true;
26914 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26916 endUpdate : function(){
26917 this.updating = false;
26918 this.autoSizeTabs();
26922 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26924 autoSizeTabs : function(){
26925 var count = this.items.length;
26926 var vcount = count - this.hiddenCount;
26927 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26928 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26929 var availWidth = Math.floor(w / vcount);
26930 var b = this.stripBody;
26931 if(b.getWidth() > w){
26932 var tabs = this.items;
26933 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26934 if(availWidth < this.minTabWidth){
26935 /*if(!this.sleft){ // incomplete scrolling code
26936 this.createScrollButtons();
26939 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26942 if(this.currentTabWidth < this.preferredTabWidth){
26943 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26949 * Returns the number of tabs in this TabPanel.
26952 getCount : function(){
26953 return this.items.length;
26957 * Resizes all the tabs to the passed width
26958 * @param {Number} The new width
26960 setTabWidth : function(width){
26961 this.currentTabWidth = width;
26962 for(var i = 0, len = this.items.length; i < len; i++) {
26963 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26968 * Destroys this TabPanel
26969 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26971 destroy : function(removeEl){
26972 Roo.EventManager.removeResizeListener(this.onResize, this);
26973 for(var i = 0, len = this.items.length; i < len; i++){
26974 this.items[i].purgeListeners();
26976 if(removeEl === true){
26977 this.el.update("");
26984 * @class Roo.TabPanelItem
26985 * @extends Roo.util.Observable
26986 * Represents an individual item (tab plus body) in a TabPanel.
26987 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26988 * @param {String} id The id of this TabPanelItem
26989 * @param {String} text The text for the tab of this TabPanelItem
26990 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26992 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26994 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26995 * @type Roo.TabPanel
26997 this.tabPanel = tabPanel;
26999 * The id for this TabPanelItem
27004 this.disabled = false;
27008 this.loaded = false;
27009 this.closable = closable;
27012 * The body element for this TabPanelItem.
27013 * @type Roo.Element
27015 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27016 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27017 this.bodyEl.setStyle("display", "block");
27018 this.bodyEl.setStyle("zoom", "1");
27021 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27023 this.el = Roo.get(els.el, true);
27024 this.inner = Roo.get(els.inner, true);
27025 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27026 this.pnode = Roo.get(els.el.parentNode, true);
27027 this.el.on("mousedown", this.onTabMouseDown, this);
27028 this.el.on("click", this.onTabClick, this);
27031 var c = Roo.get(els.close, true);
27032 c.dom.title = this.closeText;
27033 c.addClassOnOver("close-over");
27034 c.on("click", this.closeClick, this);
27040 * Fires when this tab becomes the active tab.
27041 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27042 * @param {Roo.TabPanelItem} this
27046 * @event beforeclose
27047 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27048 * @param {Roo.TabPanelItem} this
27049 * @param {Object} e Set cancel to true on this object to cancel the close.
27051 "beforeclose": true,
27054 * Fires when this tab is closed.
27055 * @param {Roo.TabPanelItem} this
27059 * @event deactivate
27060 * Fires when this tab is no longer the active tab.
27061 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27062 * @param {Roo.TabPanelItem} this
27064 "deactivate" : true
27066 this.hidden = false;
27068 Roo.TabPanelItem.superclass.constructor.call(this);
27071 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27072 purgeListeners : function(){
27073 Roo.util.Observable.prototype.purgeListeners.call(this);
27074 this.el.removeAllListeners();
27077 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27080 this.pnode.addClass("on");
27083 this.tabPanel.stripWrap.repaint();
27085 this.fireEvent("activate", this.tabPanel, this);
27089 * Returns true if this tab is the active tab.
27090 * @return {Boolean}
27092 isActive : function(){
27093 return this.tabPanel.getActiveTab() == this;
27097 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27100 this.pnode.removeClass("on");
27102 this.fireEvent("deactivate", this.tabPanel, this);
27105 hideAction : function(){
27106 this.bodyEl.hide();
27107 this.bodyEl.setStyle("position", "absolute");
27108 this.bodyEl.setLeft("-20000px");
27109 this.bodyEl.setTop("-20000px");
27112 showAction : function(){
27113 this.bodyEl.setStyle("position", "relative");
27114 this.bodyEl.setTop("");
27115 this.bodyEl.setLeft("");
27116 this.bodyEl.show();
27120 * Set the tooltip for the tab.
27121 * @param {String} tooltip The tab's tooltip
27123 setTooltip : function(text){
27124 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27125 this.textEl.dom.qtip = text;
27126 this.textEl.dom.removeAttribute('title');
27128 this.textEl.dom.title = text;
27132 onTabClick : function(e){
27133 e.preventDefault();
27134 this.tabPanel.activate(this.id);
27137 onTabMouseDown : function(e){
27138 e.preventDefault();
27139 this.tabPanel.activate(this.id);
27142 getWidth : function(){
27143 return this.inner.getWidth();
27146 setWidth : function(width){
27147 var iwidth = width - this.pnode.getPadding("lr");
27148 this.inner.setWidth(iwidth);
27149 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27150 this.pnode.setWidth(width);
27154 * Show or hide the tab
27155 * @param {Boolean} hidden True to hide or false to show.
27157 setHidden : function(hidden){
27158 this.hidden = hidden;
27159 this.pnode.setStyle("display", hidden ? "none" : "");
27163 * Returns true if this tab is "hidden"
27164 * @return {Boolean}
27166 isHidden : function(){
27167 return this.hidden;
27171 * Returns the text for this tab
27174 getText : function(){
27178 autoSize : function(){
27179 //this.el.beginMeasure();
27180 this.textEl.setWidth(1);
27182 * #2804 [new] Tabs in Roojs
27183 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27185 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27186 //this.el.endMeasure();
27190 * Sets the text for the tab (Note: this also sets the tooltip text)
27191 * @param {String} text The tab's text and tooltip
27193 setText : function(text){
27195 this.textEl.update(text);
27196 this.setTooltip(text);
27197 if(!this.tabPanel.resizeTabs){
27202 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27204 activate : function(){
27205 this.tabPanel.activate(this.id);
27209 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27211 disable : function(){
27212 if(this.tabPanel.active != this){
27213 this.disabled = true;
27214 this.pnode.addClass("disabled");
27219 * Enables this TabPanelItem if it was previously disabled.
27221 enable : function(){
27222 this.disabled = false;
27223 this.pnode.removeClass("disabled");
27227 * Sets the content for this TabPanelItem.
27228 * @param {String} content The content
27229 * @param {Boolean} loadScripts true to look for and load scripts
27231 setContent : function(content, loadScripts){
27232 this.bodyEl.update(content, loadScripts);
27236 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27237 * @return {Roo.UpdateManager} The UpdateManager
27239 getUpdateManager : function(){
27240 return this.bodyEl.getUpdateManager();
27244 * Set a URL to be used to load the content for this TabPanelItem.
27245 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27246 * @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)
27247 * @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)
27248 * @return {Roo.UpdateManager} The UpdateManager
27250 setUrl : function(url, params, loadOnce){
27251 if(this.refreshDelegate){
27252 this.un('activate', this.refreshDelegate);
27254 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27255 this.on("activate", this.refreshDelegate);
27256 return this.bodyEl.getUpdateManager();
27260 _handleRefresh : function(url, params, loadOnce){
27261 if(!loadOnce || !this.loaded){
27262 var updater = this.bodyEl.getUpdateManager();
27263 updater.update(url, params, this._setLoaded.createDelegate(this));
27268 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27269 * Will fail silently if the setUrl method has not been called.
27270 * This does not activate the panel, just updates its content.
27272 refresh : function(){
27273 if(this.refreshDelegate){
27274 this.loaded = false;
27275 this.refreshDelegate();
27280 _setLoaded : function(){
27281 this.loaded = true;
27285 closeClick : function(e){
27288 this.fireEvent("beforeclose", this, o);
27289 if(o.cancel !== true){
27290 this.tabPanel.removeTab(this.id);
27294 * The text displayed in the tooltip for the close icon.
27297 closeText : "Close this tab"
27301 Roo.TabPanel.prototype.createStrip = function(container){
27302 var strip = document.createElement("div");
27303 strip.className = "x-tabs-wrap";
27304 container.appendChild(strip);
27308 Roo.TabPanel.prototype.createStripList = function(strip){
27309 // div wrapper for retard IE
27310 // returns the "tr" element.
27311 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27312 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27313 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27314 return strip.firstChild.firstChild.firstChild.firstChild;
27317 Roo.TabPanel.prototype.createBody = function(container){
27318 var body = document.createElement("div");
27319 Roo.id(body, "tab-body");
27320 Roo.fly(body).addClass("x-tabs-body");
27321 container.appendChild(body);
27325 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27326 var body = Roo.getDom(id);
27328 body = document.createElement("div");
27331 Roo.fly(body).addClass("x-tabs-item-body");
27332 bodyEl.insertBefore(body, bodyEl.firstChild);
27336 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27337 var td = document.createElement("td");
27338 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27339 //stripEl.appendChild(td);
27341 td.className = "x-tabs-closable";
27342 if(!this.closeTpl){
27343 this.closeTpl = new Roo.Template(
27344 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27345 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27346 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27349 var el = this.closeTpl.overwrite(td, {"text": text});
27350 var close = el.getElementsByTagName("div")[0];
27351 var inner = el.getElementsByTagName("em")[0];
27352 return {"el": el, "close": close, "inner": inner};
27355 this.tabTpl = new Roo.Template(
27356 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27357 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27360 var el = this.tabTpl.overwrite(td, {"text": text});
27361 var inner = el.getElementsByTagName("em")[0];
27362 return {"el": el, "inner": inner};
27366 * Ext JS Library 1.1.1
27367 * Copyright(c) 2006-2007, Ext JS, LLC.
27369 * Originally Released Under LGPL - original licence link has changed is not relivant.
27372 * <script type="text/javascript">
27376 * @class Roo.Button
27377 * @extends Roo.util.Observable
27378 * Simple Button class
27379 * @cfg {String} text The button text
27380 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27381 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27382 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27383 * @cfg {Object} scope The scope of the handler
27384 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27385 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27386 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27387 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27388 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27389 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27390 applies if enableToggle = true)
27391 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27392 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27393 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27395 * Create a new button
27396 * @param {Object} config The config object
27398 Roo.Button = function(renderTo, config)
27402 renderTo = config.renderTo || false;
27405 Roo.apply(this, config);
27409 * Fires when this button is clicked
27410 * @param {Button} this
27411 * @param {EventObject} e The click event
27416 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27417 * @param {Button} this
27418 * @param {Boolean} pressed
27423 * Fires when the mouse hovers over the button
27424 * @param {Button} this
27425 * @param {Event} e The event object
27427 'mouseover' : true,
27430 * Fires when the mouse exits the button
27431 * @param {Button} this
27432 * @param {Event} e The event object
27437 * Fires when the button is rendered
27438 * @param {Button} this
27443 this.menu = Roo.menu.MenuMgr.get(this.menu);
27445 // register listeners first!! - so render can be captured..
27446 Roo.util.Observable.call(this);
27448 this.render(renderTo);
27454 Roo.extend(Roo.Button, Roo.util.Observable, {
27460 * Read-only. True if this button is hidden
27465 * Read-only. True if this button is disabled
27470 * Read-only. True if this button is pressed (only if enableToggle = true)
27476 * @cfg {Number} tabIndex
27477 * The DOM tabIndex for this button (defaults to undefined)
27479 tabIndex : undefined,
27482 * @cfg {Boolean} enableToggle
27483 * True to enable pressed/not pressed toggling (defaults to false)
27485 enableToggle: false,
27487 * @cfg {Mixed} menu
27488 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27492 * @cfg {String} menuAlign
27493 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27495 menuAlign : "tl-bl?",
27498 * @cfg {String} iconCls
27499 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27501 iconCls : undefined,
27503 * @cfg {String} type
27504 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27509 menuClassTarget: 'tr',
27512 * @cfg {String} clickEvent
27513 * The type of event to map to the button's event handler (defaults to 'click')
27515 clickEvent : 'click',
27518 * @cfg {Boolean} handleMouseEvents
27519 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27521 handleMouseEvents : true,
27524 * @cfg {String} tooltipType
27525 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27527 tooltipType : 'qtip',
27530 * @cfg {String} cls
27531 * A CSS class to apply to the button's main element.
27535 * @cfg {Roo.Template} template (Optional)
27536 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27537 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27538 * require code modifications if required elements (e.g. a button) aren't present.
27542 render : function(renderTo){
27544 if(this.hideParent){
27545 this.parentEl = Roo.get(renderTo);
27547 if(!this.dhconfig){
27548 if(!this.template){
27549 if(!Roo.Button.buttonTemplate){
27550 // hideous table template
27551 Roo.Button.buttonTemplate = new Roo.Template(
27552 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27553 '<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>',
27554 "</tr></tbody></table>");
27556 this.template = Roo.Button.buttonTemplate;
27558 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27559 var btnEl = btn.child("button:first");
27560 btnEl.on('focus', this.onFocus, this);
27561 btnEl.on('blur', this.onBlur, this);
27563 btn.addClass(this.cls);
27566 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27569 btnEl.addClass(this.iconCls);
27571 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27574 if(this.tabIndex !== undefined){
27575 btnEl.dom.tabIndex = this.tabIndex;
27578 if(typeof this.tooltip == 'object'){
27579 Roo.QuickTips.tips(Roo.apply({
27583 btnEl.dom[this.tooltipType] = this.tooltip;
27587 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27591 this.el.dom.id = this.el.id = this.id;
27594 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27595 this.menu.on("show", this.onMenuShow, this);
27596 this.menu.on("hide", this.onMenuHide, this);
27598 btn.addClass("x-btn");
27599 if(Roo.isIE && !Roo.isIE7){
27600 this.autoWidth.defer(1, this);
27604 if(this.handleMouseEvents){
27605 btn.on("mouseover", this.onMouseOver, this);
27606 btn.on("mouseout", this.onMouseOut, this);
27607 btn.on("mousedown", this.onMouseDown, this);
27609 btn.on(this.clickEvent, this.onClick, this);
27610 //btn.on("mouseup", this.onMouseUp, this);
27617 Roo.ButtonToggleMgr.register(this);
27619 this.el.addClass("x-btn-pressed");
27622 var repeater = new Roo.util.ClickRepeater(btn,
27623 typeof this.repeat == "object" ? this.repeat : {}
27625 repeater.on("click", this.onClick, this);
27628 this.fireEvent('render', this);
27632 * Returns the button's underlying element
27633 * @return {Roo.Element} The element
27635 getEl : function(){
27640 * Destroys this Button and removes any listeners.
27642 destroy : function(){
27643 Roo.ButtonToggleMgr.unregister(this);
27644 this.el.removeAllListeners();
27645 this.purgeListeners();
27650 autoWidth : function(){
27652 this.el.setWidth("auto");
27653 if(Roo.isIE7 && Roo.isStrict){
27654 var ib = this.el.child('button');
27655 if(ib && ib.getWidth() > 20){
27657 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27662 this.el.beginMeasure();
27664 if(this.el.getWidth() < this.minWidth){
27665 this.el.setWidth(this.minWidth);
27668 this.el.endMeasure();
27675 * Assigns this button's click handler
27676 * @param {Function} handler The function to call when the button is clicked
27677 * @param {Object} scope (optional) Scope for the function passed in
27679 setHandler : function(handler, scope){
27680 this.handler = handler;
27681 this.scope = scope;
27685 * Sets this button's text
27686 * @param {String} text The button text
27688 setText : function(text){
27691 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27697 * Gets the text for this button
27698 * @return {String} The button text
27700 getText : function(){
27708 this.hidden = false;
27710 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27718 this.hidden = true;
27720 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27725 * Convenience function for boolean show/hide
27726 * @param {Boolean} visible True to show, false to hide
27728 setVisible: function(visible){
27737 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27738 * @param {Boolean} state (optional) Force a particular state
27740 toggle : function(state){
27741 state = state === undefined ? !this.pressed : state;
27742 if(state != this.pressed){
27744 this.el.addClass("x-btn-pressed");
27745 this.pressed = true;
27746 this.fireEvent("toggle", this, true);
27748 this.el.removeClass("x-btn-pressed");
27749 this.pressed = false;
27750 this.fireEvent("toggle", this, false);
27752 if(this.toggleHandler){
27753 this.toggleHandler.call(this.scope || this, this, state);
27761 focus : function(){
27762 this.el.child('button:first').focus();
27766 * Disable this button
27768 disable : function(){
27770 this.el.addClass("x-btn-disabled");
27772 this.disabled = true;
27776 * Enable this button
27778 enable : function(){
27780 this.el.removeClass("x-btn-disabled");
27782 this.disabled = false;
27786 * Convenience function for boolean enable/disable
27787 * @param {Boolean} enabled True to enable, false to disable
27789 setDisabled : function(v){
27790 this[v !== true ? "enable" : "disable"]();
27794 onClick : function(e){
27796 e.preventDefault();
27801 if(!this.disabled){
27802 if(this.enableToggle){
27805 if(this.menu && !this.menu.isVisible()){
27806 this.menu.show(this.el, this.menuAlign);
27808 this.fireEvent("click", this, e);
27810 this.el.removeClass("x-btn-over");
27811 this.handler.call(this.scope || this, this, e);
27816 onMouseOver : function(e){
27817 if(!this.disabled){
27818 this.el.addClass("x-btn-over");
27819 this.fireEvent('mouseover', this, e);
27823 onMouseOut : function(e){
27824 if(!e.within(this.el, true)){
27825 this.el.removeClass("x-btn-over");
27826 this.fireEvent('mouseout', this, e);
27830 onFocus : function(e){
27831 if(!this.disabled){
27832 this.el.addClass("x-btn-focus");
27836 onBlur : function(e){
27837 this.el.removeClass("x-btn-focus");
27840 onMouseDown : function(e){
27841 if(!this.disabled && e.button == 0){
27842 this.el.addClass("x-btn-click");
27843 Roo.get(document).on('mouseup', this.onMouseUp, this);
27847 onMouseUp : function(e){
27849 this.el.removeClass("x-btn-click");
27850 Roo.get(document).un('mouseup', this.onMouseUp, this);
27854 onMenuShow : function(e){
27855 this.el.addClass("x-btn-menu-active");
27858 onMenuHide : function(e){
27859 this.el.removeClass("x-btn-menu-active");
27863 // Private utility class used by Button
27864 Roo.ButtonToggleMgr = function(){
27867 function toggleGroup(btn, state){
27869 var g = groups[btn.toggleGroup];
27870 for(var i = 0, l = g.length; i < l; i++){
27872 g[i].toggle(false);
27879 register : function(btn){
27880 if(!btn.toggleGroup){
27883 var g = groups[btn.toggleGroup];
27885 g = groups[btn.toggleGroup] = [];
27888 btn.on("toggle", toggleGroup);
27891 unregister : function(btn){
27892 if(!btn.toggleGroup){
27895 var g = groups[btn.toggleGroup];
27898 btn.un("toggle", toggleGroup);
27904 * Ext JS Library 1.1.1
27905 * Copyright(c) 2006-2007, Ext JS, LLC.
27907 * Originally Released Under LGPL - original licence link has changed is not relivant.
27910 * <script type="text/javascript">
27914 * @class Roo.SplitButton
27915 * @extends Roo.Button
27916 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27917 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27918 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27919 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27920 * @cfg {String} arrowTooltip The title attribute of the arrow
27922 * Create a new menu button
27923 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27924 * @param {Object} config The config object
27926 Roo.SplitButton = function(renderTo, config){
27927 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27929 * @event arrowclick
27930 * Fires when this button's arrow is clicked
27931 * @param {SplitButton} this
27932 * @param {EventObject} e The click event
27934 this.addEvents({"arrowclick":true});
27937 Roo.extend(Roo.SplitButton, Roo.Button, {
27938 render : function(renderTo){
27939 // this is one sweet looking template!
27940 var tpl = new Roo.Template(
27941 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27942 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27943 '<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>',
27944 "</tbody></table></td><td>",
27945 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27946 '<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>',
27947 "</tbody></table></td></tr></table>"
27949 var btn = tpl.append(renderTo, [this.text, this.type], true);
27950 var btnEl = btn.child("button");
27952 btn.addClass(this.cls);
27955 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27958 btnEl.addClass(this.iconCls);
27960 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27964 if(this.handleMouseEvents){
27965 btn.on("mouseover", this.onMouseOver, this);
27966 btn.on("mouseout", this.onMouseOut, this);
27967 btn.on("mousedown", this.onMouseDown, this);
27968 btn.on("mouseup", this.onMouseUp, this);
27970 btn.on(this.clickEvent, this.onClick, this);
27972 if(typeof this.tooltip == 'object'){
27973 Roo.QuickTips.tips(Roo.apply({
27977 btnEl.dom[this.tooltipType] = this.tooltip;
27980 if(this.arrowTooltip){
27981 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27990 this.el.addClass("x-btn-pressed");
27992 if(Roo.isIE && !Roo.isIE7){
27993 this.autoWidth.defer(1, this);
27998 this.menu.on("show", this.onMenuShow, this);
27999 this.menu.on("hide", this.onMenuHide, this);
28001 this.fireEvent('render', this);
28005 autoWidth : function(){
28007 var tbl = this.el.child("table:first");
28008 var tbl2 = this.el.child("table:last");
28009 this.el.setWidth("auto");
28010 tbl.setWidth("auto");
28011 if(Roo.isIE7 && Roo.isStrict){
28012 var ib = this.el.child('button:first');
28013 if(ib && ib.getWidth() > 20){
28015 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28020 this.el.beginMeasure();
28022 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28023 tbl.setWidth(this.minWidth-tbl2.getWidth());
28026 this.el.endMeasure();
28029 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28033 * Sets this button's click handler
28034 * @param {Function} handler The function to call when the button is clicked
28035 * @param {Object} scope (optional) Scope for the function passed above
28037 setHandler : function(handler, scope){
28038 this.handler = handler;
28039 this.scope = scope;
28043 * Sets this button's arrow click handler
28044 * @param {Function} handler The function to call when the arrow is clicked
28045 * @param {Object} scope (optional) Scope for the function passed above
28047 setArrowHandler : function(handler, scope){
28048 this.arrowHandler = handler;
28049 this.scope = scope;
28055 focus : function(){
28057 this.el.child("button:first").focus();
28062 onClick : function(e){
28063 e.preventDefault();
28064 if(!this.disabled){
28065 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28066 if(this.menu && !this.menu.isVisible()){
28067 this.menu.show(this.el, this.menuAlign);
28069 this.fireEvent("arrowclick", this, e);
28070 if(this.arrowHandler){
28071 this.arrowHandler.call(this.scope || this, this, e);
28074 this.fireEvent("click", this, e);
28076 this.handler.call(this.scope || this, this, e);
28082 onMouseDown : function(e){
28083 if(!this.disabled){
28084 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28088 onMouseUp : function(e){
28089 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28094 // backwards compat
28095 Roo.MenuButton = Roo.SplitButton;/*
28097 * Ext JS Library 1.1.1
28098 * Copyright(c) 2006-2007, Ext JS, LLC.
28100 * Originally Released Under LGPL - original licence link has changed is not relivant.
28103 * <script type="text/javascript">
28107 * @class Roo.Toolbar
28108 * Basic Toolbar class.
28110 * Creates a new Toolbar
28111 * @param {Object} container The config object
28113 Roo.Toolbar = function(container, buttons, config)
28115 /// old consturctor format still supported..
28116 if(container instanceof Array){ // omit the container for later rendering
28117 buttons = container;
28121 if (typeof(container) == 'object' && container.xtype) {
28122 config = container;
28123 container = config.container;
28124 buttons = config.buttons || []; // not really - use items!!
28127 if (config && config.items) {
28128 xitems = config.items;
28129 delete config.items;
28131 Roo.apply(this, config);
28132 this.buttons = buttons;
28135 this.render(container);
28137 this.xitems = xitems;
28138 Roo.each(xitems, function(b) {
28144 Roo.Toolbar.prototype = {
28146 * @cfg {Array} items
28147 * array of button configs or elements to add (will be converted to a MixedCollection)
28151 * @cfg {String/HTMLElement/Element} container
28152 * The id or element that will contain the toolbar
28155 render : function(ct){
28156 this.el = Roo.get(ct);
28158 this.el.addClass(this.cls);
28160 // using a table allows for vertical alignment
28161 // 100% width is needed by Safari...
28162 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28163 this.tr = this.el.child("tr", true);
28165 this.items = new Roo.util.MixedCollection(false, function(o){
28166 return o.id || ("item" + (++autoId));
28169 this.add.apply(this, this.buttons);
28170 delete this.buttons;
28175 * Adds element(s) to the toolbar -- this function takes a variable number of
28176 * arguments of mixed type and adds them to the toolbar.
28177 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28179 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28180 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28181 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28182 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28183 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28184 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28185 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28186 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28187 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28189 * @param {Mixed} arg2
28190 * @param {Mixed} etc.
28193 var a = arguments, l = a.length;
28194 for(var i = 0; i < l; i++){
28199 _add : function(el) {
28202 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28205 if (el.applyTo){ // some kind of form field
28206 return this.addField(el);
28208 if (el.render){ // some kind of Toolbar.Item
28209 return this.addItem(el);
28211 if (typeof el == "string"){ // string
28212 if(el == "separator" || el == "-"){
28213 return this.addSeparator();
28216 return this.addSpacer();
28219 return this.addFill();
28221 return this.addText(el);
28224 if(el.tagName){ // element
28225 return this.addElement(el);
28227 if(typeof el == "object"){ // must be button config?
28228 return this.addButton(el);
28230 // and now what?!?!
28236 * Add an Xtype element
28237 * @param {Object} xtype Xtype Object
28238 * @return {Object} created Object
28240 addxtype : function(e){
28241 return this.add(e);
28245 * Returns the Element for this toolbar.
28246 * @return {Roo.Element}
28248 getEl : function(){
28254 * @return {Roo.Toolbar.Item} The separator item
28256 addSeparator : function(){
28257 return this.addItem(new Roo.Toolbar.Separator());
28261 * Adds a spacer element
28262 * @return {Roo.Toolbar.Spacer} The spacer item
28264 addSpacer : function(){
28265 return this.addItem(new Roo.Toolbar.Spacer());
28269 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28270 * @return {Roo.Toolbar.Fill} The fill item
28272 addFill : function(){
28273 return this.addItem(new Roo.Toolbar.Fill());
28277 * Adds any standard HTML element to the toolbar
28278 * @param {String/HTMLElement/Element} el The element or id of the element to add
28279 * @return {Roo.Toolbar.Item} The element's item
28281 addElement : function(el){
28282 return this.addItem(new Roo.Toolbar.Item(el));
28285 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28286 * @type Roo.util.MixedCollection
28291 * Adds any Toolbar.Item or subclass
28292 * @param {Roo.Toolbar.Item} item
28293 * @return {Roo.Toolbar.Item} The item
28295 addItem : function(item){
28296 var td = this.nextBlock();
28298 this.items.add(item);
28303 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28304 * @param {Object/Array} config A button config or array of configs
28305 * @return {Roo.Toolbar.Button/Array}
28307 addButton : function(config){
28308 if(config instanceof Array){
28310 for(var i = 0, len = config.length; i < len; i++) {
28311 buttons.push(this.addButton(config[i]));
28316 if(!(config instanceof Roo.Toolbar.Button)){
28318 new Roo.Toolbar.SplitButton(config) :
28319 new Roo.Toolbar.Button(config);
28321 var td = this.nextBlock();
28328 * Adds text to the toolbar
28329 * @param {String} text The text to add
28330 * @return {Roo.Toolbar.Item} The element's item
28332 addText : function(text){
28333 return this.addItem(new Roo.Toolbar.TextItem(text));
28337 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28338 * @param {Number} index The index where the item is to be inserted
28339 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28340 * @return {Roo.Toolbar.Button/Item}
28342 insertButton : function(index, item){
28343 if(item instanceof Array){
28345 for(var i = 0, len = item.length; i < len; i++) {
28346 buttons.push(this.insertButton(index + i, item[i]));
28350 if (!(item instanceof Roo.Toolbar.Button)){
28351 item = new Roo.Toolbar.Button(item);
28353 var td = document.createElement("td");
28354 this.tr.insertBefore(td, this.tr.childNodes[index]);
28356 this.items.insert(index, item);
28361 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28362 * @param {Object} config
28363 * @return {Roo.Toolbar.Item} The element's item
28365 addDom : function(config, returnEl){
28366 var td = this.nextBlock();
28367 Roo.DomHelper.overwrite(td, config);
28368 var ti = new Roo.Toolbar.Item(td.firstChild);
28370 this.items.add(ti);
28375 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28376 * @type Roo.util.MixedCollection
28381 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28382 * Note: the field should not have been rendered yet. For a field that has already been
28383 * rendered, use {@link #addElement}.
28384 * @param {Roo.form.Field} field
28385 * @return {Roo.ToolbarItem}
28389 addField : function(field) {
28390 if (!this.fields) {
28392 this.fields = new Roo.util.MixedCollection(false, function(o){
28393 return o.id || ("item" + (++autoId));
28398 var td = this.nextBlock();
28400 var ti = new Roo.Toolbar.Item(td.firstChild);
28402 this.items.add(ti);
28403 this.fields.add(field);
28414 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28415 this.el.child('div').hide();
28423 this.el.child('div').show();
28427 nextBlock : function(){
28428 var td = document.createElement("td");
28429 this.tr.appendChild(td);
28434 destroy : function(){
28435 if(this.items){ // rendered?
28436 Roo.destroy.apply(Roo, this.items.items);
28438 if(this.fields){ // rendered?
28439 Roo.destroy.apply(Roo, this.fields.items);
28441 Roo.Element.uncache(this.el, this.tr);
28446 * @class Roo.Toolbar.Item
28447 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28449 * Creates a new Item
28450 * @param {HTMLElement} el
28452 Roo.Toolbar.Item = function(el){
28453 this.el = Roo.getDom(el);
28454 this.id = Roo.id(this.el);
28455 this.hidden = false;
28458 Roo.Toolbar.Item.prototype = {
28461 * Get this item's HTML Element
28462 * @return {HTMLElement}
28464 getEl : function(){
28469 render : function(td){
28471 td.appendChild(this.el);
28475 * Removes and destroys this item.
28477 destroy : function(){
28478 this.td.parentNode.removeChild(this.td);
28485 this.hidden = false;
28486 this.td.style.display = "";
28493 this.hidden = true;
28494 this.td.style.display = "none";
28498 * Convenience function for boolean show/hide.
28499 * @param {Boolean} visible true to show/false to hide
28501 setVisible: function(visible){
28510 * Try to focus this item.
28512 focus : function(){
28513 Roo.fly(this.el).focus();
28517 * Disables this item.
28519 disable : function(){
28520 Roo.fly(this.td).addClass("x-item-disabled");
28521 this.disabled = true;
28522 this.el.disabled = true;
28526 * Enables this item.
28528 enable : function(){
28529 Roo.fly(this.td).removeClass("x-item-disabled");
28530 this.disabled = false;
28531 this.el.disabled = false;
28537 * @class Roo.Toolbar.Separator
28538 * @extends Roo.Toolbar.Item
28539 * A simple toolbar separator class
28541 * Creates a new Separator
28543 Roo.Toolbar.Separator = function(){
28544 var s = document.createElement("span");
28545 s.className = "ytb-sep";
28546 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
28548 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28549 enable:Roo.emptyFn,
28550 disable:Roo.emptyFn,
28555 * @class Roo.Toolbar.Spacer
28556 * @extends Roo.Toolbar.Item
28557 * A simple element that adds extra horizontal space to a toolbar.
28559 * Creates a new Spacer
28561 Roo.Toolbar.Spacer = function(){
28562 var s = document.createElement("div");
28563 s.className = "ytb-spacer";
28564 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
28566 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28567 enable:Roo.emptyFn,
28568 disable:Roo.emptyFn,
28573 * @class Roo.Toolbar.Fill
28574 * @extends Roo.Toolbar.Spacer
28575 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28577 * Creates a new Spacer
28579 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28581 render : function(td){
28582 td.style.width = '100%';
28583 Roo.Toolbar.Fill.superclass.render.call(this, td);
28588 * @class Roo.Toolbar.TextItem
28589 * @extends Roo.Toolbar.Item
28590 * A simple class that renders text directly into a toolbar.
28592 * Creates a new TextItem
28593 * @param {String} text
28595 Roo.Toolbar.TextItem = function(text){
28596 if (typeof(text) == 'object') {
28599 var s = document.createElement("span");
28600 s.className = "ytb-text";
28601 s.innerHTML = text;
28602 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28604 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28605 enable:Roo.emptyFn,
28606 disable:Roo.emptyFn,
28611 * @class Roo.Toolbar.Button
28612 * @extends Roo.Button
28613 * A button that renders into a toolbar.
28615 * Creates a new Button
28616 * @param {Object} config A standard {@link Roo.Button} config object
28618 Roo.Toolbar.Button = function(config){
28619 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28621 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28622 render : function(td){
28624 Roo.Toolbar.Button.superclass.render.call(this, td);
28628 * Removes and destroys this button
28630 destroy : function(){
28631 Roo.Toolbar.Button.superclass.destroy.call(this);
28632 this.td.parentNode.removeChild(this.td);
28636 * Shows this button
28639 this.hidden = false;
28640 this.td.style.display = "";
28644 * Hides this button
28647 this.hidden = true;
28648 this.td.style.display = "none";
28652 * Disables this item
28654 disable : function(){
28655 Roo.fly(this.td).addClass("x-item-disabled");
28656 this.disabled = true;
28660 * Enables this item
28662 enable : function(){
28663 Roo.fly(this.td).removeClass("x-item-disabled");
28664 this.disabled = false;
28667 // backwards compat
28668 Roo.ToolbarButton = Roo.Toolbar.Button;
28671 * @class Roo.Toolbar.SplitButton
28672 * @extends Roo.SplitButton
28673 * A menu button that renders into a toolbar.
28675 * Creates a new SplitButton
28676 * @param {Object} config A standard {@link Roo.SplitButton} config object
28678 Roo.Toolbar.SplitButton = function(config){
28679 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28681 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28682 render : function(td){
28684 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28688 * Removes and destroys this button
28690 destroy : function(){
28691 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28692 this.td.parentNode.removeChild(this.td);
28696 * Shows this button
28699 this.hidden = false;
28700 this.td.style.display = "";
28704 * Hides this button
28707 this.hidden = true;
28708 this.td.style.display = "none";
28712 // backwards compat
28713 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28715 * Ext JS Library 1.1.1
28716 * Copyright(c) 2006-2007, Ext JS, LLC.
28718 * Originally Released Under LGPL - original licence link has changed is not relivant.
28721 * <script type="text/javascript">
28725 * @class Roo.PagingToolbar
28726 * @extends Roo.Toolbar
28727 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28729 * Create a new PagingToolbar
28730 * @param {Object} config The config object
28732 Roo.PagingToolbar = function(el, ds, config)
28734 // old args format still supported... - xtype is prefered..
28735 if (typeof(el) == 'object' && el.xtype) {
28736 // created from xtype...
28738 ds = el.dataSource;
28739 el = config.container;
28742 if (config.items) {
28743 items = config.items;
28747 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28750 this.renderButtons(this.el);
28753 // supprot items array.
28755 Roo.each(items, function(e) {
28756 this.add(Roo.factory(e));
28761 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28763 * @cfg {Roo.data.Store} dataSource
28764 * The underlying data store providing the paged data
28767 * @cfg {String/HTMLElement/Element} container
28768 * container The id or element that will contain the toolbar
28771 * @cfg {Boolean} displayInfo
28772 * True to display the displayMsg (defaults to false)
28775 * @cfg {Number} pageSize
28776 * The number of records to display per page (defaults to 20)
28780 * @cfg {String} displayMsg
28781 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28783 displayMsg : 'Displaying {0} - {1} of {2}',
28785 * @cfg {String} emptyMsg
28786 * The message to display when no records are found (defaults to "No data to display")
28788 emptyMsg : 'No data to display',
28790 * Customizable piece of the default paging text (defaults to "Page")
28793 beforePageText : "Page",
28795 * Customizable piece of the default paging text (defaults to "of %0")
28798 afterPageText : "of {0}",
28800 * Customizable piece of the default paging text (defaults to "First Page")
28803 firstText : "First Page",
28805 * Customizable piece of the default paging text (defaults to "Previous Page")
28808 prevText : "Previous Page",
28810 * Customizable piece of the default paging text (defaults to "Next Page")
28813 nextText : "Next Page",
28815 * Customizable piece of the default paging text (defaults to "Last Page")
28818 lastText : "Last Page",
28820 * Customizable piece of the default paging text (defaults to "Refresh")
28823 refreshText : "Refresh",
28826 renderButtons : function(el){
28827 Roo.PagingToolbar.superclass.render.call(this, el);
28828 this.first = this.addButton({
28829 tooltip: this.firstText,
28830 cls: "x-btn-icon x-grid-page-first",
28832 handler: this.onClick.createDelegate(this, ["first"])
28834 this.prev = this.addButton({
28835 tooltip: this.prevText,
28836 cls: "x-btn-icon x-grid-page-prev",
28838 handler: this.onClick.createDelegate(this, ["prev"])
28840 //this.addSeparator();
28841 this.add(this.beforePageText);
28842 this.field = Roo.get(this.addDom({
28847 cls: "x-grid-page-number"
28849 this.field.on("keydown", this.onPagingKeydown, this);
28850 this.field.on("focus", function(){this.dom.select();});
28851 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28852 this.field.setHeight(18);
28853 //this.addSeparator();
28854 this.next = this.addButton({
28855 tooltip: this.nextText,
28856 cls: "x-btn-icon x-grid-page-next",
28858 handler: this.onClick.createDelegate(this, ["next"])
28860 this.last = this.addButton({
28861 tooltip: this.lastText,
28862 cls: "x-btn-icon x-grid-page-last",
28864 handler: this.onClick.createDelegate(this, ["last"])
28866 //this.addSeparator();
28867 this.loading = this.addButton({
28868 tooltip: this.refreshText,
28869 cls: "x-btn-icon x-grid-loading",
28870 handler: this.onClick.createDelegate(this, ["refresh"])
28873 if(this.displayInfo){
28874 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28879 updateInfo : function(){
28880 if(this.displayEl){
28881 var count = this.ds.getCount();
28882 var msg = count == 0 ?
28886 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28888 this.displayEl.update(msg);
28893 onLoad : function(ds, r, o){
28894 this.cursor = o.params ? o.params.start : 0;
28895 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28897 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28898 this.field.dom.value = ap;
28899 this.first.setDisabled(ap == 1);
28900 this.prev.setDisabled(ap == 1);
28901 this.next.setDisabled(ap == ps);
28902 this.last.setDisabled(ap == ps);
28903 this.loading.enable();
28908 getPageData : function(){
28909 var total = this.ds.getTotalCount();
28912 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28913 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28918 onLoadError : function(){
28919 this.loading.enable();
28923 onPagingKeydown : function(e){
28924 var k = e.getKey();
28925 var d = this.getPageData();
28927 var v = this.field.dom.value, pageNum;
28928 if(!v || isNaN(pageNum = parseInt(v, 10))){
28929 this.field.dom.value = d.activePage;
28932 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28933 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28936 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))
28938 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28939 this.field.dom.value = pageNum;
28940 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28943 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28945 var v = this.field.dom.value, pageNum;
28946 var increment = (e.shiftKey) ? 10 : 1;
28947 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28949 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28950 this.field.dom.value = d.activePage;
28953 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28955 this.field.dom.value = parseInt(v, 10) + increment;
28956 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28957 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28964 beforeLoad : function(){
28966 this.loading.disable();
28971 onClick : function(which){
28975 ds.load({params:{start: 0, limit: this.pageSize}});
28978 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28981 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28984 var total = ds.getTotalCount();
28985 var extra = total % this.pageSize;
28986 var lastStart = extra ? (total - extra) : total-this.pageSize;
28987 ds.load({params:{start: lastStart, limit: this.pageSize}});
28990 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28996 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28997 * @param {Roo.data.Store} store The data store to unbind
28999 unbind : function(ds){
29000 ds.un("beforeload", this.beforeLoad, this);
29001 ds.un("load", this.onLoad, this);
29002 ds.un("loadexception", this.onLoadError, this);
29003 ds.un("remove", this.updateInfo, this);
29004 ds.un("add", this.updateInfo, this);
29005 this.ds = undefined;
29009 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29010 * @param {Roo.data.Store} store The data store to bind
29012 bind : function(ds){
29013 ds.on("beforeload", this.beforeLoad, this);
29014 ds.on("load", this.onLoad, this);
29015 ds.on("loadexception", this.onLoadError, this);
29016 ds.on("remove", this.updateInfo, this);
29017 ds.on("add", this.updateInfo, this);
29022 * Ext JS Library 1.1.1
29023 * Copyright(c) 2006-2007, Ext JS, LLC.
29025 * Originally Released Under LGPL - original licence link has changed is not relivant.
29028 * <script type="text/javascript">
29032 * @class Roo.Resizable
29033 * @extends Roo.util.Observable
29034 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29035 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29036 * 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
29037 * the element will be wrapped for you automatically.</p>
29038 * <p>Here is the list of valid resize handles:</p>
29041 ------ -------------------
29050 'hd' horizontal drag
29053 * <p>Here's an example showing the creation of a typical Resizable:</p>
29055 var resizer = new Roo.Resizable("element-id", {
29063 resizer.on("resize", myHandler);
29065 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29066 * resizer.east.setDisplayed(false);</p>
29067 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29068 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29069 * resize operation's new size (defaults to [0, 0])
29070 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29071 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29072 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29073 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29074 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29075 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29076 * @cfg {Number} width The width of the element in pixels (defaults to null)
29077 * @cfg {Number} height The height of the element in pixels (defaults to null)
29078 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29079 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29080 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29081 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29082 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29083 * in favor of the handles config option (defaults to false)
29084 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29085 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29086 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29087 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29088 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29089 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29090 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29091 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29092 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29093 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29094 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29096 * Create a new resizable component
29097 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29098 * @param {Object} config configuration options
29100 Roo.Resizable = function(el, config)
29102 this.el = Roo.get(el);
29104 if(config && config.wrap){
29105 config.resizeChild = this.el;
29106 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29107 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29108 this.el.setStyle("overflow", "hidden");
29109 this.el.setPositioning(config.resizeChild.getPositioning());
29110 config.resizeChild.clearPositioning();
29111 if(!config.width || !config.height){
29112 var csize = config.resizeChild.getSize();
29113 this.el.setSize(csize.width, csize.height);
29115 if(config.pinned && !config.adjustments){
29116 config.adjustments = "auto";
29120 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29121 this.proxy.unselectable();
29122 this.proxy.enableDisplayMode('block');
29124 Roo.apply(this, config);
29127 this.disableTrackOver = true;
29128 this.el.addClass("x-resizable-pinned");
29130 // if the element isn't positioned, make it relative
29131 var position = this.el.getStyle("position");
29132 if(position != "absolute" && position != "fixed"){
29133 this.el.setStyle("position", "relative");
29135 if(!this.handles){ // no handles passed, must be legacy style
29136 this.handles = 's,e,se';
29137 if(this.multiDirectional){
29138 this.handles += ',n,w';
29141 if(this.handles == "all"){
29142 this.handles = "n s e w ne nw se sw";
29144 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29145 var ps = Roo.Resizable.positions;
29146 for(var i = 0, len = hs.length; i < len; i++){
29147 if(hs[i] && ps[hs[i]]){
29148 var pos = ps[hs[i]];
29149 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29153 this.corner = this.southeast;
29155 // updateBox = the box can move..
29156 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29157 this.updateBox = true;
29160 this.activeHandle = null;
29162 if(this.resizeChild){
29163 if(typeof this.resizeChild == "boolean"){
29164 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29166 this.resizeChild = Roo.get(this.resizeChild, true);
29170 if(this.adjustments == "auto"){
29171 var rc = this.resizeChild;
29172 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29173 if(rc && (hw || hn)){
29174 rc.position("relative");
29175 rc.setLeft(hw ? hw.el.getWidth() : 0);
29176 rc.setTop(hn ? hn.el.getHeight() : 0);
29178 this.adjustments = [
29179 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29180 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29184 if(this.draggable){
29185 this.dd = this.dynamic ?
29186 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29187 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29193 * @event beforeresize
29194 * Fired before resize is allowed. Set enabled to false to cancel resize.
29195 * @param {Roo.Resizable} this
29196 * @param {Roo.EventObject} e The mousedown event
29198 "beforeresize" : true,
29201 * Fired a resizing.
29202 * @param {Roo.Resizable} this
29203 * @param {Number} x The new x position
29204 * @param {Number} y The new y position
29205 * @param {Number} w The new w width
29206 * @param {Number} h The new h hight
29207 * @param {Roo.EventObject} e The mouseup event
29212 * Fired after a resize.
29213 * @param {Roo.Resizable} this
29214 * @param {Number} width The new width
29215 * @param {Number} height The new height
29216 * @param {Roo.EventObject} e The mouseup event
29221 if(this.width !== null && this.height !== null){
29222 this.resizeTo(this.width, this.height);
29224 this.updateChildSize();
29227 this.el.dom.style.zoom = 1;
29229 Roo.Resizable.superclass.constructor.call(this);
29232 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29233 resizeChild : false,
29234 adjustments : [0, 0],
29244 multiDirectional : false,
29245 disableTrackOver : false,
29246 easing : 'easeOutStrong',
29247 widthIncrement : 0,
29248 heightIncrement : 0,
29252 preserveRatio : false,
29253 transparent: false,
29259 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29261 constrainTo: undefined,
29263 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29265 resizeRegion: undefined,
29269 * Perform a manual resize
29270 * @param {Number} width
29271 * @param {Number} height
29273 resizeTo : function(width, height){
29274 this.el.setSize(width, height);
29275 this.updateChildSize();
29276 this.fireEvent("resize", this, width, height, null);
29280 startSizing : function(e, handle){
29281 this.fireEvent("beforeresize", this, e);
29282 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29285 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29286 this.overlay.unselectable();
29287 this.overlay.enableDisplayMode("block");
29288 this.overlay.on("mousemove", this.onMouseMove, this);
29289 this.overlay.on("mouseup", this.onMouseUp, this);
29291 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29293 this.resizing = true;
29294 this.startBox = this.el.getBox();
29295 this.startPoint = e.getXY();
29296 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29297 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29299 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29300 this.overlay.show();
29302 if(this.constrainTo) {
29303 var ct = Roo.get(this.constrainTo);
29304 this.resizeRegion = ct.getRegion().adjust(
29305 ct.getFrameWidth('t'),
29306 ct.getFrameWidth('l'),
29307 -ct.getFrameWidth('b'),
29308 -ct.getFrameWidth('r')
29312 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29314 this.proxy.setBox(this.startBox);
29316 this.proxy.setStyle('visibility', 'visible');
29322 onMouseDown : function(handle, e){
29325 this.activeHandle = handle;
29326 this.startSizing(e, handle);
29331 onMouseUp : function(e){
29332 var size = this.resizeElement();
29333 this.resizing = false;
29335 this.overlay.hide();
29337 this.fireEvent("resize", this, size.width, size.height, e);
29341 updateChildSize : function(){
29343 if(this.resizeChild){
29345 var child = this.resizeChild;
29346 var adj = this.adjustments;
29347 if(el.dom.offsetWidth){
29348 var b = el.getSize(true);
29349 child.setSize(b.width+adj[0], b.height+adj[1]);
29351 // Second call here for IE
29352 // The first call enables instant resizing and
29353 // the second call corrects scroll bars if they
29356 setTimeout(function(){
29357 if(el.dom.offsetWidth){
29358 var b = el.getSize(true);
29359 child.setSize(b.width+adj[0], b.height+adj[1]);
29367 snap : function(value, inc, min){
29368 if(!inc || !value) return value;
29369 var newValue = value;
29370 var m = value % inc;
29373 newValue = value + (inc-m);
29375 newValue = value - m;
29378 return Math.max(min, newValue);
29382 resizeElement : function(){
29383 var box = this.proxy.getBox();
29384 if(this.updateBox){
29385 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29387 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29389 this.updateChildSize();
29397 constrain : function(v, diff, m, mx){
29400 }else if(v - diff > mx){
29407 onMouseMove : function(e){
29410 try{// try catch so if something goes wrong the user doesn't get hung
29412 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29416 //var curXY = this.startPoint;
29417 var curSize = this.curSize || this.startBox;
29418 var x = this.startBox.x, y = this.startBox.y;
29419 var ox = x, oy = y;
29420 var w = curSize.width, h = curSize.height;
29421 var ow = w, oh = h;
29422 var mw = this.minWidth, mh = this.minHeight;
29423 var mxw = this.maxWidth, mxh = this.maxHeight;
29424 var wi = this.widthIncrement;
29425 var hi = this.heightIncrement;
29427 var eventXY = e.getXY();
29428 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29429 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29431 var pos = this.activeHandle.position;
29436 w = Math.min(Math.max(mw, w), mxw);
29441 h = Math.min(Math.max(mh, h), mxh);
29446 w = Math.min(Math.max(mw, w), mxw);
29447 h = Math.min(Math.max(mh, h), mxh);
29450 diffY = this.constrain(h, diffY, mh, mxh);
29457 var adiffX = Math.abs(diffX);
29458 var sub = (adiffX % wi); // how much
29459 if (sub > (wi/2)) { // far enough to snap
29460 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29462 // remove difference..
29463 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29467 x = Math.max(this.minX, x);
29470 diffX = this.constrain(w, diffX, mw, mxw);
29476 w = Math.min(Math.max(mw, w), mxw);
29477 diffY = this.constrain(h, diffY, mh, mxh);
29482 diffX = this.constrain(w, diffX, mw, mxw);
29483 diffY = this.constrain(h, diffY, mh, mxh);
29490 diffX = this.constrain(w, diffX, mw, mxw);
29492 h = Math.min(Math.max(mh, h), mxh);
29498 var sw = this.snap(w, wi, mw);
29499 var sh = this.snap(h, hi, mh);
29500 if(sw != w || sh != h){
29523 if(this.preserveRatio){
29528 h = Math.min(Math.max(mh, h), mxh);
29533 w = Math.min(Math.max(mw, w), mxw);
29538 w = Math.min(Math.max(mw, w), mxw);
29544 w = Math.min(Math.max(mw, w), mxw);
29550 h = Math.min(Math.max(mh, h), mxh);
29558 h = Math.min(Math.max(mh, h), mxh);
29568 h = Math.min(Math.max(mh, h), mxh);
29576 if (pos == 'hdrag') {
29579 this.proxy.setBounds(x, y, w, h);
29581 this.resizeElement();
29585 this.fireEvent("resizing", this, x, y, w, h, e);
29589 handleOver : function(){
29591 this.el.addClass("x-resizable-over");
29596 handleOut : function(){
29597 if(!this.resizing){
29598 this.el.removeClass("x-resizable-over");
29603 * Returns the element this component is bound to.
29604 * @return {Roo.Element}
29606 getEl : function(){
29611 * Returns the resizeChild element (or null).
29612 * @return {Roo.Element}
29614 getResizeChild : function(){
29615 return this.resizeChild;
29617 groupHandler : function()
29622 * Destroys this resizable. If the element was wrapped and
29623 * removeEl is not true then the element remains.
29624 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29626 destroy : function(removeEl){
29627 this.proxy.remove();
29629 this.overlay.removeAllListeners();
29630 this.overlay.remove();
29632 var ps = Roo.Resizable.positions;
29634 if(typeof ps[k] != "function" && this[ps[k]]){
29635 var h = this[ps[k]];
29636 h.el.removeAllListeners();
29641 this.el.update("");
29648 // hash to map config positions to true positions
29649 Roo.Resizable.positions = {
29650 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29655 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29657 // only initialize the template if resizable is used
29658 var tpl = Roo.DomHelper.createTemplate(
29659 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29662 Roo.Resizable.Handle.prototype.tpl = tpl;
29664 this.position = pos;
29666 // show north drag fro topdra
29667 var handlepos = pos == 'hdrag' ? 'north' : pos;
29669 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29670 if (pos == 'hdrag') {
29671 this.el.setStyle('cursor', 'pointer');
29673 this.el.unselectable();
29675 this.el.setOpacity(0);
29677 this.el.on("mousedown", this.onMouseDown, this);
29678 if(!disableTrackOver){
29679 this.el.on("mouseover", this.onMouseOver, this);
29680 this.el.on("mouseout", this.onMouseOut, this);
29685 Roo.Resizable.Handle.prototype = {
29686 afterResize : function(rz){
29691 onMouseDown : function(e){
29692 this.rz.onMouseDown(this, e);
29695 onMouseOver : function(e){
29696 this.rz.handleOver(this, e);
29699 onMouseOut : function(e){
29700 this.rz.handleOut(this, e);
29704 * Ext JS Library 1.1.1
29705 * Copyright(c) 2006-2007, Ext JS, LLC.
29707 * Originally Released Under LGPL - original licence link has changed is not relivant.
29710 * <script type="text/javascript">
29714 * @class Roo.Editor
29715 * @extends Roo.Component
29716 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29718 * Create a new Editor
29719 * @param {Roo.form.Field} field The Field object (or descendant)
29720 * @param {Object} config The config object
29722 Roo.Editor = function(field, config){
29723 Roo.Editor.superclass.constructor.call(this, config);
29724 this.field = field;
29727 * @event beforestartedit
29728 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29729 * false from the handler of this event.
29730 * @param {Editor} this
29731 * @param {Roo.Element} boundEl The underlying element bound to this editor
29732 * @param {Mixed} value The field value being set
29734 "beforestartedit" : true,
29737 * Fires when this editor is displayed
29738 * @param {Roo.Element} boundEl The underlying element bound to this editor
29739 * @param {Mixed} value The starting field value
29741 "startedit" : true,
29743 * @event beforecomplete
29744 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29745 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29746 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29747 * event will not fire since no edit actually occurred.
29748 * @param {Editor} this
29749 * @param {Mixed} value The current field value
29750 * @param {Mixed} startValue The original field value
29752 "beforecomplete" : true,
29755 * Fires after editing is complete and any changed value has been written to the underlying field.
29756 * @param {Editor} this
29757 * @param {Mixed} value The current field value
29758 * @param {Mixed} startValue The original field value
29762 * @event specialkey
29763 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29764 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29765 * @param {Roo.form.Field} this
29766 * @param {Roo.EventObject} e The event object
29768 "specialkey" : true
29772 Roo.extend(Roo.Editor, Roo.Component, {
29774 * @cfg {Boolean/String} autosize
29775 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29776 * or "height" to adopt the height only (defaults to false)
29779 * @cfg {Boolean} revertInvalid
29780 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29781 * validation fails (defaults to true)
29784 * @cfg {Boolean} ignoreNoChange
29785 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29786 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29787 * will never be ignored.
29790 * @cfg {Boolean} hideEl
29791 * False to keep the bound element visible while the editor is displayed (defaults to true)
29794 * @cfg {Mixed} value
29795 * The data value of the underlying field (defaults to "")
29799 * @cfg {String} alignment
29800 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29804 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29805 * for bottom-right shadow (defaults to "frame")
29809 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29813 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29815 completeOnEnter : false,
29817 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29819 cancelOnEsc : false,
29821 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29826 onRender : function(ct, position){
29827 this.el = new Roo.Layer({
29828 shadow: this.shadow,
29834 constrain: this.constrain
29836 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29837 if(this.field.msgTarget != 'title'){
29838 this.field.msgTarget = 'qtip';
29840 this.field.render(this.el);
29842 this.field.el.dom.setAttribute('autocomplete', 'off');
29844 this.field.on("specialkey", this.onSpecialKey, this);
29845 if(this.swallowKeys){
29846 this.field.el.swallowEvent(['keydown','keypress']);
29849 this.field.on("blur", this.onBlur, this);
29850 if(this.field.grow){
29851 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29855 onSpecialKey : function(field, e)
29857 //Roo.log('editor onSpecialKey');
29858 if(this.completeOnEnter && e.getKey() == e.ENTER){
29860 this.completeEdit();
29863 // do not fire special key otherwise it might hide close the editor...
29864 if(e.getKey() == e.ENTER){
29867 if(this.cancelOnEsc && e.getKey() == e.ESC){
29871 this.fireEvent('specialkey', field, e);
29876 * Starts the editing process and shows the editor.
29877 * @param {String/HTMLElement/Element} el The element to edit
29878 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29879 * to the innerHTML of el.
29881 startEdit : function(el, value){
29883 this.completeEdit();
29885 this.boundEl = Roo.get(el);
29886 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29887 if(!this.rendered){
29888 this.render(this.parentEl || document.body);
29890 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29893 this.startValue = v;
29894 this.field.setValue(v);
29896 var sz = this.boundEl.getSize();
29897 switch(this.autoSize){
29899 this.setSize(sz.width, "");
29902 this.setSize("", sz.height);
29905 this.setSize(sz.width, sz.height);
29908 this.el.alignTo(this.boundEl, this.alignment);
29909 this.editing = true;
29911 Roo.QuickTips.disable();
29917 * Sets the height and width of this editor.
29918 * @param {Number} width The new width
29919 * @param {Number} height The new height
29921 setSize : function(w, h){
29922 this.field.setSize(w, h);
29929 * Realigns the editor to the bound field based on the current alignment config value.
29931 realign : function(){
29932 this.el.alignTo(this.boundEl, this.alignment);
29936 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29937 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29939 completeEdit : function(remainVisible){
29943 var v = this.getValue();
29944 if(this.revertInvalid !== false && !this.field.isValid()){
29945 v = this.startValue;
29946 this.cancelEdit(true);
29948 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29949 this.editing = false;
29953 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29954 this.editing = false;
29955 if(this.updateEl && this.boundEl){
29956 this.boundEl.update(v);
29958 if(remainVisible !== true){
29961 this.fireEvent("complete", this, v, this.startValue);
29966 onShow : function(){
29968 if(this.hideEl !== false){
29969 this.boundEl.hide();
29972 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29973 this.fixIEFocus = true;
29974 this.deferredFocus.defer(50, this);
29976 this.field.focus();
29978 this.fireEvent("startedit", this.boundEl, this.startValue);
29981 deferredFocus : function(){
29983 this.field.focus();
29988 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29989 * reverted to the original starting value.
29990 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29991 * cancel (defaults to false)
29993 cancelEdit : function(remainVisible){
29995 this.setValue(this.startValue);
29996 if(remainVisible !== true){
30003 onBlur : function(){
30004 if(this.allowBlur !== true && this.editing){
30005 this.completeEdit();
30010 onHide : function(){
30012 this.completeEdit();
30016 if(this.field.collapse){
30017 this.field.collapse();
30020 if(this.hideEl !== false){
30021 this.boundEl.show();
30024 Roo.QuickTips.enable();
30029 * Sets the data value of the editor
30030 * @param {Mixed} value Any valid value supported by the underlying field
30032 setValue : function(v){
30033 this.field.setValue(v);
30037 * Gets the data value of the editor
30038 * @return {Mixed} The data value
30040 getValue : function(){
30041 return this.field.getValue();
30045 * Ext JS Library 1.1.1
30046 * Copyright(c) 2006-2007, Ext JS, LLC.
30048 * Originally Released Under LGPL - original licence link has changed is not relivant.
30051 * <script type="text/javascript">
30055 * @class Roo.BasicDialog
30056 * @extends Roo.util.Observable
30057 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30059 var dlg = new Roo.BasicDialog("my-dlg", {
30068 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30069 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30070 dlg.addButton('Cancel', dlg.hide, dlg);
30073 <b>A Dialog should always be a direct child of the body element.</b>
30074 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30075 * @cfg {String} title Default text to display in the title bar (defaults to null)
30076 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30077 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30078 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30079 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30080 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30081 * (defaults to null with no animation)
30082 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30083 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30084 * property for valid values (defaults to 'all')
30085 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30086 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30087 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30088 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30089 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30090 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30091 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30092 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30093 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30094 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30095 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30096 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30097 * draggable = true (defaults to false)
30098 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30099 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30100 * shadow (defaults to false)
30101 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30102 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30103 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30104 * @cfg {Array} buttons Array of buttons
30105 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30107 * Create a new BasicDialog.
30108 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30109 * @param {Object} config Configuration options
30111 Roo.BasicDialog = function(el, config){
30112 this.el = Roo.get(el);
30113 var dh = Roo.DomHelper;
30114 if(!this.el && config && config.autoCreate){
30115 if(typeof config.autoCreate == "object"){
30116 if(!config.autoCreate.id){
30117 config.autoCreate.id = el;
30119 this.el = dh.append(document.body,
30120 config.autoCreate, true);
30122 this.el = dh.append(document.body,
30123 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30127 el.setDisplayed(true);
30128 el.hide = this.hideAction;
30130 el.addClass("x-dlg");
30132 Roo.apply(this, config);
30134 this.proxy = el.createProxy("x-dlg-proxy");
30135 this.proxy.hide = this.hideAction;
30136 this.proxy.setOpacity(.5);
30140 el.setWidth(config.width);
30143 el.setHeight(config.height);
30145 this.size = el.getSize();
30146 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30147 this.xy = [config.x,config.y];
30149 this.xy = el.getCenterXY(true);
30151 /** The header element @type Roo.Element */
30152 this.header = el.child("> .x-dlg-hd");
30153 /** The body element @type Roo.Element */
30154 this.body = el.child("> .x-dlg-bd");
30155 /** The footer element @type Roo.Element */
30156 this.footer = el.child("> .x-dlg-ft");
30159 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30162 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30165 this.header.unselectable();
30167 this.header.update(this.title);
30169 // this element allows the dialog to be focused for keyboard event
30170 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30171 this.focusEl.swallowEvent("click", true);
30173 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30175 // wrap the body and footer for special rendering
30176 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30178 this.bwrap.dom.appendChild(this.footer.dom);
30181 this.bg = this.el.createChild({
30182 tag: "div", cls:"x-dlg-bg",
30183 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30185 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30188 if(this.autoScroll !== false && !this.autoTabs){
30189 this.body.setStyle("overflow", "auto");
30192 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30194 if(this.closable !== false){
30195 this.el.addClass("x-dlg-closable");
30196 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30197 this.close.on("click", this.closeClick, this);
30198 this.close.addClassOnOver("x-dlg-close-over");
30200 if(this.collapsible !== false){
30201 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30202 this.collapseBtn.on("click", this.collapseClick, this);
30203 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30204 this.header.on("dblclick", this.collapseClick, this);
30206 if(this.resizable !== false){
30207 this.el.addClass("x-dlg-resizable");
30208 this.resizer = new Roo.Resizable(el, {
30209 minWidth: this.minWidth || 80,
30210 minHeight:this.minHeight || 80,
30211 handles: this.resizeHandles || "all",
30214 this.resizer.on("beforeresize", this.beforeResize, this);
30215 this.resizer.on("resize", this.onResize, this);
30217 if(this.draggable !== false){
30218 el.addClass("x-dlg-draggable");
30219 if (!this.proxyDrag) {
30220 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30223 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30225 dd.setHandleElId(this.header.id);
30226 dd.endDrag = this.endMove.createDelegate(this);
30227 dd.startDrag = this.startMove.createDelegate(this);
30228 dd.onDrag = this.onDrag.createDelegate(this);
30233 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30234 this.mask.enableDisplayMode("block");
30236 this.el.addClass("x-dlg-modal");
30239 this.shadow = new Roo.Shadow({
30240 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30241 offset : this.shadowOffset
30244 this.shadowOffset = 0;
30246 if(Roo.useShims && this.shim !== false){
30247 this.shim = this.el.createShim();
30248 this.shim.hide = this.hideAction;
30256 if (this.buttons) {
30257 var bts= this.buttons;
30259 Roo.each(bts, function(b) {
30268 * Fires when a key is pressed
30269 * @param {Roo.BasicDialog} this
30270 * @param {Roo.EventObject} e
30275 * Fires when this dialog is moved by the user.
30276 * @param {Roo.BasicDialog} this
30277 * @param {Number} x The new page X
30278 * @param {Number} y The new page Y
30283 * Fires when this dialog is resized by the user.
30284 * @param {Roo.BasicDialog} this
30285 * @param {Number} width The new width
30286 * @param {Number} height The new height
30290 * @event beforehide
30291 * Fires before this dialog is hidden.
30292 * @param {Roo.BasicDialog} this
30294 "beforehide" : true,
30297 * Fires when this dialog is hidden.
30298 * @param {Roo.BasicDialog} this
30302 * @event beforeshow
30303 * Fires before this dialog is shown.
30304 * @param {Roo.BasicDialog} this
30306 "beforeshow" : true,
30309 * Fires when this dialog is shown.
30310 * @param {Roo.BasicDialog} this
30314 el.on("keydown", this.onKeyDown, this);
30315 el.on("mousedown", this.toFront, this);
30316 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30318 Roo.DialogManager.register(this);
30319 Roo.BasicDialog.superclass.constructor.call(this);
30322 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30323 shadowOffset: Roo.isIE ? 6 : 5,
30326 minButtonWidth: 75,
30327 defaultButton: null,
30328 buttonAlign: "right",
30333 * Sets the dialog title text
30334 * @param {String} text The title text to display
30335 * @return {Roo.BasicDialog} this
30337 setTitle : function(text){
30338 this.header.update(text);
30343 closeClick : function(){
30348 collapseClick : function(){
30349 this[this.collapsed ? "expand" : "collapse"]();
30353 * Collapses the dialog to its minimized state (only the title bar is visible).
30354 * Equivalent to the user clicking the collapse dialog button.
30356 collapse : function(){
30357 if(!this.collapsed){
30358 this.collapsed = true;
30359 this.el.addClass("x-dlg-collapsed");
30360 this.restoreHeight = this.el.getHeight();
30361 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30366 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30367 * clicking the expand dialog button.
30369 expand : function(){
30370 if(this.collapsed){
30371 this.collapsed = false;
30372 this.el.removeClass("x-dlg-collapsed");
30373 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30378 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30379 * @return {Roo.TabPanel} The tabs component
30381 initTabs : function(){
30382 var tabs = this.getTabs();
30383 while(tabs.getTab(0)){
30386 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30388 tabs.addTab(Roo.id(dom), dom.title);
30396 beforeResize : function(){
30397 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30401 onResize : function(){
30402 this.refreshSize();
30403 this.syncBodyHeight();
30404 this.adjustAssets();
30406 this.fireEvent("resize", this, this.size.width, this.size.height);
30410 onKeyDown : function(e){
30411 if(this.isVisible()){
30412 this.fireEvent("keydown", this, e);
30417 * Resizes the dialog.
30418 * @param {Number} width
30419 * @param {Number} height
30420 * @return {Roo.BasicDialog} this
30422 resizeTo : function(width, height){
30423 this.el.setSize(width, height);
30424 this.size = {width: width, height: height};
30425 this.syncBodyHeight();
30426 if(this.fixedcenter){
30429 if(this.isVisible()){
30430 this.constrainXY();
30431 this.adjustAssets();
30433 this.fireEvent("resize", this, width, height);
30439 * Resizes the dialog to fit the specified content size.
30440 * @param {Number} width
30441 * @param {Number} height
30442 * @return {Roo.BasicDialog} this
30444 setContentSize : function(w, h){
30445 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30446 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30447 //if(!this.el.isBorderBox()){
30448 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30449 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30452 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30453 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30455 this.resizeTo(w, h);
30460 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30461 * executed in response to a particular key being pressed while the dialog is active.
30462 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30463 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30464 * @param {Function} fn The function to call
30465 * @param {Object} scope (optional) The scope of the function
30466 * @return {Roo.BasicDialog} this
30468 addKeyListener : function(key, fn, scope){
30469 var keyCode, shift, ctrl, alt;
30470 if(typeof key == "object" && !(key instanceof Array)){
30471 keyCode = key["key"];
30472 shift = key["shift"];
30473 ctrl = key["ctrl"];
30478 var handler = function(dlg, e){
30479 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30480 var k = e.getKey();
30481 if(keyCode instanceof Array){
30482 for(var i = 0, len = keyCode.length; i < len; i++){
30483 if(keyCode[i] == k){
30484 fn.call(scope || window, dlg, k, e);
30490 fn.call(scope || window, dlg, k, e);
30495 this.on("keydown", handler);
30500 * Returns the TabPanel component (creates it if it doesn't exist).
30501 * Note: If you wish to simply check for the existence of tabs without creating them,
30502 * check for a null 'tabs' property.
30503 * @return {Roo.TabPanel} The tabs component
30505 getTabs : function(){
30507 this.el.addClass("x-dlg-auto-tabs");
30508 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30509 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30515 * Adds a button to the footer section of the dialog.
30516 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30517 * object or a valid Roo.DomHelper element config
30518 * @param {Function} handler The function called when the button is clicked
30519 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30520 * @return {Roo.Button} The new button
30522 addButton : function(config, handler, scope){
30523 var dh = Roo.DomHelper;
30525 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30527 if(!this.btnContainer){
30528 var tb = this.footer.createChild({
30530 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30531 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30533 this.btnContainer = tb.firstChild.firstChild.firstChild;
30538 minWidth: this.minButtonWidth,
30541 if(typeof config == "string"){
30542 bconfig.text = config;
30545 bconfig.dhconfig = config;
30547 Roo.apply(bconfig, config);
30551 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30552 bconfig.position = Math.max(0, bconfig.position);
30553 fc = this.btnContainer.childNodes[bconfig.position];
30556 var btn = new Roo.Button(
30558 this.btnContainer.insertBefore(document.createElement("td"),fc)
30559 : this.btnContainer.appendChild(document.createElement("td")),
30560 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30563 this.syncBodyHeight();
30566 * Array of all the buttons that have been added to this dialog via addButton
30571 this.buttons.push(btn);
30576 * Sets the default button to be focused when the dialog is displayed.
30577 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30578 * @return {Roo.BasicDialog} this
30580 setDefaultButton : function(btn){
30581 this.defaultButton = btn;
30586 getHeaderFooterHeight : function(safe){
30589 height += this.header.getHeight();
30592 var fm = this.footer.getMargins();
30593 height += (this.footer.getHeight()+fm.top+fm.bottom);
30595 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30596 height += this.centerBg.getPadding("tb");
30601 syncBodyHeight : function()
30603 var bd = this.body, // the text
30604 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30606 var height = this.size.height - this.getHeaderFooterHeight(false);
30607 bd.setHeight(height-bd.getMargins("tb"));
30608 var hh = this.header.getHeight();
30609 var h = this.size.height-hh;
30612 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30613 bw.setHeight(h-cb.getPadding("tb"));
30615 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30616 bd.setWidth(bw.getWidth(true));
30618 this.tabs.syncHeight();
30620 this.tabs.el.repaint();
30626 * Restores the previous state of the dialog if Roo.state is configured.
30627 * @return {Roo.BasicDialog} this
30629 restoreState : function(){
30630 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30631 if(box && box.width){
30632 this.xy = [box.x, box.y];
30633 this.resizeTo(box.width, box.height);
30639 beforeShow : function(){
30641 if(this.fixedcenter){
30642 this.xy = this.el.getCenterXY(true);
30645 Roo.get(document.body).addClass("x-body-masked");
30646 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30649 this.constrainXY();
30653 animShow : function(){
30654 var b = Roo.get(this.animateTarget).getBox();
30655 this.proxy.setSize(b.width, b.height);
30656 this.proxy.setLocation(b.x, b.y);
30658 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30659 true, .35, this.showEl.createDelegate(this));
30663 * Shows the dialog.
30664 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30665 * @return {Roo.BasicDialog} this
30667 show : function(animateTarget){
30668 if (this.fireEvent("beforeshow", this) === false){
30671 if(this.syncHeightBeforeShow){
30672 this.syncBodyHeight();
30673 }else if(this.firstShow){
30674 this.firstShow = false;
30675 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30677 this.animateTarget = animateTarget || this.animateTarget;
30678 if(!this.el.isVisible()){
30680 if(this.animateTarget && Roo.get(this.animateTarget)){
30690 showEl : function(){
30692 this.el.setXY(this.xy);
30694 this.adjustAssets(true);
30697 // IE peekaboo bug - fix found by Dave Fenwick
30701 this.fireEvent("show", this);
30705 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30706 * dialog itself will receive focus.
30708 focus : function(){
30709 if(this.defaultButton){
30710 this.defaultButton.focus();
30712 this.focusEl.focus();
30717 constrainXY : function(){
30718 if(this.constraintoviewport !== false){
30719 if(!this.viewSize){
30720 if(this.container){
30721 var s = this.container.getSize();
30722 this.viewSize = [s.width, s.height];
30724 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30727 var s = Roo.get(this.container||document).getScroll();
30729 var x = this.xy[0], y = this.xy[1];
30730 var w = this.size.width, h = this.size.height;
30731 var vw = this.viewSize[0], vh = this.viewSize[1];
30732 // only move it if it needs it
30734 // first validate right/bottom
30735 if(x + w > vw+s.left){
30739 if(y + h > vh+s.top){
30743 // then make sure top/left isn't negative
30755 if(this.isVisible()){
30756 this.el.setLocation(x, y);
30757 this.adjustAssets();
30764 onDrag : function(){
30765 if(!this.proxyDrag){
30766 this.xy = this.el.getXY();
30767 this.adjustAssets();
30772 adjustAssets : function(doShow){
30773 var x = this.xy[0], y = this.xy[1];
30774 var w = this.size.width, h = this.size.height;
30775 if(doShow === true){
30777 this.shadow.show(this.el);
30783 if(this.shadow && this.shadow.isVisible()){
30784 this.shadow.show(this.el);
30786 if(this.shim && this.shim.isVisible()){
30787 this.shim.setBounds(x, y, w, h);
30792 adjustViewport : function(w, h){
30794 w = Roo.lib.Dom.getViewWidth();
30795 h = Roo.lib.Dom.getViewHeight();
30798 this.viewSize = [w, h];
30799 if(this.modal && this.mask.isVisible()){
30800 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30801 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30803 if(this.isVisible()){
30804 this.constrainXY();
30809 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30810 * shadow, proxy, mask, etc.) Also removes all event listeners.
30811 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30813 destroy : function(removeEl){
30814 if(this.isVisible()){
30815 this.animateTarget = null;
30818 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30820 this.tabs.destroy(removeEl);
30833 for(var i = 0, len = this.buttons.length; i < len; i++){
30834 this.buttons[i].destroy();
30837 this.el.removeAllListeners();
30838 if(removeEl === true){
30839 this.el.update("");
30842 Roo.DialogManager.unregister(this);
30846 startMove : function(){
30847 if(this.proxyDrag){
30850 if(this.constraintoviewport !== false){
30851 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30856 endMove : function(){
30857 if(!this.proxyDrag){
30858 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30860 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30863 this.refreshSize();
30864 this.adjustAssets();
30866 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30870 * Brings this dialog to the front of any other visible dialogs
30871 * @return {Roo.BasicDialog} this
30873 toFront : function(){
30874 Roo.DialogManager.bringToFront(this);
30879 * Sends this dialog to the back (under) of any other visible dialogs
30880 * @return {Roo.BasicDialog} this
30882 toBack : function(){
30883 Roo.DialogManager.sendToBack(this);
30888 * Centers this dialog in the viewport
30889 * @return {Roo.BasicDialog} this
30891 center : function(){
30892 var xy = this.el.getCenterXY(true);
30893 this.moveTo(xy[0], xy[1]);
30898 * Moves the dialog's top-left corner to the specified point
30899 * @param {Number} x
30900 * @param {Number} y
30901 * @return {Roo.BasicDialog} this
30903 moveTo : function(x, y){
30905 if(this.isVisible()){
30906 this.el.setXY(this.xy);
30907 this.adjustAssets();
30913 * Aligns the dialog to the specified element
30914 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30915 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30916 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30917 * @return {Roo.BasicDialog} this
30919 alignTo : function(element, position, offsets){
30920 this.xy = this.el.getAlignToXY(element, position, offsets);
30921 if(this.isVisible()){
30922 this.el.setXY(this.xy);
30923 this.adjustAssets();
30929 * Anchors an element to another element and realigns it when the window is resized.
30930 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30931 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30932 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30933 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30934 * is a number, it is used as the buffer delay (defaults to 50ms).
30935 * @return {Roo.BasicDialog} this
30937 anchorTo : function(el, alignment, offsets, monitorScroll){
30938 var action = function(){
30939 this.alignTo(el, alignment, offsets);
30941 Roo.EventManager.onWindowResize(action, this);
30942 var tm = typeof monitorScroll;
30943 if(tm != 'undefined'){
30944 Roo.EventManager.on(window, 'scroll', action, this,
30945 {buffer: tm == 'number' ? monitorScroll : 50});
30952 * Returns true if the dialog is visible
30953 * @return {Boolean}
30955 isVisible : function(){
30956 return this.el.isVisible();
30960 animHide : function(callback){
30961 var b = Roo.get(this.animateTarget).getBox();
30963 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30965 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30966 this.hideEl.createDelegate(this, [callback]));
30970 * Hides the dialog.
30971 * @param {Function} callback (optional) Function to call when the dialog is hidden
30972 * @return {Roo.BasicDialog} this
30974 hide : function(callback){
30975 if (this.fireEvent("beforehide", this) === false){
30979 this.shadow.hide();
30984 // sometimes animateTarget seems to get set.. causing problems...
30985 // this just double checks..
30986 if(this.animateTarget && Roo.get(this.animateTarget)) {
30987 this.animHide(callback);
30990 this.hideEl(callback);
30996 hideEl : function(callback){
31000 Roo.get(document.body).removeClass("x-body-masked");
31002 this.fireEvent("hide", this);
31003 if(typeof callback == "function"){
31009 hideAction : function(){
31010 this.setLeft("-10000px");
31011 this.setTop("-10000px");
31012 this.setStyle("visibility", "hidden");
31016 refreshSize : function(){
31017 this.size = this.el.getSize();
31018 this.xy = this.el.getXY();
31019 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31023 // z-index is managed by the DialogManager and may be overwritten at any time
31024 setZIndex : function(index){
31026 this.mask.setStyle("z-index", index);
31029 this.shim.setStyle("z-index", ++index);
31032 this.shadow.setZIndex(++index);
31034 this.el.setStyle("z-index", ++index);
31036 this.proxy.setStyle("z-index", ++index);
31039 this.resizer.proxy.setStyle("z-index", ++index);
31042 this.lastZIndex = index;
31046 * Returns the element for this dialog
31047 * @return {Roo.Element} The underlying dialog Element
31049 getEl : function(){
31055 * @class Roo.DialogManager
31056 * Provides global access to BasicDialogs that have been created and
31057 * support for z-indexing (layering) multiple open dialogs.
31059 Roo.DialogManager = function(){
31061 var accessList = [];
31065 var sortDialogs = function(d1, d2){
31066 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31070 var orderDialogs = function(){
31071 accessList.sort(sortDialogs);
31072 var seed = Roo.DialogManager.zseed;
31073 for(var i = 0, len = accessList.length; i < len; i++){
31074 var dlg = accessList[i];
31076 dlg.setZIndex(seed + (i*10));
31083 * The starting z-index for BasicDialogs (defaults to 9000)
31084 * @type Number The z-index value
31089 register : function(dlg){
31090 list[dlg.id] = dlg;
31091 accessList.push(dlg);
31095 unregister : function(dlg){
31096 delete list[dlg.id];
31099 if(!accessList.indexOf){
31100 for( i = 0, len = accessList.length; i < len; i++){
31101 if(accessList[i] == dlg){
31102 accessList.splice(i, 1);
31107 i = accessList.indexOf(dlg);
31109 accessList.splice(i, 1);
31115 * Gets a registered dialog by id
31116 * @param {String/Object} id The id of the dialog or a dialog
31117 * @return {Roo.BasicDialog} this
31119 get : function(id){
31120 return typeof id == "object" ? id : list[id];
31124 * Brings the specified dialog to the front
31125 * @param {String/Object} dlg The id of the dialog or a dialog
31126 * @return {Roo.BasicDialog} this
31128 bringToFront : function(dlg){
31129 dlg = this.get(dlg);
31132 dlg._lastAccess = new Date().getTime();
31139 * Sends the specified dialog to the back
31140 * @param {String/Object} dlg The id of the dialog or a dialog
31141 * @return {Roo.BasicDialog} this
31143 sendToBack : function(dlg){
31144 dlg = this.get(dlg);
31145 dlg._lastAccess = -(new Date().getTime());
31151 * Hides all dialogs
31153 hideAll : function(){
31154 for(var id in list){
31155 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31164 * @class Roo.LayoutDialog
31165 * @extends Roo.BasicDialog
31166 * Dialog which provides adjustments for working with a layout in a Dialog.
31167 * Add your necessary layout config options to the dialog's config.<br>
31168 * Example usage (including a nested layout):
31171 dialog = new Roo.LayoutDialog("download-dlg", {
31180 // layout config merges with the dialog config
31182 tabPosition: "top",
31183 alwaysShowTabs: true
31186 dialog.addKeyListener(27, dialog.hide, dialog);
31187 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31188 dialog.addButton("Build It!", this.getDownload, this);
31190 // we can even add nested layouts
31191 var innerLayout = new Roo.BorderLayout("dl-inner", {
31201 innerLayout.beginUpdate();
31202 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31203 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31204 innerLayout.endUpdate(true);
31206 var layout = dialog.getLayout();
31207 layout.beginUpdate();
31208 layout.add("center", new Roo.ContentPanel("standard-panel",
31209 {title: "Download the Source", fitToFrame:true}));
31210 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31211 {title: "Build your own roo.js"}));
31212 layout.getRegion("center").showPanel(sp);
31213 layout.endUpdate();
31217 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31218 * @param {Object} config configuration options
31220 Roo.LayoutDialog = function(el, cfg){
31223 if (typeof(cfg) == 'undefined') {
31224 config = Roo.apply({}, el);
31225 // not sure why we use documentElement here.. - it should always be body.
31226 // IE7 borks horribly if we use documentElement.
31227 // webkit also does not like documentElement - it creates a body element...
31228 el = Roo.get( document.body || document.documentElement ).createChild();
31229 //config.autoCreate = true;
31233 config.autoTabs = false;
31234 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31235 this.body.setStyle({overflow:"hidden", position:"relative"});
31236 this.layout = new Roo.BorderLayout(this.body.dom, config);
31237 this.layout.monitorWindowResize = false;
31238 this.el.addClass("x-dlg-auto-layout");
31239 // fix case when center region overwrites center function
31240 this.center = Roo.BasicDialog.prototype.center;
31241 this.on("show", this.layout.layout, this.layout, true);
31242 if (config.items) {
31243 var xitems = config.items;
31244 delete config.items;
31245 Roo.each(xitems, this.addxtype, this);
31250 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31252 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31255 endUpdate : function(){
31256 this.layout.endUpdate();
31260 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31263 beginUpdate : function(){
31264 this.layout.beginUpdate();
31268 * Get the BorderLayout for this dialog
31269 * @return {Roo.BorderLayout}
31271 getLayout : function(){
31272 return this.layout;
31275 showEl : function(){
31276 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31278 this.layout.layout();
31283 // Use the syncHeightBeforeShow config option to control this automatically
31284 syncBodyHeight : function(){
31285 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31286 if(this.layout){this.layout.layout();}
31290 * Add an xtype element (actually adds to the layout.)
31291 * @return {Object} xdata xtype object data.
31294 addxtype : function(c) {
31295 return this.layout.addxtype(c);
31299 * Ext JS Library 1.1.1
31300 * Copyright(c) 2006-2007, Ext JS, LLC.
31302 * Originally Released Under LGPL - original licence link has changed is not relivant.
31305 * <script type="text/javascript">
31309 * @class Roo.MessageBox
31310 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31314 Roo.Msg.alert('Status', 'Changes saved successfully.');
31316 // Prompt for user data:
31317 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31319 // process text value...
31323 // Show a dialog using config options:
31325 title:'Save Changes?',
31326 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31327 buttons: Roo.Msg.YESNOCANCEL,
31334 Roo.MessageBox = function(){
31335 var dlg, opt, mask, waitTimer;
31336 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31337 var buttons, activeTextEl, bwidth;
31340 var handleButton = function(button){
31342 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31346 var handleHide = function(){
31347 if(opt && opt.cls){
31348 dlg.el.removeClass(opt.cls);
31351 Roo.TaskMgr.stop(waitTimer);
31357 var updateButtons = function(b){
31360 buttons["ok"].hide();
31361 buttons["cancel"].hide();
31362 buttons["yes"].hide();
31363 buttons["no"].hide();
31364 dlg.footer.dom.style.display = 'none';
31367 dlg.footer.dom.style.display = '';
31368 for(var k in buttons){
31369 if(typeof buttons[k] != "function"){
31372 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31373 width += buttons[k].el.getWidth()+15;
31383 var handleEsc = function(d, k, e){
31384 if(opt && opt.closable !== false){
31394 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31395 * @return {Roo.BasicDialog} The BasicDialog element
31397 getDialog : function(){
31399 dlg = new Roo.BasicDialog("x-msg-box", {
31404 constraintoviewport:false,
31406 collapsible : false,
31409 width:400, height:100,
31410 buttonAlign:"center",
31411 closeClick : function(){
31412 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31413 handleButton("no");
31415 handleButton("cancel");
31419 dlg.on("hide", handleHide);
31421 dlg.addKeyListener(27, handleEsc);
31423 var bt = this.buttonText;
31424 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31425 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31426 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31427 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31428 bodyEl = dlg.body.createChild({
31430 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>'
31432 msgEl = bodyEl.dom.firstChild;
31433 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31434 textboxEl.enableDisplayMode();
31435 textboxEl.addKeyListener([10,13], function(){
31436 if(dlg.isVisible() && opt && opt.buttons){
31437 if(opt.buttons.ok){
31438 handleButton("ok");
31439 }else if(opt.buttons.yes){
31440 handleButton("yes");
31444 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31445 textareaEl.enableDisplayMode();
31446 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31447 progressEl.enableDisplayMode();
31448 var pf = progressEl.dom.firstChild;
31450 pp = Roo.get(pf.firstChild);
31451 pp.setHeight(pf.offsetHeight);
31459 * Updates the message box body text
31460 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31461 * the XHTML-compliant non-breaking space character '&#160;')
31462 * @return {Roo.MessageBox} This message box
31464 updateText : function(text){
31465 if(!dlg.isVisible() && !opt.width){
31466 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31468 msgEl.innerHTML = text || ' ';
31470 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31471 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31473 Math.min(opt.width || cw , this.maxWidth),
31474 Math.max(opt.minWidth || this.minWidth, bwidth)
31477 activeTextEl.setWidth(w);
31479 if(dlg.isVisible()){
31480 dlg.fixedcenter = false;
31482 // to big, make it scroll. = But as usual stupid IE does not support
31485 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31486 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31487 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31489 bodyEl.dom.style.height = '';
31490 bodyEl.dom.style.overflowY = '';
31493 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31495 bodyEl.dom.style.overflowX = '';
31498 dlg.setContentSize(w, bodyEl.getHeight());
31499 if(dlg.isVisible()){
31500 dlg.fixedcenter = true;
31506 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31507 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31508 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31509 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31510 * @return {Roo.MessageBox} This message box
31512 updateProgress : function(value, text){
31514 this.updateText(text);
31516 if (pp) { // weird bug on my firefox - for some reason this is not defined
31517 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31523 * Returns true if the message box is currently displayed
31524 * @return {Boolean} True if the message box is visible, else false
31526 isVisible : function(){
31527 return dlg && dlg.isVisible();
31531 * Hides the message box if it is displayed
31534 if(this.isVisible()){
31540 * Displays a new message box, or reinitializes an existing message box, based on the config options
31541 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31542 * The following config object properties are supported:
31544 Property Type Description
31545 ---------- --------------- ------------------------------------------------------------------------------------
31546 animEl String/Element An id or Element from which the message box should animate as it opens and
31547 closes (defaults to undefined)
31548 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31549 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31550 closable Boolean False to hide the top-right close button (defaults to true). Note that
31551 progress and wait dialogs will ignore this property and always hide the
31552 close button as they can only be closed programmatically.
31553 cls String A custom CSS class to apply to the message box element
31554 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31555 displayed (defaults to 75)
31556 fn Function A callback function to execute after closing the dialog. The arguments to the
31557 function will be btn (the name of the button that was clicked, if applicable,
31558 e.g. "ok"), and text (the value of the active text field, if applicable).
31559 Progress and wait dialogs will ignore this option since they do not respond to
31560 user actions and can only be closed programmatically, so any required function
31561 should be called by the same code after it closes the dialog.
31562 icon String A CSS class that provides a background image to be used as an icon for
31563 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31564 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31565 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31566 modal Boolean False to allow user interaction with the page while the message box is
31567 displayed (defaults to true)
31568 msg String A string that will replace the existing message box body text (defaults
31569 to the XHTML-compliant non-breaking space character ' ')
31570 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31571 progress Boolean True to display a progress bar (defaults to false)
31572 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31573 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31574 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31575 title String The title text
31576 value String The string value to set into the active textbox element if displayed
31577 wait Boolean True to display a progress bar (defaults to false)
31578 width Number The width of the dialog in pixels
31585 msg: 'Please enter your address:',
31587 buttons: Roo.MessageBox.OKCANCEL,
31590 animEl: 'addAddressBtn'
31593 * @param {Object} config Configuration options
31594 * @return {Roo.MessageBox} This message box
31596 show : function(options)
31599 // this causes nightmares if you show one dialog after another
31600 // especially on callbacks..
31602 if(this.isVisible()){
31605 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31606 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31607 Roo.log("New Dialog Message:" + options.msg )
31608 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31609 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31612 var d = this.getDialog();
31614 d.setTitle(opt.title || " ");
31615 d.close.setDisplayed(opt.closable !== false);
31616 activeTextEl = textboxEl;
31617 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31622 textareaEl.setHeight(typeof opt.multiline == "number" ?
31623 opt.multiline : this.defaultTextHeight);
31624 activeTextEl = textareaEl;
31633 progressEl.setDisplayed(opt.progress === true);
31634 this.updateProgress(0);
31635 activeTextEl.dom.value = opt.value || "";
31637 dlg.setDefaultButton(activeTextEl);
31639 var bs = opt.buttons;
31642 db = buttons["ok"];
31643 }else if(bs && bs.yes){
31644 db = buttons["yes"];
31646 dlg.setDefaultButton(db);
31648 bwidth = updateButtons(opt.buttons);
31649 this.updateText(opt.msg);
31651 d.el.addClass(opt.cls);
31653 d.proxyDrag = opt.proxyDrag === true;
31654 d.modal = opt.modal !== false;
31655 d.mask = opt.modal !== false ? mask : false;
31656 if(!d.isVisible()){
31657 // force it to the end of the z-index stack so it gets a cursor in FF
31658 document.body.appendChild(dlg.el.dom);
31659 d.animateTarget = null;
31660 d.show(options.animEl);
31666 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31667 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31668 * and closing the message box when the process is complete.
31669 * @param {String} title The title bar text
31670 * @param {String} msg The message box body text
31671 * @return {Roo.MessageBox} This message box
31673 progress : function(title, msg){
31680 minWidth: this.minProgressWidth,
31687 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31688 * If a callback function is passed it will be called after the user clicks the button, and the
31689 * id of the button that was clicked will be passed as the only parameter to the callback
31690 * (could also be the top-right close button).
31691 * @param {String} title The title bar text
31692 * @param {String} msg The message box body text
31693 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31694 * @param {Object} scope (optional) The scope of the callback function
31695 * @return {Roo.MessageBox} This message box
31697 alert : function(title, msg, fn, scope){
31710 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31711 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31712 * You are responsible for closing the message box when the process is complete.
31713 * @param {String} msg The message box body text
31714 * @param {String} title (optional) The title bar text
31715 * @return {Roo.MessageBox} This message box
31717 wait : function(msg, title){
31728 waitTimer = Roo.TaskMgr.start({
31730 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31738 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31739 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31740 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31741 * @param {String} title The title bar text
31742 * @param {String} msg The message box body text
31743 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31744 * @param {Object} scope (optional) The scope of the callback function
31745 * @return {Roo.MessageBox} This message box
31747 confirm : function(title, msg, fn, scope){
31751 buttons: this.YESNO,
31760 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31761 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31762 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31763 * (could also be the top-right close button) and the text that was entered will be passed as the two
31764 * parameters to the callback.
31765 * @param {String} title The title bar text
31766 * @param {String} msg The message box body text
31767 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31768 * @param {Object} scope (optional) The scope of the callback function
31769 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31770 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31771 * @return {Roo.MessageBox} This message box
31773 prompt : function(title, msg, fn, scope, multiline){
31777 buttons: this.OKCANCEL,
31782 multiline: multiline,
31789 * Button config that displays a single OK button
31794 * Button config that displays Yes and No buttons
31797 YESNO : {yes:true, no:true},
31799 * Button config that displays OK and Cancel buttons
31802 OKCANCEL : {ok:true, cancel:true},
31804 * Button config that displays Yes, No and Cancel buttons
31807 YESNOCANCEL : {yes:true, no:true, cancel:true},
31810 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31813 defaultTextHeight : 75,
31815 * The maximum width in pixels of the message box (defaults to 600)
31820 * The minimum width in pixels of the message box (defaults to 100)
31825 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31826 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31829 minProgressWidth : 250,
31831 * An object containing the default button text strings that can be overriden for localized language support.
31832 * Supported properties are: ok, cancel, yes and no.
31833 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31846 * Shorthand for {@link Roo.MessageBox}
31848 Roo.Msg = Roo.MessageBox;/*
31850 * Ext JS Library 1.1.1
31851 * Copyright(c) 2006-2007, Ext JS, LLC.
31853 * Originally Released Under LGPL - original licence link has changed is not relivant.
31856 * <script type="text/javascript">
31859 * @class Roo.QuickTips
31860 * Provides attractive and customizable tooltips for any element.
31863 Roo.QuickTips = function(){
31864 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31865 var ce, bd, xy, dd;
31866 var visible = false, disabled = true, inited = false;
31867 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31869 var onOver = function(e){
31873 var t = e.getTarget();
31874 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31877 if(ce && t == ce.el){
31878 clearTimeout(hideProc);
31881 if(t && tagEls[t.id]){
31882 tagEls[t.id].el = t;
31883 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31886 var ttp, et = Roo.fly(t);
31887 var ns = cfg.namespace;
31888 if(tm.interceptTitles && t.title){
31891 t.removeAttribute("title");
31892 e.preventDefault();
31894 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31897 showProc = show.defer(tm.showDelay, tm, [{
31900 width: et.getAttributeNS(ns, cfg.width),
31901 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31902 title: et.getAttributeNS(ns, cfg.title),
31903 cls: et.getAttributeNS(ns, cfg.cls)
31908 var onOut = function(e){
31909 clearTimeout(showProc);
31910 var t = e.getTarget();
31911 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31912 hideProc = setTimeout(hide, tm.hideDelay);
31916 var onMove = function(e){
31922 if(tm.trackMouse && ce){
31927 var onDown = function(e){
31928 clearTimeout(showProc);
31929 clearTimeout(hideProc);
31931 if(tm.hideOnClick){
31934 tm.enable.defer(100, tm);
31939 var getPad = function(){
31940 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31943 var show = function(o){
31947 clearTimeout(dismissProc);
31949 if(removeCls){ // in case manually hidden
31950 el.removeClass(removeCls);
31954 el.addClass(ce.cls);
31955 removeCls = ce.cls;
31958 tipTitle.update(ce.title);
31961 tipTitle.update('');
31964 el.dom.style.width = tm.maxWidth+'px';
31965 //tipBody.dom.style.width = '';
31966 tipBodyText.update(o.text);
31967 var p = getPad(), w = ce.width;
31969 var td = tipBodyText.dom;
31970 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31971 if(aw > tm.maxWidth){
31973 }else if(aw < tm.minWidth){
31979 //tipBody.setWidth(w);
31980 el.setWidth(parseInt(w, 10) + p);
31981 if(ce.autoHide === false){
31982 close.setDisplayed(true);
31987 close.setDisplayed(false);
31993 el.avoidY = xy[1]-18;
31998 el.setStyle("visibility", "visible");
31999 el.fadeIn({callback: afterShow});
32005 var afterShow = function(){
32009 if(tm.autoDismiss && ce.autoHide !== false){
32010 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32015 var hide = function(noanim){
32016 clearTimeout(dismissProc);
32017 clearTimeout(hideProc);
32019 if(el.isVisible()){
32021 if(noanim !== true && tm.animate){
32022 el.fadeOut({callback: afterHide});
32029 var afterHide = function(){
32032 el.removeClass(removeCls);
32039 * @cfg {Number} minWidth
32040 * The minimum width of the quick tip (defaults to 40)
32044 * @cfg {Number} maxWidth
32045 * The maximum width of the quick tip (defaults to 300)
32049 * @cfg {Boolean} interceptTitles
32050 * True to automatically use the element's DOM title value if available (defaults to false)
32052 interceptTitles : false,
32054 * @cfg {Boolean} trackMouse
32055 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32057 trackMouse : false,
32059 * @cfg {Boolean} hideOnClick
32060 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32062 hideOnClick : true,
32064 * @cfg {Number} showDelay
32065 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32069 * @cfg {Number} hideDelay
32070 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32074 * @cfg {Boolean} autoHide
32075 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32076 * Used in conjunction with hideDelay.
32081 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32082 * (defaults to true). Used in conjunction with autoDismissDelay.
32084 autoDismiss : true,
32087 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32089 autoDismissDelay : 5000,
32091 * @cfg {Boolean} animate
32092 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32097 * @cfg {String} title
32098 * Title text to display (defaults to ''). This can be any valid HTML markup.
32102 * @cfg {String} text
32103 * Body text to display (defaults to ''). This can be any valid HTML markup.
32107 * @cfg {String} cls
32108 * A CSS class to apply to the base quick tip element (defaults to '').
32112 * @cfg {Number} width
32113 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32114 * minWidth or maxWidth.
32119 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32120 * or display QuickTips in a page.
32123 tm = Roo.QuickTips;
32124 cfg = tm.tagConfig;
32126 if(!Roo.isReady){ // allow calling of init() before onReady
32127 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32130 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32131 el.fxDefaults = {stopFx: true};
32132 // maximum custom styling
32133 //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>');
32134 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>');
32135 tipTitle = el.child('h3');
32136 tipTitle.enableDisplayMode("block");
32137 tipBody = el.child('div.x-tip-bd');
32138 tipBodyText = el.child('div.x-tip-bd-inner');
32139 //bdLeft = el.child('div.x-tip-bd-left');
32140 //bdRight = el.child('div.x-tip-bd-right');
32141 close = el.child('div.x-tip-close');
32142 close.enableDisplayMode("block");
32143 close.on("click", hide);
32144 var d = Roo.get(document);
32145 d.on("mousedown", onDown);
32146 d.on("mouseover", onOver);
32147 d.on("mouseout", onOut);
32148 d.on("mousemove", onMove);
32149 esc = d.addKeyListener(27, hide);
32152 dd = el.initDD("default", null, {
32153 onDrag : function(){
32157 dd.setHandleElId(tipTitle.id);
32166 * Configures a new quick tip instance and assigns it to a target element. The following config options
32169 Property Type Description
32170 ---------- --------------------- ------------------------------------------------------------------------
32171 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32173 * @param {Object} config The config object
32175 register : function(config){
32176 var cs = config instanceof Array ? config : arguments;
32177 for(var i = 0, len = cs.length; i < len; i++) {
32179 var target = c.target;
32181 if(target instanceof Array){
32182 for(var j = 0, jlen = target.length; j < jlen; j++){
32183 tagEls[target[j]] = c;
32186 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32193 * Removes this quick tip from its element and destroys it.
32194 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32196 unregister : function(el){
32197 delete tagEls[Roo.id(el)];
32201 * Enable this quick tip.
32203 enable : function(){
32204 if(inited && disabled){
32206 if(locks.length < 1){
32213 * Disable this quick tip.
32215 disable : function(){
32217 clearTimeout(showProc);
32218 clearTimeout(hideProc);
32219 clearTimeout(dismissProc);
32227 * Returns true if the quick tip is enabled, else false.
32229 isEnabled : function(){
32236 attribute : "qtip",
32246 // backwards compat
32247 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32249 * Ext JS Library 1.1.1
32250 * Copyright(c) 2006-2007, Ext JS, LLC.
32252 * Originally Released Under LGPL - original licence link has changed is not relivant.
32255 * <script type="text/javascript">
32260 * @class Roo.tree.TreePanel
32261 * @extends Roo.data.Tree
32263 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32264 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32265 * @cfg {Boolean} enableDD true to enable drag and drop
32266 * @cfg {Boolean} enableDrag true to enable just drag
32267 * @cfg {Boolean} enableDrop true to enable just drop
32268 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32269 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32270 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32271 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32272 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32273 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32274 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32275 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32276 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32277 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32278 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32279 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32280 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32281 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32282 * @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>
32283 * @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>
32286 * @param {String/HTMLElement/Element} el The container element
32287 * @param {Object} config
32289 Roo.tree.TreePanel = function(el, config){
32291 var loader = false;
32293 root = config.root;
32294 delete config.root;
32296 if (config.loader) {
32297 loader = config.loader;
32298 delete config.loader;
32301 Roo.apply(this, config);
32302 Roo.tree.TreePanel.superclass.constructor.call(this);
32303 this.el = Roo.get(el);
32304 this.el.addClass('x-tree');
32305 //console.log(root);
32307 this.setRootNode( Roo.factory(root, Roo.tree));
32310 this.loader = Roo.factory(loader, Roo.tree);
32313 * Read-only. The id of the container element becomes this TreePanel's id.
32315 this.id = this.el.id;
32318 * @event beforeload
32319 * Fires before a node is loaded, return false to cancel
32320 * @param {Node} node The node being loaded
32322 "beforeload" : true,
32325 * Fires when a node is loaded
32326 * @param {Node} node The node that was loaded
32330 * @event textchange
32331 * Fires when the text for a node is changed
32332 * @param {Node} node The node
32333 * @param {String} text The new text
32334 * @param {String} oldText The old text
32336 "textchange" : true,
32338 * @event beforeexpand
32339 * Fires before a node is expanded, return false to cancel.
32340 * @param {Node} node The node
32341 * @param {Boolean} deep
32342 * @param {Boolean} anim
32344 "beforeexpand" : true,
32346 * @event beforecollapse
32347 * Fires before a node is collapsed, return false to cancel.
32348 * @param {Node} node The node
32349 * @param {Boolean} deep
32350 * @param {Boolean} anim
32352 "beforecollapse" : true,
32355 * Fires when a node is expanded
32356 * @param {Node} node The node
32360 * @event disabledchange
32361 * Fires when the disabled status of a node changes
32362 * @param {Node} node The node
32363 * @param {Boolean} disabled
32365 "disabledchange" : true,
32368 * Fires when a node is collapsed
32369 * @param {Node} node The node
32373 * @event beforeclick
32374 * Fires before click processing on a node. Return false to cancel the default action.
32375 * @param {Node} node The node
32376 * @param {Roo.EventObject} e The event object
32378 "beforeclick":true,
32380 * @event checkchange
32381 * Fires when a node with a checkbox's checked property changes
32382 * @param {Node} this This node
32383 * @param {Boolean} checked
32385 "checkchange":true,
32388 * Fires when a node is clicked
32389 * @param {Node} node The node
32390 * @param {Roo.EventObject} e The event object
32395 * Fires when a node is double clicked
32396 * @param {Node} node The node
32397 * @param {Roo.EventObject} e The event object
32401 * @event contextmenu
32402 * Fires when a node is right clicked
32403 * @param {Node} node The node
32404 * @param {Roo.EventObject} e The event object
32406 "contextmenu":true,
32408 * @event beforechildrenrendered
32409 * Fires right before the child nodes for a node are rendered
32410 * @param {Node} node The node
32412 "beforechildrenrendered":true,
32415 * Fires when a node starts being dragged
32416 * @param {Roo.tree.TreePanel} this
32417 * @param {Roo.tree.TreeNode} node
32418 * @param {event} e The raw browser event
32420 "startdrag" : true,
32423 * Fires when a drag operation is complete
32424 * @param {Roo.tree.TreePanel} this
32425 * @param {Roo.tree.TreeNode} node
32426 * @param {event} e The raw browser event
32431 * Fires when a dragged node is dropped on a valid DD target
32432 * @param {Roo.tree.TreePanel} this
32433 * @param {Roo.tree.TreeNode} node
32434 * @param {DD} dd The dd it was dropped on
32435 * @param {event} e The raw browser event
32439 * @event beforenodedrop
32440 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32441 * passed to handlers has the following properties:<br />
32442 * <ul style="padding:5px;padding-left:16px;">
32443 * <li>tree - The TreePanel</li>
32444 * <li>target - The node being targeted for the drop</li>
32445 * <li>data - The drag data from the drag source</li>
32446 * <li>point - The point of the drop - append, above or below</li>
32447 * <li>source - The drag source</li>
32448 * <li>rawEvent - Raw mouse event</li>
32449 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32450 * to be inserted by setting them on this object.</li>
32451 * <li>cancel - Set this to true to cancel the drop.</li>
32453 * @param {Object} dropEvent
32455 "beforenodedrop" : true,
32458 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32459 * passed to handlers has the following properties:<br />
32460 * <ul style="padding:5px;padding-left:16px;">
32461 * <li>tree - The TreePanel</li>
32462 * <li>target - The node being targeted for the drop</li>
32463 * <li>data - The drag data from the drag source</li>
32464 * <li>point - The point of the drop - append, above or below</li>
32465 * <li>source - The drag source</li>
32466 * <li>rawEvent - Raw mouse event</li>
32467 * <li>dropNode - Dropped node(s).</li>
32469 * @param {Object} dropEvent
32473 * @event nodedragover
32474 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32475 * passed to handlers has the following properties:<br />
32476 * <ul style="padding:5px;padding-left:16px;">
32477 * <li>tree - The TreePanel</li>
32478 * <li>target - The node being targeted for the drop</li>
32479 * <li>data - The drag data from the drag source</li>
32480 * <li>point - The point of the drop - append, above or below</li>
32481 * <li>source - The drag source</li>
32482 * <li>rawEvent - Raw mouse event</li>
32483 * <li>dropNode - Drop node(s) provided by the source.</li>
32484 * <li>cancel - Set this to true to signal drop not allowed.</li>
32486 * @param {Object} dragOverEvent
32488 "nodedragover" : true
32491 if(this.singleExpand){
32492 this.on("beforeexpand", this.restrictExpand, this);
32495 this.editor.tree = this;
32496 this.editor = Roo.factory(this.editor, Roo.tree);
32499 if (this.selModel) {
32500 this.selModel = Roo.factory(this.selModel, Roo.tree);
32504 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32505 rootVisible : true,
32506 animate: Roo.enableFx,
32509 hlDrop : Roo.enableFx,
32513 rendererTip: false,
32515 restrictExpand : function(node){
32516 var p = node.parentNode;
32518 if(p.expandedChild && p.expandedChild.parentNode == p){
32519 p.expandedChild.collapse();
32521 p.expandedChild = node;
32525 // private override
32526 setRootNode : function(node){
32527 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32528 if(!this.rootVisible){
32529 node.ui = new Roo.tree.RootTreeNodeUI(node);
32535 * Returns the container element for this TreePanel
32537 getEl : function(){
32542 * Returns the default TreeLoader for this TreePanel
32544 getLoader : function(){
32545 return this.loader;
32551 expandAll : function(){
32552 this.root.expand(true);
32556 * Collapse all nodes
32558 collapseAll : function(){
32559 this.root.collapse(true);
32563 * Returns the selection model used by this TreePanel
32565 getSelectionModel : function(){
32566 if(!this.selModel){
32567 this.selModel = new Roo.tree.DefaultSelectionModel();
32569 return this.selModel;
32573 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32574 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32575 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32578 getChecked : function(a, startNode){
32579 startNode = startNode || this.root;
32581 var f = function(){
32582 if(this.attributes.checked){
32583 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32586 startNode.cascade(f);
32591 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32592 * @param {String} path
32593 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32594 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32595 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32597 expandPath : function(path, attr, callback){
32598 attr = attr || "id";
32599 var keys = path.split(this.pathSeparator);
32600 var curNode = this.root;
32601 if(curNode.attributes[attr] != keys[1]){ // invalid root
32603 callback(false, null);
32608 var f = function(){
32609 if(++index == keys.length){
32611 callback(true, curNode);
32615 var c = curNode.findChild(attr, keys[index]);
32618 callback(false, curNode);
32623 c.expand(false, false, f);
32625 curNode.expand(false, false, f);
32629 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32630 * @param {String} path
32631 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32632 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32633 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32635 selectPath : function(path, attr, callback){
32636 attr = attr || "id";
32637 var keys = path.split(this.pathSeparator);
32638 var v = keys.pop();
32639 if(keys.length > 0){
32640 var f = function(success, node){
32641 if(success && node){
32642 var n = node.findChild(attr, v);
32648 }else if(callback){
32649 callback(false, n);
32653 callback(false, n);
32657 this.expandPath(keys.join(this.pathSeparator), attr, f);
32659 this.root.select();
32661 callback(true, this.root);
32666 getTreeEl : function(){
32671 * Trigger rendering of this TreePanel
32673 render : function(){
32674 if (this.innerCt) {
32675 return this; // stop it rendering more than once!!
32678 this.innerCt = this.el.createChild({tag:"ul",
32679 cls:"x-tree-root-ct " +
32680 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32682 if(this.containerScroll){
32683 Roo.dd.ScrollManager.register(this.el);
32685 if((this.enableDD || this.enableDrop) && !this.dropZone){
32687 * The dropZone used by this tree if drop is enabled
32688 * @type Roo.tree.TreeDropZone
32690 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32691 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32694 if((this.enableDD || this.enableDrag) && !this.dragZone){
32696 * The dragZone used by this tree if drag is enabled
32697 * @type Roo.tree.TreeDragZone
32699 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32700 ddGroup: this.ddGroup || "TreeDD",
32701 scroll: this.ddScroll
32704 this.getSelectionModel().init(this);
32706 Roo.log("ROOT not set in tree");
32709 this.root.render();
32710 if(!this.rootVisible){
32711 this.root.renderChildren();
32717 * Ext JS Library 1.1.1
32718 * Copyright(c) 2006-2007, Ext JS, LLC.
32720 * Originally Released Under LGPL - original licence link has changed is not relivant.
32723 * <script type="text/javascript">
32728 * @class Roo.tree.DefaultSelectionModel
32729 * @extends Roo.util.Observable
32730 * The default single selection for a TreePanel.
32731 * @param {Object} cfg Configuration
32733 Roo.tree.DefaultSelectionModel = function(cfg){
32734 this.selNode = null;
32740 * @event selectionchange
32741 * Fires when the selected node changes
32742 * @param {DefaultSelectionModel} this
32743 * @param {TreeNode} node the new selection
32745 "selectionchange" : true,
32748 * @event beforeselect
32749 * Fires before the selected node changes, return false to cancel the change
32750 * @param {DefaultSelectionModel} this
32751 * @param {TreeNode} node the new selection
32752 * @param {TreeNode} node the old selection
32754 "beforeselect" : true
32757 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32760 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32761 init : function(tree){
32763 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32764 tree.on("click", this.onNodeClick, this);
32767 onNodeClick : function(node, e){
32768 if (e.ctrlKey && this.selNode == node) {
32769 this.unselect(node);
32777 * @param {TreeNode} node The node to select
32778 * @return {TreeNode} The selected node
32780 select : function(node){
32781 var last = this.selNode;
32782 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32784 last.ui.onSelectedChange(false);
32786 this.selNode = node;
32787 node.ui.onSelectedChange(true);
32788 this.fireEvent("selectionchange", this, node, last);
32795 * @param {TreeNode} node The node to unselect
32797 unselect : function(node){
32798 if(this.selNode == node){
32799 this.clearSelections();
32804 * Clear all selections
32806 clearSelections : function(){
32807 var n = this.selNode;
32809 n.ui.onSelectedChange(false);
32810 this.selNode = null;
32811 this.fireEvent("selectionchange", this, null);
32817 * Get the selected node
32818 * @return {TreeNode} The selected node
32820 getSelectedNode : function(){
32821 return this.selNode;
32825 * Returns true if the node is selected
32826 * @param {TreeNode} node The node to check
32827 * @return {Boolean}
32829 isSelected : function(node){
32830 return this.selNode == node;
32834 * Selects the node above the selected node in the tree, intelligently walking the nodes
32835 * @return TreeNode The new selection
32837 selectPrevious : function(){
32838 var s = this.selNode || this.lastSelNode;
32842 var ps = s.previousSibling;
32844 if(!ps.isExpanded() || ps.childNodes.length < 1){
32845 return this.select(ps);
32847 var lc = ps.lastChild;
32848 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32851 return this.select(lc);
32853 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32854 return this.select(s.parentNode);
32860 * Selects the node above the selected node in the tree, intelligently walking the nodes
32861 * @return TreeNode The new selection
32863 selectNext : function(){
32864 var s = this.selNode || this.lastSelNode;
32868 if(s.firstChild && s.isExpanded()){
32869 return this.select(s.firstChild);
32870 }else if(s.nextSibling){
32871 return this.select(s.nextSibling);
32872 }else if(s.parentNode){
32874 s.parentNode.bubble(function(){
32875 if(this.nextSibling){
32876 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32885 onKeyDown : function(e){
32886 var s = this.selNode || this.lastSelNode;
32887 // undesirable, but required
32892 var k = e.getKey();
32900 this.selectPrevious();
32903 e.preventDefault();
32904 if(s.hasChildNodes()){
32905 if(!s.isExpanded()){
32907 }else if(s.firstChild){
32908 this.select(s.firstChild, e);
32913 e.preventDefault();
32914 if(s.hasChildNodes() && s.isExpanded()){
32916 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32917 this.select(s.parentNode, e);
32925 * @class Roo.tree.MultiSelectionModel
32926 * @extends Roo.util.Observable
32927 * Multi selection for a TreePanel.
32928 * @param {Object} cfg Configuration
32930 Roo.tree.MultiSelectionModel = function(){
32931 this.selNodes = [];
32935 * @event selectionchange
32936 * Fires when the selected nodes change
32937 * @param {MultiSelectionModel} this
32938 * @param {Array} nodes Array of the selected nodes
32940 "selectionchange" : true
32942 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32946 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32947 init : function(tree){
32949 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32950 tree.on("click", this.onNodeClick, this);
32953 onNodeClick : function(node, e){
32954 this.select(node, e, e.ctrlKey);
32959 * @param {TreeNode} node The node to select
32960 * @param {EventObject} e (optional) An event associated with the selection
32961 * @param {Boolean} keepExisting True to retain existing selections
32962 * @return {TreeNode} The selected node
32964 select : function(node, e, keepExisting){
32965 if(keepExisting !== true){
32966 this.clearSelections(true);
32968 if(this.isSelected(node)){
32969 this.lastSelNode = node;
32972 this.selNodes.push(node);
32973 this.selMap[node.id] = node;
32974 this.lastSelNode = node;
32975 node.ui.onSelectedChange(true);
32976 this.fireEvent("selectionchange", this, this.selNodes);
32982 * @param {TreeNode} node The node to unselect
32984 unselect : function(node){
32985 if(this.selMap[node.id]){
32986 node.ui.onSelectedChange(false);
32987 var sn = this.selNodes;
32990 index = sn.indexOf(node);
32992 for(var i = 0, len = sn.length; i < len; i++){
33000 this.selNodes.splice(index, 1);
33002 delete this.selMap[node.id];
33003 this.fireEvent("selectionchange", this, this.selNodes);
33008 * Clear all selections
33010 clearSelections : function(suppressEvent){
33011 var sn = this.selNodes;
33013 for(var i = 0, len = sn.length; i < len; i++){
33014 sn[i].ui.onSelectedChange(false);
33016 this.selNodes = [];
33018 if(suppressEvent !== true){
33019 this.fireEvent("selectionchange", this, this.selNodes);
33025 * Returns true if the node is selected
33026 * @param {TreeNode} node The node to check
33027 * @return {Boolean}
33029 isSelected : function(node){
33030 return this.selMap[node.id] ? true : false;
33034 * Returns an array of the selected nodes
33037 getSelectedNodes : function(){
33038 return this.selNodes;
33041 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33043 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33045 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33048 * Ext JS Library 1.1.1
33049 * Copyright(c) 2006-2007, Ext JS, LLC.
33051 * Originally Released Under LGPL - original licence link has changed is not relivant.
33054 * <script type="text/javascript">
33058 * @class Roo.tree.TreeNode
33059 * @extends Roo.data.Node
33060 * @cfg {String} text The text for this node
33061 * @cfg {Boolean} expanded true to start the node expanded
33062 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33063 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33064 * @cfg {Boolean} disabled true to start the node disabled
33065 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33066 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33067 * @cfg {String} cls A css class to be added to the node
33068 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33069 * @cfg {String} href URL of the link used for the node (defaults to #)
33070 * @cfg {String} hrefTarget target frame for the link
33071 * @cfg {String} qtip An Ext QuickTip for the node
33072 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33073 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33074 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33075 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33076 * (defaults to undefined with no checkbox rendered)
33078 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33080 Roo.tree.TreeNode = function(attributes){
33081 attributes = attributes || {};
33082 if(typeof attributes == "string"){
33083 attributes = {text: attributes};
33085 this.childrenRendered = false;
33086 this.rendered = false;
33087 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33088 this.expanded = attributes.expanded === true;
33089 this.isTarget = attributes.isTarget !== false;
33090 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33091 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33094 * Read-only. The text for this node. To change it use setText().
33097 this.text = attributes.text;
33099 * True if this node is disabled.
33102 this.disabled = attributes.disabled === true;
33106 * @event textchange
33107 * Fires when the text for this node is changed
33108 * @param {Node} this This node
33109 * @param {String} text The new text
33110 * @param {String} oldText The old text
33112 "textchange" : true,
33114 * @event beforeexpand
33115 * Fires before this node is expanded, return false to cancel.
33116 * @param {Node} this This node
33117 * @param {Boolean} deep
33118 * @param {Boolean} anim
33120 "beforeexpand" : true,
33122 * @event beforecollapse
33123 * Fires before this node is collapsed, return false to cancel.
33124 * @param {Node} this This node
33125 * @param {Boolean} deep
33126 * @param {Boolean} anim
33128 "beforecollapse" : true,
33131 * Fires when this node is expanded
33132 * @param {Node} this This node
33136 * @event disabledchange
33137 * Fires when the disabled status of this node changes
33138 * @param {Node} this This node
33139 * @param {Boolean} disabled
33141 "disabledchange" : true,
33144 * Fires when this node is collapsed
33145 * @param {Node} this This node
33149 * @event beforeclick
33150 * Fires before click processing. Return false to cancel the default action.
33151 * @param {Node} this This node
33152 * @param {Roo.EventObject} e The event object
33154 "beforeclick":true,
33156 * @event checkchange
33157 * Fires when a node with a checkbox's checked property changes
33158 * @param {Node} this This node
33159 * @param {Boolean} checked
33161 "checkchange":true,
33164 * Fires when this node is clicked
33165 * @param {Node} this This node
33166 * @param {Roo.EventObject} e The event object
33171 * Fires when this node is double clicked
33172 * @param {Node} this This node
33173 * @param {Roo.EventObject} e The event object
33177 * @event contextmenu
33178 * Fires when this node is right clicked
33179 * @param {Node} this This node
33180 * @param {Roo.EventObject} e The event object
33182 "contextmenu":true,
33184 * @event beforechildrenrendered
33185 * Fires right before the child nodes for this node are rendered
33186 * @param {Node} this This node
33188 "beforechildrenrendered":true
33191 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33194 * Read-only. The UI for this node
33197 this.ui = new uiClass(this);
33199 // finally support items[]
33200 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33205 Roo.each(this.attributes.items, function(c) {
33206 this.appendChild(Roo.factory(c,Roo.Tree));
33208 delete this.attributes.items;
33213 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33214 preventHScroll: true,
33216 * Returns true if this node is expanded
33217 * @return {Boolean}
33219 isExpanded : function(){
33220 return this.expanded;
33224 * Returns the UI object for this node
33225 * @return {TreeNodeUI}
33227 getUI : function(){
33231 // private override
33232 setFirstChild : function(node){
33233 var of = this.firstChild;
33234 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33235 if(this.childrenRendered && of && node != of){
33236 of.renderIndent(true, true);
33239 this.renderIndent(true, true);
33243 // private override
33244 setLastChild : function(node){
33245 var ol = this.lastChild;
33246 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33247 if(this.childrenRendered && ol && node != ol){
33248 ol.renderIndent(true, true);
33251 this.renderIndent(true, true);
33255 // these methods are overridden to provide lazy rendering support
33256 // private override
33257 appendChild : function()
33259 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33260 if(node && this.childrenRendered){
33263 this.ui.updateExpandIcon();
33267 // private override
33268 removeChild : function(node){
33269 this.ownerTree.getSelectionModel().unselect(node);
33270 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33271 // if it's been rendered remove dom node
33272 if(this.childrenRendered){
33275 if(this.childNodes.length < 1){
33276 this.collapse(false, false);
33278 this.ui.updateExpandIcon();
33280 if(!this.firstChild) {
33281 this.childrenRendered = false;
33286 // private override
33287 insertBefore : function(node, refNode){
33288 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33289 if(newNode && refNode && this.childrenRendered){
33292 this.ui.updateExpandIcon();
33297 * Sets the text for this node
33298 * @param {String} text
33300 setText : function(text){
33301 var oldText = this.text;
33303 this.attributes.text = text;
33304 if(this.rendered){ // event without subscribing
33305 this.ui.onTextChange(this, text, oldText);
33307 this.fireEvent("textchange", this, text, oldText);
33311 * Triggers selection of this node
33313 select : function(){
33314 this.getOwnerTree().getSelectionModel().select(this);
33318 * Triggers deselection of this node
33320 unselect : function(){
33321 this.getOwnerTree().getSelectionModel().unselect(this);
33325 * Returns true if this node is selected
33326 * @return {Boolean}
33328 isSelected : function(){
33329 return this.getOwnerTree().getSelectionModel().isSelected(this);
33333 * Expand this node.
33334 * @param {Boolean} deep (optional) True to expand all children as well
33335 * @param {Boolean} anim (optional) false to cancel the default animation
33336 * @param {Function} callback (optional) A callback to be called when
33337 * expanding this node completes (does not wait for deep expand to complete).
33338 * Called with 1 parameter, this node.
33340 expand : function(deep, anim, callback){
33341 if(!this.expanded){
33342 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33345 if(!this.childrenRendered){
33346 this.renderChildren();
33348 this.expanded = true;
33349 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33350 this.ui.animExpand(function(){
33351 this.fireEvent("expand", this);
33352 if(typeof callback == "function"){
33356 this.expandChildNodes(true);
33358 }.createDelegate(this));
33362 this.fireEvent("expand", this);
33363 if(typeof callback == "function"){
33368 if(typeof callback == "function"){
33373 this.expandChildNodes(true);
33377 isHiddenRoot : function(){
33378 return this.isRoot && !this.getOwnerTree().rootVisible;
33382 * Collapse this node.
33383 * @param {Boolean} deep (optional) True to collapse all children as well
33384 * @param {Boolean} anim (optional) false to cancel the default animation
33386 collapse : function(deep, anim){
33387 if(this.expanded && !this.isHiddenRoot()){
33388 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33391 this.expanded = false;
33392 if((this.getOwnerTree().animate && anim !== false) || anim){
33393 this.ui.animCollapse(function(){
33394 this.fireEvent("collapse", this);
33396 this.collapseChildNodes(true);
33398 }.createDelegate(this));
33401 this.ui.collapse();
33402 this.fireEvent("collapse", this);
33406 var cs = this.childNodes;
33407 for(var i = 0, len = cs.length; i < len; i++) {
33408 cs[i].collapse(true, false);
33414 delayedExpand : function(delay){
33415 if(!this.expandProcId){
33416 this.expandProcId = this.expand.defer(delay, this);
33421 cancelExpand : function(){
33422 if(this.expandProcId){
33423 clearTimeout(this.expandProcId);
33425 this.expandProcId = false;
33429 * Toggles expanded/collapsed state of the node
33431 toggle : function(){
33440 * Ensures all parent nodes are expanded
33442 ensureVisible : function(callback){
33443 var tree = this.getOwnerTree();
33444 tree.expandPath(this.parentNode.getPath(), false, function(){
33445 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33446 Roo.callback(callback);
33447 }.createDelegate(this));
33451 * Expand all child nodes
33452 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33454 expandChildNodes : function(deep){
33455 var cs = this.childNodes;
33456 for(var i = 0, len = cs.length; i < len; i++) {
33457 cs[i].expand(deep);
33462 * Collapse all child nodes
33463 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33465 collapseChildNodes : function(deep){
33466 var cs = this.childNodes;
33467 for(var i = 0, len = cs.length; i < len; i++) {
33468 cs[i].collapse(deep);
33473 * Disables this node
33475 disable : function(){
33476 this.disabled = true;
33478 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33479 this.ui.onDisableChange(this, true);
33481 this.fireEvent("disabledchange", this, true);
33485 * Enables this node
33487 enable : function(){
33488 this.disabled = false;
33489 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33490 this.ui.onDisableChange(this, false);
33492 this.fireEvent("disabledchange", this, false);
33496 renderChildren : function(suppressEvent){
33497 if(suppressEvent !== false){
33498 this.fireEvent("beforechildrenrendered", this);
33500 var cs = this.childNodes;
33501 for(var i = 0, len = cs.length; i < len; i++){
33502 cs[i].render(true);
33504 this.childrenRendered = true;
33508 sort : function(fn, scope){
33509 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33510 if(this.childrenRendered){
33511 var cs = this.childNodes;
33512 for(var i = 0, len = cs.length; i < len; i++){
33513 cs[i].render(true);
33519 render : function(bulkRender){
33520 this.ui.render(bulkRender);
33521 if(!this.rendered){
33522 this.rendered = true;
33524 this.expanded = false;
33525 this.expand(false, false);
33531 renderIndent : function(deep, refresh){
33533 this.ui.childIndent = null;
33535 this.ui.renderIndent();
33536 if(deep === true && this.childrenRendered){
33537 var cs = this.childNodes;
33538 for(var i = 0, len = cs.length; i < len; i++){
33539 cs[i].renderIndent(true, refresh);
33545 * Ext JS Library 1.1.1
33546 * Copyright(c) 2006-2007, Ext JS, LLC.
33548 * Originally Released Under LGPL - original licence link has changed is not relivant.
33551 * <script type="text/javascript">
33555 * @class Roo.tree.AsyncTreeNode
33556 * @extends Roo.tree.TreeNode
33557 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33559 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33561 Roo.tree.AsyncTreeNode = function(config){
33562 this.loaded = false;
33563 this.loading = false;
33564 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33566 * @event beforeload
33567 * Fires before this node is loaded, return false to cancel
33568 * @param {Node} this This node
33570 this.addEvents({'beforeload':true, 'load': true});
33573 * Fires when this node is loaded
33574 * @param {Node} this This node
33577 * The loader used by this node (defaults to using the tree's defined loader)
33582 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33583 expand : function(deep, anim, callback){
33584 if(this.loading){ // if an async load is already running, waiting til it's done
33586 var f = function(){
33587 if(!this.loading){ // done loading
33588 clearInterval(timer);
33589 this.expand(deep, anim, callback);
33591 }.createDelegate(this);
33592 timer = setInterval(f, 200);
33596 if(this.fireEvent("beforeload", this) === false){
33599 this.loading = true;
33600 this.ui.beforeLoad(this);
33601 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33603 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33607 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33611 * Returns true if this node is currently loading
33612 * @return {Boolean}
33614 isLoading : function(){
33615 return this.loading;
33618 loadComplete : function(deep, anim, callback){
33619 this.loading = false;
33620 this.loaded = true;
33621 this.ui.afterLoad(this);
33622 this.fireEvent("load", this);
33623 this.expand(deep, anim, callback);
33627 * Returns true if this node has been loaded
33628 * @return {Boolean}
33630 isLoaded : function(){
33631 return this.loaded;
33634 hasChildNodes : function(){
33635 if(!this.isLeaf() && !this.loaded){
33638 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33643 * Trigger a reload for this node
33644 * @param {Function} callback
33646 reload : function(callback){
33647 this.collapse(false, false);
33648 while(this.firstChild){
33649 this.removeChild(this.firstChild);
33651 this.childrenRendered = false;
33652 this.loaded = false;
33653 if(this.isHiddenRoot()){
33654 this.expanded = false;
33656 this.expand(false, false, callback);
33660 * Ext JS Library 1.1.1
33661 * Copyright(c) 2006-2007, Ext JS, LLC.
33663 * Originally Released Under LGPL - original licence link has changed is not relivant.
33666 * <script type="text/javascript">
33670 * @class Roo.tree.TreeNodeUI
33672 * @param {Object} node The node to render
33673 * The TreeNode UI implementation is separate from the
33674 * tree implementation. Unless you are customizing the tree UI,
33675 * you should never have to use this directly.
33677 Roo.tree.TreeNodeUI = function(node){
33679 this.rendered = false;
33680 this.animating = false;
33681 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33684 Roo.tree.TreeNodeUI.prototype = {
33685 removeChild : function(node){
33687 this.ctNode.removeChild(node.ui.getEl());
33691 beforeLoad : function(){
33692 this.addClass("x-tree-node-loading");
33695 afterLoad : function(){
33696 this.removeClass("x-tree-node-loading");
33699 onTextChange : function(node, text, oldText){
33701 this.textNode.innerHTML = text;
33705 onDisableChange : function(node, state){
33706 this.disabled = state;
33708 this.addClass("x-tree-node-disabled");
33710 this.removeClass("x-tree-node-disabled");
33714 onSelectedChange : function(state){
33717 this.addClass("x-tree-selected");
33720 this.removeClass("x-tree-selected");
33724 onMove : function(tree, node, oldParent, newParent, index, refNode){
33725 this.childIndent = null;
33727 var targetNode = newParent.ui.getContainer();
33728 if(!targetNode){//target not rendered
33729 this.holder = document.createElement("div");
33730 this.holder.appendChild(this.wrap);
33733 var insertBefore = refNode ? refNode.ui.getEl() : null;
33735 targetNode.insertBefore(this.wrap, insertBefore);
33737 targetNode.appendChild(this.wrap);
33739 this.node.renderIndent(true);
33743 addClass : function(cls){
33745 Roo.fly(this.elNode).addClass(cls);
33749 removeClass : function(cls){
33751 Roo.fly(this.elNode).removeClass(cls);
33755 remove : function(){
33757 this.holder = document.createElement("div");
33758 this.holder.appendChild(this.wrap);
33762 fireEvent : function(){
33763 return this.node.fireEvent.apply(this.node, arguments);
33766 initEvents : function(){
33767 this.node.on("move", this.onMove, this);
33768 var E = Roo.EventManager;
33769 var a = this.anchor;
33771 var el = Roo.fly(a, '_treeui');
33773 if(Roo.isOpera){ // opera render bug ignores the CSS
33774 el.setStyle("text-decoration", "none");
33777 el.on("click", this.onClick, this);
33778 el.on("dblclick", this.onDblClick, this);
33781 Roo.EventManager.on(this.checkbox,
33782 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33785 el.on("contextmenu", this.onContextMenu, this);
33787 var icon = Roo.fly(this.iconNode);
33788 icon.on("click", this.onClick, this);
33789 icon.on("dblclick", this.onDblClick, this);
33790 icon.on("contextmenu", this.onContextMenu, this);
33791 E.on(this.ecNode, "click", this.ecClick, this, true);
33793 if(this.node.disabled){
33794 this.addClass("x-tree-node-disabled");
33796 if(this.node.hidden){
33797 this.addClass("x-tree-node-disabled");
33799 var ot = this.node.getOwnerTree();
33800 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33801 if(dd && (!this.node.isRoot || ot.rootVisible)){
33802 Roo.dd.Registry.register(this.elNode, {
33804 handles: this.getDDHandles(),
33810 getDDHandles : function(){
33811 return [this.iconNode, this.textNode];
33816 this.wrap.style.display = "none";
33822 this.wrap.style.display = "";
33826 onContextMenu : function(e){
33827 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33828 e.preventDefault();
33830 this.fireEvent("contextmenu", this.node, e);
33834 onClick : function(e){
33839 if(this.fireEvent("beforeclick", this.node, e) !== false){
33840 if(!this.disabled && this.node.attributes.href){
33841 this.fireEvent("click", this.node, e);
33844 e.preventDefault();
33849 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33850 this.node.toggle();
33853 this.fireEvent("click", this.node, e);
33859 onDblClick : function(e){
33860 e.preventDefault();
33865 this.toggleCheck();
33867 if(!this.animating && this.node.hasChildNodes()){
33868 this.node.toggle();
33870 this.fireEvent("dblclick", this.node, e);
33873 onCheckChange : function(){
33874 var checked = this.checkbox.checked;
33875 this.node.attributes.checked = checked;
33876 this.fireEvent('checkchange', this.node, checked);
33879 ecClick : function(e){
33880 if(!this.animating && this.node.hasChildNodes()){
33881 this.node.toggle();
33885 startDrop : function(){
33886 this.dropping = true;
33889 // delayed drop so the click event doesn't get fired on a drop
33890 endDrop : function(){
33891 setTimeout(function(){
33892 this.dropping = false;
33893 }.createDelegate(this), 50);
33896 expand : function(){
33897 this.updateExpandIcon();
33898 this.ctNode.style.display = "";
33901 focus : function(){
33902 if(!this.node.preventHScroll){
33903 try{this.anchor.focus();
33905 }else if(!Roo.isIE){
33907 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33908 var l = noscroll.scrollLeft;
33909 this.anchor.focus();
33910 noscroll.scrollLeft = l;
33915 toggleCheck : function(value){
33916 var cb = this.checkbox;
33918 cb.checked = (value === undefined ? !cb.checked : value);
33924 this.anchor.blur();
33928 animExpand : function(callback){
33929 var ct = Roo.get(this.ctNode);
33931 if(!this.node.hasChildNodes()){
33932 this.updateExpandIcon();
33933 this.ctNode.style.display = "";
33934 Roo.callback(callback);
33937 this.animating = true;
33938 this.updateExpandIcon();
33941 callback : function(){
33942 this.animating = false;
33943 Roo.callback(callback);
33946 duration: this.node.ownerTree.duration || .25
33950 highlight : function(){
33951 var tree = this.node.getOwnerTree();
33952 Roo.fly(this.wrap).highlight(
33953 tree.hlColor || "C3DAF9",
33954 {endColor: tree.hlBaseColor}
33958 collapse : function(){
33959 this.updateExpandIcon();
33960 this.ctNode.style.display = "none";
33963 animCollapse : function(callback){
33964 var ct = Roo.get(this.ctNode);
33965 ct.enableDisplayMode('block');
33968 this.animating = true;
33969 this.updateExpandIcon();
33972 callback : function(){
33973 this.animating = false;
33974 Roo.callback(callback);
33977 duration: this.node.ownerTree.duration || .25
33981 getContainer : function(){
33982 return this.ctNode;
33985 getEl : function(){
33989 appendDDGhost : function(ghostNode){
33990 ghostNode.appendChild(this.elNode.cloneNode(true));
33993 getDDRepairXY : function(){
33994 return Roo.lib.Dom.getXY(this.iconNode);
33997 onRender : function(){
34001 render : function(bulkRender){
34002 var n = this.node, a = n.attributes;
34003 var targetNode = n.parentNode ?
34004 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34006 if(!this.rendered){
34007 this.rendered = true;
34009 this.renderElements(n, a, targetNode, bulkRender);
34012 if(this.textNode.setAttributeNS){
34013 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34015 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34018 this.textNode.setAttribute("ext:qtip", a.qtip);
34020 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34023 }else if(a.qtipCfg){
34024 a.qtipCfg.target = Roo.id(this.textNode);
34025 Roo.QuickTips.register(a.qtipCfg);
34028 if(!this.node.expanded){
34029 this.updateExpandIcon();
34032 if(bulkRender === true) {
34033 targetNode.appendChild(this.wrap);
34038 renderElements : function(n, a, targetNode, bulkRender)
34040 // add some indent caching, this helps performance when rendering a large tree
34041 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34042 var t = n.getOwnerTree();
34043 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34044 if (typeof(n.attributes.html) != 'undefined') {
34045 txt = n.attributes.html;
34047 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34048 var cb = typeof a.checked == 'boolean';
34049 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34050 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34051 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34052 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34053 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34054 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34055 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34056 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34057 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34058 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34061 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34062 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34063 n.nextSibling.ui.getEl(), buf.join(""));
34065 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34068 this.elNode = this.wrap.childNodes[0];
34069 this.ctNode = this.wrap.childNodes[1];
34070 var cs = this.elNode.childNodes;
34071 this.indentNode = cs[0];
34072 this.ecNode = cs[1];
34073 this.iconNode = cs[2];
34076 this.checkbox = cs[3];
34079 this.anchor = cs[index];
34080 this.textNode = cs[index].firstChild;
34083 getAnchor : function(){
34084 return this.anchor;
34087 getTextEl : function(){
34088 return this.textNode;
34091 getIconEl : function(){
34092 return this.iconNode;
34095 isChecked : function(){
34096 return this.checkbox ? this.checkbox.checked : false;
34099 updateExpandIcon : function(){
34101 var n = this.node, c1, c2;
34102 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34103 var hasChild = n.hasChildNodes();
34107 c1 = "x-tree-node-collapsed";
34108 c2 = "x-tree-node-expanded";
34111 c1 = "x-tree-node-expanded";
34112 c2 = "x-tree-node-collapsed";
34115 this.removeClass("x-tree-node-leaf");
34116 this.wasLeaf = false;
34118 if(this.c1 != c1 || this.c2 != c2){
34119 Roo.fly(this.elNode).replaceClass(c1, c2);
34120 this.c1 = c1; this.c2 = c2;
34123 // this changes non-leafs into leafs if they have no children.
34124 // it's not very rational behaviour..
34126 if(!this.wasLeaf && this.node.leaf){
34127 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34130 this.wasLeaf = true;
34133 var ecc = "x-tree-ec-icon "+cls;
34134 if(this.ecc != ecc){
34135 this.ecNode.className = ecc;
34141 getChildIndent : function(){
34142 if(!this.childIndent){
34146 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34148 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34150 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34155 this.childIndent = buf.join("");
34157 return this.childIndent;
34160 renderIndent : function(){
34163 var p = this.node.parentNode;
34165 indent = p.ui.getChildIndent();
34167 if(this.indentMarkup != indent){ // don't rerender if not required
34168 this.indentNode.innerHTML = indent;
34169 this.indentMarkup = indent;
34171 this.updateExpandIcon();
34176 Roo.tree.RootTreeNodeUI = function(){
34177 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34179 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34180 render : function(){
34181 if(!this.rendered){
34182 var targetNode = this.node.ownerTree.innerCt.dom;
34183 this.node.expanded = true;
34184 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34185 this.wrap = this.ctNode = targetNode.firstChild;
34188 collapse : function(){
34190 expand : function(){
34194 * Ext JS Library 1.1.1
34195 * Copyright(c) 2006-2007, Ext JS, LLC.
34197 * Originally Released Under LGPL - original licence link has changed is not relivant.
34200 * <script type="text/javascript">
34203 * @class Roo.tree.TreeLoader
34204 * @extends Roo.util.Observable
34205 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34206 * nodes from a specified URL. The response must be a javascript Array definition
34207 * who's elements are node definition objects. eg:
34212 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34213 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34220 * The old style respose with just an array is still supported, but not recommended.
34223 * A server request is sent, and child nodes are loaded only when a node is expanded.
34224 * The loading node's id is passed to the server under the parameter name "node" to
34225 * enable the server to produce the correct child nodes.
34227 * To pass extra parameters, an event handler may be attached to the "beforeload"
34228 * event, and the parameters specified in the TreeLoader's baseParams property:
34230 myTreeLoader.on("beforeload", function(treeLoader, node) {
34231 this.baseParams.category = node.attributes.category;
34234 * This would pass an HTTP parameter called "category" to the server containing
34235 * the value of the Node's "category" attribute.
34237 * Creates a new Treeloader.
34238 * @param {Object} config A config object containing config properties.
34240 Roo.tree.TreeLoader = function(config){
34241 this.baseParams = {};
34242 this.requestMethod = "POST";
34243 Roo.apply(this, config);
34248 * @event beforeload
34249 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34250 * @param {Object} This TreeLoader object.
34251 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34252 * @param {Object} callback The callback function specified in the {@link #load} call.
34257 * Fires when the node has been successfuly loaded.
34258 * @param {Object} This TreeLoader object.
34259 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34260 * @param {Object} response The response object containing the data from the server.
34264 * @event loadexception
34265 * Fires if the network request failed.
34266 * @param {Object} This TreeLoader object.
34267 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34268 * @param {Object} response The response object containing the data from the server.
34270 loadexception : true,
34273 * Fires before a node is created, enabling you to return custom Node types
34274 * @param {Object} This TreeLoader object.
34275 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34280 Roo.tree.TreeLoader.superclass.constructor.call(this);
34283 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34285 * @cfg {String} dataUrl The URL from which to request a Json string which
34286 * specifies an array of node definition object representing the child nodes
34290 * @cfg {String} requestMethod either GET or POST
34291 * defaults to POST (due to BC)
34295 * @cfg {Object} baseParams (optional) An object containing properties which
34296 * specify HTTP parameters to be passed to each request for child nodes.
34299 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34300 * created by this loader. If the attributes sent by the server have an attribute in this object,
34301 * they take priority.
34304 * @cfg {Object} uiProviders (optional) An object containing properties which
34306 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34307 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34308 * <i>uiProvider</i> attribute of a returned child node is a string rather
34309 * than a reference to a TreeNodeUI implementation, this that string value
34310 * is used as a property name in the uiProviders object. You can define the provider named
34311 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34316 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34317 * child nodes before loading.
34319 clearOnLoad : true,
34322 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34323 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34324 * Grid query { data : [ .....] }
34329 * @cfg {String} queryParam (optional)
34330 * Name of the query as it will be passed on the querystring (defaults to 'node')
34331 * eg. the request will be ?node=[id]
34338 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34339 * This is called automatically when a node is expanded, but may be used to reload
34340 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34341 * @param {Roo.tree.TreeNode} node
34342 * @param {Function} callback
34344 load : function(node, callback){
34345 if(this.clearOnLoad){
34346 while(node.firstChild){
34347 node.removeChild(node.firstChild);
34350 if(node.attributes.children){ // preloaded json children
34351 var cs = node.attributes.children;
34352 for(var i = 0, len = cs.length; i < len; i++){
34353 node.appendChild(this.createNode(cs[i]));
34355 if(typeof callback == "function"){
34358 }else if(this.dataUrl){
34359 this.requestData(node, callback);
34363 getParams: function(node){
34364 var buf = [], bp = this.baseParams;
34365 for(var key in bp){
34366 if(typeof bp[key] != "function"){
34367 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34370 var n = this.queryParam === false ? 'node' : this.queryParam;
34371 buf.push(n + "=", encodeURIComponent(node.id));
34372 return buf.join("");
34375 requestData : function(node, callback){
34376 if(this.fireEvent("beforeload", this, node, callback) !== false){
34377 this.transId = Roo.Ajax.request({
34378 method:this.requestMethod,
34379 url: this.dataUrl||this.url,
34380 success: this.handleResponse,
34381 failure: this.handleFailure,
34383 argument: {callback: callback, node: node},
34384 params: this.getParams(node)
34387 // if the load is cancelled, make sure we notify
34388 // the node that we are done
34389 if(typeof callback == "function"){
34395 isLoading : function(){
34396 return this.transId ? true : false;
34399 abort : function(){
34400 if(this.isLoading()){
34401 Roo.Ajax.abort(this.transId);
34406 createNode : function(attr)
34408 // apply baseAttrs, nice idea Corey!
34409 if(this.baseAttrs){
34410 Roo.applyIf(attr, this.baseAttrs);
34412 if(this.applyLoader !== false){
34413 attr.loader = this;
34415 // uiProvider = depreciated..
34417 if(typeof(attr.uiProvider) == 'string'){
34418 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34419 /** eval:var:attr */ eval(attr.uiProvider);
34421 if(typeof(this.uiProviders['default']) != 'undefined') {
34422 attr.uiProvider = this.uiProviders['default'];
34425 this.fireEvent('create', this, attr);
34427 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34429 new Roo.tree.TreeNode(attr) :
34430 new Roo.tree.AsyncTreeNode(attr));
34433 processResponse : function(response, node, callback)
34435 var json = response.responseText;
34438 var o = Roo.decode(json);
34440 if (this.root === false && typeof(o.success) != undefined) {
34441 this.root = 'data'; // the default behaviour for list like data..
34444 if (this.root !== false && !o.success) {
34445 // it's a failure condition.
34446 var a = response.argument;
34447 this.fireEvent("loadexception", this, a.node, response);
34448 Roo.log("Load failed - should have a handler really");
34454 if (this.root !== false) {
34458 for(var i = 0, len = o.length; i < len; i++){
34459 var n = this.createNode(o[i]);
34461 node.appendChild(n);
34464 if(typeof callback == "function"){
34465 callback(this, node);
34468 this.handleFailure(response);
34472 handleResponse : function(response){
34473 this.transId = false;
34474 var a = response.argument;
34475 this.processResponse(response, a.node, a.callback);
34476 this.fireEvent("load", this, a.node, response);
34479 handleFailure : function(response)
34481 // should handle failure better..
34482 this.transId = false;
34483 var a = response.argument;
34484 this.fireEvent("loadexception", this, a.node, response);
34485 if(typeof a.callback == "function"){
34486 a.callback(this, a.node);
34491 * Ext JS Library 1.1.1
34492 * Copyright(c) 2006-2007, Ext JS, LLC.
34494 * Originally Released Under LGPL - original licence link has changed is not relivant.
34497 * <script type="text/javascript">
34501 * @class Roo.tree.TreeFilter
34502 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34503 * @param {TreePanel} tree
34504 * @param {Object} config (optional)
34506 Roo.tree.TreeFilter = function(tree, config){
34508 this.filtered = {};
34509 Roo.apply(this, config);
34512 Roo.tree.TreeFilter.prototype = {
34519 * Filter the data by a specific attribute.
34520 * @param {String/RegExp} value Either string that the attribute value
34521 * should start with or a RegExp to test against the attribute
34522 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34523 * @param {TreeNode} startNode (optional) The node to start the filter at.
34525 filter : function(value, attr, startNode){
34526 attr = attr || "text";
34528 if(typeof value == "string"){
34529 var vlen = value.length;
34530 // auto clear empty filter
34531 if(vlen == 0 && this.clearBlank){
34535 value = value.toLowerCase();
34537 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34539 }else if(value.exec){ // regex?
34541 return value.test(n.attributes[attr]);
34544 throw 'Illegal filter type, must be string or regex';
34546 this.filterBy(f, null, startNode);
34550 * Filter by a function. The passed function will be called with each
34551 * node in the tree (or from the startNode). If the function returns true, the node is kept
34552 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34553 * @param {Function} fn The filter function
34554 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34556 filterBy : function(fn, scope, startNode){
34557 startNode = startNode || this.tree.root;
34558 if(this.autoClear){
34561 var af = this.filtered, rv = this.reverse;
34562 var f = function(n){
34563 if(n == startNode){
34569 var m = fn.call(scope || n, n);
34577 startNode.cascade(f);
34580 if(typeof id != "function"){
34582 if(n && n.parentNode){
34583 n.parentNode.removeChild(n);
34591 * Clears the current filter. Note: with the "remove" option
34592 * set a filter cannot be cleared.
34594 clear : function(){
34596 var af = this.filtered;
34598 if(typeof id != "function"){
34605 this.filtered = {};
34610 * Ext JS Library 1.1.1
34611 * Copyright(c) 2006-2007, Ext JS, LLC.
34613 * Originally Released Under LGPL - original licence link has changed is not relivant.
34616 * <script type="text/javascript">
34621 * @class Roo.tree.TreeSorter
34622 * Provides sorting of nodes in a TreePanel
34624 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34625 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34626 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34627 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34628 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34629 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34631 * @param {TreePanel} tree
34632 * @param {Object} config
34634 Roo.tree.TreeSorter = function(tree, config){
34635 Roo.apply(this, config);
34636 tree.on("beforechildrenrendered", this.doSort, this);
34637 tree.on("append", this.updateSort, this);
34638 tree.on("insert", this.updateSort, this);
34640 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34641 var p = this.property || "text";
34642 var sortType = this.sortType;
34643 var fs = this.folderSort;
34644 var cs = this.caseSensitive === true;
34645 var leafAttr = this.leafAttr || 'leaf';
34647 this.sortFn = function(n1, n2){
34649 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34652 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34656 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34657 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34659 return dsc ? +1 : -1;
34661 return dsc ? -1 : +1;
34668 Roo.tree.TreeSorter.prototype = {
34669 doSort : function(node){
34670 node.sort(this.sortFn);
34673 compareNodes : function(n1, n2){
34674 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34677 updateSort : function(tree, node){
34678 if(node.childrenRendered){
34679 this.doSort.defer(1, this, [node]);
34684 * Ext JS Library 1.1.1
34685 * Copyright(c) 2006-2007, Ext JS, LLC.
34687 * Originally Released Under LGPL - original licence link has changed is not relivant.
34690 * <script type="text/javascript">
34693 if(Roo.dd.DropZone){
34695 Roo.tree.TreeDropZone = function(tree, config){
34696 this.allowParentInsert = false;
34697 this.allowContainerDrop = false;
34698 this.appendOnly = false;
34699 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34701 this.lastInsertClass = "x-tree-no-status";
34702 this.dragOverData = {};
34705 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34706 ddGroup : "TreeDD",
34709 expandDelay : 1000,
34711 expandNode : function(node){
34712 if(node.hasChildNodes() && !node.isExpanded()){
34713 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34717 queueExpand : function(node){
34718 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34721 cancelExpand : function(){
34722 if(this.expandProcId){
34723 clearTimeout(this.expandProcId);
34724 this.expandProcId = false;
34728 isValidDropPoint : function(n, pt, dd, e, data){
34729 if(!n || !data){ return false; }
34730 var targetNode = n.node;
34731 var dropNode = data.node;
34732 // default drop rules
34733 if(!(targetNode && targetNode.isTarget && pt)){
34736 if(pt == "append" && targetNode.allowChildren === false){
34739 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34742 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34745 // reuse the object
34746 var overEvent = this.dragOverData;
34747 overEvent.tree = this.tree;
34748 overEvent.target = targetNode;
34749 overEvent.data = data;
34750 overEvent.point = pt;
34751 overEvent.source = dd;
34752 overEvent.rawEvent = e;
34753 overEvent.dropNode = dropNode;
34754 overEvent.cancel = false;
34755 var result = this.tree.fireEvent("nodedragover", overEvent);
34756 return overEvent.cancel === false && result !== false;
34759 getDropPoint : function(e, n, dd)
34763 return tn.allowChildren !== false ? "append" : false; // always append for root
34765 var dragEl = n.ddel;
34766 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34767 var y = Roo.lib.Event.getPageY(e);
34768 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34770 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34771 var noAppend = tn.allowChildren === false;
34772 if(this.appendOnly || tn.parentNode.allowChildren === false){
34773 return noAppend ? false : "append";
34775 var noBelow = false;
34776 if(!this.allowParentInsert){
34777 noBelow = tn.hasChildNodes() && tn.isExpanded();
34779 var q = (b - t) / (noAppend ? 2 : 3);
34780 if(y >= t && y < (t + q)){
34782 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34789 onNodeEnter : function(n, dd, e, data)
34791 this.cancelExpand();
34794 onNodeOver : function(n, dd, e, data)
34797 var pt = this.getDropPoint(e, n, dd);
34800 // auto node expand check
34801 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34802 this.queueExpand(node);
34803 }else if(pt != "append"){
34804 this.cancelExpand();
34807 // set the insert point style on the target node
34808 var returnCls = this.dropNotAllowed;
34809 if(this.isValidDropPoint(n, pt, dd, e, data)){
34814 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34815 cls = "x-tree-drag-insert-above";
34816 }else if(pt == "below"){
34817 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34818 cls = "x-tree-drag-insert-below";
34820 returnCls = "x-tree-drop-ok-append";
34821 cls = "x-tree-drag-append";
34823 if(this.lastInsertClass != cls){
34824 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34825 this.lastInsertClass = cls;
34832 onNodeOut : function(n, dd, e, data){
34834 this.cancelExpand();
34835 this.removeDropIndicators(n);
34838 onNodeDrop : function(n, dd, e, data){
34839 var point = this.getDropPoint(e, n, dd);
34840 var targetNode = n.node;
34841 targetNode.ui.startDrop();
34842 if(!this.isValidDropPoint(n, point, dd, e, data)){
34843 targetNode.ui.endDrop();
34846 // first try to find the drop node
34847 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34850 target: targetNode,
34855 dropNode: dropNode,
34858 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34859 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34860 targetNode.ui.endDrop();
34863 // allow target changing
34864 targetNode = dropEvent.target;
34865 if(point == "append" && !targetNode.isExpanded()){
34866 targetNode.expand(false, null, function(){
34867 this.completeDrop(dropEvent);
34868 }.createDelegate(this));
34870 this.completeDrop(dropEvent);
34875 completeDrop : function(de){
34876 var ns = de.dropNode, p = de.point, t = de.target;
34877 if(!(ns instanceof Array)){
34881 for(var i = 0, len = ns.length; i < len; i++){
34884 t.parentNode.insertBefore(n, t);
34885 }else if(p == "below"){
34886 t.parentNode.insertBefore(n, t.nextSibling);
34892 if(this.tree.hlDrop){
34896 this.tree.fireEvent("nodedrop", de);
34899 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34900 if(this.tree.hlDrop){
34901 dropNode.ui.focus();
34902 dropNode.ui.highlight();
34904 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34907 getTree : function(){
34911 removeDropIndicators : function(n){
34914 Roo.fly(el).removeClass([
34915 "x-tree-drag-insert-above",
34916 "x-tree-drag-insert-below",
34917 "x-tree-drag-append"]);
34918 this.lastInsertClass = "_noclass";
34922 beforeDragDrop : function(target, e, id){
34923 this.cancelExpand();
34927 afterRepair : function(data){
34928 if(data && Roo.enableFx){
34929 data.node.ui.highlight();
34939 * Ext JS Library 1.1.1
34940 * Copyright(c) 2006-2007, Ext JS, LLC.
34942 * Originally Released Under LGPL - original licence link has changed is not relivant.
34945 * <script type="text/javascript">
34949 if(Roo.dd.DragZone){
34950 Roo.tree.TreeDragZone = function(tree, config){
34951 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34955 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34956 ddGroup : "TreeDD",
34958 onBeforeDrag : function(data, e){
34960 return n && n.draggable && !n.disabled;
34964 onInitDrag : function(e){
34965 var data = this.dragData;
34966 this.tree.getSelectionModel().select(data.node);
34967 this.proxy.update("");
34968 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34969 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34972 getRepairXY : function(e, data){
34973 return data.node.ui.getDDRepairXY();
34976 onEndDrag : function(data, e){
34977 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34982 onValidDrop : function(dd, e, id){
34983 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34987 beforeInvalidDrop : function(e, id){
34988 // this scrolls the original position back into view
34989 var sm = this.tree.getSelectionModel();
34990 sm.clearSelections();
34991 sm.select(this.dragData.node);
34996 * Ext JS Library 1.1.1
34997 * Copyright(c) 2006-2007, Ext JS, LLC.
34999 * Originally Released Under LGPL - original licence link has changed is not relivant.
35002 * <script type="text/javascript">
35005 * @class Roo.tree.TreeEditor
35006 * @extends Roo.Editor
35007 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35008 * as the editor field.
35010 * @param {Object} config (used to be the tree panel.)
35011 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35013 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35014 * @cfg {Roo.form.TextField|Object} field The field configuration
35018 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35021 if (oldconfig) { // old style..
35022 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35025 tree = config.tree;
35026 config.field = config.field || {};
35027 config.field.xtype = 'TextField';
35028 field = Roo.factory(config.field, Roo.form);
35030 config = config || {};
35035 * @event beforenodeedit
35036 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35037 * false from the handler of this event.
35038 * @param {Editor} this
35039 * @param {Roo.tree.Node} node
35041 "beforenodeedit" : true
35045 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35049 tree.on('beforeclick', this.beforeNodeClick, this);
35050 tree.getTreeEl().on('mousedown', this.hide, this);
35051 this.on('complete', this.updateNode, this);
35052 this.on('beforestartedit', this.fitToTree, this);
35053 this.on('startedit', this.bindScroll, this, {delay:10});
35054 this.on('specialkey', this.onSpecialKey, this);
35057 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35059 * @cfg {String} alignment
35060 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35066 * @cfg {Boolean} hideEl
35067 * True to hide the bound element while the editor is displayed (defaults to false)
35071 * @cfg {String} cls
35072 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35074 cls: "x-small-editor x-tree-editor",
35076 * @cfg {Boolean} shim
35077 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35083 * @cfg {Number} maxWidth
35084 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35085 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35086 * scroll and client offsets into account prior to each edit.
35093 fitToTree : function(ed, el){
35094 var td = this.tree.getTreeEl().dom, nd = el.dom;
35095 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35096 td.scrollLeft = nd.offsetLeft;
35100 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35101 this.setSize(w, '');
35103 return this.fireEvent('beforenodeedit', this, this.editNode);
35108 triggerEdit : function(node){
35109 this.completeEdit();
35110 this.editNode = node;
35111 this.startEdit(node.ui.textNode, node.text);
35115 bindScroll : function(){
35116 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35120 beforeNodeClick : function(node, e){
35121 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35122 this.lastClick = new Date();
35123 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35125 this.triggerEdit(node);
35132 updateNode : function(ed, value){
35133 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35134 this.editNode.setText(value);
35138 onHide : function(){
35139 Roo.tree.TreeEditor.superclass.onHide.call(this);
35141 this.editNode.ui.focus();
35146 onSpecialKey : function(field, e){
35147 var k = e.getKey();
35151 }else if(k == e.ENTER && !e.hasModifier()){
35153 this.completeEdit();
35156 });//<Script type="text/javascript">
35159 * Ext JS Library 1.1.1
35160 * Copyright(c) 2006-2007, Ext JS, LLC.
35162 * Originally Released Under LGPL - original licence link has changed is not relivant.
35165 * <script type="text/javascript">
35169 * Not documented??? - probably should be...
35172 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35173 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35175 renderElements : function(n, a, targetNode, bulkRender){
35176 //consel.log("renderElements?");
35177 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35179 var t = n.getOwnerTree();
35180 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35182 var cols = t.columns;
35183 var bw = t.borderWidth;
35185 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35186 var cb = typeof a.checked == "boolean";
35187 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35188 var colcls = 'x-t-' + tid + '-c0';
35190 '<li class="x-tree-node">',
35193 '<div class="x-tree-node-el ', a.cls,'">',
35195 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35198 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35199 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35200 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35201 (a.icon ? ' x-tree-node-inline-icon' : ''),
35202 (a.iconCls ? ' '+a.iconCls : ''),
35203 '" unselectable="on" />',
35204 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35205 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35207 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35208 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35209 '<span unselectable="on" qtip="' + tx + '">',
35213 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35214 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35216 for(var i = 1, len = cols.length; i < len; i++){
35218 colcls = 'x-t-' + tid + '-c' +i;
35219 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35220 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35221 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35227 '<div class="x-clear"></div></div>',
35228 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35231 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35232 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35233 n.nextSibling.ui.getEl(), buf.join(""));
35235 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35237 var el = this.wrap.firstChild;
35239 this.elNode = el.firstChild;
35240 this.ranchor = el.childNodes[1];
35241 this.ctNode = this.wrap.childNodes[1];
35242 var cs = el.firstChild.childNodes;
35243 this.indentNode = cs[0];
35244 this.ecNode = cs[1];
35245 this.iconNode = cs[2];
35248 this.checkbox = cs[3];
35251 this.anchor = cs[index];
35253 this.textNode = cs[index].firstChild;
35255 //el.on("click", this.onClick, this);
35256 //el.on("dblclick", this.onDblClick, this);
35259 // console.log(this);
35261 initEvents : function(){
35262 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35265 var a = this.ranchor;
35267 var el = Roo.get(a);
35269 if(Roo.isOpera){ // opera render bug ignores the CSS
35270 el.setStyle("text-decoration", "none");
35273 el.on("click", this.onClick, this);
35274 el.on("dblclick", this.onDblClick, this);
35275 el.on("contextmenu", this.onContextMenu, this);
35279 /*onSelectedChange : function(state){
35282 this.addClass("x-tree-selected");
35285 this.removeClass("x-tree-selected");
35288 addClass : function(cls){
35290 Roo.fly(this.elRow).addClass(cls);
35296 removeClass : function(cls){
35298 Roo.fly(this.elRow).removeClass(cls);
35304 });//<Script type="text/javascript">
35308 * Ext JS Library 1.1.1
35309 * Copyright(c) 2006-2007, Ext JS, LLC.
35311 * Originally Released Under LGPL - original licence link has changed is not relivant.
35314 * <script type="text/javascript">
35319 * @class Roo.tree.ColumnTree
35320 * @extends Roo.data.TreePanel
35321 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35322 * @cfg {int} borderWidth compined right/left border allowance
35324 * @param {String/HTMLElement/Element} el The container element
35325 * @param {Object} config
35327 Roo.tree.ColumnTree = function(el, config)
35329 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35333 * Fire this event on a container when it resizes
35334 * @param {int} w Width
35335 * @param {int} h Height
35339 this.on('resize', this.onResize, this);
35342 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35346 borderWidth: Roo.isBorderBox ? 0 : 2,
35349 render : function(){
35350 // add the header.....
35352 Roo.tree.ColumnTree.superclass.render.apply(this);
35354 this.el.addClass('x-column-tree');
35356 this.headers = this.el.createChild(
35357 {cls:'x-tree-headers'},this.innerCt.dom);
35359 var cols = this.columns, c;
35360 var totalWidth = 0;
35362 var len = cols.length;
35363 for(var i = 0; i < len; i++){
35365 totalWidth += c.width;
35366 this.headEls.push(this.headers.createChild({
35367 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35369 cls:'x-tree-hd-text',
35372 style:'width:'+(c.width-this.borderWidth)+'px;'
35375 this.headers.createChild({cls:'x-clear'});
35376 // prevent floats from wrapping when clipped
35377 this.headers.setWidth(totalWidth);
35378 //this.innerCt.setWidth(totalWidth);
35379 this.innerCt.setStyle({ overflow: 'auto' });
35380 this.onResize(this.width, this.height);
35384 onResize : function(w,h)
35389 this.innerCt.setWidth(this.width);
35390 this.innerCt.setHeight(this.height-20);
35393 var cols = this.columns, c;
35394 var totalWidth = 0;
35396 var len = cols.length;
35397 for(var i = 0; i < len; i++){
35399 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35400 // it's the expander..
35401 expEl = this.headEls[i];
35404 totalWidth += c.width;
35408 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35410 this.headers.setWidth(w-20);
35419 * Ext JS Library 1.1.1
35420 * Copyright(c) 2006-2007, Ext JS, LLC.
35422 * Originally Released Under LGPL - original licence link has changed is not relivant.
35425 * <script type="text/javascript">
35429 * @class Roo.menu.Menu
35430 * @extends Roo.util.Observable
35431 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35432 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35434 * Creates a new Menu
35435 * @param {Object} config Configuration options
35437 Roo.menu.Menu = function(config){
35438 Roo.apply(this, config);
35439 this.id = this.id || Roo.id();
35442 * @event beforeshow
35443 * Fires before this menu is displayed
35444 * @param {Roo.menu.Menu} this
35448 * @event beforehide
35449 * Fires before this menu is hidden
35450 * @param {Roo.menu.Menu} this
35455 * Fires after this menu is displayed
35456 * @param {Roo.menu.Menu} this
35461 * Fires after this menu is hidden
35462 * @param {Roo.menu.Menu} this
35467 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35468 * @param {Roo.menu.Menu} this
35469 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35470 * @param {Roo.EventObject} e
35475 * Fires when the mouse is hovering over this menu
35476 * @param {Roo.menu.Menu} this
35477 * @param {Roo.EventObject} e
35478 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35483 * Fires when the mouse exits this menu
35484 * @param {Roo.menu.Menu} this
35485 * @param {Roo.EventObject} e
35486 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35491 * Fires when a menu item contained in this menu is clicked
35492 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35493 * @param {Roo.EventObject} e
35497 if (this.registerMenu) {
35498 Roo.menu.MenuMgr.register(this);
35501 var mis = this.items;
35502 this.items = new Roo.util.MixedCollection();
35504 this.add.apply(this, mis);
35508 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35510 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35514 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35515 * for bottom-right shadow (defaults to "sides")
35519 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35520 * this menu (defaults to "tl-tr?")
35522 subMenuAlign : "tl-tr?",
35524 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35525 * relative to its element of origin (defaults to "tl-bl?")
35527 defaultAlign : "tl-bl?",
35529 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35531 allowOtherMenus : false,
35533 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35535 registerMenu : true,
35540 render : function(){
35544 var el = this.el = new Roo.Layer({
35546 shadow:this.shadow,
35548 parentEl: this.parentEl || document.body,
35552 this.keyNav = new Roo.menu.MenuNav(this);
35555 el.addClass("x-menu-plain");
35558 el.addClass(this.cls);
35560 // generic focus element
35561 this.focusEl = el.createChild({
35562 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35564 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35565 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35567 ul.on("mouseover", this.onMouseOver, this);
35568 ul.on("mouseout", this.onMouseOut, this);
35569 this.items.each(function(item){
35574 var li = document.createElement("li");
35575 li.className = "x-menu-list-item";
35576 ul.dom.appendChild(li);
35577 item.render(li, this);
35584 autoWidth : function(){
35585 var el = this.el, ul = this.ul;
35589 var w = this.width;
35592 }else if(Roo.isIE){
35593 el.setWidth(this.minWidth);
35594 var t = el.dom.offsetWidth; // force recalc
35595 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35600 delayAutoWidth : function(){
35603 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35605 this.awTask.delay(20);
35610 findTargetItem : function(e){
35611 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35612 if(t && t.menuItemId){
35613 return this.items.get(t.menuItemId);
35618 onClick : function(e){
35619 Roo.log("menu.onClick");
35620 var t = this.findTargetItem(e);
35625 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35626 if(t == this.activeItem && t.shouldDeactivate(e)){
35627 this.activeItem.deactivate();
35628 delete this.activeItem;
35632 this.setActiveItem(t, true);
35640 this.fireEvent("click", this, t, e);
35644 setActiveItem : function(item, autoExpand){
35645 if(item != this.activeItem){
35646 if(this.activeItem){
35647 this.activeItem.deactivate();
35649 this.activeItem = item;
35650 item.activate(autoExpand);
35651 }else if(autoExpand){
35657 tryActivate : function(start, step){
35658 var items = this.items;
35659 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35660 var item = items.get(i);
35661 if(!item.disabled && item.canActivate){
35662 this.setActiveItem(item, false);
35670 onMouseOver : function(e){
35672 if(t = this.findTargetItem(e)){
35673 if(t.canActivate && !t.disabled){
35674 this.setActiveItem(t, true);
35677 this.fireEvent("mouseover", this, e, t);
35681 onMouseOut : function(e){
35683 if(t = this.findTargetItem(e)){
35684 if(t == this.activeItem && t.shouldDeactivate(e)){
35685 this.activeItem.deactivate();
35686 delete this.activeItem;
35689 this.fireEvent("mouseout", this, e, t);
35693 * Read-only. Returns true if the menu is currently displayed, else false.
35696 isVisible : function(){
35697 return this.el && !this.hidden;
35701 * Displays this menu relative to another element
35702 * @param {String/HTMLElement/Roo.Element} element The element to align to
35703 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35704 * the element (defaults to this.defaultAlign)
35705 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35707 show : function(el, pos, parentMenu){
35708 this.parentMenu = parentMenu;
35712 this.fireEvent("beforeshow", this);
35713 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35717 * Displays this menu at a specific xy position
35718 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35719 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35721 showAt : function(xy, parentMenu, /* private: */_e){
35722 this.parentMenu = parentMenu;
35727 this.fireEvent("beforeshow", this);
35728 xy = this.el.adjustForConstraints(xy);
35732 this.hidden = false;
35734 this.fireEvent("show", this);
35737 focus : function(){
35739 this.doFocus.defer(50, this);
35743 doFocus : function(){
35745 this.focusEl.focus();
35750 * Hides this menu and optionally all parent menus
35751 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35753 hide : function(deep){
35754 if(this.el && this.isVisible()){
35755 this.fireEvent("beforehide", this);
35756 if(this.activeItem){
35757 this.activeItem.deactivate();
35758 this.activeItem = null;
35761 this.hidden = true;
35762 this.fireEvent("hide", this);
35764 if(deep === true && this.parentMenu){
35765 this.parentMenu.hide(true);
35770 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35771 * Any of the following are valid:
35773 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35774 * <li>An HTMLElement object which will be converted to a menu item</li>
35775 * <li>A menu item config object that will be created as a new menu item</li>
35776 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35777 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35782 var menu = new Roo.menu.Menu();
35784 // Create a menu item to add by reference
35785 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35787 // Add a bunch of items at once using different methods.
35788 // Only the last item added will be returned.
35789 var item = menu.add(
35790 menuItem, // add existing item by ref
35791 'Dynamic Item', // new TextItem
35792 '-', // new separator
35793 { text: 'Config Item' } // new item by config
35796 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35797 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35800 var a = arguments, l = a.length, item;
35801 for(var i = 0; i < l; i++){
35803 if ((typeof(el) == "object") && el.xtype && el.xns) {
35804 el = Roo.factory(el, Roo.menu);
35807 if(el.render){ // some kind of Item
35808 item = this.addItem(el);
35809 }else if(typeof el == "string"){ // string
35810 if(el == "separator" || el == "-"){
35811 item = this.addSeparator();
35813 item = this.addText(el);
35815 }else if(el.tagName || el.el){ // element
35816 item = this.addElement(el);
35817 }else if(typeof el == "object"){ // must be menu item config?
35818 item = this.addMenuItem(el);
35825 * Returns this menu's underlying {@link Roo.Element} object
35826 * @return {Roo.Element} The element
35828 getEl : function(){
35836 * Adds a separator bar to the menu
35837 * @return {Roo.menu.Item} The menu item that was added
35839 addSeparator : function(){
35840 return this.addItem(new Roo.menu.Separator());
35844 * Adds an {@link Roo.Element} object to the menu
35845 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35846 * @return {Roo.menu.Item} The menu item that was added
35848 addElement : function(el){
35849 return this.addItem(new Roo.menu.BaseItem(el));
35853 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35854 * @param {Roo.menu.Item} item The menu item to add
35855 * @return {Roo.menu.Item} The menu item that was added
35857 addItem : function(item){
35858 this.items.add(item);
35860 var li = document.createElement("li");
35861 li.className = "x-menu-list-item";
35862 this.ul.dom.appendChild(li);
35863 item.render(li, this);
35864 this.delayAutoWidth();
35870 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35871 * @param {Object} config A MenuItem config object
35872 * @return {Roo.menu.Item} The menu item that was added
35874 addMenuItem : function(config){
35875 if(!(config instanceof Roo.menu.Item)){
35876 if(typeof config.checked == "boolean"){ // must be check menu item config?
35877 config = new Roo.menu.CheckItem(config);
35879 config = new Roo.menu.Item(config);
35882 return this.addItem(config);
35886 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35887 * @param {String} text The text to display in the menu item
35888 * @return {Roo.menu.Item} The menu item that was added
35890 addText : function(text){
35891 return this.addItem(new Roo.menu.TextItem({ text : text }));
35895 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35896 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35897 * @param {Roo.menu.Item} item The menu item to add
35898 * @return {Roo.menu.Item} The menu item that was added
35900 insert : function(index, item){
35901 this.items.insert(index, item);
35903 var li = document.createElement("li");
35904 li.className = "x-menu-list-item";
35905 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35906 item.render(li, this);
35907 this.delayAutoWidth();
35913 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35914 * @param {Roo.menu.Item} item The menu item to remove
35916 remove : function(item){
35917 this.items.removeKey(item.id);
35922 * Removes and destroys all items in the menu
35924 removeAll : function(){
35926 while(f = this.items.first()){
35932 // MenuNav is a private utility class used internally by the Menu
35933 Roo.menu.MenuNav = function(menu){
35934 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35935 this.scope = this.menu = menu;
35938 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35939 doRelay : function(e, h){
35940 var k = e.getKey();
35941 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35942 this.menu.tryActivate(0, 1);
35945 return h.call(this.scope || this, e, this.menu);
35948 up : function(e, m){
35949 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35950 m.tryActivate(m.items.length-1, -1);
35954 down : function(e, m){
35955 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35956 m.tryActivate(0, 1);
35960 right : function(e, m){
35962 m.activeItem.expandMenu(true);
35966 left : function(e, m){
35968 if(m.parentMenu && m.parentMenu.activeItem){
35969 m.parentMenu.activeItem.activate();
35973 enter : function(e, m){
35975 e.stopPropagation();
35976 m.activeItem.onClick(e);
35977 m.fireEvent("click", this, m.activeItem);
35983 * Ext JS Library 1.1.1
35984 * Copyright(c) 2006-2007, Ext JS, LLC.
35986 * Originally Released Under LGPL - original licence link has changed is not relivant.
35989 * <script type="text/javascript">
35993 * @class Roo.menu.MenuMgr
35994 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35997 Roo.menu.MenuMgr = function(){
35998 var menus, active, groups = {}, attached = false, lastShow = new Date();
36000 // private - called when first menu is created
36003 active = new Roo.util.MixedCollection();
36004 Roo.get(document).addKeyListener(27, function(){
36005 if(active.length > 0){
36012 function hideAll(){
36013 if(active && active.length > 0){
36014 var c = active.clone();
36015 c.each(function(m){
36022 function onHide(m){
36024 if(active.length < 1){
36025 Roo.get(document).un("mousedown", onMouseDown);
36031 function onShow(m){
36032 var last = active.last();
36033 lastShow = new Date();
36036 Roo.get(document).on("mousedown", onMouseDown);
36040 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36041 m.parentMenu.activeChild = m;
36042 }else if(last && last.isVisible()){
36043 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36048 function onBeforeHide(m){
36050 m.activeChild.hide();
36052 if(m.autoHideTimer){
36053 clearTimeout(m.autoHideTimer);
36054 delete m.autoHideTimer;
36059 function onBeforeShow(m){
36060 var pm = m.parentMenu;
36061 if(!pm && !m.allowOtherMenus){
36063 }else if(pm && pm.activeChild && active != m){
36064 pm.activeChild.hide();
36069 function onMouseDown(e){
36070 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36076 function onBeforeCheck(mi, state){
36078 var g = groups[mi.group];
36079 for(var i = 0, l = g.length; i < l; i++){
36081 g[i].setChecked(false);
36090 * Hides all menus that are currently visible
36092 hideAll : function(){
36097 register : function(menu){
36101 menus[menu.id] = menu;
36102 menu.on("beforehide", onBeforeHide);
36103 menu.on("hide", onHide);
36104 menu.on("beforeshow", onBeforeShow);
36105 menu.on("show", onShow);
36106 var g = menu.group;
36107 if(g && menu.events["checkchange"]){
36111 groups[g].push(menu);
36112 menu.on("checkchange", onCheck);
36117 * Returns a {@link Roo.menu.Menu} object
36118 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36119 * be used to generate and return a new Menu instance.
36121 get : function(menu){
36122 if(typeof menu == "string"){ // menu id
36123 return menus[menu];
36124 }else if(menu.events){ // menu instance
36126 }else if(typeof menu.length == 'number'){ // array of menu items?
36127 return new Roo.menu.Menu({items:menu});
36128 }else{ // otherwise, must be a config
36129 return new Roo.menu.Menu(menu);
36134 unregister : function(menu){
36135 delete menus[menu.id];
36136 menu.un("beforehide", onBeforeHide);
36137 menu.un("hide", onHide);
36138 menu.un("beforeshow", onBeforeShow);
36139 menu.un("show", onShow);
36140 var g = menu.group;
36141 if(g && menu.events["checkchange"]){
36142 groups[g].remove(menu);
36143 menu.un("checkchange", onCheck);
36148 registerCheckable : function(menuItem){
36149 var g = menuItem.group;
36154 groups[g].push(menuItem);
36155 menuItem.on("beforecheckchange", onBeforeCheck);
36160 unregisterCheckable : function(menuItem){
36161 var g = menuItem.group;
36163 groups[g].remove(menuItem);
36164 menuItem.un("beforecheckchange", onBeforeCheck);
36170 * Ext JS Library 1.1.1
36171 * Copyright(c) 2006-2007, Ext JS, LLC.
36173 * Originally Released Under LGPL - original licence link has changed is not relivant.
36176 * <script type="text/javascript">
36181 * @class Roo.menu.BaseItem
36182 * @extends Roo.Component
36183 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36184 * management and base configuration options shared by all menu components.
36186 * Creates a new BaseItem
36187 * @param {Object} config Configuration options
36189 Roo.menu.BaseItem = function(config){
36190 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36195 * Fires when this item is clicked
36196 * @param {Roo.menu.BaseItem} this
36197 * @param {Roo.EventObject} e
36202 * Fires when this item is activated
36203 * @param {Roo.menu.BaseItem} this
36207 * @event deactivate
36208 * Fires when this item is deactivated
36209 * @param {Roo.menu.BaseItem} this
36215 this.on("click", this.handler, this.scope, true);
36219 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36221 * @cfg {Function} handler
36222 * A function that will handle the click event of this menu item (defaults to undefined)
36225 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36227 canActivate : false,
36230 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36235 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36237 activeClass : "x-menu-item-active",
36239 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36241 hideOnClick : true,
36243 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36248 ctype: "Roo.menu.BaseItem",
36251 actionMode : "container",
36254 render : function(container, parentMenu){
36255 this.parentMenu = parentMenu;
36256 Roo.menu.BaseItem.superclass.render.call(this, container);
36257 this.container.menuItemId = this.id;
36261 onRender : function(container, position){
36262 this.el = Roo.get(this.el);
36263 container.dom.appendChild(this.el.dom);
36267 onClick : function(e){
36268 if(!this.disabled && this.fireEvent("click", this, e) !== false
36269 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36270 this.handleClick(e);
36277 activate : function(){
36281 var li = this.container;
36282 li.addClass(this.activeClass);
36283 this.region = li.getRegion().adjust(2, 2, -2, -2);
36284 this.fireEvent("activate", this);
36289 deactivate : function(){
36290 this.container.removeClass(this.activeClass);
36291 this.fireEvent("deactivate", this);
36295 shouldDeactivate : function(e){
36296 return !this.region || !this.region.contains(e.getPoint());
36300 handleClick : function(e){
36301 if(this.hideOnClick){
36302 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36307 expandMenu : function(autoActivate){
36312 hideMenu : function(){
36317 * Ext JS Library 1.1.1
36318 * Copyright(c) 2006-2007, Ext JS, LLC.
36320 * Originally Released Under LGPL - original licence link has changed is not relivant.
36323 * <script type="text/javascript">
36327 * @class Roo.menu.Adapter
36328 * @extends Roo.menu.BaseItem
36329 * 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.
36330 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36332 * Creates a new Adapter
36333 * @param {Object} config Configuration options
36335 Roo.menu.Adapter = function(component, config){
36336 Roo.menu.Adapter.superclass.constructor.call(this, config);
36337 this.component = component;
36339 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36341 canActivate : true,
36344 onRender : function(container, position){
36345 this.component.render(container);
36346 this.el = this.component.getEl();
36350 activate : function(){
36354 this.component.focus();
36355 this.fireEvent("activate", this);
36360 deactivate : function(){
36361 this.fireEvent("deactivate", this);
36365 disable : function(){
36366 this.component.disable();
36367 Roo.menu.Adapter.superclass.disable.call(this);
36371 enable : function(){
36372 this.component.enable();
36373 Roo.menu.Adapter.superclass.enable.call(this);
36377 * Ext JS Library 1.1.1
36378 * Copyright(c) 2006-2007, Ext JS, LLC.
36380 * Originally Released Under LGPL - original licence link has changed is not relivant.
36383 * <script type="text/javascript">
36387 * @class Roo.menu.TextItem
36388 * @extends Roo.menu.BaseItem
36389 * Adds a static text string to a menu, usually used as either a heading or group separator.
36390 * Note: old style constructor with text is still supported.
36393 * Creates a new TextItem
36394 * @param {Object} cfg Configuration
36396 Roo.menu.TextItem = function(cfg){
36397 if (typeof(cfg) == 'string') {
36400 Roo.apply(this,cfg);
36403 Roo.menu.TextItem.superclass.constructor.call(this);
36406 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36408 * @cfg {Boolean} text Text to show on item.
36413 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36415 hideOnClick : false,
36417 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36419 itemCls : "x-menu-text",
36422 onRender : function(){
36423 var s = document.createElement("span");
36424 s.className = this.itemCls;
36425 s.innerHTML = this.text;
36427 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36431 * Ext JS Library 1.1.1
36432 * Copyright(c) 2006-2007, Ext JS, LLC.
36434 * Originally Released Under LGPL - original licence link has changed is not relivant.
36437 * <script type="text/javascript">
36441 * @class Roo.menu.Separator
36442 * @extends Roo.menu.BaseItem
36443 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36444 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36446 * @param {Object} config Configuration options
36448 Roo.menu.Separator = function(config){
36449 Roo.menu.Separator.superclass.constructor.call(this, config);
36452 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36454 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36456 itemCls : "x-menu-sep",
36458 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36460 hideOnClick : false,
36463 onRender : function(li){
36464 var s = document.createElement("span");
36465 s.className = this.itemCls;
36466 s.innerHTML = " ";
36468 li.addClass("x-menu-sep-li");
36469 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36473 * Ext JS Library 1.1.1
36474 * Copyright(c) 2006-2007, Ext JS, LLC.
36476 * Originally Released Under LGPL - original licence link has changed is not relivant.
36479 * <script type="text/javascript">
36482 * @class Roo.menu.Item
36483 * @extends Roo.menu.BaseItem
36484 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36485 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36486 * activation and click handling.
36488 * Creates a new Item
36489 * @param {Object} config Configuration options
36491 Roo.menu.Item = function(config){
36492 Roo.menu.Item.superclass.constructor.call(this, config);
36494 this.menu = Roo.menu.MenuMgr.get(this.menu);
36497 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36500 * @cfg {String} text
36501 * The text to show on the menu item.
36505 * @cfg {String} HTML to render in menu
36506 * The text to show on the menu item (HTML version).
36510 * @cfg {String} icon
36511 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36515 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36517 itemCls : "x-menu-item",
36519 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36521 canActivate : true,
36523 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36526 // doc'd in BaseItem
36530 ctype: "Roo.menu.Item",
36533 onRender : function(container, position){
36534 var el = document.createElement("a");
36535 el.hideFocus = true;
36536 el.unselectable = "on";
36537 el.href = this.href || "#";
36538 if(this.hrefTarget){
36539 el.target = this.hrefTarget;
36541 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36543 var html = this.html.length ? this.html : String.format('{0}',this.text);
36545 el.innerHTML = String.format(
36546 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36547 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36549 Roo.menu.Item.superclass.onRender.call(this, container, position);
36553 * Sets the text to display in this menu item
36554 * @param {String} text The text to display
36555 * @param {Boolean} isHTML true to indicate text is pure html.
36557 setText : function(text, isHTML){
36565 var html = this.html.length ? this.html : String.format('{0}',this.text);
36567 this.el.update(String.format(
36568 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36569 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36570 this.parentMenu.autoWidth();
36575 handleClick : function(e){
36576 if(!this.href){ // if no link defined, stop the event automatically
36579 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36583 activate : function(autoExpand){
36584 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36594 shouldDeactivate : function(e){
36595 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36596 if(this.menu && this.menu.isVisible()){
36597 return !this.menu.getEl().getRegion().contains(e.getPoint());
36605 deactivate : function(){
36606 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36611 expandMenu : function(autoActivate){
36612 if(!this.disabled && this.menu){
36613 clearTimeout(this.hideTimer);
36614 delete this.hideTimer;
36615 if(!this.menu.isVisible() && !this.showTimer){
36616 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36617 }else if (this.menu.isVisible() && autoActivate){
36618 this.menu.tryActivate(0, 1);
36624 deferExpand : function(autoActivate){
36625 delete this.showTimer;
36626 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36628 this.menu.tryActivate(0, 1);
36633 hideMenu : function(){
36634 clearTimeout(this.showTimer);
36635 delete this.showTimer;
36636 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36637 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36642 deferHide : function(){
36643 delete this.hideTimer;
36648 * Ext JS Library 1.1.1
36649 * Copyright(c) 2006-2007, Ext JS, LLC.
36651 * Originally Released Under LGPL - original licence link has changed is not relivant.
36654 * <script type="text/javascript">
36658 * @class Roo.menu.CheckItem
36659 * @extends Roo.menu.Item
36660 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36662 * Creates a new CheckItem
36663 * @param {Object} config Configuration options
36665 Roo.menu.CheckItem = function(config){
36666 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36669 * @event beforecheckchange
36670 * Fires before the checked value is set, providing an opportunity to cancel if needed
36671 * @param {Roo.menu.CheckItem} this
36672 * @param {Boolean} checked The new checked value that will be set
36674 "beforecheckchange" : true,
36676 * @event checkchange
36677 * Fires after the checked value has been set
36678 * @param {Roo.menu.CheckItem} this
36679 * @param {Boolean} checked The checked value that was set
36681 "checkchange" : true
36683 if(this.checkHandler){
36684 this.on('checkchange', this.checkHandler, this.scope);
36687 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36689 * @cfg {String} group
36690 * All check items with the same group name will automatically be grouped into a single-select
36691 * radio button group (defaults to '')
36694 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36696 itemCls : "x-menu-item x-menu-check-item",
36698 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36700 groupClass : "x-menu-group-item",
36703 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36704 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36705 * initialized with checked = true will be rendered as checked.
36710 ctype: "Roo.menu.CheckItem",
36713 onRender : function(c){
36714 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36716 this.el.addClass(this.groupClass);
36718 Roo.menu.MenuMgr.registerCheckable(this);
36720 this.checked = false;
36721 this.setChecked(true, true);
36726 destroy : function(){
36728 Roo.menu.MenuMgr.unregisterCheckable(this);
36730 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36734 * Set the checked state of this item
36735 * @param {Boolean} checked The new checked value
36736 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36738 setChecked : function(state, suppressEvent){
36739 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36740 if(this.container){
36741 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36743 this.checked = state;
36744 if(suppressEvent !== true){
36745 this.fireEvent("checkchange", this, state);
36751 handleClick : function(e){
36752 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36753 this.setChecked(!this.checked);
36755 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36759 * Ext JS Library 1.1.1
36760 * Copyright(c) 2006-2007, Ext JS, LLC.
36762 * Originally Released Under LGPL - original licence link has changed is not relivant.
36765 * <script type="text/javascript">
36769 * @class Roo.menu.DateItem
36770 * @extends Roo.menu.Adapter
36771 * A menu item that wraps the {@link Roo.DatPicker} component.
36773 * Creates a new DateItem
36774 * @param {Object} config Configuration options
36776 Roo.menu.DateItem = function(config){
36777 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36778 /** The Roo.DatePicker object @type Roo.DatePicker */
36779 this.picker = this.component;
36780 this.addEvents({select: true});
36782 this.picker.on("render", function(picker){
36783 picker.getEl().swallowEvent("click");
36784 picker.container.addClass("x-menu-date-item");
36787 this.picker.on("select", this.onSelect, this);
36790 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36792 onSelect : function(picker, date){
36793 this.fireEvent("select", this, date, picker);
36794 Roo.menu.DateItem.superclass.handleClick.call(this);
36798 * Ext JS Library 1.1.1
36799 * Copyright(c) 2006-2007, Ext JS, LLC.
36801 * Originally Released Under LGPL - original licence link has changed is not relivant.
36804 * <script type="text/javascript">
36808 * @class Roo.menu.ColorItem
36809 * @extends Roo.menu.Adapter
36810 * A menu item that wraps the {@link Roo.ColorPalette} component.
36812 * Creates a new ColorItem
36813 * @param {Object} config Configuration options
36815 Roo.menu.ColorItem = function(config){
36816 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36817 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36818 this.palette = this.component;
36819 this.relayEvents(this.palette, ["select"]);
36820 if(this.selectHandler){
36821 this.on('select', this.selectHandler, this.scope);
36824 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36826 * Ext JS Library 1.1.1
36827 * Copyright(c) 2006-2007, Ext JS, LLC.
36829 * Originally Released Under LGPL - original licence link has changed is not relivant.
36832 * <script type="text/javascript">
36837 * @class Roo.menu.DateMenu
36838 * @extends Roo.menu.Menu
36839 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36841 * Creates a new DateMenu
36842 * @param {Object} config Configuration options
36844 Roo.menu.DateMenu = function(config){
36845 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36847 var di = new Roo.menu.DateItem(config);
36850 * The {@link Roo.DatePicker} instance for this DateMenu
36853 this.picker = di.picker;
36856 * @param {DatePicker} picker
36857 * @param {Date} date
36859 this.relayEvents(di, ["select"]);
36860 this.on('beforeshow', function(){
36862 this.picker.hideMonthPicker(false);
36866 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36870 * Ext JS Library 1.1.1
36871 * Copyright(c) 2006-2007, Ext JS, LLC.
36873 * Originally Released Under LGPL - original licence link has changed is not relivant.
36876 * <script type="text/javascript">
36881 * @class Roo.menu.ColorMenu
36882 * @extends Roo.menu.Menu
36883 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36885 * Creates a new ColorMenu
36886 * @param {Object} config Configuration options
36888 Roo.menu.ColorMenu = function(config){
36889 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36891 var ci = new Roo.menu.ColorItem(config);
36894 * The {@link Roo.ColorPalette} instance for this ColorMenu
36895 * @type ColorPalette
36897 this.palette = ci.palette;
36900 * @param {ColorPalette} palette
36901 * @param {String} color
36903 this.relayEvents(ci, ["select"]);
36905 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36907 * Ext JS Library 1.1.1
36908 * Copyright(c) 2006-2007, Ext JS, LLC.
36910 * Originally Released Under LGPL - original licence link has changed is not relivant.
36913 * <script type="text/javascript">
36917 * @class Roo.form.Field
36918 * @extends Roo.BoxComponent
36919 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36921 * Creates a new Field
36922 * @param {Object} config Configuration options
36924 Roo.form.Field = function(config){
36925 Roo.form.Field.superclass.constructor.call(this, config);
36928 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36930 * @cfg {String} fieldLabel Label to use when rendering a form.
36933 * @cfg {String} qtip Mouse over tip
36937 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36939 invalidClass : "x-form-invalid",
36941 * @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")
36943 invalidText : "The value in this field is invalid",
36945 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36947 focusClass : "x-form-focus",
36949 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36950 automatic validation (defaults to "keyup").
36952 validationEvent : "keyup",
36954 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36956 validateOnBlur : true,
36958 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36960 validationDelay : 250,
36962 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36963 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36965 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36967 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36969 fieldClass : "x-form-field",
36971 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36974 ----------- ----------------------------------------------------------------------
36975 qtip Display a quick tip when the user hovers over the field
36976 title Display a default browser title attribute popup
36977 under Add a block div beneath the field containing the error text
36978 side Add an error icon to the right of the field with a popup on hover
36979 [element id] Add the error text directly to the innerHTML of the specified element
36982 msgTarget : 'qtip',
36984 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36989 * @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.
36994 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36999 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37001 inputType : undefined,
37004 * @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).
37006 tabIndex : undefined,
37009 isFormField : true,
37014 * @property {Roo.Element} fieldEl
37015 * Element Containing the rendered Field (with label etc.)
37018 * @cfg {Mixed} value A value to initialize this field with.
37023 * @cfg {String} name The field's HTML name attribute.
37026 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37030 initComponent : function(){
37031 Roo.form.Field.superclass.initComponent.call(this);
37035 * Fires when this field receives input focus.
37036 * @param {Roo.form.Field} this
37041 * Fires when this field loses input focus.
37042 * @param {Roo.form.Field} this
37046 * @event specialkey
37047 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37048 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37049 * @param {Roo.form.Field} this
37050 * @param {Roo.EventObject} e The event object
37055 * Fires just before the field blurs if the field value has changed.
37056 * @param {Roo.form.Field} this
37057 * @param {Mixed} newValue The new value
37058 * @param {Mixed} oldValue The original value
37063 * Fires after the field has been marked as invalid.
37064 * @param {Roo.form.Field} this
37065 * @param {String} msg The validation message
37070 * Fires after the field has been validated with no errors.
37071 * @param {Roo.form.Field} this
37076 * Fires after the key up
37077 * @param {Roo.form.Field} this
37078 * @param {Roo.EventObject} e The event Object
37085 * Returns the name attribute of the field if available
37086 * @return {String} name The field name
37088 getName: function(){
37089 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37093 onRender : function(ct, position){
37094 Roo.form.Field.superclass.onRender.call(this, ct, position);
37096 var cfg = this.getAutoCreate();
37098 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37100 if (!cfg.name.length) {
37103 if(this.inputType){
37104 cfg.type = this.inputType;
37106 this.el = ct.createChild(cfg, position);
37108 var type = this.el.dom.type;
37110 if(type == 'password'){
37113 this.el.addClass('x-form-'+type);
37116 this.el.dom.readOnly = true;
37118 if(this.tabIndex !== undefined){
37119 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37122 this.el.addClass([this.fieldClass, this.cls]);
37127 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37128 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37129 * @return {Roo.form.Field} this
37131 applyTo : function(target){
37132 this.allowDomMove = false;
37133 this.el = Roo.get(target);
37134 this.render(this.el.dom.parentNode);
37139 initValue : function(){
37140 if(this.value !== undefined){
37141 this.setValue(this.value);
37142 }else if(this.el.dom.value.length > 0){
37143 this.setValue(this.el.dom.value);
37148 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37150 isDirty : function() {
37151 if(this.disabled) {
37154 return String(this.getValue()) !== String(this.originalValue);
37158 afterRender : function(){
37159 Roo.form.Field.superclass.afterRender.call(this);
37164 fireKey : function(e){
37165 //Roo.log('field ' + e.getKey());
37166 if(e.isNavKeyPress()){
37167 this.fireEvent("specialkey", this, e);
37172 * Resets the current field value to the originally loaded value and clears any validation messages
37174 reset : function(){
37175 this.setValue(this.resetValue);
37176 this.clearInvalid();
37180 initEvents : function(){
37181 // safari killled keypress - so keydown is now used..
37182 this.el.on("keydown" , this.fireKey, this);
37183 this.el.on("focus", this.onFocus, this);
37184 this.el.on("blur", this.onBlur, this);
37185 this.el.relayEvent('keyup', this);
37187 // reference to original value for reset
37188 this.originalValue = this.getValue();
37189 this.resetValue = this.getValue();
37193 onFocus : function(){
37194 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37195 this.el.addClass(this.focusClass);
37197 if(!this.hasFocus){
37198 this.hasFocus = true;
37199 this.startValue = this.getValue();
37200 this.fireEvent("focus", this);
37204 beforeBlur : Roo.emptyFn,
37207 onBlur : function(){
37209 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37210 this.el.removeClass(this.focusClass);
37212 this.hasFocus = false;
37213 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37216 var v = this.getValue();
37217 if(String(v) !== String(this.startValue)){
37218 this.fireEvent('change', this, v, this.startValue);
37220 this.fireEvent("blur", this);
37224 * Returns whether or not the field value is currently valid
37225 * @param {Boolean} preventMark True to disable marking the field invalid
37226 * @return {Boolean} True if the value is valid, else false
37228 isValid : function(preventMark){
37232 var restore = this.preventMark;
37233 this.preventMark = preventMark === true;
37234 var v = this.validateValue(this.processValue(this.getRawValue()));
37235 this.preventMark = restore;
37240 * Validates the field value
37241 * @return {Boolean} True if the value is valid, else false
37243 validate : function(){
37244 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37245 this.clearInvalid();
37251 processValue : function(value){
37256 // Subclasses should provide the validation implementation by overriding this
37257 validateValue : function(value){
37262 * Mark this field as invalid
37263 * @param {String} msg The validation message
37265 markInvalid : function(msg){
37266 if(!this.rendered || this.preventMark){ // not rendered
37270 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37272 obj.el.addClass(this.invalidClass);
37273 msg = msg || this.invalidText;
37274 switch(this.msgTarget){
37276 obj.el.dom.qtip = msg;
37277 obj.el.dom.qclass = 'x-form-invalid-tip';
37278 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37279 Roo.QuickTips.enable();
37283 this.el.dom.title = msg;
37287 var elp = this.el.findParent('.x-form-element', 5, true);
37288 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37289 this.errorEl.setWidth(elp.getWidth(true)-20);
37291 this.errorEl.update(msg);
37292 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37295 if(!this.errorIcon){
37296 var elp = this.el.findParent('.x-form-element', 5, true);
37297 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37299 this.alignErrorIcon();
37300 this.errorIcon.dom.qtip = msg;
37301 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37302 this.errorIcon.show();
37303 this.on('resize', this.alignErrorIcon, this);
37306 var t = Roo.getDom(this.msgTarget);
37308 t.style.display = this.msgDisplay;
37311 this.fireEvent('invalid', this, msg);
37315 alignErrorIcon : function(){
37316 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37320 * Clear any invalid styles/messages for this field
37322 clearInvalid : function(){
37323 if(!this.rendered || this.preventMark){ // not rendered
37326 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37328 obj.el.removeClass(this.invalidClass);
37329 switch(this.msgTarget){
37331 obj.el.dom.qtip = '';
37334 this.el.dom.title = '';
37338 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37342 if(this.errorIcon){
37343 this.errorIcon.dom.qtip = '';
37344 this.errorIcon.hide();
37345 this.un('resize', this.alignErrorIcon, this);
37349 var t = Roo.getDom(this.msgTarget);
37351 t.style.display = 'none';
37354 this.fireEvent('valid', this);
37358 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37359 * @return {Mixed} value The field value
37361 getRawValue : function(){
37362 var v = this.el.getValue();
37368 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37369 * @return {Mixed} value The field value
37371 getValue : function(){
37372 var v = this.el.getValue();
37378 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37379 * @param {Mixed} value The value to set
37381 setRawValue : function(v){
37382 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37386 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37387 * @param {Mixed} value The value to set
37389 setValue : function(v){
37392 this.el.dom.value = (v === null || v === undefined ? '' : v);
37397 adjustSize : function(w, h){
37398 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37399 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37403 adjustWidth : function(tag, w){
37404 tag = tag.toLowerCase();
37405 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37406 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37407 if(tag == 'input'){
37410 if(tag == 'textarea'){
37413 }else if(Roo.isOpera){
37414 if(tag == 'input'){
37417 if(tag == 'textarea'){
37427 // anything other than normal should be considered experimental
37428 Roo.form.Field.msgFx = {
37430 show: function(msgEl, f){
37431 msgEl.setDisplayed('block');
37434 hide : function(msgEl, f){
37435 msgEl.setDisplayed(false).update('');
37440 show: function(msgEl, f){
37441 msgEl.slideIn('t', {stopFx:true});
37444 hide : function(msgEl, f){
37445 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37450 show: function(msgEl, f){
37451 msgEl.fixDisplay();
37452 msgEl.alignTo(f.el, 'tl-tr');
37453 msgEl.slideIn('l', {stopFx:true});
37456 hide : function(msgEl, f){
37457 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37462 * Ext JS Library 1.1.1
37463 * Copyright(c) 2006-2007, Ext JS, LLC.
37465 * Originally Released Under LGPL - original licence link has changed is not relivant.
37468 * <script type="text/javascript">
37473 * @class Roo.form.TextField
37474 * @extends Roo.form.Field
37475 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37476 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37478 * Creates a new TextField
37479 * @param {Object} config Configuration options
37481 Roo.form.TextField = function(config){
37482 Roo.form.TextField.superclass.constructor.call(this, config);
37486 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37487 * according to the default logic, but this event provides a hook for the developer to apply additional
37488 * logic at runtime to resize the field if needed.
37489 * @param {Roo.form.Field} this This text field
37490 * @param {Number} width The new field width
37496 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37498 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37502 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37506 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37510 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37514 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37518 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37520 disableKeyFilter : false,
37522 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37526 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37530 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37532 maxLength : Number.MAX_VALUE,
37534 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37536 minLengthText : "The minimum length for this field is {0}",
37538 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37540 maxLengthText : "The maximum length for this field is {0}",
37542 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37544 selectOnFocus : false,
37546 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37548 blankText : "This field is required",
37550 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37551 * If available, this function will be called only after the basic validators all return true, and will be passed the
37552 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37556 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37557 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37558 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37562 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37566 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37572 initEvents : function()
37574 if (this.emptyText) {
37575 this.el.attr('placeholder', this.emptyText);
37578 Roo.form.TextField.superclass.initEvents.call(this);
37579 if(this.validationEvent == 'keyup'){
37580 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37581 this.el.on('keyup', this.filterValidation, this);
37583 else if(this.validationEvent !== false){
37584 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37587 if(this.selectOnFocus){
37588 this.on("focus", this.preFocus, this);
37591 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37592 this.el.on("keypress", this.filterKeys, this);
37595 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37596 this.el.on("click", this.autoSize, this);
37598 if(this.el.is('input[type=password]') && Roo.isSafari){
37599 this.el.on('keydown', this.SafariOnKeyDown, this);
37603 processValue : function(value){
37604 if(this.stripCharsRe){
37605 var newValue = value.replace(this.stripCharsRe, '');
37606 if(newValue !== value){
37607 this.setRawValue(newValue);
37614 filterValidation : function(e){
37615 if(!e.isNavKeyPress()){
37616 this.validationTask.delay(this.validationDelay);
37621 onKeyUp : function(e){
37622 if(!e.isNavKeyPress()){
37628 * Resets the current field value to the originally-loaded value and clears any validation messages.
37631 reset : function(){
37632 Roo.form.TextField.superclass.reset.call(this);
37638 preFocus : function(){
37640 if(this.selectOnFocus){
37641 this.el.dom.select();
37647 filterKeys : function(e){
37648 var k = e.getKey();
37649 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37652 var c = e.getCharCode(), cc = String.fromCharCode(c);
37653 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37656 if(!this.maskRe.test(cc)){
37661 setValue : function(v){
37663 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37669 * Validates a value according to the field's validation rules and marks the field as invalid
37670 * if the validation fails
37671 * @param {Mixed} value The value to validate
37672 * @return {Boolean} True if the value is valid, else false
37674 validateValue : function(value){
37675 if(value.length < 1) { // if it's blank
37676 if(this.allowBlank){
37677 this.clearInvalid();
37680 this.markInvalid(this.blankText);
37684 if(value.length < this.minLength){
37685 this.markInvalid(String.format(this.minLengthText, this.minLength));
37688 if(value.length > this.maxLength){
37689 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37693 var vt = Roo.form.VTypes;
37694 if(!vt[this.vtype](value, this)){
37695 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37699 if(typeof this.validator == "function"){
37700 var msg = this.validator(value);
37702 this.markInvalid(msg);
37706 if(this.regex && !this.regex.test(value)){
37707 this.markInvalid(this.regexText);
37714 * Selects text in this field
37715 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37716 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37718 selectText : function(start, end){
37719 var v = this.getRawValue();
37721 start = start === undefined ? 0 : start;
37722 end = end === undefined ? v.length : end;
37723 var d = this.el.dom;
37724 if(d.setSelectionRange){
37725 d.setSelectionRange(start, end);
37726 }else if(d.createTextRange){
37727 var range = d.createTextRange();
37728 range.moveStart("character", start);
37729 range.moveEnd("character", v.length-end);
37736 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37737 * This only takes effect if grow = true, and fires the autosize event.
37739 autoSize : function(){
37740 if(!this.grow || !this.rendered){
37744 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37747 var v = el.dom.value;
37748 var d = document.createElement('div');
37749 d.appendChild(document.createTextNode(v));
37753 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37754 this.el.setWidth(w);
37755 this.fireEvent("autosize", this, w);
37759 SafariOnKeyDown : function(event)
37761 // this is a workaround for a password hang bug on chrome/ webkit.
37763 var isSelectAll = false;
37765 if(this.el.dom.selectionEnd > 0){
37766 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37768 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37769 event.preventDefault();
37774 if(isSelectAll){ // backspace and delete key
37776 event.preventDefault();
37777 // this is very hacky as keydown always get's upper case.
37779 var cc = String.fromCharCode(event.getCharCode());
37780 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37788 * Ext JS Library 1.1.1
37789 * Copyright(c) 2006-2007, Ext JS, LLC.
37791 * Originally Released Under LGPL - original licence link has changed is not relivant.
37794 * <script type="text/javascript">
37798 * @class Roo.form.Hidden
37799 * @extends Roo.form.TextField
37800 * Simple Hidden element used on forms
37802 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37805 * Creates a new Hidden form element.
37806 * @param {Object} config Configuration options
37811 // easy hidden field...
37812 Roo.form.Hidden = function(config){
37813 Roo.form.Hidden.superclass.constructor.call(this, config);
37816 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37818 inputType: 'hidden',
37821 labelSeparator: '',
37823 itemCls : 'x-form-item-display-none'
37831 * Ext JS Library 1.1.1
37832 * Copyright(c) 2006-2007, Ext JS, LLC.
37834 * Originally Released Under LGPL - original licence link has changed is not relivant.
37837 * <script type="text/javascript">
37841 * @class Roo.form.TriggerField
37842 * @extends Roo.form.TextField
37843 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37844 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37845 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37846 * for which you can provide a custom implementation. For example:
37848 var trigger = new Roo.form.TriggerField();
37849 trigger.onTriggerClick = myTriggerFn;
37850 trigger.applyTo('my-field');
37853 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37854 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37855 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37856 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37858 * Create a new TriggerField.
37859 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37860 * to the base TextField)
37862 Roo.form.TriggerField = function(config){
37863 this.mimicing = false;
37864 Roo.form.TriggerField.superclass.constructor.call(this, config);
37867 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37869 * @cfg {String} triggerClass A CSS class to apply to the trigger
37872 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37873 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37875 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37877 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37881 /** @cfg {Boolean} grow @hide */
37882 /** @cfg {Number} growMin @hide */
37883 /** @cfg {Number} growMax @hide */
37889 autoSize: Roo.emptyFn,
37893 deferHeight : true,
37896 actionMode : 'wrap',
37898 onResize : function(w, h){
37899 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37900 if(typeof w == 'number'){
37901 var x = w - this.trigger.getWidth();
37902 this.el.setWidth(this.adjustWidth('input', x));
37903 this.trigger.setStyle('left', x+'px');
37908 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37911 getResizeEl : function(){
37916 getPositionEl : function(){
37921 alignErrorIcon : function(){
37922 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37926 onRender : function(ct, position){
37927 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37928 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37929 this.trigger = this.wrap.createChild(this.triggerConfig ||
37930 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37931 if(this.hideTrigger){
37932 this.trigger.setDisplayed(false);
37934 this.initTrigger();
37936 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37941 initTrigger : function(){
37942 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37943 this.trigger.addClassOnOver('x-form-trigger-over');
37944 this.trigger.addClassOnClick('x-form-trigger-click');
37948 onDestroy : function(){
37950 this.trigger.removeAllListeners();
37951 this.trigger.remove();
37954 this.wrap.remove();
37956 Roo.form.TriggerField.superclass.onDestroy.call(this);
37960 onFocus : function(){
37961 Roo.form.TriggerField.superclass.onFocus.call(this);
37962 if(!this.mimicing){
37963 this.wrap.addClass('x-trigger-wrap-focus');
37964 this.mimicing = true;
37965 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37966 if(this.monitorTab){
37967 this.el.on("keydown", this.checkTab, this);
37973 checkTab : function(e){
37974 if(e.getKey() == e.TAB){
37975 this.triggerBlur();
37980 onBlur : function(){
37985 mimicBlur : function(e, t){
37986 if(!this.wrap.contains(t) && this.validateBlur()){
37987 this.triggerBlur();
37992 triggerBlur : function(){
37993 this.mimicing = false;
37994 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37995 if(this.monitorTab){
37996 this.el.un("keydown", this.checkTab, this);
37998 this.wrap.removeClass('x-trigger-wrap-focus');
37999 Roo.form.TriggerField.superclass.onBlur.call(this);
38003 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38004 validateBlur : function(e, t){
38009 onDisable : function(){
38010 Roo.form.TriggerField.superclass.onDisable.call(this);
38012 this.wrap.addClass('x-item-disabled');
38017 onEnable : function(){
38018 Roo.form.TriggerField.superclass.onEnable.call(this);
38020 this.wrap.removeClass('x-item-disabled');
38025 onShow : function(){
38026 var ae = this.getActionEl();
38029 ae.dom.style.display = '';
38030 ae.dom.style.visibility = 'visible';
38036 onHide : function(){
38037 var ae = this.getActionEl();
38038 ae.dom.style.display = 'none';
38042 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38043 * by an implementing function.
38045 * @param {EventObject} e
38047 onTriggerClick : Roo.emptyFn
38050 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38051 // to be extended by an implementing class. For an example of implementing this class, see the custom
38052 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38053 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38054 initComponent : function(){
38055 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38057 this.triggerConfig = {
38058 tag:'span', cls:'x-form-twin-triggers', cn:[
38059 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38060 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38064 getTrigger : function(index){
38065 return this.triggers[index];
38068 initTrigger : function(){
38069 var ts = this.trigger.select('.x-form-trigger', true);
38070 this.wrap.setStyle('overflow', 'hidden');
38071 var triggerField = this;
38072 ts.each(function(t, all, index){
38073 t.hide = function(){
38074 var w = triggerField.wrap.getWidth();
38075 this.dom.style.display = 'none';
38076 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38078 t.show = function(){
38079 var w = triggerField.wrap.getWidth();
38080 this.dom.style.display = '';
38081 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38083 var triggerIndex = 'Trigger'+(index+1);
38085 if(this['hide'+triggerIndex]){
38086 t.dom.style.display = 'none';
38088 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38089 t.addClassOnOver('x-form-trigger-over');
38090 t.addClassOnClick('x-form-trigger-click');
38092 this.triggers = ts.elements;
38095 onTrigger1Click : Roo.emptyFn,
38096 onTrigger2Click : Roo.emptyFn
38099 * Ext JS Library 1.1.1
38100 * Copyright(c) 2006-2007, Ext JS, LLC.
38102 * Originally Released Under LGPL - original licence link has changed is not relivant.
38105 * <script type="text/javascript">
38109 * @class Roo.form.TextArea
38110 * @extends Roo.form.TextField
38111 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38112 * support for auto-sizing.
38114 * Creates a new TextArea
38115 * @param {Object} config Configuration options
38117 Roo.form.TextArea = function(config){
38118 Roo.form.TextArea.superclass.constructor.call(this, config);
38119 // these are provided exchanges for backwards compat
38120 // minHeight/maxHeight were replaced by growMin/growMax to be
38121 // compatible with TextField growing config values
38122 if(this.minHeight !== undefined){
38123 this.growMin = this.minHeight;
38125 if(this.maxHeight !== undefined){
38126 this.growMax = this.maxHeight;
38130 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38132 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38136 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38140 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38141 * in the field (equivalent to setting overflow: hidden, defaults to false)
38143 preventScrollbars: false,
38145 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38146 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38150 onRender : function(ct, position){
38152 this.defaultAutoCreate = {
38154 style:"width:300px;height:60px;",
38155 autocomplete: "off"
38158 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38160 this.textSizeEl = Roo.DomHelper.append(document.body, {
38161 tag: "pre", cls: "x-form-grow-sizer"
38163 if(this.preventScrollbars){
38164 this.el.setStyle("overflow", "hidden");
38166 this.el.setHeight(this.growMin);
38170 onDestroy : function(){
38171 if(this.textSizeEl){
38172 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38174 Roo.form.TextArea.superclass.onDestroy.call(this);
38178 onKeyUp : function(e){
38179 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38185 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38186 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38188 autoSize : function(){
38189 if(!this.grow || !this.textSizeEl){
38193 var v = el.dom.value;
38194 var ts = this.textSizeEl;
38197 ts.appendChild(document.createTextNode(v));
38200 Roo.fly(ts).setWidth(this.el.getWidth());
38202 v = "  ";
38205 v = v.replace(/\n/g, '<p> </p>');
38207 v += " \n ";
38210 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38211 if(h != this.lastHeight){
38212 this.lastHeight = h;
38213 this.el.setHeight(h);
38214 this.fireEvent("autosize", this, h);
38219 * Ext JS Library 1.1.1
38220 * Copyright(c) 2006-2007, Ext JS, LLC.
38222 * Originally Released Under LGPL - original licence link has changed is not relivant.
38225 * <script type="text/javascript">
38230 * @class Roo.form.NumberField
38231 * @extends Roo.form.TextField
38232 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38234 * Creates a new NumberField
38235 * @param {Object} config Configuration options
38237 Roo.form.NumberField = function(config){
38238 Roo.form.NumberField.superclass.constructor.call(this, config);
38241 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38243 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38245 fieldClass: "x-form-field x-form-num-field",
38247 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38249 allowDecimals : true,
38251 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38253 decimalSeparator : ".",
38255 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38257 decimalPrecision : 2,
38259 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38261 allowNegative : true,
38263 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38265 minValue : Number.NEGATIVE_INFINITY,
38267 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38269 maxValue : Number.MAX_VALUE,
38271 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38273 minText : "The minimum value for this field is {0}",
38275 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38277 maxText : "The maximum value for this field is {0}",
38279 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38280 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38282 nanText : "{0} is not a valid number",
38285 initEvents : function(){
38286 Roo.form.NumberField.superclass.initEvents.call(this);
38287 var allowed = "0123456789";
38288 if(this.allowDecimals){
38289 allowed += this.decimalSeparator;
38291 if(this.allowNegative){
38294 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38295 var keyPress = function(e){
38296 var k = e.getKey();
38297 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38300 var c = e.getCharCode();
38301 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38305 this.el.on("keypress", keyPress, this);
38309 validateValue : function(value){
38310 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38313 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38316 var num = this.parseValue(value);
38318 this.markInvalid(String.format(this.nanText, value));
38321 if(num < this.minValue){
38322 this.markInvalid(String.format(this.minText, this.minValue));
38325 if(num > this.maxValue){
38326 this.markInvalid(String.format(this.maxText, this.maxValue));
38332 getValue : function(){
38333 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38337 parseValue : function(value){
38338 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38339 return isNaN(value) ? '' : value;
38343 fixPrecision : function(value){
38344 var nan = isNaN(value);
38345 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38346 return nan ? '' : value;
38348 return parseFloat(value).toFixed(this.decimalPrecision);
38351 setValue : function(v){
38352 v = this.fixPrecision(v);
38353 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38357 decimalPrecisionFcn : function(v){
38358 return Math.floor(v);
38361 beforeBlur : function(){
38362 var v = this.parseValue(this.getRawValue());
38369 * Ext JS Library 1.1.1
38370 * Copyright(c) 2006-2007, Ext JS, LLC.
38372 * Originally Released Under LGPL - original licence link has changed is not relivant.
38375 * <script type="text/javascript">
38379 * @class Roo.form.DateField
38380 * @extends Roo.form.TriggerField
38381 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38383 * Create a new DateField
38384 * @param {Object} config
38386 Roo.form.DateField = function(config){
38387 Roo.form.DateField.superclass.constructor.call(this, config);
38393 * Fires when a date is selected
38394 * @param {Roo.form.DateField} combo This combo box
38395 * @param {Date} date The date selected
38402 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38403 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38404 this.ddMatch = null;
38405 if(this.disabledDates){
38406 var dd = this.disabledDates;
38408 for(var i = 0; i < dd.length; i++){
38410 if(i != dd.length-1) re += "|";
38412 this.ddMatch = new RegExp(re + ")");
38416 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38418 * @cfg {String} format
38419 * The default date format string which can be overriden for localization support. The format must be
38420 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38424 * @cfg {String} altFormats
38425 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38426 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38428 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38430 * @cfg {Array} disabledDays
38431 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38433 disabledDays : null,
38435 * @cfg {String} disabledDaysText
38436 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38438 disabledDaysText : "Disabled",
38440 * @cfg {Array} disabledDates
38441 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38442 * expression so they are very powerful. Some examples:
38444 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38445 * <li>["03/08", "09/16"] would disable those days for every year</li>
38446 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38447 * <li>["03/../2006"] would disable every day in March 2006</li>
38448 * <li>["^03"] would disable every day in every March</li>
38450 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38451 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38453 disabledDates : null,
38455 * @cfg {String} disabledDatesText
38456 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38458 disabledDatesText : "Disabled",
38460 * @cfg {Date/String} minValue
38461 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38462 * valid format (defaults to null).
38466 * @cfg {Date/String} maxValue
38467 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38468 * valid format (defaults to null).
38472 * @cfg {String} minText
38473 * The error text to display when the date in the cell is before minValue (defaults to
38474 * 'The date in this field must be after {minValue}').
38476 minText : "The date in this field must be equal to or after {0}",
38478 * @cfg {String} maxText
38479 * The error text to display when the date in the cell is after maxValue (defaults to
38480 * 'The date in this field must be before {maxValue}').
38482 maxText : "The date in this field must be equal to or before {0}",
38484 * @cfg {String} invalidText
38485 * The error text to display when the date in the field is invalid (defaults to
38486 * '{value} is not a valid date - it must be in the format {format}').
38488 invalidText : "{0} is not a valid date - it must be in the format {1}",
38490 * @cfg {String} triggerClass
38491 * An additional CSS class used to style the trigger button. The trigger will always get the
38492 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38493 * which displays a calendar icon).
38495 triggerClass : 'x-form-date-trigger',
38499 * @cfg {Boolean} useIso
38500 * if enabled, then the date field will use a hidden field to store the
38501 * real value as iso formated date. default (false)
38505 * @cfg {String/Object} autoCreate
38506 * A DomHelper element spec, or true for a default element spec (defaults to
38507 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38510 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38513 hiddenField: false,
38515 onRender : function(ct, position)
38517 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38519 //this.el.dom.removeAttribute('name');
38520 Roo.log("Changing name?");
38521 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38522 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38524 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38525 // prevent input submission
38526 this.hiddenName = this.name;
38533 validateValue : function(value)
38535 value = this.formatDate(value);
38536 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38537 Roo.log('super failed');
38540 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38543 var svalue = value;
38544 value = this.parseDate(value);
38546 Roo.log('parse date failed' + svalue);
38547 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38550 var time = value.getTime();
38551 if(this.minValue && time < this.minValue.getTime()){
38552 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38555 if(this.maxValue && time > this.maxValue.getTime()){
38556 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38559 if(this.disabledDays){
38560 var day = value.getDay();
38561 for(var i = 0; i < this.disabledDays.length; i++) {
38562 if(day === this.disabledDays[i]){
38563 this.markInvalid(this.disabledDaysText);
38568 var fvalue = this.formatDate(value);
38569 if(this.ddMatch && this.ddMatch.test(fvalue)){
38570 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38577 // Provides logic to override the default TriggerField.validateBlur which just returns true
38578 validateBlur : function(){
38579 return !this.menu || !this.menu.isVisible();
38582 getName: function()
38584 // returns hidden if it's set..
38585 if (!this.rendered) {return ''};
38586 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38591 * Returns the current date value of the date field.
38592 * @return {Date} The date value
38594 getValue : function(){
38596 return this.hiddenField ?
38597 this.hiddenField.value :
38598 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38602 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38603 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38604 * (the default format used is "m/d/y").
38607 //All of these calls set the same date value (May 4, 2006)
38609 //Pass a date object:
38610 var dt = new Date('5/4/06');
38611 dateField.setValue(dt);
38613 //Pass a date string (default format):
38614 dateField.setValue('5/4/06');
38616 //Pass a date string (custom format):
38617 dateField.format = 'Y-m-d';
38618 dateField.setValue('2006-5-4');
38620 * @param {String/Date} date The date or valid date string
38622 setValue : function(date){
38623 if (this.hiddenField) {
38624 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38626 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38627 // make sure the value field is always stored as a date..
38628 this.value = this.parseDate(date);
38634 parseDate : function(value){
38635 if(!value || value instanceof Date){
38638 var v = Date.parseDate(value, this.format);
38639 if (!v && this.useIso) {
38640 v = Date.parseDate(value, 'Y-m-d');
38642 if(!v && this.altFormats){
38643 if(!this.altFormatsArray){
38644 this.altFormatsArray = this.altFormats.split("|");
38646 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38647 v = Date.parseDate(value, this.altFormatsArray[i]);
38654 formatDate : function(date, fmt){
38655 return (!date || !(date instanceof Date)) ?
38656 date : date.dateFormat(fmt || this.format);
38661 select: function(m, d){
38664 this.fireEvent('select', this, d);
38666 show : function(){ // retain focus styling
38670 this.focus.defer(10, this);
38671 var ml = this.menuListeners;
38672 this.menu.un("select", ml.select, this);
38673 this.menu.un("show", ml.show, this);
38674 this.menu.un("hide", ml.hide, this);
38679 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38680 onTriggerClick : function(){
38684 if(this.menu == null){
38685 this.menu = new Roo.menu.DateMenu();
38687 Roo.apply(this.menu.picker, {
38688 showClear: this.allowBlank,
38689 minDate : this.minValue,
38690 maxDate : this.maxValue,
38691 disabledDatesRE : this.ddMatch,
38692 disabledDatesText : this.disabledDatesText,
38693 disabledDays : this.disabledDays,
38694 disabledDaysText : this.disabledDaysText,
38695 format : this.useIso ? 'Y-m-d' : this.format,
38696 minText : String.format(this.minText, this.formatDate(this.minValue)),
38697 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38699 this.menu.on(Roo.apply({}, this.menuListeners, {
38702 this.menu.picker.setValue(this.getValue() || new Date());
38703 this.menu.show(this.el, "tl-bl?");
38706 beforeBlur : function(){
38707 var v = this.parseDate(this.getRawValue());
38717 isDirty : function() {
38718 if(this.disabled) {
38722 if(typeof(this.startValue) === 'undefined'){
38726 return String(this.getValue()) !== String(this.startValue);
38731 * Ext JS Library 1.1.1
38732 * Copyright(c) 2006-2007, Ext JS, LLC.
38734 * Originally Released Under LGPL - original licence link has changed is not relivant.
38737 * <script type="text/javascript">
38741 * @class Roo.form.MonthField
38742 * @extends Roo.form.TriggerField
38743 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38745 * Create a new MonthField
38746 * @param {Object} config
38748 Roo.form.MonthField = function(config){
38750 Roo.form.MonthField.superclass.constructor.call(this, config);
38756 * Fires when a date is selected
38757 * @param {Roo.form.MonthFieeld} combo This combo box
38758 * @param {Date} date The date selected
38765 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38766 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38767 this.ddMatch = null;
38768 if(this.disabledDates){
38769 var dd = this.disabledDates;
38771 for(var i = 0; i < dd.length; i++){
38773 if(i != dd.length-1) re += "|";
38775 this.ddMatch = new RegExp(re + ")");
38779 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38781 * @cfg {String} format
38782 * The default date format string which can be overriden for localization support. The format must be
38783 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38787 * @cfg {String} altFormats
38788 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38789 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38791 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38793 * @cfg {Array} disabledDays
38794 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38796 disabledDays : [0,1,2,3,4,5,6],
38798 * @cfg {String} disabledDaysText
38799 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38801 disabledDaysText : "Disabled",
38803 * @cfg {Array} disabledDates
38804 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38805 * expression so they are very powerful. Some examples:
38807 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38808 * <li>["03/08", "09/16"] would disable those days for every year</li>
38809 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38810 * <li>["03/../2006"] would disable every day in March 2006</li>
38811 * <li>["^03"] would disable every day in every March</li>
38813 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38814 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38816 disabledDates : null,
38818 * @cfg {String} disabledDatesText
38819 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38821 disabledDatesText : "Disabled",
38823 * @cfg {Date/String} minValue
38824 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38825 * valid format (defaults to null).
38829 * @cfg {Date/String} maxValue
38830 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38831 * valid format (defaults to null).
38835 * @cfg {String} minText
38836 * The error text to display when the date in the cell is before minValue (defaults to
38837 * 'The date in this field must be after {minValue}').
38839 minText : "The date in this field must be equal to or after {0}",
38841 * @cfg {String} maxTextf
38842 * The error text to display when the date in the cell is after maxValue (defaults to
38843 * 'The date in this field must be before {maxValue}').
38845 maxText : "The date in this field must be equal to or before {0}",
38847 * @cfg {String} invalidText
38848 * The error text to display when the date in the field is invalid (defaults to
38849 * '{value} is not a valid date - it must be in the format {format}').
38851 invalidText : "{0} is not a valid date - it must be in the format {1}",
38853 * @cfg {String} triggerClass
38854 * An additional CSS class used to style the trigger button. The trigger will always get the
38855 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38856 * which displays a calendar icon).
38858 triggerClass : 'x-form-date-trigger',
38862 * @cfg {Boolean} useIso
38863 * if enabled, then the date field will use a hidden field to store the
38864 * real value as iso formated date. default (true)
38868 * @cfg {String/Object} autoCreate
38869 * A DomHelper element spec, or true for a default element spec (defaults to
38870 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38873 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38876 hiddenField: false,
38878 hideMonthPicker : false,
38880 onRender : function(ct, position)
38882 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38884 this.el.dom.removeAttribute('name');
38885 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38887 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38888 // prevent input submission
38889 this.hiddenName = this.name;
38896 validateValue : function(value)
38898 value = this.formatDate(value);
38899 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38902 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38905 var svalue = value;
38906 value = this.parseDate(value);
38908 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38911 var time = value.getTime();
38912 if(this.minValue && time < this.minValue.getTime()){
38913 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38916 if(this.maxValue && time > this.maxValue.getTime()){
38917 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38920 /*if(this.disabledDays){
38921 var day = value.getDay();
38922 for(var i = 0; i < this.disabledDays.length; i++) {
38923 if(day === this.disabledDays[i]){
38924 this.markInvalid(this.disabledDaysText);
38930 var fvalue = this.formatDate(value);
38931 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38932 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38940 // Provides logic to override the default TriggerField.validateBlur which just returns true
38941 validateBlur : function(){
38942 return !this.menu || !this.menu.isVisible();
38946 * Returns the current date value of the date field.
38947 * @return {Date} The date value
38949 getValue : function(){
38953 return this.hiddenField ?
38954 this.hiddenField.value :
38955 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38959 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38960 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38961 * (the default format used is "m/d/y").
38964 //All of these calls set the same date value (May 4, 2006)
38966 //Pass a date object:
38967 var dt = new Date('5/4/06');
38968 monthField.setValue(dt);
38970 //Pass a date string (default format):
38971 monthField.setValue('5/4/06');
38973 //Pass a date string (custom format):
38974 monthField.format = 'Y-m-d';
38975 monthField.setValue('2006-5-4');
38977 * @param {String/Date} date The date or valid date string
38979 setValue : function(date){
38980 Roo.log('month setValue' + date);
38981 // can only be first of month..
38983 var val = this.parseDate(date);
38985 if (this.hiddenField) {
38986 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38988 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38989 this.value = this.parseDate(date);
38993 parseDate : function(value){
38994 if(!value || value instanceof Date){
38995 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38998 var v = Date.parseDate(value, this.format);
38999 if (!v && this.useIso) {
39000 v = Date.parseDate(value, 'Y-m-d');
39004 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39008 if(!v && this.altFormats){
39009 if(!this.altFormatsArray){
39010 this.altFormatsArray = this.altFormats.split("|");
39012 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39013 v = Date.parseDate(value, this.altFormatsArray[i]);
39020 formatDate : function(date, fmt){
39021 return (!date || !(date instanceof Date)) ?
39022 date : date.dateFormat(fmt || this.format);
39027 select: function(m, d){
39029 this.fireEvent('select', this, d);
39031 show : function(){ // retain focus styling
39035 this.focus.defer(10, this);
39036 var ml = this.menuListeners;
39037 this.menu.un("select", ml.select, this);
39038 this.menu.un("show", ml.show, this);
39039 this.menu.un("hide", ml.hide, this);
39043 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39044 onTriggerClick : function(){
39048 if(this.menu == null){
39049 this.menu = new Roo.menu.DateMenu();
39053 Roo.apply(this.menu.picker, {
39055 showClear: this.allowBlank,
39056 minDate : this.minValue,
39057 maxDate : this.maxValue,
39058 disabledDatesRE : this.ddMatch,
39059 disabledDatesText : this.disabledDatesText,
39061 format : this.useIso ? 'Y-m-d' : this.format,
39062 minText : String.format(this.minText, this.formatDate(this.minValue)),
39063 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39066 this.menu.on(Roo.apply({}, this.menuListeners, {
39074 // hide month picker get's called when we called by 'before hide';
39076 var ignorehide = true;
39077 p.hideMonthPicker = function(disableAnim){
39081 if(this.monthPicker){
39082 Roo.log("hideMonthPicker called");
39083 if(disableAnim === true){
39084 this.monthPicker.hide();
39086 this.monthPicker.slideOut('t', {duration:.2});
39087 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39088 p.fireEvent("select", this, this.value);
39094 Roo.log('picker set value');
39095 Roo.log(this.getValue());
39096 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39097 m.show(this.el, 'tl-bl?');
39098 ignorehide = false;
39099 // this will trigger hideMonthPicker..
39102 // hidden the day picker
39103 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39109 p.showMonthPicker.defer(100, p);
39115 beforeBlur : function(){
39116 var v = this.parseDate(this.getRawValue());
39122 /** @cfg {Boolean} grow @hide */
39123 /** @cfg {Number} growMin @hide */
39124 /** @cfg {Number} growMax @hide */
39131 * Ext JS Library 1.1.1
39132 * Copyright(c) 2006-2007, Ext JS, LLC.
39134 * Originally Released Under LGPL - original licence link has changed is not relivant.
39137 * <script type="text/javascript">
39142 * @class Roo.form.ComboBox
39143 * @extends Roo.form.TriggerField
39144 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39146 * Create a new ComboBox.
39147 * @param {Object} config Configuration options
39149 Roo.form.ComboBox = function(config){
39150 Roo.form.ComboBox.superclass.constructor.call(this, config);
39154 * Fires when the dropdown list is expanded
39155 * @param {Roo.form.ComboBox} combo This combo box
39160 * Fires when the dropdown list is collapsed
39161 * @param {Roo.form.ComboBox} combo This combo box
39165 * @event beforeselect
39166 * Fires before a list item is selected. Return false to cancel the selection.
39167 * @param {Roo.form.ComboBox} combo This combo box
39168 * @param {Roo.data.Record} record The data record returned from the underlying store
39169 * @param {Number} index The index of the selected item in the dropdown list
39171 'beforeselect' : true,
39174 * Fires when a list item is selected
39175 * @param {Roo.form.ComboBox} combo This combo box
39176 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39177 * @param {Number} index The index of the selected item in the dropdown list
39181 * @event beforequery
39182 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39183 * The event object passed has these properties:
39184 * @param {Roo.form.ComboBox} combo This combo box
39185 * @param {String} query The query
39186 * @param {Boolean} forceAll true to force "all" query
39187 * @param {Boolean} cancel true to cancel the query
39188 * @param {Object} e The query event object
39190 'beforequery': true,
39193 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39194 * @param {Roo.form.ComboBox} combo This combo box
39199 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39200 * @param {Roo.form.ComboBox} combo This combo box
39201 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39207 if(this.transform){
39208 this.allowDomMove = false;
39209 var s = Roo.getDom(this.transform);
39210 if(!this.hiddenName){
39211 this.hiddenName = s.name;
39214 this.mode = 'local';
39215 var d = [], opts = s.options;
39216 for(var i = 0, len = opts.length;i < len; i++){
39218 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39220 this.value = value;
39222 d.push([value, o.text]);
39224 this.store = new Roo.data.SimpleStore({
39226 fields: ['value', 'text'],
39229 this.valueField = 'value';
39230 this.displayField = 'text';
39232 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39233 if(!this.lazyRender){
39234 this.target = true;
39235 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39236 s.parentNode.removeChild(s); // remove it
39237 this.render(this.el.parentNode);
39239 s.parentNode.removeChild(s); // remove it
39244 this.store = Roo.factory(this.store, Roo.data);
39247 this.selectedIndex = -1;
39248 if(this.mode == 'local'){
39249 if(config.queryDelay === undefined){
39250 this.queryDelay = 10;
39252 if(config.minChars === undefined){
39258 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39260 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39263 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39264 * rendering into an Roo.Editor, defaults to false)
39267 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39268 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39271 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39274 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39275 * the dropdown list (defaults to undefined, with no header element)
39279 * @cfg {String/Roo.Template} tpl The template to use to render the output
39283 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39285 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39287 listWidth: undefined,
39289 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39290 * mode = 'remote' or 'text' if mode = 'local')
39292 displayField: undefined,
39294 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39295 * mode = 'remote' or 'value' if mode = 'local').
39296 * Note: use of a valueField requires the user make a selection
39297 * in order for a value to be mapped.
39299 valueField: undefined,
39303 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39304 * field's data value (defaults to the underlying DOM element's name)
39306 hiddenName: undefined,
39308 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39312 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39314 selectedClass: 'x-combo-selected',
39316 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39317 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39318 * which displays a downward arrow icon).
39320 triggerClass : 'x-form-arrow-trigger',
39322 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39326 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39327 * anchor positions (defaults to 'tl-bl')
39329 listAlign: 'tl-bl?',
39331 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39335 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39336 * query specified by the allQuery config option (defaults to 'query')
39338 triggerAction: 'query',
39340 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39341 * (defaults to 4, does not apply if editable = false)
39345 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39346 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39350 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39351 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39355 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39356 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39360 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39361 * when editable = true (defaults to false)
39363 selectOnFocus:false,
39365 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39367 queryParam: 'query',
39369 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39370 * when mode = 'remote' (defaults to 'Loading...')
39372 loadingText: 'Loading...',
39374 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39378 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39382 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39383 * traditional select (defaults to true)
39387 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39391 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39395 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39396 * listWidth has a higher value)
39400 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39401 * allow the user to set arbitrary text into the field (defaults to false)
39403 forceSelection:false,
39405 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39406 * if typeAhead = true (defaults to 250)
39408 typeAheadDelay : 250,
39410 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39411 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39413 valueNotFoundText : undefined,
39415 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39417 blockFocus : false,
39420 * @cfg {Boolean} disableClear Disable showing of clear button.
39422 disableClear : false,
39424 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39426 alwaysQuery : false,
39432 // element that contains real text value.. (when hidden is used..)
39435 onRender : function(ct, position){
39436 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39437 if(this.hiddenName){
39438 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39440 this.hiddenField.value =
39441 this.hiddenValue !== undefined ? this.hiddenValue :
39442 this.value !== undefined ? this.value : '';
39444 // prevent input submission
39445 this.el.dom.removeAttribute('name');
39450 this.el.dom.setAttribute('autocomplete', 'off');
39453 var cls = 'x-combo-list';
39455 this.list = new Roo.Layer({
39456 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39459 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39460 this.list.setWidth(lw);
39461 this.list.swallowEvent('mousewheel');
39462 this.assetHeight = 0;
39465 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39466 this.assetHeight += this.header.getHeight();
39469 this.innerList = this.list.createChild({cls:cls+'-inner'});
39470 this.innerList.on('mouseover', this.onViewOver, this);
39471 this.innerList.on('mousemove', this.onViewMove, this);
39472 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39474 if(this.allowBlank && !this.pageSize && !this.disableClear){
39475 this.footer = this.list.createChild({cls:cls+'-ft'});
39476 this.pageTb = new Roo.Toolbar(this.footer);
39480 this.footer = this.list.createChild({cls:cls+'-ft'});
39481 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39482 {pageSize: this.pageSize});
39486 if (this.pageTb && this.allowBlank && !this.disableClear) {
39488 this.pageTb.add(new Roo.Toolbar.Fill(), {
39489 cls: 'x-btn-icon x-btn-clear',
39491 handler: function()
39494 _this.clearValue();
39495 _this.onSelect(false, -1);
39500 this.assetHeight += this.footer.getHeight();
39505 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39508 this.view = new Roo.View(this.innerList, this.tpl, {
39509 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39512 this.view.on('click', this.onViewClick, this);
39514 this.store.on('beforeload', this.onBeforeLoad, this);
39515 this.store.on('load', this.onLoad, this);
39516 this.store.on('loadexception', this.onLoadException, this);
39518 if(this.resizable){
39519 this.resizer = new Roo.Resizable(this.list, {
39520 pinned:true, handles:'se'
39522 this.resizer.on('resize', function(r, w, h){
39523 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39524 this.listWidth = w;
39525 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39526 this.restrictHeight();
39528 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39530 if(!this.editable){
39531 this.editable = true;
39532 this.setEditable(false);
39536 if (typeof(this.events.add.listeners) != 'undefined') {
39538 this.addicon = this.wrap.createChild(
39539 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39541 this.addicon.on('click', function(e) {
39542 this.fireEvent('add', this);
39545 if (typeof(this.events.edit.listeners) != 'undefined') {
39547 this.editicon = this.wrap.createChild(
39548 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39549 if (this.addicon) {
39550 this.editicon.setStyle('margin-left', '40px');
39552 this.editicon.on('click', function(e) {
39554 // we fire even if inothing is selected..
39555 this.fireEvent('edit', this, this.lastData );
39565 initEvents : function(){
39566 Roo.form.ComboBox.superclass.initEvents.call(this);
39568 this.keyNav = new Roo.KeyNav(this.el, {
39569 "up" : function(e){
39570 this.inKeyMode = true;
39574 "down" : function(e){
39575 if(!this.isExpanded()){
39576 this.onTriggerClick();
39578 this.inKeyMode = true;
39583 "enter" : function(e){
39584 this.onViewClick();
39588 "esc" : function(e){
39592 "tab" : function(e){
39593 this.onViewClick(false);
39594 this.fireEvent("specialkey", this, e);
39600 doRelay : function(foo, bar, hname){
39601 if(hname == 'down' || this.scope.isExpanded()){
39602 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39609 this.queryDelay = Math.max(this.queryDelay || 10,
39610 this.mode == 'local' ? 10 : 250);
39611 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39612 if(this.typeAhead){
39613 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39615 if(this.editable !== false){
39616 this.el.on("keyup", this.onKeyUp, this);
39618 if(this.forceSelection){
39619 this.on('blur', this.doForce, this);
39623 onDestroy : function(){
39625 this.view.setStore(null);
39626 this.view.el.removeAllListeners();
39627 this.view.el.remove();
39628 this.view.purgeListeners();
39631 this.list.destroy();
39634 this.store.un('beforeload', this.onBeforeLoad, this);
39635 this.store.un('load', this.onLoad, this);
39636 this.store.un('loadexception', this.onLoadException, this);
39638 Roo.form.ComboBox.superclass.onDestroy.call(this);
39642 fireKey : function(e){
39643 if(e.isNavKeyPress() && !this.list.isVisible()){
39644 this.fireEvent("specialkey", this, e);
39649 onResize: function(w, h){
39650 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39652 if(typeof w != 'number'){
39653 // we do not handle it!?!?
39656 var tw = this.trigger.getWidth();
39657 tw += this.addicon ? this.addicon.getWidth() : 0;
39658 tw += this.editicon ? this.editicon.getWidth() : 0;
39660 this.el.setWidth( this.adjustWidth('input', x));
39662 this.trigger.setStyle('left', x+'px');
39664 if(this.list && this.listWidth === undefined){
39665 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39666 this.list.setWidth(lw);
39667 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39675 * Allow or prevent the user from directly editing the field text. If false is passed,
39676 * the user will only be able to select from the items defined in the dropdown list. This method
39677 * is the runtime equivalent of setting the 'editable' config option at config time.
39678 * @param {Boolean} value True to allow the user to directly edit the field text
39680 setEditable : function(value){
39681 if(value == this.editable){
39684 this.editable = value;
39686 this.el.dom.setAttribute('readOnly', true);
39687 this.el.on('mousedown', this.onTriggerClick, this);
39688 this.el.addClass('x-combo-noedit');
39690 this.el.dom.setAttribute('readOnly', false);
39691 this.el.un('mousedown', this.onTriggerClick, this);
39692 this.el.removeClass('x-combo-noedit');
39697 onBeforeLoad : function(){
39698 if(!this.hasFocus){
39701 this.innerList.update(this.loadingText ?
39702 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39703 this.restrictHeight();
39704 this.selectedIndex = -1;
39708 onLoad : function(){
39709 if(!this.hasFocus){
39712 if(this.store.getCount() > 0){
39714 this.restrictHeight();
39715 if(this.lastQuery == this.allQuery){
39717 this.el.dom.select();
39719 if(!this.selectByValue(this.value, true)){
39720 this.select(0, true);
39724 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39725 this.taTask.delay(this.typeAheadDelay);
39729 this.onEmptyResults();
39734 onLoadException : function()
39737 Roo.log(this.store.reader.jsonData);
39738 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39739 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39745 onTypeAhead : function(){
39746 if(this.store.getCount() > 0){
39747 var r = this.store.getAt(0);
39748 var newValue = r.data[this.displayField];
39749 var len = newValue.length;
39750 var selStart = this.getRawValue().length;
39751 if(selStart != len){
39752 this.setRawValue(newValue);
39753 this.selectText(selStart, newValue.length);
39759 onSelect : function(record, index){
39760 if(this.fireEvent('beforeselect', this, record, index) !== false){
39761 this.setFromData(index > -1 ? record.data : false);
39763 this.fireEvent('select', this, record, index);
39768 * Returns the currently selected field value or empty string if no value is set.
39769 * @return {String} value The selected value
39771 getValue : function(){
39772 if(this.valueField){
39773 return typeof this.value != 'undefined' ? this.value : '';
39775 return Roo.form.ComboBox.superclass.getValue.call(this);
39780 * Clears any text/value currently set in the field
39782 clearValue : function(){
39783 if(this.hiddenField){
39784 this.hiddenField.value = '';
39787 this.setRawValue('');
39788 this.lastSelectionText = '';
39793 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39794 * will be displayed in the field. If the value does not match the data value of an existing item,
39795 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39796 * Otherwise the field will be blank (although the value will still be set).
39797 * @param {String} value The value to match
39799 setValue : function(v){
39801 if(this.valueField){
39802 var r = this.findRecord(this.valueField, v);
39804 text = r.data[this.displayField];
39805 }else if(this.valueNotFoundText !== undefined){
39806 text = this.valueNotFoundText;
39809 this.lastSelectionText = text;
39810 if(this.hiddenField){
39811 this.hiddenField.value = v;
39813 Roo.form.ComboBox.superclass.setValue.call(this, text);
39817 * @property {Object} the last set data for the element
39822 * Sets the value of the field based on a object which is related to the record format for the store.
39823 * @param {Object} value the value to set as. or false on reset?
39825 setFromData : function(o){
39826 var dv = ''; // display value
39827 var vv = ''; // value value..
39829 if (this.displayField) {
39830 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39832 // this is an error condition!!!
39833 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39836 if(this.valueField){
39837 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39839 if(this.hiddenField){
39840 this.hiddenField.value = vv;
39842 this.lastSelectionText = dv;
39843 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39847 // no hidden field.. - we store the value in 'value', but still display
39848 // display field!!!!
39849 this.lastSelectionText = dv;
39850 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39856 reset : function(){
39857 // overridden so that last data is reset..
39858 this.setValue(this.resetValue);
39859 this.clearInvalid();
39860 this.lastData = false;
39862 this.view.clearSelections();
39866 findRecord : function(prop, value){
39868 if(this.store.getCount() > 0){
39869 this.store.each(function(r){
39870 if(r.data[prop] == value){
39880 getName: function()
39882 // returns hidden if it's set..
39883 if (!this.rendered) {return ''};
39884 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39888 onViewMove : function(e, t){
39889 this.inKeyMode = false;
39893 onViewOver : function(e, t){
39894 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39897 var item = this.view.findItemFromChild(t);
39899 var index = this.view.indexOf(item);
39900 this.select(index, false);
39905 onViewClick : function(doFocus)
39907 var index = this.view.getSelectedIndexes()[0];
39908 var r = this.store.getAt(index);
39910 this.onSelect(r, index);
39912 if(doFocus !== false && !this.blockFocus){
39918 restrictHeight : function(){
39919 this.innerList.dom.style.height = '';
39920 var inner = this.innerList.dom;
39921 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39922 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39923 this.list.beginUpdate();
39924 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39925 this.list.alignTo(this.el, this.listAlign);
39926 this.list.endUpdate();
39930 onEmptyResults : function(){
39935 * Returns true if the dropdown list is expanded, else false.
39937 isExpanded : function(){
39938 return this.list.isVisible();
39942 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39943 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39944 * @param {String} value The data value of the item to select
39945 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39946 * selected item if it is not currently in view (defaults to true)
39947 * @return {Boolean} True if the value matched an item in the list, else false
39949 selectByValue : function(v, scrollIntoView){
39950 if(v !== undefined && v !== null){
39951 var r = this.findRecord(this.valueField || this.displayField, v);
39953 this.select(this.store.indexOf(r), scrollIntoView);
39961 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39962 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39963 * @param {Number} index The zero-based index of the list item to select
39964 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39965 * selected item if it is not currently in view (defaults to true)
39967 select : function(index, scrollIntoView){
39968 this.selectedIndex = index;
39969 this.view.select(index);
39970 if(scrollIntoView !== false){
39971 var el = this.view.getNode(index);
39973 this.innerList.scrollChildIntoView(el, false);
39979 selectNext : function(){
39980 var ct = this.store.getCount();
39982 if(this.selectedIndex == -1){
39984 }else if(this.selectedIndex < ct-1){
39985 this.select(this.selectedIndex+1);
39991 selectPrev : function(){
39992 var ct = this.store.getCount();
39994 if(this.selectedIndex == -1){
39996 }else if(this.selectedIndex != 0){
39997 this.select(this.selectedIndex-1);
40003 onKeyUp : function(e){
40004 if(this.editable !== false && !e.isSpecialKey()){
40005 this.lastKey = e.getKey();
40006 this.dqTask.delay(this.queryDelay);
40011 validateBlur : function(){
40012 return !this.list || !this.list.isVisible();
40016 initQuery : function(){
40017 this.doQuery(this.getRawValue());
40021 doForce : function(){
40022 if(this.el.dom.value.length > 0){
40023 this.el.dom.value =
40024 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40030 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40031 * query allowing the query action to be canceled if needed.
40032 * @param {String} query The SQL query to execute
40033 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40034 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40035 * saved in the current store (defaults to false)
40037 doQuery : function(q, forceAll){
40038 if(q === undefined || q === null){
40043 forceAll: forceAll,
40047 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40051 forceAll = qe.forceAll;
40052 if(forceAll === true || (q.length >= this.minChars)){
40053 if(this.lastQuery != q || this.alwaysQuery){
40054 this.lastQuery = q;
40055 if(this.mode == 'local'){
40056 this.selectedIndex = -1;
40058 this.store.clearFilter();
40060 this.store.filter(this.displayField, q);
40064 this.store.baseParams[this.queryParam] = q;
40066 params: this.getParams(q)
40071 this.selectedIndex = -1;
40078 getParams : function(q){
40080 //p[this.queryParam] = q;
40083 p.limit = this.pageSize;
40089 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40091 collapse : function(){
40092 if(!this.isExpanded()){
40096 Roo.get(document).un('mousedown', this.collapseIf, this);
40097 Roo.get(document).un('mousewheel', this.collapseIf, this);
40098 if (!this.editable) {
40099 Roo.get(document).un('keydown', this.listKeyPress, this);
40101 this.fireEvent('collapse', this);
40105 collapseIf : function(e){
40106 if(!e.within(this.wrap) && !e.within(this.list)){
40112 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40114 expand : function(){
40115 if(this.isExpanded() || !this.hasFocus){
40118 this.list.alignTo(this.el, this.listAlign);
40120 Roo.get(document).on('mousedown', this.collapseIf, this);
40121 Roo.get(document).on('mousewheel', this.collapseIf, this);
40122 if (!this.editable) {
40123 Roo.get(document).on('keydown', this.listKeyPress, this);
40126 this.fireEvent('expand', this);
40130 // Implements the default empty TriggerField.onTriggerClick function
40131 onTriggerClick : function(){
40135 if(this.isExpanded()){
40137 if (!this.blockFocus) {
40142 this.hasFocus = true;
40143 if(this.triggerAction == 'all') {
40144 this.doQuery(this.allQuery, true);
40146 this.doQuery(this.getRawValue());
40148 if (!this.blockFocus) {
40153 listKeyPress : function(e)
40155 //Roo.log('listkeypress');
40156 // scroll to first matching element based on key pres..
40157 if (e.isSpecialKey()) {
40160 var k = String.fromCharCode(e.getKey()).toUpperCase();
40163 var csel = this.view.getSelectedNodes();
40164 var cselitem = false;
40166 var ix = this.view.indexOf(csel[0]);
40167 cselitem = this.store.getAt(ix);
40168 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40174 this.store.each(function(v) {
40176 // start at existing selection.
40177 if (cselitem.id == v.id) {
40183 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40184 match = this.store.indexOf(v);
40189 if (match === false) {
40190 return true; // no more action?
40193 this.view.select(match);
40194 var sn = Roo.get(this.view.getSelectedNodes()[0])
40195 sn.scrollIntoView(sn.dom.parentNode, false);
40199 * @cfg {Boolean} grow
40203 * @cfg {Number} growMin
40207 * @cfg {Number} growMax
40215 * Copyright(c) 2010-2012, Roo J Solutions Limited
40222 * @class Roo.form.ComboBoxArray
40223 * @extends Roo.form.TextField
40224 * A facebook style adder... for lists of email / people / countries etc...
40225 * pick multiple items from a combo box, and shows each one.
40227 * Fred [x] Brian [x] [Pick another |v]
40230 * For this to work: it needs various extra information
40231 * - normal combo problay has
40233 * + displayField, valueField
40235 * For our purpose...
40238 * If we change from 'extends' to wrapping...
40245 * Create a new ComboBoxArray.
40246 * @param {Object} config Configuration options
40250 Roo.form.ComboBoxArray = function(config)
40255 * Fires when remove the value from the list
40256 * @param {Roo.form.ComboBoxArray} _self This combo box array
40257 * @param {Roo.form.ComboBoxArray.Item} item removed item
40264 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40266 this.items = new Roo.util.MixedCollection(false);
40268 // construct the child combo...
40278 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40281 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40286 // behavies liek a hiddne field
40287 inputType: 'hidden',
40289 * @cfg {Number} width The width of the box that displays the selected element
40296 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40300 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40302 hiddenName : false,
40305 // private the array of items that are displayed..
40307 // private - the hidden field el.
40309 // private - the filed el..
40312 //validateValue : function() { return true; }, // all values are ok!
40313 //onAddClick: function() { },
40315 onRender : function(ct, position)
40318 // create the standard hidden element
40319 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40322 // give fake names to child combo;
40323 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40324 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40326 this.combo = Roo.factory(this.combo, Roo.form);
40327 this.combo.onRender(ct, position);
40328 if (typeof(this.combo.width) != 'undefined') {
40329 this.combo.onResize(this.combo.width,0);
40332 this.combo.initEvents();
40334 // assigned so form know we need to do this..
40335 this.store = this.combo.store;
40336 this.valueField = this.combo.valueField;
40337 this.displayField = this.combo.displayField ;
40340 this.combo.wrap.addClass('x-cbarray-grp');
40342 var cbwrap = this.combo.wrap.createChild(
40343 {tag: 'div', cls: 'x-cbarray-cb'},
40348 this.hiddenEl = this.combo.wrap.createChild({
40349 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40351 this.el = this.combo.wrap.createChild({
40352 tag: 'input', type:'hidden' , name: this.name, value : ''
40354 // this.el.dom.removeAttribute("name");
40357 this.outerWrap = this.combo.wrap;
40358 this.wrap = cbwrap;
40360 this.outerWrap.setWidth(this.width);
40361 this.outerWrap.dom.removeChild(this.el.dom);
40363 this.wrap.dom.appendChild(this.el.dom);
40364 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40365 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40367 this.combo.trigger.setStyle('position','relative');
40368 this.combo.trigger.setStyle('left', '0px');
40369 this.combo.trigger.setStyle('top', '2px');
40371 this.combo.el.setStyle('vertical-align', 'text-bottom');
40373 //this.trigger.setStyle('vertical-align', 'top');
40375 // this should use the code from combo really... on('add' ....)
40379 this.adder = this.outerWrap.createChild(
40380 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40382 this.adder.on('click', function(e) {
40383 _t.fireEvent('adderclick', this, e);
40387 //this.adder.on('click', this.onAddClick, _t);
40390 this.combo.on('select', function(cb, rec, ix) {
40391 this.addItem(rec.data);
40394 cb.el.dom.value = '';
40395 //cb.lastData = rec.data;
40404 getName: function()
40406 // returns hidden if it's set..
40407 if (!this.rendered) {return ''};
40408 return this.hiddenName ? this.hiddenName : this.name;
40413 onResize: function(w, h){
40416 // not sure if this is needed..
40417 //this.combo.onResize(w,h);
40419 if(typeof w != 'number'){
40420 // we do not handle it!?!?
40423 var tw = this.combo.trigger.getWidth();
40424 tw += this.addicon ? this.addicon.getWidth() : 0;
40425 tw += this.editicon ? this.editicon.getWidth() : 0;
40427 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40429 this.combo.trigger.setStyle('left', '0px');
40431 if(this.list && this.listWidth === undefined){
40432 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40433 this.list.setWidth(lw);
40434 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40441 addItem: function(rec)
40443 var valueField = this.combo.valueField;
40444 var displayField = this.combo.displayField;
40445 if (this.items.indexOfKey(rec[valueField]) > -1) {
40446 //console.log("GOT " + rec.data.id);
40450 var x = new Roo.form.ComboBoxArray.Item({
40451 //id : rec[this.idField],
40453 displayField : displayField ,
40454 tipField : displayField ,
40458 this.items.add(rec[valueField],x);
40459 // add it before the element..
40460 this.updateHiddenEl();
40461 x.render(this.outerWrap, this.wrap.dom);
40462 // add the image handler..
40465 updateHiddenEl : function()
40468 if (!this.hiddenEl) {
40472 var idField = this.combo.valueField;
40474 this.items.each(function(f) {
40475 ar.push(f.data[idField]);
40478 this.hiddenEl.dom.value = ar.join(',');
40484 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40485 this.items.each(function(f) {
40488 this.el.dom.value = '';
40489 if (this.hiddenEl) {
40490 this.hiddenEl.dom.value = '';
40494 getValue: function()
40496 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40498 setValue: function(v) // not a valid action - must use addItems..
40505 if (this.store.isLocal && (typeof(v) == 'string')) {
40506 // then we can use the store to find the values..
40507 // comma seperated at present.. this needs to allow JSON based encoding..
40508 this.hiddenEl.value = v;
40510 Roo.each(v.split(','), function(k) {
40511 Roo.log("CHECK " + this.valueField + ',' + k);
40512 var li = this.store.query(this.valueField, k);
40517 add[this.valueField] = k;
40518 add[this.displayField] = li.item(0).data[this.displayField];
40524 if (typeof(v) == 'object') {
40525 // then let's assume it's an array of objects..
40526 Roo.each(v, function(l) {
40534 setFromData: function(v)
40536 // this recieves an object, if setValues is called.
40538 this.el.dom.value = v[this.displayField];
40539 this.hiddenEl.dom.value = v[this.valueField];
40540 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40543 var kv = v[this.valueField];
40544 var dv = v[this.displayField];
40545 kv = typeof(kv) != 'string' ? '' : kv;
40546 dv = typeof(dv) != 'string' ? '' : dv;
40549 var keys = kv.split(',');
40550 var display = dv.split(',');
40551 for (var i = 0 ; i < keys.length; i++) {
40554 add[this.valueField] = keys[i];
40555 add[this.displayField] = display[i];
40563 * Validates the combox array value
40564 * @return {Boolean} True if the value is valid, else false
40566 validate : function(){
40567 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40568 this.clearInvalid();
40574 validateValue : function(value){
40575 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40583 isDirty : function() {
40584 if(this.disabled) {
40589 var d = Roo.decode(String(this.originalValue));
40591 return String(this.getValue()) !== String(this.originalValue);
40594 var originalValue = [];
40596 for (var i = 0; i < d.length; i++){
40597 originalValue.push(d[i][this.valueField]);
40600 return String(this.getValue()) !== String(originalValue.join(','));
40609 * @class Roo.form.ComboBoxArray.Item
40610 * @extends Roo.BoxComponent
40611 * A selected item in the list
40612 * Fred [x] Brian [x] [Pick another |v]
40615 * Create a new item.
40616 * @param {Object} config Configuration options
40619 Roo.form.ComboBoxArray.Item = function(config) {
40620 config.id = Roo.id();
40621 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40624 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40627 displayField : false,
40631 defaultAutoCreate : {
40633 cls: 'x-cbarray-item',
40640 src : Roo.BLANK_IMAGE_URL ,
40648 onRender : function(ct, position)
40650 Roo.form.Field.superclass.onRender.call(this, ct, position);
40653 var cfg = this.getAutoCreate();
40654 this.el = ct.createChild(cfg, position);
40657 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40659 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40660 this.cb.renderer(this.data) :
40661 String.format('{0}',this.data[this.displayField]);
40664 this.el.child('div').dom.setAttribute('qtip',
40665 String.format('{0}',this.data[this.tipField])
40668 this.el.child('img').on('click', this.remove, this);
40672 remove : function()
40674 this.cb.items.remove(this);
40675 this.el.child('img').un('click', this.remove, this);
40677 this.cb.updateHiddenEl();
40679 this.cb.fireEvent('remove', this.cb, this);
40683 * Ext JS Library 1.1.1
40684 * Copyright(c) 2006-2007, Ext JS, LLC.
40686 * Originally Released Under LGPL - original licence link has changed is not relivant.
40689 * <script type="text/javascript">
40692 * @class Roo.form.Checkbox
40693 * @extends Roo.form.Field
40694 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40696 * Creates a new Checkbox
40697 * @param {Object} config Configuration options
40699 Roo.form.Checkbox = function(config){
40700 Roo.form.Checkbox.superclass.constructor.call(this, config);
40704 * Fires when the checkbox is checked or unchecked.
40705 * @param {Roo.form.Checkbox} this This checkbox
40706 * @param {Boolean} checked The new checked value
40712 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40714 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40716 focusClass : undefined,
40718 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40720 fieldClass: "x-form-field",
40722 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40726 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40727 * {tag: "input", type: "checkbox", autocomplete: "off"})
40729 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40731 * @cfg {String} boxLabel The text that appears beside the checkbox
40735 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40739 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40741 valueOff: '0', // value when not checked..
40743 actionMode : 'viewEl',
40746 itemCls : 'x-menu-check-item x-form-item',
40747 groupClass : 'x-menu-group-item',
40748 inputType : 'hidden',
40751 inSetChecked: false, // check that we are not calling self...
40753 inputElement: false, // real input element?
40754 basedOn: false, // ????
40756 isFormField: true, // not sure where this is needed!!!!
40758 onResize : function(){
40759 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40760 if(!this.boxLabel){
40761 this.el.alignTo(this.wrap, 'c-c');
40765 initEvents : function(){
40766 Roo.form.Checkbox.superclass.initEvents.call(this);
40767 this.el.on("click", this.onClick, this);
40768 this.el.on("change", this.onClick, this);
40772 getResizeEl : function(){
40776 getPositionEl : function(){
40781 onRender : function(ct, position){
40782 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40784 if(this.inputValue !== undefined){
40785 this.el.dom.value = this.inputValue;
40788 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40789 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40790 var viewEl = this.wrap.createChild({
40791 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40792 this.viewEl = viewEl;
40793 this.wrap.on('click', this.onClick, this);
40795 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40796 this.el.on('propertychange', this.setFromHidden, this); //ie
40801 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40802 // viewEl.on('click', this.onClick, this);
40804 //if(this.checked){
40805 this.setChecked(this.checked);
40807 //this.checked = this.el.dom;
40813 initValue : Roo.emptyFn,
40816 * Returns the checked state of the checkbox.
40817 * @return {Boolean} True if checked, else false
40819 getValue : function(){
40821 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40823 return this.valueOff;
40828 onClick : function(){
40829 this.setChecked(!this.checked);
40831 //if(this.el.dom.checked != this.checked){
40832 // this.setValue(this.el.dom.checked);
40837 * Sets the checked state of the checkbox.
40838 * On is always based on a string comparison between inputValue and the param.
40839 * @param {Boolean/String} value - the value to set
40840 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40842 setValue : function(v,suppressEvent){
40845 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40846 //if(this.el && this.el.dom){
40847 // this.el.dom.checked = this.checked;
40848 // this.el.dom.defaultChecked = this.checked;
40850 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40851 //this.fireEvent("check", this, this.checked);
40854 setChecked : function(state,suppressEvent)
40856 if (this.inSetChecked) {
40857 this.checked = state;
40863 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40865 this.checked = state;
40866 if(suppressEvent !== true){
40867 this.fireEvent('check', this, state);
40869 this.inSetChecked = true;
40870 this.el.dom.value = state ? this.inputValue : this.valueOff;
40871 this.inSetChecked = false;
40874 // handle setting of hidden value by some other method!!?!?
40875 setFromHidden: function()
40880 //console.log("SET FROM HIDDEN");
40881 //alert('setFrom hidden');
40882 this.setValue(this.el.dom.value);
40885 onDestroy : function()
40888 Roo.get(this.viewEl).remove();
40891 Roo.form.Checkbox.superclass.onDestroy.call(this);
40896 * Ext JS Library 1.1.1
40897 * Copyright(c) 2006-2007, Ext JS, LLC.
40899 * Originally Released Under LGPL - original licence link has changed is not relivant.
40902 * <script type="text/javascript">
40906 * @class Roo.form.Radio
40907 * @extends Roo.form.Checkbox
40908 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40909 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40911 * Creates a new Radio
40912 * @param {Object} config Configuration options
40914 Roo.form.Radio = function(){
40915 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40917 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40918 inputType: 'radio',
40921 * If this radio is part of a group, it will return the selected value
40924 getGroupValue : function(){
40925 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40929 onRender : function(ct, position){
40930 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40932 if(this.inputValue !== undefined){
40933 this.el.dom.value = this.inputValue;
40936 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40937 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40938 //var viewEl = this.wrap.createChild({
40939 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40940 //this.viewEl = viewEl;
40941 //this.wrap.on('click', this.onClick, this);
40943 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40944 //this.el.on('propertychange', this.setFromHidden, this); //ie
40949 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40950 // viewEl.on('click', this.onClick, this);
40953 this.el.dom.checked = 'checked' ;
40959 });//<script type="text/javascript">
40962 * Based Ext JS Library 1.1.1
40963 * Copyright(c) 2006-2007, Ext JS, LLC.
40969 * @class Roo.HtmlEditorCore
40970 * @extends Roo.Component
40971 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
40973 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40976 Roo.HtmlEditorCore = function(config){
40979 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
40982 * @event initialize
40983 * Fires when the editor is fully initialized (including the iframe)
40984 * @param {Roo.HtmlEditorCore} this
40989 * Fires when the editor is first receives the focus. Any insertion must wait
40990 * until after this event.
40991 * @param {Roo.HtmlEditorCore} this
40995 * @event beforesync
40996 * Fires before the textarea is updated with content from the editor iframe. Return false
40997 * to cancel the sync.
40998 * @param {Roo.HtmlEditorCore} this
40999 * @param {String} html
41003 * @event beforepush
41004 * Fires before the iframe editor is updated with content from the textarea. Return false
41005 * to cancel the push.
41006 * @param {Roo.HtmlEditorCore} this
41007 * @param {String} html
41012 * Fires when the textarea is updated with content from the editor iframe.
41013 * @param {Roo.HtmlEditorCore} this
41014 * @param {String} html
41019 * Fires when the iframe editor is updated with content from the textarea.
41020 * @param {Roo.HtmlEditorCore} this
41021 * @param {String} html
41026 * @event editorevent
41027 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41028 * @param {Roo.HtmlEditorCore} this
41036 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41040 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41046 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41051 * @cfg {Number} height (in pixels)
41055 * @cfg {Number} width (in pixels)
41060 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41063 stylesheets: false,
41068 // private properties
41069 validationEvent : false,
41071 initialized : false,
41073 sourceEditMode : false,
41074 onFocus : Roo.emptyFn,
41076 hideMode:'offsets',
41084 * Protected method that will not generally be called directly. It
41085 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41086 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41088 getDocMarkup : function(){
41091 Roo.log(this.stylesheets);
41093 // inherit styels from page...??
41094 if (this.stylesheets === false) {
41096 Roo.get(document.head).select('style').each(function(node) {
41097 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41100 Roo.get(document.head).select('link').each(function(node) {
41101 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41104 } else if (!this.stylesheets.length) {
41106 st = '<style type="text/css">' +
41107 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41110 Roo.each(this.stylesheets, function(s) {
41111 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
41116 st += '<style type="text/css">' +
41117 'IMG { cursor: pointer } ' +
41121 return '<html><head>' + st +
41122 //<style type="text/css">' +
41123 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41125 ' </head><body class="roo-htmleditor-body"></body></html>';
41129 onRender : function(ct, position)
41132 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41133 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41136 this.el.dom.style.border = '0 none';
41137 this.el.dom.setAttribute('tabIndex', -1);
41138 this.el.addClass('x-hidden hide');
41142 if(Roo.isIE){ // fix IE 1px bogus margin
41143 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41147 this.frameId = Roo.id();
41151 var iframe = this.owner.wrap.createChild({
41153 cls: 'form-control', // bootstrap..
41155 name: this.frameId,
41156 frameBorder : 'no',
41157 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41162 this.iframe = iframe.dom;
41164 this.assignDocWin();
41166 this.doc.designMode = 'on';
41169 this.doc.write(this.getDocMarkup());
41173 var task = { // must defer to wait for browser to be ready
41175 //console.log("run task?" + this.doc.readyState);
41176 this.assignDocWin();
41177 if(this.doc.body || this.doc.readyState == 'complete'){
41179 this.doc.designMode="on";
41183 Roo.TaskMgr.stop(task);
41184 this.initEditor.defer(10, this);
41191 Roo.TaskMgr.start(task);
41198 onResize : function(w, h)
41200 Roo.log('resize: ' +w + ',' + h );
41201 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41205 if(typeof w == 'number'){
41207 this.iframe.style.width = w + 'px';
41209 if(typeof h == 'number'){
41211 this.iframe.style.height = h + 'px';
41213 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41220 * Toggles the editor between standard and source edit mode.
41221 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41223 toggleSourceEdit : function(sourceEditMode){
41225 this.sourceEditMode = sourceEditMode === true;
41227 if(this.sourceEditMode){
41229 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41232 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41233 //this.iframe.className = '';
41236 //this.setSize(this.owner.wrap.getSize());
41237 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41244 * Protected method that will not generally be called directly. If you need/want
41245 * custom HTML cleanup, this is the method you should override.
41246 * @param {String} html The HTML to be cleaned
41247 * return {String} The cleaned HTML
41249 cleanHtml : function(html){
41250 html = String(html);
41251 if(html.length > 5){
41252 if(Roo.isSafari){ // strip safari nonsense
41253 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41256 if(html == ' '){
41263 * HTML Editor -> Textarea
41264 * Protected method that will not generally be called directly. Syncs the contents
41265 * of the editor iframe with the textarea.
41267 syncValue : function(){
41268 if(this.initialized){
41269 var bd = (this.doc.body || this.doc.documentElement);
41270 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41271 var html = bd.innerHTML;
41273 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41274 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41276 html = '<div style="'+m[0]+'">' + html + '</div>';
41279 html = this.cleanHtml(html);
41280 // fix up the special chars.. normaly like back quotes in word...
41281 // however we do not want to do this with chinese..
41282 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41283 var cc = b.charCodeAt();
41285 (cc >= 0x4E00 && cc < 0xA000 ) ||
41286 (cc >= 0x3400 && cc < 0x4E00 ) ||
41287 (cc >= 0xf900 && cc < 0xfb00 )
41293 if(this.owner.fireEvent('beforesync', this, html) !== false){
41294 this.el.dom.value = html;
41295 this.owner.fireEvent('sync', this, html);
41301 * Protected method that will not generally be called directly. Pushes the value of the textarea
41302 * into the iframe editor.
41304 pushValue : function(){
41305 if(this.initialized){
41306 var v = this.el.dom.value.trim();
41308 // if(v.length < 1){
41312 if(this.owner.fireEvent('beforepush', this, v) !== false){
41313 var d = (this.doc.body || this.doc.documentElement);
41315 this.cleanUpPaste();
41316 this.el.dom.value = d.innerHTML;
41317 this.owner.fireEvent('push', this, v);
41323 deferFocus : function(){
41324 this.focus.defer(10, this);
41328 focus : function(){
41329 if(this.win && !this.sourceEditMode){
41336 assignDocWin: function()
41338 var iframe = this.iframe;
41341 this.doc = iframe.contentWindow.document;
41342 this.win = iframe.contentWindow;
41344 if (!Roo.get(this.frameId)) {
41347 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41348 this.win = Roo.get(this.frameId).dom.contentWindow;
41353 initEditor : function(){
41354 //console.log("INIT EDITOR");
41355 this.assignDocWin();
41359 this.doc.designMode="on";
41361 this.doc.write(this.getDocMarkup());
41364 var dbody = (this.doc.body || this.doc.documentElement);
41365 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41366 // this copies styles from the containing element into thsi one..
41367 // not sure why we need all of this..
41368 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41370 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41371 //ss['background-attachment'] = 'fixed'; // w3c
41372 dbody.bgProperties = 'fixed'; // ie
41373 //Roo.DomHelper.applyStyles(dbody, ss);
41374 Roo.EventManager.on(this.doc, {
41375 //'mousedown': this.onEditorEvent,
41376 'mouseup': this.onEditorEvent,
41377 'dblclick': this.onEditorEvent,
41378 'click': this.onEditorEvent,
41379 'keyup': this.onEditorEvent,
41384 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41386 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41387 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41389 this.initialized = true;
41391 this.owner.fireEvent('initialize', this);
41396 onDestroy : function(){
41402 //for (var i =0; i < this.toolbars.length;i++) {
41403 // // fixme - ask toolbars for heights?
41404 // this.toolbars[i].onDestroy();
41407 //this.wrap.dom.innerHTML = '';
41408 //this.wrap.remove();
41413 onFirstFocus : function(){
41415 this.assignDocWin();
41418 this.activated = true;
41421 if(Roo.isGecko){ // prevent silly gecko errors
41423 var s = this.win.getSelection();
41424 if(!s.focusNode || s.focusNode.nodeType != 3){
41425 var r = s.getRangeAt(0);
41426 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41431 this.execCmd('useCSS', true);
41432 this.execCmd('styleWithCSS', false);
41435 this.owner.fireEvent('activate', this);
41439 adjustFont: function(btn){
41440 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41441 //if(Roo.isSafari){ // safari
41444 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41445 if(Roo.isSafari){ // safari
41446 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41447 v = (v < 10) ? 10 : v;
41448 v = (v > 48) ? 48 : v;
41449 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41454 v = Math.max(1, v+adjust);
41456 this.execCmd('FontSize', v );
41459 onEditorEvent : function(e){
41460 this.owner.fireEvent('editorevent', this, e);
41461 // this.updateToolbar();
41462 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41465 insertTag : function(tg)
41467 // could be a bit smarter... -> wrap the current selected tRoo..
41468 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41470 range = this.createRange(this.getSelection());
41471 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41472 wrappingNode.appendChild(range.extractContents());
41473 range.insertNode(wrappingNode);
41480 this.execCmd("formatblock", tg);
41484 insertText : function(txt)
41488 var range = this.createRange();
41489 range.deleteContents();
41490 //alert(Sender.getAttribute('label'));
41492 range.insertNode(this.doc.createTextNode(txt));
41498 * Executes a Midas editor command on the editor document and performs necessary focus and
41499 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41500 * @param {String} cmd The Midas command
41501 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41503 relayCmd : function(cmd, value){
41505 this.execCmd(cmd, value);
41506 this.owner.fireEvent('editorevent', this);
41507 //this.updateToolbar();
41508 this.owner.deferFocus();
41512 * Executes a Midas editor command directly on the editor document.
41513 * For visual commands, you should use {@link #relayCmd} instead.
41514 * <b>This should only be called after the editor is initialized.</b>
41515 * @param {String} cmd The Midas command
41516 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41518 execCmd : function(cmd, value){
41519 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41526 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41528 * @param {String} text | dom node..
41530 insertAtCursor : function(text)
41535 if(!this.activated){
41541 var r = this.doc.selection.createRange();
41552 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41556 // from jquery ui (MIT licenced)
41558 var win = this.win;
41560 if (win.getSelection && win.getSelection().getRangeAt) {
41561 range = win.getSelection().getRangeAt(0);
41562 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41563 range.insertNode(node);
41564 } else if (win.document.selection && win.document.selection.createRange) {
41565 // no firefox support
41566 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41567 win.document.selection.createRange().pasteHTML(txt);
41569 // no firefox support
41570 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41571 this.execCmd('InsertHTML', txt);
41580 mozKeyPress : function(e){
41582 var c = e.getCharCode(), cmd;
41585 c = String.fromCharCode(c).toLowerCase();
41599 this.cleanUpPaste.defer(100, this);
41607 e.preventDefault();
41615 fixKeys : function(){ // load time branching for fastest keydown performance
41617 return function(e){
41618 var k = e.getKey(), r;
41621 r = this.doc.selection.createRange();
41624 r.pasteHTML('    ');
41631 r = this.doc.selection.createRange();
41633 var target = r.parentElement();
41634 if(!target || target.tagName.toLowerCase() != 'li'){
41636 r.pasteHTML('<br />');
41642 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41643 this.cleanUpPaste.defer(100, this);
41649 }else if(Roo.isOpera){
41650 return function(e){
41651 var k = e.getKey();
41655 this.execCmd('InsertHTML','    ');
41658 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41659 this.cleanUpPaste.defer(100, this);
41664 }else if(Roo.isSafari){
41665 return function(e){
41666 var k = e.getKey();
41670 this.execCmd('InsertText','\t');
41674 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41675 this.cleanUpPaste.defer(100, this);
41683 getAllAncestors: function()
41685 var p = this.getSelectedNode();
41688 a.push(p); // push blank onto stack..
41689 p = this.getParentElement();
41693 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41697 a.push(this.doc.body);
41701 lastSelNode : false,
41704 getSelection : function()
41706 this.assignDocWin();
41707 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41710 getSelectedNode: function()
41712 // this may only work on Gecko!!!
41714 // should we cache this!!!!
41719 var range = this.createRange(this.getSelection()).cloneRange();
41722 var parent = range.parentElement();
41724 var testRange = range.duplicate();
41725 testRange.moveToElementText(parent);
41726 if (testRange.inRange(range)) {
41729 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41732 parent = parent.parentElement;
41737 // is ancestor a text element.
41738 var ac = range.commonAncestorContainer;
41739 if (ac.nodeType == 3) {
41740 ac = ac.parentNode;
41743 var ar = ac.childNodes;
41746 var other_nodes = [];
41747 var has_other_nodes = false;
41748 for (var i=0;i<ar.length;i++) {
41749 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41752 // fullly contained node.
41754 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41759 // probably selected..
41760 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41761 other_nodes.push(ar[i]);
41765 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41770 has_other_nodes = true;
41772 if (!nodes.length && other_nodes.length) {
41773 nodes= other_nodes;
41775 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41781 createRange: function(sel)
41783 // this has strange effects when using with
41784 // top toolbar - not sure if it's a great idea.
41785 //this.editor.contentWindow.focus();
41786 if (typeof sel != "undefined") {
41788 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41790 return this.doc.createRange();
41793 return this.doc.createRange();
41796 getParentElement: function()
41799 this.assignDocWin();
41800 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41802 var range = this.createRange(sel);
41805 var p = range.commonAncestorContainer;
41806 while (p.nodeType == 3) { // text node
41817 * Range intersection.. the hard stuff...
41821 * [ -- selected range --- ]
41825 * if end is before start or hits it. fail.
41826 * if start is after end or hits it fail.
41828 * if either hits (but other is outside. - then it's not
41834 // @see http://www.thismuchiknow.co.uk/?p=64.
41835 rangeIntersectsNode : function(range, node)
41837 var nodeRange = node.ownerDocument.createRange();
41839 nodeRange.selectNode(node);
41841 nodeRange.selectNodeContents(node);
41844 var rangeStartRange = range.cloneRange();
41845 rangeStartRange.collapse(true);
41847 var rangeEndRange = range.cloneRange();
41848 rangeEndRange.collapse(false);
41850 var nodeStartRange = nodeRange.cloneRange();
41851 nodeStartRange.collapse(true);
41853 var nodeEndRange = nodeRange.cloneRange();
41854 nodeEndRange.collapse(false);
41856 return rangeStartRange.compareBoundaryPoints(
41857 Range.START_TO_START, nodeEndRange) == -1 &&
41858 rangeEndRange.compareBoundaryPoints(
41859 Range.START_TO_START, nodeStartRange) == 1;
41863 rangeCompareNode : function(range, node)
41865 var nodeRange = node.ownerDocument.createRange();
41867 nodeRange.selectNode(node);
41869 nodeRange.selectNodeContents(node);
41873 range.collapse(true);
41875 nodeRange.collapse(true);
41877 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41878 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41880 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41882 var nodeIsBefore = ss == 1;
41883 var nodeIsAfter = ee == -1;
41885 if (nodeIsBefore && nodeIsAfter)
41887 if (!nodeIsBefore && nodeIsAfter)
41888 return 1; //right trailed.
41890 if (nodeIsBefore && !nodeIsAfter)
41891 return 2; // left trailed.
41896 // private? - in a new class?
41897 cleanUpPaste : function()
41899 // cleans up the whole document..
41900 Roo.log('cleanuppaste');
41902 this.cleanUpChildren(this.doc.body);
41903 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41904 if (clean != this.doc.body.innerHTML) {
41905 this.doc.body.innerHTML = clean;
41910 cleanWordChars : function(input) {// change the chars to hex code
41911 var he = Roo.HtmlEditorCore;
41913 var output = input;
41914 Roo.each(he.swapCodes, function(sw) {
41915 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41917 output = output.replace(swapper, sw[1]);
41924 cleanUpChildren : function (n)
41926 if (!n.childNodes.length) {
41929 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41930 this.cleanUpChild(n.childNodes[i]);
41937 cleanUpChild : function (node)
41940 //console.log(node);
41941 if (node.nodeName == "#text") {
41942 // clean up silly Windows -- stuff?
41945 if (node.nodeName == "#comment") {
41946 node.parentNode.removeChild(node);
41947 // clean up silly Windows -- stuff?
41951 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
41953 node.parentNode.removeChild(node);
41958 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
41960 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41961 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41963 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41964 // remove_keep_children = true;
41967 if (remove_keep_children) {
41968 this.cleanUpChildren(node);
41969 // inserts everything just before this node...
41970 while (node.childNodes.length) {
41971 var cn = node.childNodes[0];
41972 node.removeChild(cn);
41973 node.parentNode.insertBefore(cn, node);
41975 node.parentNode.removeChild(node);
41979 if (!node.attributes || !node.attributes.length) {
41980 this.cleanUpChildren(node);
41984 function cleanAttr(n,v)
41987 if (v.match(/^\./) || v.match(/^\//)) {
41990 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41993 if (v.match(/^#/)) {
41996 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41997 node.removeAttribute(n);
42001 function cleanStyle(n,v)
42003 if (v.match(/expression/)) { //XSS?? should we even bother..
42004 node.removeAttribute(n);
42007 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
42008 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
42011 var parts = v.split(/;/);
42014 Roo.each(parts, function(p) {
42015 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42019 var l = p.split(':').shift().replace(/\s+/g,'');
42020 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42022 if ( cblack.indexOf(l) > -1) {
42023 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42024 //node.removeAttribute(n);
42028 // only allow 'c whitelisted system attributes'
42029 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42030 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42031 //node.removeAttribute(n);
42041 if (clean.length) {
42042 node.setAttribute(n, clean.join(';'));
42044 node.removeAttribute(n);
42050 for (var i = node.attributes.length-1; i > -1 ; i--) {
42051 var a = node.attributes[i];
42054 if (a.name.toLowerCase().substr(0,2)=='on') {
42055 node.removeAttribute(a.name);
42058 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42059 node.removeAttribute(a.name);
42062 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42063 cleanAttr(a.name,a.value); // fixme..
42066 if (a.name == 'style') {
42067 cleanStyle(a.name,a.value);
42070 /// clean up MS crap..
42071 // tecnically this should be a list of valid class'es..
42074 if (a.name == 'class') {
42075 if (a.value.match(/^Mso/)) {
42076 node.className = '';
42079 if (a.value.match(/body/)) {
42080 node.className = '';
42091 this.cleanUpChildren(node);
42096 * Clean up MS wordisms...
42098 cleanWord : function(node)
42101 var cleanWordChildren = function()
42103 if (!node.childNodes.length) {
42106 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42107 _t.cleanWord(node.childNodes[i]);
42113 this.cleanWord(this.doc.body);
42116 if (node.nodeName == "#text") {
42117 // clean up silly Windows -- stuff?
42120 if (node.nodeName == "#comment") {
42121 node.parentNode.removeChild(node);
42122 // clean up silly Windows -- stuff?
42126 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42127 node.parentNode.removeChild(node);
42131 // remove - but keep children..
42132 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42133 while (node.childNodes.length) {
42134 var cn = node.childNodes[0];
42135 node.removeChild(cn);
42136 node.parentNode.insertBefore(cn, node);
42138 node.parentNode.removeChild(node);
42139 cleanWordChildren();
42143 if (node.className.length) {
42145 var cn = node.className.split(/\W+/);
42147 Roo.each(cn, function(cls) {
42148 if (cls.match(/Mso[a-zA-Z]+/)) {
42153 node.className = cna.length ? cna.join(' ') : '';
42155 node.removeAttribute("class");
42159 if (node.hasAttribute("lang")) {
42160 node.removeAttribute("lang");
42163 if (node.hasAttribute("style")) {
42165 var styles = node.getAttribute("style").split(";");
42167 Roo.each(styles, function(s) {
42168 if (!s.match(/:/)) {
42171 var kv = s.split(":");
42172 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42175 // what ever is left... we allow.
42178 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42179 if (!nstyle.length) {
42180 node.removeAttribute('style');
42184 cleanWordChildren();
42188 domToHTML : function(currentElement, depth, nopadtext) {
42190 depth = depth || 0;
42191 nopadtext = nopadtext || false;
42193 if (!currentElement) {
42194 return this.domToHTML(this.doc.body);
42197 //Roo.log(currentElement);
42199 var allText = false;
42200 var nodeName = currentElement.nodeName;
42201 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42203 if (nodeName == '#text') {
42204 return currentElement.nodeValue;
42209 if (nodeName != 'BODY') {
42212 // Prints the node tagName, such as <A>, <IMG>, etc
42215 for(i = 0; i < currentElement.attributes.length;i++) {
42217 var aname = currentElement.attributes.item(i).name;
42218 if (!currentElement.attributes.item(i).value.length) {
42221 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42224 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42233 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42236 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42241 // Traverse the tree
42243 var currentElementChild = currentElement.childNodes.item(i);
42244 var allText = true;
42245 var innerHTML = '';
42247 while (currentElementChild) {
42248 // Formatting code (indent the tree so it looks nice on the screen)
42249 var nopad = nopadtext;
42250 if (lastnode == 'SPAN') {
42254 if (currentElementChild.nodeName == '#text') {
42255 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42256 if (!nopad && toadd.length > 80) {
42257 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42259 innerHTML += toadd;
42262 currentElementChild = currentElement.childNodes.item(i);
42268 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42270 // Recursively traverse the tree structure of the child node
42271 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42272 lastnode = currentElementChild.nodeName;
42274 currentElementChild=currentElement.childNodes.item(i);
42280 // The remaining code is mostly for formatting the tree
42281 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42286 ret+= "</"+tagName+">";
42292 // hide stuff that is not compatible
42306 * @event specialkey
42310 * @cfg {String} fieldClass @hide
42313 * @cfg {String} focusClass @hide
42316 * @cfg {String} autoCreate @hide
42319 * @cfg {String} inputType @hide
42322 * @cfg {String} invalidClass @hide
42325 * @cfg {String} invalidText @hide
42328 * @cfg {String} msgFx @hide
42331 * @cfg {String} validateOnBlur @hide
42335 Roo.HtmlEditorCore.white = [
42336 'area', 'br', 'img', 'input', 'hr', 'wbr',
42338 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42339 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42340 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42341 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42342 'table', 'ul', 'xmp',
42344 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42347 'dir', 'menu', 'ol', 'ul', 'dl',
42353 Roo.HtmlEditorCore.black = [
42354 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42356 'base', 'basefont', 'bgsound', 'blink', 'body',
42357 'frame', 'frameset', 'head', 'html', 'ilayer',
42358 'iframe', 'layer', 'link', 'meta', 'object',
42359 'script', 'style' ,'title', 'xml' // clean later..
42361 Roo.HtmlEditorCore.clean = [
42362 'script', 'style', 'title', 'xml'
42364 Roo.HtmlEditorCore.remove = [
42369 Roo.HtmlEditorCore.ablack = [
42373 Roo.HtmlEditorCore.aclean = [
42374 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42378 Roo.HtmlEditorCore.pwhite= [
42379 'http', 'https', 'mailto'
42382 // white listed style attributes.
42383 Roo.HtmlEditorCore.cwhite= [
42384 // 'text-align', /// default is to allow most things..
42390 // black listed style attributes.
42391 Roo.HtmlEditorCore.cblack= [
42392 // 'font-size' -- this can be set by the project
42396 Roo.HtmlEditorCore.swapCodes =[
42407 //<script type="text/javascript">
42410 * Ext JS Library 1.1.1
42411 * Copyright(c) 2006-2007, Ext JS, LLC.
42417 Roo.form.HtmlEditor = function(config){
42421 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42423 if (!this.toolbars) {
42424 this.toolbars = [];
42426 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42432 * @class Roo.form.HtmlEditor
42433 * @extends Roo.form.Field
42434 * Provides a lightweight HTML Editor component.
42436 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42438 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42439 * supported by this editor.</b><br/><br/>
42440 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42441 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42443 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42445 * @cfg {Boolean} clearUp
42449 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42454 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42459 * @cfg {Number} height (in pixels)
42463 * @cfg {Number} width (in pixels)
42468 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42471 stylesheets: false,
42476 // private properties
42477 validationEvent : false,
42479 initialized : false,
42482 onFocus : Roo.emptyFn,
42484 hideMode:'offsets',
42486 defaultAutoCreate : { // modified by initCompnoent..
42488 style:"width:500px;height:300px;",
42489 autocomplete: "off"
42493 initComponent : function(){
42496 * @event initialize
42497 * Fires when the editor is fully initialized (including the iframe)
42498 * @param {HtmlEditor} this
42503 * Fires when the editor is first receives the focus. Any insertion must wait
42504 * until after this event.
42505 * @param {HtmlEditor} this
42509 * @event beforesync
42510 * Fires before the textarea is updated with content from the editor iframe. Return false
42511 * to cancel the sync.
42512 * @param {HtmlEditor} this
42513 * @param {String} html
42517 * @event beforepush
42518 * Fires before the iframe editor is updated with content from the textarea. Return false
42519 * to cancel the push.
42520 * @param {HtmlEditor} this
42521 * @param {String} html
42526 * Fires when the textarea is updated with content from the editor iframe.
42527 * @param {HtmlEditor} this
42528 * @param {String} html
42533 * Fires when the iframe editor is updated with content from the textarea.
42534 * @param {HtmlEditor} this
42535 * @param {String} html
42539 * @event editmodechange
42540 * Fires when the editor switches edit modes
42541 * @param {HtmlEditor} this
42542 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42544 editmodechange: true,
42546 * @event editorevent
42547 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42548 * @param {HtmlEditor} this
42552 * @event firstfocus
42553 * Fires when on first focus - needed by toolbars..
42554 * @param {HtmlEditor} this
42559 * Auto save the htmlEditor value as a file into Events
42560 * @param {HtmlEditor} this
42564 * @event savedpreview
42565 * preview the saved version of htmlEditor
42566 * @param {HtmlEditor} this
42570 this.defaultAutoCreate = {
42572 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42573 autocomplete: "off"
42578 * Protected method that will not generally be called directly. It
42579 * is called when the editor creates its toolbar. Override this method if you need to
42580 * add custom toolbar buttons.
42581 * @param {HtmlEditor} editor
42583 createToolbar : function(editor){
42584 Roo.log("create toolbars");
42585 if (!editor.toolbars || !editor.toolbars.length) {
42586 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42589 for (var i =0 ; i < editor.toolbars.length;i++) {
42590 editor.toolbars[i] = Roo.factory(
42591 typeof(editor.toolbars[i]) == 'string' ?
42592 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42593 Roo.form.HtmlEditor);
42594 editor.toolbars[i].init(editor);
42602 onRender : function(ct, position)
42605 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
42607 this.wrap = this.el.wrap({
42608 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
42611 this.editorcore.onRender(ct, position);
42613 if (this.resizable) {
42614 this.resizeEl = new Roo.Resizable(this.wrap, {
42618 minHeight : this.height,
42619 height: this.height,
42620 handles : this.resizable,
42623 resize : function(r, w, h) {
42624 _t.onResize(w,h); // -something
42630 this.createToolbar(this);
42634 this.setSize(this.wrap.getSize());
42636 if (this.resizeEl) {
42637 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
42638 // should trigger onReize..
42641 // if(this.autosave && this.w){
42642 // this.autoSaveFn = setInterval(this.autosave, 1000);
42647 onResize : function(w, h)
42649 //Roo.log('resize: ' +w + ',' + h );
42650 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
42655 if(typeof w == 'number'){
42656 var aw = w - this.wrap.getFrameWidth('lr');
42657 this.el.setWidth(this.adjustWidth('textarea', aw));
42660 if(typeof h == 'number'){
42662 for (var i =0; i < this.toolbars.length;i++) {
42663 // fixme - ask toolbars for heights?
42664 tbh += this.toolbars[i].tb.el.getHeight();
42665 if (this.toolbars[i].footer) {
42666 tbh += this.toolbars[i].footer.el.getHeight();
42673 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
42674 ah -= 5; // knock a few pixes off for look..
42675 this.el.setHeight(this.adjustWidth('textarea', ah));
42679 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
42680 this.editorcore.onResize(ew,eh);
42685 * Toggles the editor between standard and source edit mode.
42686 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42688 toggleSourceEdit : function(sourceEditMode)
42690 this.editorcore.toggleSourceEdit(sourceEditMode);
42692 if(this.editorcore.sourceEditMode){
42693 Roo.log('editor - showing textarea');
42696 // Roo.log(this.syncValue());
42697 this.editorcore.syncValue();
42698 this.el.removeClass('x-hidden');
42699 this.el.dom.removeAttribute('tabIndex');
42702 Roo.log('editor - hiding textarea');
42704 // Roo.log(this.pushValue());
42705 this.editorcore.pushValue();
42707 this.el.addClass('x-hidden');
42708 this.el.dom.setAttribute('tabIndex', -1);
42709 //this.deferFocus();
42712 this.setSize(this.wrap.getSize());
42713 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
42716 // private (for BoxComponent)
42717 adjustSize : Roo.BoxComponent.prototype.adjustSize,
42719 // private (for BoxComponent)
42720 getResizeEl : function(){
42724 // private (for BoxComponent)
42725 getPositionEl : function(){
42730 initEvents : function(){
42731 this.originalValue = this.getValue();
42735 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42738 markInvalid : Roo.emptyFn,
42740 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42743 clearInvalid : Roo.emptyFn,
42745 setValue : function(v){
42746 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
42747 this.editorcore.pushValue();
42752 deferFocus : function(){
42753 this.focus.defer(10, this);
42757 focus : function(){
42758 this.editorcore.focus();
42764 onDestroy : function(){
42770 for (var i =0; i < this.toolbars.length;i++) {
42771 // fixme - ask toolbars for heights?
42772 this.toolbars[i].onDestroy();
42775 this.wrap.dom.innerHTML = '';
42776 this.wrap.remove();
42781 onFirstFocus : function(){
42782 //Roo.log("onFirstFocus");
42783 this.editorcore.onFirstFocus();
42784 for (var i =0; i < this.toolbars.length;i++) {
42785 this.toolbars[i].onFirstFocus();
42791 syncValue : function()
42793 this.editorcore.syncValue();
42796 pushValue : function()
42798 this.editorcore.pushValue();
42802 // hide stuff that is not compatible
42816 * @event specialkey
42820 * @cfg {String} fieldClass @hide
42823 * @cfg {String} focusClass @hide
42826 * @cfg {String} autoCreate @hide
42829 * @cfg {String} inputType @hide
42832 * @cfg {String} invalidClass @hide
42835 * @cfg {String} invalidText @hide
42838 * @cfg {String} msgFx @hide
42841 * @cfg {String} validateOnBlur @hide
42845 // <script type="text/javascript">
42848 * Ext JS Library 1.1.1
42849 * Copyright(c) 2006-2007, Ext JS, LLC.
42855 * @class Roo.form.HtmlEditorToolbar1
42860 new Roo.form.HtmlEditor({
42863 new Roo.form.HtmlEditorToolbar1({
42864 disable : { fonts: 1 , format: 1, ..., ... , ...],
42870 * @cfg {Object} disable List of elements to disable..
42871 * @cfg {Array} btns List of additional buttons.
42875 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
42878 Roo.form.HtmlEditor.ToolbarStandard = function(config)
42881 Roo.apply(this, config);
42883 // default disabled, based on 'good practice'..
42884 this.disable = this.disable || {};
42885 Roo.applyIf(this.disable, {
42888 specialElements : true
42892 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42893 // dont call parent... till later.
42896 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
42903 editorcore : false,
42905 * @cfg {Object} disable List of toolbar elements to disable
42912 * @cfg {String} createLinkText The default text for the create link prompt
42914 createLinkText : 'Please enter the URL for the link:',
42916 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
42918 defaultLinkValue : 'http:/'+'/',
42922 * @cfg {Array} fontFamilies An array of available font families
42940 // "á" , ?? a acute?
42945 "°" // , // degrees
42947 // "é" , // e ecute
42948 // "ú" , // u ecute?
42951 specialElements : [
42953 text: "Insert Table",
42956 ihtml : '<table><tr><td>Cell</td></tr></table>'
42960 text: "Insert Image",
42963 ihtml : '<img src="about:blank"/>'
42972 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
42973 "input:submit", "input:button", "select", "textarea", "label" ],
42976 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
42978 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
42986 * @cfg {String} defaultFont default font to use.
42988 defaultFont: 'tahoma',
42990 fontSelect : false,
42993 formatCombo : false,
42995 init : function(editor)
42997 this.editor = editor;
42998 this.editorcore = editor.editorcore ? editor.editorcore : editor;
42999 var editorcore = this.editorcore;
43003 var fid = editorcore.frameId;
43005 function btn(id, toggle, handler){
43006 var xid = fid + '-'+ id ;
43010 cls : 'x-btn-icon x-edit-'+id,
43011 enableToggle:toggle !== false,
43012 scope: _t, // was editor...
43013 handler:handler||_t.relayBtnCmd,
43014 clickEvent:'mousedown',
43015 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43022 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43024 // stop form submits
43025 tb.el.on('click', function(e){
43026 e.preventDefault(); // what does this do?
43029 if(!this.disable.font) { // && !Roo.isSafari){
43030 /* why no safari for fonts
43031 editor.fontSelect = tb.el.createChild({
43034 cls:'x-font-select',
43035 html: this.createFontOptions()
43038 editor.fontSelect.on('change', function(){
43039 var font = editor.fontSelect.dom.value;
43040 editor.relayCmd('fontname', font);
43041 editor.deferFocus();
43045 editor.fontSelect.dom,
43051 if(!this.disable.formats){
43052 this.formatCombo = new Roo.form.ComboBox({
43053 store: new Roo.data.SimpleStore({
43056 data : this.formats // from states.js
43060 //autoCreate : {tag: "div", size: "20"},
43061 displayField:'tag',
43065 triggerAction: 'all',
43066 emptyText:'Add tag',
43067 selectOnFocus:true,
43070 'select': function(c, r, i) {
43071 editorcore.insertTag(r.get('tag'));
43077 tb.addField(this.formatCombo);
43081 if(!this.disable.format){
43088 if(!this.disable.fontSize){
43093 btn('increasefontsize', false, editorcore.adjustFont),
43094 btn('decreasefontsize', false, editorcore.adjustFont)
43099 if(!this.disable.colors){
43102 id:editorcore.frameId +'-forecolor',
43103 cls:'x-btn-icon x-edit-forecolor',
43104 clickEvent:'mousedown',
43105 tooltip: this.buttonTips['forecolor'] || undefined,
43107 menu : new Roo.menu.ColorMenu({
43108 allowReselect: true,
43109 focus: Roo.emptyFn,
43112 selectHandler: function(cp, color){
43113 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43114 editor.deferFocus();
43117 clickEvent:'mousedown'
43120 id:editorcore.frameId +'backcolor',
43121 cls:'x-btn-icon x-edit-backcolor',
43122 clickEvent:'mousedown',
43123 tooltip: this.buttonTips['backcolor'] || undefined,
43125 menu : new Roo.menu.ColorMenu({
43126 focus: Roo.emptyFn,
43129 allowReselect: true,
43130 selectHandler: function(cp, color){
43132 editorcore.execCmd('useCSS', false);
43133 editorcore.execCmd('hilitecolor', color);
43134 editorcore.execCmd('useCSS', true);
43135 editor.deferFocus();
43137 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43138 Roo.isSafari || Roo.isIE ? '#'+color : color);
43139 editor.deferFocus();
43143 clickEvent:'mousedown'
43148 // now add all the items...
43151 if(!this.disable.alignments){
43154 btn('justifyleft'),
43155 btn('justifycenter'),
43156 btn('justifyright')
43160 //if(!Roo.isSafari){
43161 if(!this.disable.links){
43164 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43168 if(!this.disable.lists){
43171 btn('insertorderedlist'),
43172 btn('insertunorderedlist')
43175 if(!this.disable.sourceEdit){
43178 btn('sourceedit', true, function(btn){
43180 this.toggleSourceEdit(btn.pressed);
43187 // special menu.. - needs to be tidied up..
43188 if (!this.disable.special) {
43191 cls: 'x-edit-none',
43197 for (var i =0; i < this.specialChars.length; i++) {
43198 smenu.menu.items.push({
43200 html: this.specialChars[i],
43201 handler: function(a,b) {
43202 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43203 //editor.insertAtCursor(a.html);
43217 if (!this.disable.cleanStyles) {
43219 cls: 'x-btn-icon x-btn-clear',
43225 for (var i =0; i < this.cleanStyles.length; i++) {
43226 cmenu.menu.items.push({
43227 actiontype : this.cleanStyles[i],
43228 html: 'Remove ' + this.cleanStyles[i],
43229 handler: function(a,b) {
43232 var c = Roo.get(editorcore.doc.body);
43233 c.select('[style]').each(function(s) {
43234 s.dom.style.removeProperty(a.actiontype);
43236 editorcore.syncValue();
43241 cmenu.menu.items.push({
43242 actiontype : 'word',
43243 html: 'Remove MS Word Formating',
43244 handler: function(a,b) {
43245 editorcore.cleanWord();
43246 editorcore.syncValue();
43251 cmenu.menu.items.push({
43252 actiontype : 'all',
43253 html: 'Remove All Styles',
43254 handler: function(a,b) {
43256 var c = Roo.get(editorcore.doc.body);
43257 c.select('[style]').each(function(s) {
43258 s.dom.removeAttribute('style');
43260 editorcore.syncValue();
43264 cmenu.menu.items.push({
43265 actiontype : 'word',
43266 html: 'Tidy HTML Source',
43267 handler: function(a,b) {
43268 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43269 editorcore.syncValue();
43278 if (!this.disable.specialElements) {
43281 cls: 'x-edit-none',
43286 for (var i =0; i < this.specialElements.length; i++) {
43287 semenu.menu.items.push(
43289 handler: function(a,b) {
43290 editor.insertAtCursor(this.ihtml);
43292 }, this.specialElements[i])
43304 for(var i =0; i< this.btns.length;i++) {
43305 var b = Roo.factory(this.btns[i],Roo.form);
43306 b.cls = 'x-edit-none';
43307 b.scope = editorcore;
43315 // disable everything...
43317 this.tb.items.each(function(item){
43318 if(item.id != editorcore.frameId+ '-sourceedit'){
43322 this.rendered = true;
43324 // the all the btns;
43325 editor.on('editorevent', this.updateToolbar, this);
43326 // other toolbars need to implement this..
43327 //editor.on('editmodechange', this.updateToolbar, this);
43331 relayBtnCmd : function(btn) {
43332 this.editorcore.relayCmd(btn.cmd);
43334 // private used internally
43335 createLink : function(){
43336 Roo.log("create link?");
43337 var url = prompt(this.createLinkText, this.defaultLinkValue);
43338 if(url && url != 'http:/'+'/'){
43339 this.editorcore.relayCmd('createlink', url);
43345 * Protected method that will not generally be called directly. It triggers
43346 * a toolbar update by reading the markup state of the current selection in the editor.
43348 updateToolbar: function(){
43350 if(!this.editorcore.activated){
43351 this.editor.onFirstFocus();
43355 var btns = this.tb.items.map,
43356 doc = this.editorcore.doc,
43357 frameId = this.editorcore.frameId;
43359 if(!this.disable.font && !Roo.isSafari){
43361 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43362 if(name != this.fontSelect.dom.value){
43363 this.fontSelect.dom.value = name;
43367 if(!this.disable.format){
43368 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43369 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43370 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43372 if(!this.disable.alignments){
43373 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43374 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43375 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43377 if(!Roo.isSafari && !this.disable.lists){
43378 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43379 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43382 var ans = this.editorcore.getAllAncestors();
43383 if (this.formatCombo) {
43386 var store = this.formatCombo.store;
43387 this.formatCombo.setValue("");
43388 for (var i =0; i < ans.length;i++) {
43389 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43391 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43399 // hides menus... - so this cant be on a menu...
43400 Roo.menu.MenuMgr.hideAll();
43402 //this.editorsyncValue();
43406 createFontOptions : function(){
43407 var buf = [], fs = this.fontFamilies, ff, lc;
43411 for(var i = 0, len = fs.length; i< len; i++){
43413 lc = ff.toLowerCase();
43415 '<option value="',lc,'" style="font-family:',ff,';"',
43416 (this.defaultFont == lc ? ' selected="true">' : '>'),
43421 return buf.join('');
43424 toggleSourceEdit : function(sourceEditMode){
43426 Roo.log("toolbar toogle");
43427 if(sourceEditMode === undefined){
43428 sourceEditMode = !this.sourceEditMode;
43430 this.sourceEditMode = sourceEditMode === true;
43431 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43432 // just toggle the button?
43433 if(btn.pressed !== this.sourceEditMode){
43434 btn.toggle(this.sourceEditMode);
43438 if(sourceEditMode){
43439 Roo.log("disabling buttons");
43440 this.tb.items.each(function(item){
43441 if(item.cmd != 'sourceedit'){
43447 Roo.log("enabling buttons");
43448 if(this.editorcore.initialized){
43449 this.tb.items.each(function(item){
43455 Roo.log("calling toggole on editor");
43456 // tell the editor that it's been pressed..
43457 this.editor.toggleSourceEdit(sourceEditMode);
43461 * Object collection of toolbar tooltips for the buttons in the editor. The key
43462 * is the command id associated with that button and the value is a valid QuickTips object.
43467 title: 'Bold (Ctrl+B)',
43468 text: 'Make the selected text bold.',
43469 cls: 'x-html-editor-tip'
43472 title: 'Italic (Ctrl+I)',
43473 text: 'Make the selected text italic.',
43474 cls: 'x-html-editor-tip'
43482 title: 'Bold (Ctrl+B)',
43483 text: 'Make the selected text bold.',
43484 cls: 'x-html-editor-tip'
43487 title: 'Italic (Ctrl+I)',
43488 text: 'Make the selected text italic.',
43489 cls: 'x-html-editor-tip'
43492 title: 'Underline (Ctrl+U)',
43493 text: 'Underline the selected text.',
43494 cls: 'x-html-editor-tip'
43496 increasefontsize : {
43497 title: 'Grow Text',
43498 text: 'Increase the font size.',
43499 cls: 'x-html-editor-tip'
43501 decreasefontsize : {
43502 title: 'Shrink Text',
43503 text: 'Decrease the font size.',
43504 cls: 'x-html-editor-tip'
43507 title: 'Text Highlight Color',
43508 text: 'Change the background color of the selected text.',
43509 cls: 'x-html-editor-tip'
43512 title: 'Font Color',
43513 text: 'Change the color of the selected text.',
43514 cls: 'x-html-editor-tip'
43517 title: 'Align Text Left',
43518 text: 'Align text to the left.',
43519 cls: 'x-html-editor-tip'
43522 title: 'Center Text',
43523 text: 'Center text in the editor.',
43524 cls: 'x-html-editor-tip'
43527 title: 'Align Text Right',
43528 text: 'Align text to the right.',
43529 cls: 'x-html-editor-tip'
43531 insertunorderedlist : {
43532 title: 'Bullet List',
43533 text: 'Start a bulleted list.',
43534 cls: 'x-html-editor-tip'
43536 insertorderedlist : {
43537 title: 'Numbered List',
43538 text: 'Start a numbered list.',
43539 cls: 'x-html-editor-tip'
43542 title: 'Hyperlink',
43543 text: 'Make the selected text a hyperlink.',
43544 cls: 'x-html-editor-tip'
43547 title: 'Source Edit',
43548 text: 'Switch to source editing mode.',
43549 cls: 'x-html-editor-tip'
43553 onDestroy : function(){
43556 this.tb.items.each(function(item){
43558 item.menu.removeAll();
43560 item.menu.el.destroy();
43568 onFirstFocus: function() {
43569 this.tb.items.each(function(item){
43578 // <script type="text/javascript">
43581 * Ext JS Library 1.1.1
43582 * Copyright(c) 2006-2007, Ext JS, LLC.
43589 * @class Roo.form.HtmlEditor.ToolbarContext
43594 new Roo.form.HtmlEditor({
43597 { xtype: 'ToolbarStandard', styles : {} }
43598 { xtype: 'ToolbarContext', disable : {} }
43604 * @config : {Object} disable List of elements to disable.. (not done yet.)
43605 * @config : {Object} styles Map of styles available.
43609 Roo.form.HtmlEditor.ToolbarContext = function(config)
43612 Roo.apply(this, config);
43613 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43614 // dont call parent... till later.
43615 this.styles = this.styles || {};
43620 Roo.form.HtmlEditor.ToolbarContext.types = {
43632 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
43698 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
43703 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
43713 style : 'fontFamily',
43714 displayField: 'display',
43715 optname : 'font-family',
43764 // should we really allow this??
43765 // should this just be
43776 style : 'fontFamily',
43777 displayField: 'display',
43778 optname : 'font-family',
43785 style : 'fontFamily',
43786 displayField: 'display',
43787 optname : 'font-family',
43794 style : 'fontFamily',
43795 displayField: 'display',
43796 optname : 'font-family',
43807 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
43808 Roo.form.HtmlEditor.ToolbarContext.stores = false;
43810 Roo.form.HtmlEditor.ToolbarContext.options = {
43812 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
43813 [ 'Courier New', 'Courier New'],
43814 [ 'Tahoma', 'Tahoma'],
43815 [ 'Times New Roman,serif', 'Times'],
43816 [ 'Verdana','Verdana' ]
43820 // fixme - these need to be configurable..
43823 Roo.form.HtmlEditor.ToolbarContext.types
43826 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
43833 editorcore : false,
43835 * @cfg {Object} disable List of toolbar elements to disable
43840 * @cfg {Object} styles List of styles
43841 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
43843 * These must be defined in the page, so they get rendered correctly..
43854 init : function(editor)
43856 this.editor = editor;
43857 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43858 var editorcore = this.editorcore;
43860 var fid = editorcore.frameId;
43862 function btn(id, toggle, handler){
43863 var xid = fid + '-'+ id ;
43867 cls : 'x-btn-icon x-edit-'+id,
43868 enableToggle:toggle !== false,
43869 scope: editorcore, // was editor...
43870 handler:handler||editorcore.relayBtnCmd,
43871 clickEvent:'mousedown',
43872 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43876 // create a new element.
43877 var wdiv = editor.wrap.createChild({
43879 }, editor.wrap.dom.firstChild.nextSibling, true);
43881 // can we do this more than once??
43883 // stop form submits
43886 // disable everything...
43887 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43888 this.toolbars = {};
43890 for (var i in ty) {
43892 this.toolbars[i] = this.buildToolbar(ty[i],i);
43894 this.tb = this.toolbars.BODY;
43896 this.buildFooter();
43897 this.footer.show();
43898 editor.on('hide', function( ) { this.footer.hide() }, this);
43899 editor.on('show', function( ) { this.footer.show() }, this);
43902 this.rendered = true;
43904 // the all the btns;
43905 editor.on('editorevent', this.updateToolbar, this);
43906 // other toolbars need to implement this..
43907 //editor.on('editmodechange', this.updateToolbar, this);
43913 * Protected method that will not generally be called directly. It triggers
43914 * a toolbar update by reading the markup state of the current selection in the editor.
43916 updateToolbar: function(editor,ev,sel){
43919 // capture mouse up - this is handy for selecting images..
43920 // perhaps should go somewhere else...
43921 if(!this.editorcore.activated){
43922 this.editor.onFirstFocus();
43926 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
43927 // selectNode - might want to handle IE?
43929 (ev.type == 'mouseup' || ev.type == 'click' ) &&
43930 ev.target && ev.target.tagName == 'IMG') {
43931 // they have click on an image...
43932 // let's see if we can change the selection...
43935 var nodeRange = sel.ownerDocument.createRange();
43937 nodeRange.selectNode(sel);
43939 nodeRange.selectNodeContents(sel);
43941 //nodeRange.collapse(true);
43942 var s = this.editorcore.win.getSelection();
43943 s.removeAllRanges();
43944 s.addRange(nodeRange);
43948 var updateFooter = sel ? false : true;
43951 var ans = this.editorcore.getAllAncestors();
43954 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43957 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
43958 sel = sel ? sel : this.editorcore.doc.body;
43959 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
43962 // pick a menu that exists..
43963 var tn = sel.tagName.toUpperCase();
43964 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
43966 tn = sel.tagName.toUpperCase();
43968 var lastSel = this.tb.selectedNode
43970 this.tb.selectedNode = sel;
43972 // if current menu does not match..
43973 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
43976 ///console.log("show: " + tn);
43977 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
43980 this.tb.items.first().el.innerHTML = tn + ': ';
43983 // update attributes
43984 if (this.tb.fields) {
43985 this.tb.fields.each(function(e) {
43987 e.setValue(sel.style[e.stylename]);
43990 e.setValue(sel.getAttribute(e.attrname));
43994 var hasStyles = false;
43995 for(var i in this.styles) {
44002 var st = this.tb.fields.item(0);
44004 st.store.removeAll();
44007 var cn = sel.className.split(/\s+/);
44010 if (this.styles['*']) {
44012 Roo.each(this.styles['*'], function(v) {
44013 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44016 if (this.styles[tn]) {
44017 Roo.each(this.styles[tn], function(v) {
44018 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44022 st.store.loadData(avs);
44026 // flag our selected Node.
44027 this.tb.selectedNode = sel;
44030 Roo.menu.MenuMgr.hideAll();
44034 if (!updateFooter) {
44035 //this.footDisp.dom.innerHTML = '';
44038 // update the footer
44042 this.footerEls = ans.reverse();
44043 Roo.each(this.footerEls, function(a,i) {
44044 if (!a) { return; }
44045 html += html.length ? ' > ' : '';
44047 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44052 var sz = this.footDisp.up('td').getSize();
44053 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44054 this.footDisp.dom.style.marginLeft = '5px';
44056 this.footDisp.dom.style.overflow = 'hidden';
44058 this.footDisp.dom.innerHTML = html;
44060 //this.editorsyncValue();
44067 onDestroy : function(){
44070 this.tb.items.each(function(item){
44072 item.menu.removeAll();
44074 item.menu.el.destroy();
44082 onFirstFocus: function() {
44083 // need to do this for all the toolbars..
44084 this.tb.items.each(function(item){
44088 buildToolbar: function(tlist, nm)
44090 var editor = this.editor;
44091 var editorcore = this.editorcore;
44092 // create a new element.
44093 var wdiv = editor.wrap.createChild({
44095 }, editor.wrap.dom.firstChild.nextSibling, true);
44098 var tb = new Roo.Toolbar(wdiv);
44101 tb.add(nm+ ": ");
44104 for(var i in this.styles) {
44109 if (styles && styles.length) {
44111 // this needs a multi-select checkbox...
44112 tb.addField( new Roo.form.ComboBox({
44113 store: new Roo.data.SimpleStore({
44115 fields: ['val', 'selected'],
44118 name : '-roo-edit-className',
44119 attrname : 'className',
44120 displayField: 'val',
44124 triggerAction: 'all',
44125 emptyText:'Select Style',
44126 selectOnFocus:true,
44129 'select': function(c, r, i) {
44130 // initial support only for on class per el..
44131 tb.selectedNode.className = r ? r.get('val') : '';
44132 editorcore.syncValue();
44139 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44140 var tbops = tbc.options;
44142 for (var i in tlist) {
44144 var item = tlist[i];
44145 tb.add(item.title + ": ");
44148 //optname == used so you can configure the options available..
44149 var opts = item.opts ? item.opts : false;
44150 if (item.optname) {
44151 opts = tbops[item.optname];
44156 // opts == pulldown..
44157 tb.addField( new Roo.form.ComboBox({
44158 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44160 fields: ['val', 'display'],
44163 name : '-roo-edit-' + i,
44165 stylename : item.style ? item.style : false,
44166 displayField: item.displayField ? item.displayField : 'val',
44167 valueField : 'val',
44169 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44171 triggerAction: 'all',
44172 emptyText:'Select',
44173 selectOnFocus:true,
44174 width: item.width ? item.width : 130,
44176 'select': function(c, r, i) {
44178 tb.selectedNode.style[c.stylename] = r.get('val');
44181 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44190 tb.addField( new Roo.form.TextField({
44193 //allowBlank:false,
44198 tb.addField( new Roo.form.TextField({
44199 name: '-roo-edit-' + i,
44206 'change' : function(f, nv, ov) {
44207 tb.selectedNode.setAttribute(f.attrname, nv);
44216 text: 'Remove Tag',
44219 click : function ()
44222 // undo does not work.
44224 var sn = tb.selectedNode;
44226 var pn = sn.parentNode;
44228 var stn = sn.childNodes[0];
44229 var en = sn.childNodes[sn.childNodes.length - 1 ];
44230 while (sn.childNodes.length) {
44231 var node = sn.childNodes[0];
44232 sn.removeChild(node);
44234 pn.insertBefore(node, sn);
44237 pn.removeChild(sn);
44238 var range = editorcore.createRange();
44240 range.setStart(stn,0);
44241 range.setEnd(en,0); //????
44242 //range.selectNode(sel);
44245 var selection = editorcore.getSelection();
44246 selection.removeAllRanges();
44247 selection.addRange(range);
44251 //_this.updateToolbar(null, null, pn);
44252 _this.updateToolbar(null, null, null);
44253 _this.footDisp.dom.innerHTML = '';
44263 tb.el.on('click', function(e){
44264 e.preventDefault(); // what does this do?
44266 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44269 // dont need to disable them... as they will get hidden
44274 buildFooter : function()
44277 var fel = this.editor.wrap.createChild();
44278 this.footer = new Roo.Toolbar(fel);
44279 // toolbar has scrolly on left / right?
44280 var footDisp= new Roo.Toolbar.Fill();
44286 handler : function() {
44287 _t.footDisp.scrollTo('left',0,true)
44291 this.footer.add( footDisp );
44296 handler : function() {
44298 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44302 var fel = Roo.get(footDisp.el);
44303 fel.addClass('x-editor-context');
44304 this.footDispWrap = fel;
44305 this.footDispWrap.overflow = 'hidden';
44307 this.footDisp = fel.createChild();
44308 this.footDispWrap.on('click', this.onContextClick, this)
44312 onContextClick : function (ev,dom)
44314 ev.preventDefault();
44315 var cn = dom.className;
44317 if (!cn.match(/x-ed-loc-/)) {
44320 var n = cn.split('-').pop();
44321 var ans = this.footerEls;
44325 var range = this.editorcore.createRange();
44327 range.selectNodeContents(sel);
44328 //range.selectNode(sel);
44331 var selection = this.editorcore.getSelection();
44332 selection.removeAllRanges();
44333 selection.addRange(range);
44337 this.updateToolbar(null, null, sel);
44354 * Ext JS Library 1.1.1
44355 * Copyright(c) 2006-2007, Ext JS, LLC.
44357 * Originally Released Under LGPL - original licence link has changed is not relivant.
44360 * <script type="text/javascript">
44364 * @class Roo.form.BasicForm
44365 * @extends Roo.util.Observable
44366 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44368 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44369 * @param {Object} config Configuration options
44371 Roo.form.BasicForm = function(el, config){
44372 this.allItems = [];
44373 this.childForms = [];
44374 Roo.apply(this, config);
44376 * The Roo.form.Field items in this form.
44377 * @type MixedCollection
44381 this.items = new Roo.util.MixedCollection(false, function(o){
44382 return o.id || (o.id = Roo.id());
44386 * @event beforeaction
44387 * Fires before any action is performed. Return false to cancel the action.
44388 * @param {Form} this
44389 * @param {Action} action The action to be performed
44391 beforeaction: true,
44393 * @event actionfailed
44394 * Fires when an action fails.
44395 * @param {Form} this
44396 * @param {Action} action The action that failed
44398 actionfailed : true,
44400 * @event actioncomplete
44401 * Fires when an action is completed.
44402 * @param {Form} this
44403 * @param {Action} action The action that completed
44405 actioncomplete : true
44410 Roo.form.BasicForm.superclass.constructor.call(this);
44413 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44415 * @cfg {String} method
44416 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
44419 * @cfg {DataReader} reader
44420 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
44421 * This is optional as there is built-in support for processing JSON.
44424 * @cfg {DataReader} errorReader
44425 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
44426 * This is completely optional as there is built-in support for processing JSON.
44429 * @cfg {String} url
44430 * The URL to use for form actions if one isn't supplied in the action options.
44433 * @cfg {Boolean} fileUpload
44434 * Set to true if this form is a file upload.
44438 * @cfg {Object} baseParams
44439 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
44444 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
44449 activeAction : null,
44452 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
44453 * or setValues() data instead of when the form was first created.
44455 trackResetOnLoad : false,
44459 * childForms - used for multi-tab forms
44462 childForms : false,
44465 * allItems - full list of fields.
44471 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
44472 * element by passing it or its id or mask the form itself by passing in true.
44475 waitMsgTarget : false,
44478 initEl : function(el){
44479 this.el = Roo.get(el);
44480 this.id = this.el.id || Roo.id();
44481 this.el.on('submit', this.onSubmit, this);
44482 this.el.addClass('x-form');
44486 onSubmit : function(e){
44491 * Returns true if client-side validation on the form is successful.
44494 isValid : function(){
44496 this.items.each(function(f){
44505 * Returns true if any fields in this form have changed since their original load.
44508 isDirty : function(){
44510 this.items.each(function(f){
44520 * Performs a predefined action (submit or load) or custom actions you define on this form.
44521 * @param {String} actionName The name of the action type
44522 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
44523 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
44524 * accept other config options):
44526 Property Type Description
44527 ---------------- --------------- ----------------------------------------------------------------------------------
44528 url String The url for the action (defaults to the form's url)
44529 method String The form method to use (defaults to the form's method, or POST if not defined)
44530 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
44531 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
44532 validate the form on the client (defaults to false)
44534 * @return {BasicForm} this
44536 doAction : function(action, options){
44537 if(typeof action == 'string'){
44538 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
44540 if(this.fireEvent('beforeaction', this, action) !== false){
44541 this.beforeAction(action);
44542 action.run.defer(100, action);
44548 * Shortcut to do a submit action.
44549 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44550 * @return {BasicForm} this
44552 submit : function(options){
44553 this.doAction('submit', options);
44558 * Shortcut to do a load action.
44559 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44560 * @return {BasicForm} this
44562 load : function(options){
44563 this.doAction('load', options);
44568 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
44569 * @param {Record} record The record to edit
44570 * @return {BasicForm} this
44572 updateRecord : function(record){
44573 record.beginEdit();
44574 var fs = record.fields;
44575 fs.each(function(f){
44576 var field = this.findField(f.name);
44578 record.set(f.name, field.getValue());
44586 * Loads an Roo.data.Record into this form.
44587 * @param {Record} record The record to load
44588 * @return {BasicForm} this
44590 loadRecord : function(record){
44591 this.setValues(record.data);
44596 beforeAction : function(action){
44597 var o = action.options;
44600 if(this.waitMsgTarget === true){
44601 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
44602 }else if(this.waitMsgTarget){
44603 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
44604 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
44606 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
44612 afterAction : function(action, success){
44613 this.activeAction = null;
44614 var o = action.options;
44616 if(this.waitMsgTarget === true){
44618 }else if(this.waitMsgTarget){
44619 this.waitMsgTarget.unmask();
44621 Roo.MessageBox.updateProgress(1);
44622 Roo.MessageBox.hide();
44629 Roo.callback(o.success, o.scope, [this, action]);
44630 this.fireEvent('actioncomplete', this, action);
44634 // failure condition..
44635 // we have a scenario where updates need confirming.
44636 // eg. if a locking scenario exists..
44637 // we look for { errors : { needs_confirm : true }} in the response.
44639 (typeof(action.result) != 'undefined') &&
44640 (typeof(action.result.errors) != 'undefined') &&
44641 (typeof(action.result.errors.needs_confirm) != 'undefined')
44644 Roo.MessageBox.confirm(
44645 "Change requires confirmation",
44646 action.result.errorMsg,
44651 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
44661 Roo.callback(o.failure, o.scope, [this, action]);
44662 // show an error message if no failed handler is set..
44663 if (!this.hasListener('actionfailed')) {
44664 Roo.MessageBox.alert("Error",
44665 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
44666 action.result.errorMsg :
44667 "Saving Failed, please check your entries or try again"
44671 this.fireEvent('actionfailed', this, action);
44677 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
44678 * @param {String} id The value to search for
44681 findField : function(id){
44682 var field = this.items.get(id);
44684 this.items.each(function(f){
44685 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
44691 return field || null;
44695 * Add a secondary form to this one,
44696 * Used to provide tabbed forms. One form is primary, with hidden values
44697 * which mirror the elements from the other forms.
44699 * @param {Roo.form.Form} form to add.
44702 addForm : function(form)
44705 if (this.childForms.indexOf(form) > -1) {
44709 this.childForms.push(form);
44711 Roo.each(form.allItems, function (fe) {
44713 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
44714 if (this.findField(n)) { // already added..
44717 var add = new Roo.form.Hidden({
44720 add.render(this.el);
44727 * Mark fields in this form invalid in bulk.
44728 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
44729 * @return {BasicForm} this
44731 markInvalid : function(errors){
44732 if(errors instanceof Array){
44733 for(var i = 0, len = errors.length; i < len; i++){
44734 var fieldError = errors[i];
44735 var f = this.findField(fieldError.id);
44737 f.markInvalid(fieldError.msg);
44743 if(typeof errors[id] != 'function' && (field = this.findField(id))){
44744 field.markInvalid(errors[id]);
44748 Roo.each(this.childForms || [], function (f) {
44749 f.markInvalid(errors);
44756 * Set values for fields in this form in bulk.
44757 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
44758 * @return {BasicForm} this
44760 setValues : function(values){
44761 if(values instanceof Array){ // array of objects
44762 for(var i = 0, len = values.length; i < len; i++){
44764 var f = this.findField(v.id);
44766 f.setValue(v.value);
44767 if(this.trackResetOnLoad){
44768 f.originalValue = f.getValue();
44772 }else{ // object hash
44775 if(typeof values[id] != 'function' && (field = this.findField(id))){
44777 if (field.setFromData &&
44778 field.valueField &&
44779 field.displayField &&
44780 // combos' with local stores can
44781 // be queried via setValue()
44782 // to set their value..
44783 (field.store && !field.store.isLocal)
44787 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44788 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44789 field.setFromData(sd);
44792 field.setValue(values[id]);
44796 if(this.trackResetOnLoad){
44797 field.originalValue = field.getValue();
44803 Roo.each(this.childForms || [], function (f) {
44804 f.setValues(values);
44811 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
44812 * they are returned as an array.
44813 * @param {Boolean} asString
44816 getValues : function(asString){
44817 if (this.childForms) {
44818 // copy values from the child forms
44819 Roo.each(this.childForms, function (f) {
44820 this.setValues(f.getValues());
44826 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
44827 if(asString === true){
44830 return Roo.urlDecode(fs);
44834 * Returns the fields in this form as an object with key/value pairs.
44835 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
44838 getFieldValues : function(with_hidden)
44840 if (this.childForms) {
44841 // copy values from the child forms
44842 // should this call getFieldValues - probably not as we do not currently copy
44843 // hidden fields when we generate..
44844 Roo.each(this.childForms, function (f) {
44845 this.setValues(f.getValues());
44850 this.items.each(function(f){
44851 if (!f.getName()) {
44854 var v = f.getValue();
44855 if (f.inputType =='radio') {
44856 if (typeof(ret[f.getName()]) == 'undefined') {
44857 ret[f.getName()] = ''; // empty..
44860 if (!f.el.dom.checked) {
44864 v = f.el.dom.value;
44868 // not sure if this supported any more..
44869 if ((typeof(v) == 'object') && f.getRawValue) {
44870 v = f.getRawValue() ; // dates..
44872 // combo boxes where name != hiddenName...
44873 if (f.name != f.getName()) {
44874 ret[f.name] = f.getRawValue();
44876 ret[f.getName()] = v;
44883 * Clears all invalid messages in this form.
44884 * @return {BasicForm} this
44886 clearInvalid : function(){
44887 this.items.each(function(f){
44891 Roo.each(this.childForms || [], function (f) {
44900 * Resets this form.
44901 * @return {BasicForm} this
44903 reset : function(){
44904 this.items.each(function(f){
44908 Roo.each(this.childForms || [], function (f) {
44917 * Add Roo.form components to this form.
44918 * @param {Field} field1
44919 * @param {Field} field2 (optional)
44920 * @param {Field} etc (optional)
44921 * @return {BasicForm} this
44924 this.items.addAll(Array.prototype.slice.call(arguments, 0));
44930 * Removes a field from the items collection (does NOT remove its markup).
44931 * @param {Field} field
44932 * @return {BasicForm} this
44934 remove : function(field){
44935 this.items.remove(field);
44940 * Looks at the fields in this form, checks them for an id attribute,
44941 * and calls applyTo on the existing dom element with that id.
44942 * @return {BasicForm} this
44944 render : function(){
44945 this.items.each(function(f){
44946 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
44954 * Calls {@link Ext#apply} for all fields in this form with the passed object.
44955 * @param {Object} values
44956 * @return {BasicForm} this
44958 applyToFields : function(o){
44959 this.items.each(function(f){
44966 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
44967 * @param {Object} values
44968 * @return {BasicForm} this
44970 applyIfToFields : function(o){
44971 this.items.each(function(f){
44979 Roo.BasicForm = Roo.form.BasicForm;/*
44981 * Ext JS Library 1.1.1
44982 * Copyright(c) 2006-2007, Ext JS, LLC.
44984 * Originally Released Under LGPL - original licence link has changed is not relivant.
44987 * <script type="text/javascript">
44991 * @class Roo.form.Form
44992 * @extends Roo.form.BasicForm
44993 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
44995 * @param {Object} config Configuration options
44997 Roo.form.Form = function(config){
44999 if (config.items) {
45000 xitems = config.items;
45001 delete config.items;
45005 Roo.form.Form.superclass.constructor.call(this, null, config);
45006 this.url = this.url || this.action;
45008 this.root = new Roo.form.Layout(Roo.applyIf({
45012 this.active = this.root;
45014 * Array of all the buttons that have been added to this form via {@link addButton}
45018 this.allItems = [];
45021 * @event clientvalidation
45022 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45023 * @param {Form} this
45024 * @param {Boolean} valid true if the form has passed client-side validation
45026 clientvalidation: true,
45029 * Fires when the form is rendered
45030 * @param {Roo.form.Form} form
45035 if (this.progressUrl) {
45036 // push a hidden field onto the list of fields..
45040 name : 'UPLOAD_IDENTIFIER'
45045 Roo.each(xitems, this.addxtype, this);
45051 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45053 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45056 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45059 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45061 buttonAlign:'center',
45064 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45069 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45070 * This property cascades to child containers if not set.
45075 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45076 * fires a looping event with that state. This is required to bind buttons to the valid
45077 * state using the config value formBind:true on the button.
45079 monitorValid : false,
45082 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45087 * @cfg {String} progressUrl - Url to return progress data
45090 progressUrl : false,
45093 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45094 * fields are added and the column is closed. If no fields are passed the column remains open
45095 * until end() is called.
45096 * @param {Object} config The config to pass to the column
45097 * @param {Field} field1 (optional)
45098 * @param {Field} field2 (optional)
45099 * @param {Field} etc (optional)
45100 * @return Column The column container object
45102 column : function(c){
45103 var col = new Roo.form.Column(c);
45105 if(arguments.length > 1){ // duplicate code required because of Opera
45106 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45113 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45114 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45115 * until end() is called.
45116 * @param {Object} config The config to pass to the fieldset
45117 * @param {Field} field1 (optional)
45118 * @param {Field} field2 (optional)
45119 * @param {Field} etc (optional)
45120 * @return FieldSet The fieldset container object
45122 fieldset : function(c){
45123 var fs = new Roo.form.FieldSet(c);
45125 if(arguments.length > 1){ // duplicate code required because of Opera
45126 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45133 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45134 * fields are added and the container is closed. If no fields are passed the container remains open
45135 * until end() is called.
45136 * @param {Object} config The config to pass to the Layout
45137 * @param {Field} field1 (optional)
45138 * @param {Field} field2 (optional)
45139 * @param {Field} etc (optional)
45140 * @return Layout The container object
45142 container : function(c){
45143 var l = new Roo.form.Layout(c);
45145 if(arguments.length > 1){ // duplicate code required because of Opera
45146 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45153 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45154 * @param {Object} container A Roo.form.Layout or subclass of Layout
45155 * @return {Form} this
45157 start : function(c){
45158 // cascade label info
45159 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45160 this.active.stack.push(c);
45161 c.ownerCt = this.active;
45167 * Closes the current open container
45168 * @return {Form} this
45171 if(this.active == this.root){
45174 this.active = this.active.ownerCt;
45179 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45180 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45181 * as the label of the field.
45182 * @param {Field} field1
45183 * @param {Field} field2 (optional)
45184 * @param {Field} etc. (optional)
45185 * @return {Form} this
45188 this.active.stack.push.apply(this.active.stack, arguments);
45189 this.allItems.push.apply(this.allItems,arguments);
45191 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45192 if(a[i].isFormField){
45197 Roo.form.Form.superclass.add.apply(this, r);
45207 * Find any element that has been added to a form, using it's ID or name
45208 * This can include framesets, columns etc. along with regular fields..
45209 * @param {String} id - id or name to find.
45211 * @return {Element} e - or false if nothing found.
45213 findbyId : function(id)
45219 Roo.each(this.allItems, function(f){
45220 if (f.id == id || f.name == id ){
45231 * Render this form into the passed container. This should only be called once!
45232 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45233 * @return {Form} this
45235 render : function(ct)
45241 var o = this.autoCreate || {
45243 method : this.method || 'POST',
45244 id : this.id || Roo.id()
45246 this.initEl(ct.createChild(o));
45248 this.root.render(this.el);
45252 this.items.each(function(f){
45253 f.render('x-form-el-'+f.id);
45256 if(this.buttons.length > 0){
45257 // tables are required to maintain order and for correct IE layout
45258 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45259 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45260 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45262 var tr = tb.getElementsByTagName('tr')[0];
45263 for(var i = 0, len = this.buttons.length; i < len; i++) {
45264 var b = this.buttons[i];
45265 var td = document.createElement('td');
45266 td.className = 'x-form-btn-td';
45267 b.render(tr.appendChild(td));
45270 if(this.monitorValid){ // initialize after render
45271 this.startMonitoring();
45273 this.fireEvent('rendered', this);
45278 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45279 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45280 * object or a valid Roo.DomHelper element config
45281 * @param {Function} handler The function called when the button is clicked
45282 * @param {Object} scope (optional) The scope of the handler function
45283 * @return {Roo.Button}
45285 addButton : function(config, handler, scope){
45289 minWidth: this.minButtonWidth,
45292 if(typeof config == "string"){
45295 Roo.apply(bc, config);
45297 var btn = new Roo.Button(null, bc);
45298 this.buttons.push(btn);
45303 * Adds a series of form elements (using the xtype property as the factory method.
45304 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45305 * @param {Object} config
45308 addxtype : function()
45310 var ar = Array.prototype.slice.call(arguments, 0);
45312 for(var i = 0; i < ar.length; i++) {
45314 continue; // skip -- if this happends something invalid got sent, we
45315 // should ignore it, as basically that interface element will not show up
45316 // and that should be pretty obvious!!
45319 if (Roo.form[ar[i].xtype]) {
45321 var fe = Roo.factory(ar[i], Roo.form);
45327 fe.store.form = this;
45332 this.allItems.push(fe);
45333 if (fe.items && fe.addxtype) {
45334 fe.addxtype.apply(fe, fe.items);
45344 // console.log('adding ' + ar[i].xtype);
45346 if (ar[i].xtype == 'Button') {
45347 //console.log('adding button');
45348 //console.log(ar[i]);
45349 this.addButton(ar[i]);
45350 this.allItems.push(fe);
45354 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45355 alert('end is not supported on xtype any more, use items');
45357 // //console.log('adding end');
45365 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45366 * option "monitorValid"
45368 startMonitoring : function(){
45371 Roo.TaskMgr.start({
45372 run : this.bindHandler,
45373 interval : this.monitorPoll || 200,
45380 * Stops monitoring of the valid state of this form
45382 stopMonitoring : function(){
45383 this.bound = false;
45387 bindHandler : function(){
45389 return false; // stops binding
45392 this.items.each(function(f){
45393 if(!f.isValid(true)){
45398 for(var i = 0, len = this.buttons.length; i < len; i++){
45399 var btn = this.buttons[i];
45400 if(btn.formBind === true && btn.disabled === valid){
45401 btn.setDisabled(!valid);
45404 this.fireEvent('clientvalidation', this, valid);
45418 Roo.Form = Roo.form.Form;
45421 * Ext JS Library 1.1.1
45422 * Copyright(c) 2006-2007, Ext JS, LLC.
45424 * Originally Released Under LGPL - original licence link has changed is not relivant.
45427 * <script type="text/javascript">
45430 // as we use this in bootstrap.
45431 Roo.namespace('Roo.form');
45433 * @class Roo.form.Action
45434 * Internal Class used to handle form actions
45436 * @param {Roo.form.BasicForm} el The form element or its id
45437 * @param {Object} config Configuration options
45442 // define the action interface
45443 Roo.form.Action = function(form, options){
45445 this.options = options || {};
45448 * Client Validation Failed
45451 Roo.form.Action.CLIENT_INVALID = 'client';
45453 * Server Validation Failed
45456 Roo.form.Action.SERVER_INVALID = 'server';
45458 * Connect to Server Failed
45461 Roo.form.Action.CONNECT_FAILURE = 'connect';
45463 * Reading Data from Server Failed
45466 Roo.form.Action.LOAD_FAILURE = 'load';
45468 Roo.form.Action.prototype = {
45470 failureType : undefined,
45471 response : undefined,
45472 result : undefined,
45474 // interface method
45475 run : function(options){
45479 // interface method
45480 success : function(response){
45484 // interface method
45485 handleResponse : function(response){
45489 // default connection failure
45490 failure : function(response){
45492 this.response = response;
45493 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45494 this.form.afterAction(this, false);
45497 processResponse : function(response){
45498 this.response = response;
45499 if(!response.responseText){
45502 this.result = this.handleResponse(response);
45503 return this.result;
45506 // utility functions used internally
45507 getUrl : function(appendParams){
45508 var url = this.options.url || this.form.url || this.form.el.dom.action;
45510 var p = this.getParams();
45512 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
45518 getMethod : function(){
45519 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
45522 getParams : function(){
45523 var bp = this.form.baseParams;
45524 var p = this.options.params;
45526 if(typeof p == "object"){
45527 p = Roo.urlEncode(Roo.applyIf(p, bp));
45528 }else if(typeof p == 'string' && bp){
45529 p += '&' + Roo.urlEncode(bp);
45532 p = Roo.urlEncode(bp);
45537 createCallback : function(){
45539 success: this.success,
45540 failure: this.failure,
45542 timeout: (this.form.timeout*1000),
45543 upload: this.form.fileUpload ? this.success : undefined
45548 Roo.form.Action.Submit = function(form, options){
45549 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
45552 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
45555 haveProgress : false,
45556 uploadComplete : false,
45558 // uploadProgress indicator.
45559 uploadProgress : function()
45561 if (!this.form.progressUrl) {
45565 if (!this.haveProgress) {
45566 Roo.MessageBox.progress("Uploading", "Uploading");
45568 if (this.uploadComplete) {
45569 Roo.MessageBox.hide();
45573 this.haveProgress = true;
45575 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
45577 var c = new Roo.data.Connection();
45579 url : this.form.progressUrl,
45584 success : function(req){
45585 //console.log(data);
45589 rdata = Roo.decode(req.responseText)
45591 Roo.log("Invalid data from server..");
45595 if (!rdata || !rdata.success) {
45597 Roo.MessageBox.alert(Roo.encode(rdata));
45600 var data = rdata.data;
45602 if (this.uploadComplete) {
45603 Roo.MessageBox.hide();
45608 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
45609 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
45612 this.uploadProgress.defer(2000,this);
45615 failure: function(data) {
45616 Roo.log('progress url failed ');
45627 // run get Values on the form, so it syncs any secondary forms.
45628 this.form.getValues();
45630 var o = this.options;
45631 var method = this.getMethod();
45632 var isPost = method == 'POST';
45633 if(o.clientValidation === false || this.form.isValid()){
45635 if (this.form.progressUrl) {
45636 this.form.findField('UPLOAD_IDENTIFIER').setValue(
45637 (new Date() * 1) + '' + Math.random());
45642 Roo.Ajax.request(Roo.apply(this.createCallback(), {
45643 form:this.form.el.dom,
45644 url:this.getUrl(!isPost),
45646 params:isPost ? this.getParams() : null,
45647 isUpload: this.form.fileUpload
45650 this.uploadProgress();
45652 }else if (o.clientValidation !== false){ // client validation failed
45653 this.failureType = Roo.form.Action.CLIENT_INVALID;
45654 this.form.afterAction(this, false);
45658 success : function(response)
45660 this.uploadComplete= true;
45661 if (this.haveProgress) {
45662 Roo.MessageBox.hide();
45666 var result = this.processResponse(response);
45667 if(result === true || result.success){
45668 this.form.afterAction(this, true);
45672 this.form.markInvalid(result.errors);
45673 this.failureType = Roo.form.Action.SERVER_INVALID;
45675 this.form.afterAction(this, false);
45677 failure : function(response)
45679 this.uploadComplete= true;
45680 if (this.haveProgress) {
45681 Roo.MessageBox.hide();
45684 this.response = response;
45685 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45686 this.form.afterAction(this, false);
45689 handleResponse : function(response){
45690 if(this.form.errorReader){
45691 var rs = this.form.errorReader.read(response);
45694 for(var i = 0, len = rs.records.length; i < len; i++) {
45695 var r = rs.records[i];
45696 errors[i] = r.data;
45699 if(errors.length < 1){
45703 success : rs.success,
45709 ret = Roo.decode(response.responseText);
45713 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
45723 Roo.form.Action.Load = function(form, options){
45724 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
45725 this.reader = this.form.reader;
45728 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
45733 Roo.Ajax.request(Roo.apply(
45734 this.createCallback(), {
45735 method:this.getMethod(),
45736 url:this.getUrl(false),
45737 params:this.getParams()
45741 success : function(response){
45743 var result = this.processResponse(response);
45744 if(result === true || !result.success || !result.data){
45745 this.failureType = Roo.form.Action.LOAD_FAILURE;
45746 this.form.afterAction(this, false);
45749 this.form.clearInvalid();
45750 this.form.setValues(result.data);
45751 this.form.afterAction(this, true);
45754 handleResponse : function(response){
45755 if(this.form.reader){
45756 var rs = this.form.reader.read(response);
45757 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
45759 success : rs.success,
45763 return Roo.decode(response.responseText);
45767 Roo.form.Action.ACTION_TYPES = {
45768 'load' : Roo.form.Action.Load,
45769 'submit' : Roo.form.Action.Submit
45772 * Ext JS Library 1.1.1
45773 * Copyright(c) 2006-2007, Ext JS, LLC.
45775 * Originally Released Under LGPL - original licence link has changed is not relivant.
45778 * <script type="text/javascript">
45782 * @class Roo.form.Layout
45783 * @extends Roo.Component
45784 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45786 * @param {Object} config Configuration options
45788 Roo.form.Layout = function(config){
45790 if (config.items) {
45791 xitems = config.items;
45792 delete config.items;
45794 Roo.form.Layout.superclass.constructor.call(this, config);
45796 Roo.each(xitems, this.addxtype, this);
45800 Roo.extend(Roo.form.Layout, Roo.Component, {
45802 * @cfg {String/Object} autoCreate
45803 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
45806 * @cfg {String/Object/Function} style
45807 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
45808 * a function which returns such a specification.
45811 * @cfg {String} labelAlign
45812 * Valid values are "left," "top" and "right" (defaults to "left")
45815 * @cfg {Number} labelWidth
45816 * Fixed width in pixels of all field labels (defaults to undefined)
45819 * @cfg {Boolean} clear
45820 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
45824 * @cfg {String} labelSeparator
45825 * The separator to use after field labels (defaults to ':')
45827 labelSeparator : ':',
45829 * @cfg {Boolean} hideLabels
45830 * True to suppress the display of field labels in this layout (defaults to false)
45832 hideLabels : false,
45835 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
45840 onRender : function(ct, position){
45841 if(this.el){ // from markup
45842 this.el = Roo.get(this.el);
45843 }else { // generate
45844 var cfg = this.getAutoCreate();
45845 this.el = ct.createChild(cfg, position);
45848 this.el.applyStyles(this.style);
45850 if(this.labelAlign){
45851 this.el.addClass('x-form-label-'+this.labelAlign);
45853 if(this.hideLabels){
45854 this.labelStyle = "display:none";
45855 this.elementStyle = "padding-left:0;";
45857 if(typeof this.labelWidth == 'number'){
45858 this.labelStyle = "width:"+this.labelWidth+"px;";
45859 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
45861 if(this.labelAlign == 'top'){
45862 this.labelStyle = "width:auto;";
45863 this.elementStyle = "padding-left:0;";
45866 var stack = this.stack;
45867 var slen = stack.length;
45869 if(!this.fieldTpl){
45870 var t = new Roo.Template(
45871 '<div class="x-form-item {5}">',
45872 '<label for="{0}" style="{2}">{1}{4}</label>',
45873 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45875 '</div><div class="x-form-clear-left"></div>'
45877 t.disableFormats = true;
45879 Roo.form.Layout.prototype.fieldTpl = t;
45881 for(var i = 0; i < slen; i++) {
45882 if(stack[i].isFormField){
45883 this.renderField(stack[i]);
45885 this.renderComponent(stack[i]);
45890 this.el.createChild({cls:'x-form-clear'});
45895 renderField : function(f){
45896 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
45899 f.labelStyle||this.labelStyle||'', //2
45900 this.elementStyle||'', //3
45901 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
45902 f.itemCls||this.itemCls||'' //5
45903 ], true).getPrevSibling());
45907 renderComponent : function(c){
45908 c.render(c.isLayout ? this.el : this.el.createChild());
45911 * Adds a object form elements (using the xtype property as the factory method.)
45912 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
45913 * @param {Object} config
45915 addxtype : function(o)
45917 // create the lement.
45918 o.form = this.form;
45919 var fe = Roo.factory(o, Roo.form);
45920 this.form.allItems.push(fe);
45921 this.stack.push(fe);
45923 if (fe.isFormField) {
45924 this.form.items.add(fe);
45932 * @class Roo.form.Column
45933 * @extends Roo.form.Layout
45934 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
45936 * @param {Object} config Configuration options
45938 Roo.form.Column = function(config){
45939 Roo.form.Column.superclass.constructor.call(this, config);
45942 Roo.extend(Roo.form.Column, Roo.form.Layout, {
45944 * @cfg {Number/String} width
45945 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45948 * @cfg {String/Object} autoCreate
45949 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
45953 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
45956 onRender : function(ct, position){
45957 Roo.form.Column.superclass.onRender.call(this, ct, position);
45959 this.el.setWidth(this.width);
45966 * @class Roo.form.Row
45967 * @extends Roo.form.Layout
45968 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
45970 * @param {Object} config Configuration options
45974 Roo.form.Row = function(config){
45975 Roo.form.Row.superclass.constructor.call(this, config);
45978 Roo.extend(Roo.form.Row, Roo.form.Layout, {
45980 * @cfg {Number/String} width
45981 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45984 * @cfg {Number/String} height
45985 * The fixed height of the column in pixels or CSS value (defaults to "auto")
45987 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
45991 onRender : function(ct, position){
45992 //console.log('row render');
45994 var t = new Roo.Template(
45995 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
45996 '<label for="{0}" style="{2}">{1}{4}</label>',
45997 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46001 t.disableFormats = true;
46003 Roo.form.Layout.prototype.rowTpl = t;
46005 this.fieldTpl = this.rowTpl;
46007 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46008 var labelWidth = 100;
46010 if ((this.labelAlign != 'top')) {
46011 if (typeof this.labelWidth == 'number') {
46012 labelWidth = this.labelWidth
46014 this.padWidth = 20 + labelWidth;
46018 Roo.form.Column.superclass.onRender.call(this, ct, position);
46020 this.el.setWidth(this.width);
46023 this.el.setHeight(this.height);
46028 renderField : function(f){
46029 f.fieldEl = this.fieldTpl.append(this.el, [
46030 f.id, f.fieldLabel,
46031 f.labelStyle||this.labelStyle||'',
46032 this.elementStyle||'',
46033 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46034 f.itemCls||this.itemCls||'',
46035 f.width ? f.width + this.padWidth : 160 + this.padWidth
46042 * @class Roo.form.FieldSet
46043 * @extends Roo.form.Layout
46044 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46046 * @param {Object} config Configuration options
46048 Roo.form.FieldSet = function(config){
46049 Roo.form.FieldSet.superclass.constructor.call(this, config);
46052 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46054 * @cfg {String} legend
46055 * The text to display as the legend for the FieldSet (defaults to '')
46058 * @cfg {String/Object} autoCreate
46059 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46063 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46066 onRender : function(ct, position){
46067 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46069 this.setLegend(this.legend);
46074 setLegend : function(text){
46076 this.el.child('legend').update(text);
46081 * Ext JS Library 1.1.1
46082 * Copyright(c) 2006-2007, Ext JS, LLC.
46084 * Originally Released Under LGPL - original licence link has changed is not relivant.
46087 * <script type="text/javascript">
46090 * @class Roo.form.VTypes
46091 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46094 Roo.form.VTypes = function(){
46095 // closure these in so they are only created once.
46096 var alpha = /^[a-zA-Z_]+$/;
46097 var alphanum = /^[a-zA-Z0-9_]+$/;
46098 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46099 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46101 // All these messages and functions are configurable
46104 * The function used to validate email addresses
46105 * @param {String} value The email address
46107 'email' : function(v){
46108 return email.test(v);
46111 * The error text to display when the email validation function returns false
46114 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46116 * The keystroke filter mask to be applied on email input
46119 'emailMask' : /[a-z0-9_\.\-@]/i,
46122 * The function used to validate URLs
46123 * @param {String} value The URL
46125 'url' : function(v){
46126 return url.test(v);
46129 * The error text to display when the url validation function returns false
46132 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46135 * The function used to validate alpha values
46136 * @param {String} value The value
46138 'alpha' : function(v){
46139 return alpha.test(v);
46142 * The error text to display when the alpha validation function returns false
46145 'alphaText' : 'This field should only contain letters and _',
46147 * The keystroke filter mask to be applied on alpha input
46150 'alphaMask' : /[a-z_]/i,
46153 * The function used to validate alphanumeric values
46154 * @param {String} value The value
46156 'alphanum' : function(v){
46157 return alphanum.test(v);
46160 * The error text to display when the alphanumeric validation function returns false
46163 'alphanumText' : 'This field should only contain letters, numbers and _',
46165 * The keystroke filter mask to be applied on alphanumeric input
46168 'alphanumMask' : /[a-z0-9_]/i
46170 }();//<script type="text/javascript">
46173 * @class Roo.form.FCKeditor
46174 * @extends Roo.form.TextArea
46175 * Wrapper around the FCKEditor http://www.fckeditor.net
46177 * Creates a new FCKeditor
46178 * @param {Object} config Configuration options
46180 Roo.form.FCKeditor = function(config){
46181 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46184 * @event editorinit
46185 * Fired when the editor is initialized - you can add extra handlers here..
46186 * @param {FCKeditor} this
46187 * @param {Object} the FCK object.
46194 Roo.form.FCKeditor.editors = { };
46195 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46197 //defaultAutoCreate : {
46198 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46202 * @cfg {Object} fck options - see fck manual for details.
46207 * @cfg {Object} fck toolbar set (Basic or Default)
46209 toolbarSet : 'Basic',
46211 * @cfg {Object} fck BasePath
46213 basePath : '/fckeditor/',
46221 onRender : function(ct, position)
46224 this.defaultAutoCreate = {
46226 style:"width:300px;height:60px;",
46227 autocomplete: "off"
46230 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46233 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46234 if(this.preventScrollbars){
46235 this.el.setStyle("overflow", "hidden");
46237 this.el.setHeight(this.growMin);
46240 //console.log('onrender' + this.getId() );
46241 Roo.form.FCKeditor.editors[this.getId()] = this;
46244 this.replaceTextarea() ;
46248 getEditor : function() {
46249 return this.fckEditor;
46252 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46253 * @param {Mixed} value The value to set
46257 setValue : function(value)
46259 //console.log('setValue: ' + value);
46261 if(typeof(value) == 'undefined') { // not sure why this is happending...
46264 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46266 //if(!this.el || !this.getEditor()) {
46267 // this.value = value;
46268 //this.setValue.defer(100,this,[value]);
46272 if(!this.getEditor()) {
46276 this.getEditor().SetData(value);
46283 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46284 * @return {Mixed} value The field value
46286 getValue : function()
46289 if (this.frame && this.frame.dom.style.display == 'none') {
46290 return Roo.form.FCKeditor.superclass.getValue.call(this);
46293 if(!this.el || !this.getEditor()) {
46295 // this.getValue.defer(100,this);
46300 var value=this.getEditor().GetData();
46301 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46302 return Roo.form.FCKeditor.superclass.getValue.call(this);
46308 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46309 * @return {Mixed} value The field value
46311 getRawValue : function()
46313 if (this.frame && this.frame.dom.style.display == 'none') {
46314 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46317 if(!this.el || !this.getEditor()) {
46318 //this.getRawValue.defer(100,this);
46325 var value=this.getEditor().GetData();
46326 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46327 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46331 setSize : function(w,h) {
46335 //if (this.frame && this.frame.dom.style.display == 'none') {
46336 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46339 //if(!this.el || !this.getEditor()) {
46340 // this.setSize.defer(100,this, [w,h]);
46346 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46348 this.frame.dom.setAttribute('width', w);
46349 this.frame.dom.setAttribute('height', h);
46350 this.frame.setSize(w,h);
46354 toggleSourceEdit : function(value) {
46358 this.el.dom.style.display = value ? '' : 'none';
46359 this.frame.dom.style.display = value ? 'none' : '';
46364 focus: function(tag)
46366 if (this.frame.dom.style.display == 'none') {
46367 return Roo.form.FCKeditor.superclass.focus.call(this);
46369 if(!this.el || !this.getEditor()) {
46370 this.focus.defer(100,this, [tag]);
46377 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46378 this.getEditor().Focus();
46380 if (!this.getEditor().Selection.GetSelection()) {
46381 this.focus.defer(100,this, [tag]);
46386 var r = this.getEditor().EditorDocument.createRange();
46387 r.setStart(tgs[0],0);
46388 r.setEnd(tgs[0],0);
46389 this.getEditor().Selection.GetSelection().removeAllRanges();
46390 this.getEditor().Selection.GetSelection().addRange(r);
46391 this.getEditor().Focus();
46398 replaceTextarea : function()
46400 if ( document.getElementById( this.getId() + '___Frame' ) )
46402 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46404 // We must check the elements firstly using the Id and then the name.
46405 var oTextarea = document.getElementById( this.getId() );
46407 var colElementsByName = document.getElementsByName( this.getId() ) ;
46409 oTextarea.style.display = 'none' ;
46411 if ( oTextarea.tabIndex ) {
46412 this.TabIndex = oTextarea.tabIndex ;
46415 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46416 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46417 this.frame = Roo.get(this.getId() + '___Frame')
46420 _getConfigHtml : function()
46424 for ( var o in this.fckconfig ) {
46425 sConfig += sConfig.length > 0 ? '&' : '';
46426 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
46429 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
46433 _getIFrameHtml : function()
46435 var sFile = 'fckeditor.html' ;
46436 /* no idea what this is about..
46439 if ( (/fcksource=true/i).test( window.top.location.search ) )
46440 sFile = 'fckeditor.original.html' ;
46445 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
46446 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
46449 var html = '<iframe id="' + this.getId() +
46450 '___Frame" src="' + sLink +
46451 '" width="' + this.width +
46452 '" height="' + this.height + '"' +
46453 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
46454 ' frameborder="0" scrolling="no"></iframe>' ;
46459 _insertHtmlBefore : function( html, element )
46461 if ( element.insertAdjacentHTML ) {
46463 element.insertAdjacentHTML( 'beforeBegin', html ) ;
46465 var oRange = document.createRange() ;
46466 oRange.setStartBefore( element ) ;
46467 var oFragment = oRange.createContextualFragment( html );
46468 element.parentNode.insertBefore( oFragment, element ) ;
46481 //Roo.reg('fckeditor', Roo.form.FCKeditor);
46483 function FCKeditor_OnComplete(editorInstance){
46484 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
46485 f.fckEditor = editorInstance;
46486 //console.log("loaded");
46487 f.fireEvent('editorinit', f, editorInstance);
46507 //<script type="text/javascript">
46509 * @class Roo.form.GridField
46510 * @extends Roo.form.Field
46511 * Embed a grid (or editable grid into a form)
46514 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
46516 * xgrid.store = Roo.data.Store
46517 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
46518 * xgrid.store.reader = Roo.data.JsonReader
46522 * Creates a new GridField
46523 * @param {Object} config Configuration options
46525 Roo.form.GridField = function(config){
46526 Roo.form.GridField.superclass.constructor.call(this, config);
46530 Roo.extend(Roo.form.GridField, Roo.form.Field, {
46532 * @cfg {Number} width - used to restrict width of grid..
46536 * @cfg {Number} height - used to restrict height of grid..
46540 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
46546 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46547 * {tag: "input", type: "checkbox", autocomplete: "off"})
46549 // defaultAutoCreate : { tag: 'div' },
46550 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46552 * @cfg {String} addTitle Text to include for adding a title.
46556 onResize : function(){
46557 Roo.form.Field.superclass.onResize.apply(this, arguments);
46560 initEvents : function(){
46561 // Roo.form.Checkbox.superclass.initEvents.call(this);
46562 // has no events...
46567 getResizeEl : function(){
46571 getPositionEl : function(){
46576 onRender : function(ct, position){
46578 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
46579 var style = this.style;
46582 Roo.form.GridField.superclass.onRender.call(this, ct, position);
46583 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
46584 this.viewEl = this.wrap.createChild({ tag: 'div' });
46586 this.viewEl.applyStyles(style);
46589 this.viewEl.setWidth(this.width);
46592 this.viewEl.setHeight(this.height);
46594 //if(this.inputValue !== undefined){
46595 //this.setValue(this.value);
46598 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
46601 this.grid.render();
46602 this.grid.getDataSource().on('remove', this.refreshValue, this);
46603 this.grid.getDataSource().on('update', this.refreshValue, this);
46604 this.grid.on('afteredit', this.refreshValue, this);
46610 * Sets the value of the item.
46611 * @param {String} either an object or a string..
46613 setValue : function(v){
46615 v = v || []; // empty set..
46616 // this does not seem smart - it really only affects memoryproxy grids..
46617 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
46618 var ds = this.grid.getDataSource();
46619 // assumes a json reader..
46621 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
46622 ds.loadData( data);
46624 // clear selection so it does not get stale.
46625 if (this.grid.sm) {
46626 this.grid.sm.clearSelections();
46629 Roo.form.GridField.superclass.setValue.call(this, v);
46630 this.refreshValue();
46631 // should load data in the grid really....
46635 refreshValue: function() {
46637 this.grid.getDataSource().each(function(r) {
46640 this.el.dom.value = Roo.encode(val);
46648 * Ext JS Library 1.1.1
46649 * Copyright(c) 2006-2007, Ext JS, LLC.
46651 * Originally Released Under LGPL - original licence link has changed is not relivant.
46654 * <script type="text/javascript">
46657 * @class Roo.form.DisplayField
46658 * @extends Roo.form.Field
46659 * A generic Field to display non-editable data.
46661 * Creates a new Display Field item.
46662 * @param {Object} config Configuration options
46664 Roo.form.DisplayField = function(config){
46665 Roo.form.DisplayField.superclass.constructor.call(this, config);
46669 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
46670 inputType: 'hidden',
46676 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46678 focusClass : undefined,
46680 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46682 fieldClass: 'x-form-field',
46685 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
46687 valueRenderer: undefined,
46691 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46692 * {tag: "input", type: "checkbox", autocomplete: "off"})
46695 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46697 onResize : function(){
46698 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
46702 initEvents : function(){
46703 // Roo.form.Checkbox.superclass.initEvents.call(this);
46704 // has no events...
46709 getResizeEl : function(){
46713 getPositionEl : function(){
46718 onRender : function(ct, position){
46720 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
46721 //if(this.inputValue !== undefined){
46722 this.wrap = this.el.wrap();
46724 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
46726 if (this.bodyStyle) {
46727 this.viewEl.applyStyles(this.bodyStyle);
46729 //this.viewEl.setStyle('padding', '2px');
46731 this.setValue(this.value);
46736 initValue : Roo.emptyFn,
46741 onClick : function(){
46746 * Sets the checked state of the checkbox.
46747 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
46749 setValue : function(v){
46751 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
46752 // this might be called before we have a dom element..
46753 if (!this.viewEl) {
46756 this.viewEl.dom.innerHTML = html;
46757 Roo.form.DisplayField.superclass.setValue.call(this, v);
46767 * @class Roo.form.DayPicker
46768 * @extends Roo.form.Field
46769 * A Day picker show [M] [T] [W] ....
46771 * Creates a new Day Picker
46772 * @param {Object} config Configuration options
46774 Roo.form.DayPicker= function(config){
46775 Roo.form.DayPicker.superclass.constructor.call(this, config);
46779 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
46781 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46783 focusClass : undefined,
46785 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46787 fieldClass: "x-form-field",
46790 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46791 * {tag: "input", type: "checkbox", autocomplete: "off"})
46793 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
46796 actionMode : 'viewEl',
46800 inputType : 'hidden',
46803 inputElement: false, // real input element?
46804 basedOn: false, // ????
46806 isFormField: true, // not sure where this is needed!!!!
46808 onResize : function(){
46809 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
46810 if(!this.boxLabel){
46811 this.el.alignTo(this.wrap, 'c-c');
46815 initEvents : function(){
46816 Roo.form.Checkbox.superclass.initEvents.call(this);
46817 this.el.on("click", this.onClick, this);
46818 this.el.on("change", this.onClick, this);
46822 getResizeEl : function(){
46826 getPositionEl : function(){
46832 onRender : function(ct, position){
46833 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
46835 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
46837 var r1 = '<table><tr>';
46838 var r2 = '<tr class="x-form-daypick-icons">';
46839 for (var i=0; i < 7; i++) {
46840 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
46841 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
46844 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
46845 viewEl.select('img').on('click', this.onClick, this);
46846 this.viewEl = viewEl;
46849 // this will not work on Chrome!!!
46850 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
46851 this.el.on('propertychange', this.setFromHidden, this); //ie
46859 initValue : Roo.emptyFn,
46862 * Returns the checked state of the checkbox.
46863 * @return {Boolean} True if checked, else false
46865 getValue : function(){
46866 return this.el.dom.value;
46871 onClick : function(e){
46872 //this.setChecked(!this.checked);
46873 Roo.get(e.target).toggleClass('x-menu-item-checked');
46874 this.refreshValue();
46875 //if(this.el.dom.checked != this.checked){
46876 // this.setValue(this.el.dom.checked);
46881 refreshValue : function()
46884 this.viewEl.select('img',true).each(function(e,i,n) {
46885 val += e.is(".x-menu-item-checked") ? String(n) : '';
46887 this.setValue(val, true);
46891 * Sets the checked state of the checkbox.
46892 * On is always based on a string comparison between inputValue and the param.
46893 * @param {Boolean/String} value - the value to set
46894 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
46896 setValue : function(v,suppressEvent){
46897 if (!this.el.dom) {
46900 var old = this.el.dom.value ;
46901 this.el.dom.value = v;
46902 if (suppressEvent) {
46906 // update display..
46907 this.viewEl.select('img',true).each(function(e,i,n) {
46909 var on = e.is(".x-menu-item-checked");
46910 var newv = v.indexOf(String(n)) > -1;
46912 e.toggleClass('x-menu-item-checked');
46918 this.fireEvent('change', this, v, old);
46923 // handle setting of hidden value by some other method!!?!?
46924 setFromHidden: function()
46929 //console.log("SET FROM HIDDEN");
46930 //alert('setFrom hidden');
46931 this.setValue(this.el.dom.value);
46934 onDestroy : function()
46937 Roo.get(this.viewEl).remove();
46940 Roo.form.DayPicker.superclass.onDestroy.call(this);
46944 * RooJS Library 1.1.1
46945 * Copyright(c) 2008-2011 Alan Knowles
46952 * @class Roo.form.ComboCheck
46953 * @extends Roo.form.ComboBox
46954 * A combobox for multiple select items.
46956 * FIXME - could do with a reset button..
46959 * Create a new ComboCheck
46960 * @param {Object} config Configuration options
46962 Roo.form.ComboCheck = function(config){
46963 Roo.form.ComboCheck.superclass.constructor.call(this, config);
46964 // should verify some data...
46966 // hiddenName = required..
46967 // displayField = required
46968 // valudField == required
46969 var req= [ 'hiddenName', 'displayField', 'valueField' ];
46971 Roo.each(req, function(e) {
46972 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
46973 throw "Roo.form.ComboCheck : missing value for: " + e;
46980 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
46985 selectedClass: 'x-menu-item-checked',
46988 onRender : function(ct, position){
46994 var cls = 'x-combo-list';
46997 this.tpl = new Roo.Template({
46998 html : '<div class="'+cls+'-item x-menu-check-item">' +
46999 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47000 '<span>{' + this.displayField + '}</span>' +
47007 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47008 this.view.singleSelect = false;
47009 this.view.multiSelect = true;
47010 this.view.toggleSelect = true;
47011 this.pageTb.add(new Roo.Toolbar.Fill(), {
47014 handler: function()
47021 onViewOver : function(e, t){
47027 onViewClick : function(doFocus,index){
47031 select: function () {
47032 //Roo.log("SELECT CALLED");
47035 selectByValue : function(xv, scrollIntoView){
47036 var ar = this.getValueArray();
47039 Roo.each(ar, function(v) {
47040 if(v === undefined || v === null){
47043 var r = this.findRecord(this.valueField, v);
47045 sels.push(this.store.indexOf(r))
47049 this.view.select(sels);
47055 onSelect : function(record, index){
47056 // Roo.log("onselect Called");
47057 // this is only called by the clear button now..
47058 this.view.clearSelections();
47059 this.setValue('[]');
47060 if (this.value != this.valueBefore) {
47061 this.fireEvent('change', this, this.value, this.valueBefore);
47062 this.valueBefore = this.value;
47065 getValueArray : function()
47070 //Roo.log(this.value);
47071 if (typeof(this.value) == 'undefined') {
47074 var ar = Roo.decode(this.value);
47075 return ar instanceof Array ? ar : []; //?? valid?
47078 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47083 expand : function ()
47086 Roo.form.ComboCheck.superclass.expand.call(this);
47087 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47088 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47093 collapse : function(){
47094 Roo.form.ComboCheck.superclass.collapse.call(this);
47095 var sl = this.view.getSelectedIndexes();
47096 var st = this.store;
47100 Roo.each(sl, function(i) {
47102 nv.push(r.get(this.valueField));
47104 this.setValue(Roo.encode(nv));
47105 if (this.value != this.valueBefore) {
47107 this.fireEvent('change', this, this.value, this.valueBefore);
47108 this.valueBefore = this.value;
47113 setValue : function(v){
47117 var vals = this.getValueArray();
47119 Roo.each(vals, function(k) {
47120 var r = this.findRecord(this.valueField, k);
47122 tv.push(r.data[this.displayField]);
47123 }else if(this.valueNotFoundText !== undefined){
47124 tv.push( this.valueNotFoundText );
47129 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47130 this.hiddenField.value = v;
47136 * Ext JS Library 1.1.1
47137 * Copyright(c) 2006-2007, Ext JS, LLC.
47139 * Originally Released Under LGPL - original licence link has changed is not relivant.
47142 * <script type="text/javascript">
47146 * @class Roo.form.Signature
47147 * @extends Roo.form.Field
47151 * @param {Object} config Configuration options
47154 Roo.form.Signature = function(config){
47155 Roo.form.Signature.superclass.constructor.call(this, config);
47157 this.addEvents({// not in used??
47160 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47161 * @param {Roo.form.Signature} combo This combo box
47166 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47167 * @param {Roo.form.ComboBox} combo This combo box
47168 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47174 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47176 * @cfg {Object} labels Label to use when rendering a form.
47180 * confirm : "Confirm"
47185 confirm : "Confirm"
47188 * @cfg {Number} width The signature panel width (defaults to 300)
47192 * @cfg {Number} height The signature panel height (defaults to 100)
47196 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47198 allowBlank : false,
47201 // {Object} signPanel The signature SVG panel element (defaults to {})
47203 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47204 isMouseDown : false,
47205 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47206 isConfirmed : false,
47207 // {String} signatureTmp SVG mapping string (defaults to empty string)
47211 defaultAutoCreate : { // modified by initCompnoent..
47217 onRender : function(ct, position){
47219 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47221 this.wrap = this.el.wrap({
47222 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47225 this.createToolbar(this);
47226 this.signPanel = this.wrap.createChild({
47228 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47232 this.svgID = Roo.id();
47233 this.svgEl = this.signPanel.createChild({
47234 xmlns : 'http://www.w3.org/2000/svg',
47236 id : this.svgID + "-svg",
47238 height: this.height,
47239 viewBox: '0 0 '+this.width+' '+this.height,
47243 id: this.svgID + "-svg-r",
47245 height: this.height,
47250 id: this.svgID + "-svg-l",
47252 y1: (this.height*0.8), // start set the line in 80% of height
47253 x2: this.width, // end
47254 y2: (this.height*0.8), // end set the line in 80% of height
47256 'stroke-width': "1",
47257 'stroke-dasharray': "3",
47258 'shape-rendering': "crispEdges",
47259 'pointer-events': "none"
47263 id: this.svgID + "-svg-p",
47265 'stroke-width': "3",
47267 'pointer-events': 'none'
47272 this.svgBox = this.svgEl.dom.getScreenCTM();
47274 createSVG : function(){
47275 var svg = this.signPanel;
47276 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47279 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47280 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47281 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47282 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47283 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47284 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47285 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47288 isTouchEvent : function(e){
47289 return e.type.match(/^touch/);
47291 getCoords : function (e) {
47292 var pt = this.svgEl.dom.createSVGPoint();
47295 if (this.isTouchEvent(e)) {
47296 pt.x = e.targetTouches[0].clientX
47297 pt.y = e.targetTouches[0].clientY;
47299 var a = this.svgEl.dom.getScreenCTM();
47300 var b = a.inverse();
47301 var mx = pt.matrixTransform(b);
47302 return mx.x + ',' + mx.y;
47304 //mouse event headler
47305 down : function (e) {
47306 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47307 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47309 this.isMouseDown = true;
47311 e.preventDefault();
47313 move : function (e) {
47314 if (this.isMouseDown) {
47315 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47316 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47319 e.preventDefault();
47321 up : function (e) {
47322 this.isMouseDown = false;
47323 var sp = this.signatureTmp.split(' ');
47326 if(!sp[sp.length-2].match(/^L/)){
47330 this.signatureTmp = sp.join(" ");
47333 if(this.getValue() != this.signatureTmp){
47334 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47335 this.isConfirmed = false;
47337 e.preventDefault();
47341 * Protected method that will not generally be called directly. It
47342 * is called when the editor creates its toolbar. Override this method if you need to
47343 * add custom toolbar buttons.
47344 * @param {HtmlEditor} editor
47346 createToolbar : function(editor){
47347 function btn(id, toggle, handler){
47348 var xid = fid + '-'+ id ;
47352 cls : 'x-btn-icon x-edit-'+id,
47353 enableToggle:toggle !== false,
47354 scope: editor, // was editor...
47355 handler:handler||editor.relayBtnCmd,
47356 clickEvent:'mousedown',
47357 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47363 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47367 cls : ' x-signature-btn x-signature-'+id,
47368 scope: editor, // was editor...
47369 handler: this.reset,
47370 clickEvent:'mousedown',
47371 text: this.labels.clear
47378 cls : ' x-signature-btn x-signature-'+id,
47379 scope: editor, // was editor...
47380 handler: this.confirmHandler,
47381 clickEvent:'mousedown',
47382 text: this.labels.confirm
47389 * when user is clicked confirm then show this image.....
47391 * @return {String} Image Data URI
47393 getImageDataURI : function(){
47394 var svg = this.svgEl.dom.parentNode.innerHTML;
47395 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47400 * @return {Boolean} this.isConfirmed
47402 getConfirmed : function(){
47403 return this.isConfirmed;
47407 * @return {Number} this.width
47409 getWidth : function(){
47414 * @return {Number} this.height
47416 getHeight : function(){
47417 return this.height;
47420 getSignature : function(){
47421 return this.signatureTmp;
47424 reset : function(){
47425 this.signatureTmp = '';
47426 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47427 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
47428 this.isConfirmed = false;
47429 Roo.form.Signature.superclass.reset.call(this);
47431 setSignature : function(s){
47432 this.signatureTmp = s;
47433 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47434 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
47436 this.isConfirmed = false;
47437 Roo.form.Signature.superclass.reset.call(this);
47440 // Roo.log(this.signPanel.dom.contentWindow.up())
47443 setConfirmed : function(){
47447 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
47450 confirmHandler : function(){
47451 if(!this.getSignature()){
47455 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
47456 this.setValue(this.getSignature());
47457 this.isConfirmed = true;
47459 this.fireEvent('confirm', this);
47462 // Subclasses should provide the validation implementation by overriding this
47463 validateValue : function(value){
47464 if(this.allowBlank){
47468 if(this.isConfirmed){
47475 * Ext JS Library 1.1.1
47476 * Copyright(c) 2006-2007, Ext JS, LLC.
47478 * Originally Released Under LGPL - original licence link has changed is not relivant.
47481 * <script type="text/javascript">
47486 * @class Roo.form.ComboBox
47487 * @extends Roo.form.TriggerField
47488 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
47490 * Create a new ComboBox.
47491 * @param {Object} config Configuration options
47493 Roo.form.Select = function(config){
47494 Roo.form.Select.superclass.constructor.call(this, config);
47498 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
47500 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
47503 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
47504 * rendering into an Roo.Editor, defaults to false)
47507 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
47508 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
47511 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
47514 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
47515 * the dropdown list (defaults to undefined, with no header element)
47519 * @cfg {String/Roo.Template} tpl The template to use to render the output
47523 defaultAutoCreate : {tag: "select" },
47525 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
47527 listWidth: undefined,
47529 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
47530 * mode = 'remote' or 'text' if mode = 'local')
47532 displayField: undefined,
47534 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
47535 * mode = 'remote' or 'value' if mode = 'local').
47536 * Note: use of a valueField requires the user make a selection
47537 * in order for a value to be mapped.
47539 valueField: undefined,
47543 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
47544 * field's data value (defaults to the underlying DOM element's name)
47546 hiddenName: undefined,
47548 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
47552 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
47554 selectedClass: 'x-combo-selected',
47556 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
47557 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
47558 * which displays a downward arrow icon).
47560 triggerClass : 'x-form-arrow-trigger',
47562 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
47566 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
47567 * anchor positions (defaults to 'tl-bl')
47569 listAlign: 'tl-bl?',
47571 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
47575 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
47576 * query specified by the allQuery config option (defaults to 'query')
47578 triggerAction: 'query',
47580 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
47581 * (defaults to 4, does not apply if editable = false)
47585 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
47586 * delay (typeAheadDelay) if it matches a known value (defaults to false)
47590 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
47591 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
47595 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
47596 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
47600 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
47601 * when editable = true (defaults to false)
47603 selectOnFocus:false,
47605 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
47607 queryParam: 'query',
47609 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
47610 * when mode = 'remote' (defaults to 'Loading...')
47612 loadingText: 'Loading...',
47614 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
47618 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
47622 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
47623 * traditional select (defaults to true)
47627 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
47631 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
47635 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
47636 * listWidth has a higher value)
47640 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
47641 * allow the user to set arbitrary text into the field (defaults to false)
47643 forceSelection:false,
47645 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
47646 * if typeAhead = true (defaults to 250)
47648 typeAheadDelay : 250,
47650 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
47651 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
47653 valueNotFoundText : undefined,
47656 * @cfg {String} defaultValue The value displayed after loading the store.
47661 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
47663 blockFocus : false,
47666 * @cfg {Boolean} disableClear Disable showing of clear button.
47668 disableClear : false,
47670 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
47672 alwaysQuery : false,
47678 // element that contains real text value.. (when hidden is used..)
47681 onRender : function(ct, position){
47682 Roo.form.Field.prototype.onRender.call(this, ct, position);
47685 this.store.on('beforeload', this.onBeforeLoad, this);
47686 this.store.on('load', this.onLoad, this);
47687 this.store.on('loadexception', this.onLoadException, this);
47688 this.store.load({});
47696 initEvents : function(){
47697 //Roo.form.ComboBox.superclass.initEvents.call(this);
47701 onDestroy : function(){
47704 this.store.un('beforeload', this.onBeforeLoad, this);
47705 this.store.un('load', this.onLoad, this);
47706 this.store.un('loadexception', this.onLoadException, this);
47708 //Roo.form.ComboBox.superclass.onDestroy.call(this);
47712 fireKey : function(e){
47713 if(e.isNavKeyPress() && !this.list.isVisible()){
47714 this.fireEvent("specialkey", this, e);
47719 onResize: function(w, h){
47727 * Allow or prevent the user from directly editing the field text. If false is passed,
47728 * the user will only be able to select from the items defined in the dropdown list. This method
47729 * is the runtime equivalent of setting the 'editable' config option at config time.
47730 * @param {Boolean} value True to allow the user to directly edit the field text
47732 setEditable : function(value){
47737 onBeforeLoad : function(){
47739 Roo.log("Select before load");
47742 this.innerList.update(this.loadingText ?
47743 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
47744 //this.restrictHeight();
47745 this.selectedIndex = -1;
47749 onLoad : function(){
47752 var dom = this.el.dom;
47753 dom.innerHTML = '';
47754 var od = dom.ownerDocument;
47756 if (this.emptyText) {
47757 var op = od.createElement('option');
47758 op.setAttribute('value', '');
47759 op.innerHTML = String.format('{0}', this.emptyText);
47760 dom.appendChild(op);
47762 if(this.store.getCount() > 0){
47764 var vf = this.valueField;
47765 var df = this.displayField;
47766 this.store.data.each(function(r) {
47767 // which colmsn to use... testing - cdoe / title..
47768 var op = od.createElement('option');
47769 op.setAttribute('value', r.data[vf]);
47770 op.innerHTML = String.format('{0}', r.data[df]);
47771 dom.appendChild(op);
47773 if (typeof(this.defaultValue != 'undefined')) {
47774 this.setValue(this.defaultValue);
47779 //this.onEmptyResults();
47784 onLoadException : function()
47786 dom.innerHTML = '';
47788 Roo.log("Select on load exception");
47792 Roo.log(this.store.reader.jsonData);
47793 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
47794 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
47800 onTypeAhead : function(){
47805 onSelect : function(record, index){
47806 Roo.log('on select?');
47808 if(this.fireEvent('beforeselect', this, record, index) !== false){
47809 this.setFromData(index > -1 ? record.data : false);
47811 this.fireEvent('select', this, record, index);
47816 * Returns the currently selected field value or empty string if no value is set.
47817 * @return {String} value The selected value
47819 getValue : function(){
47820 var dom = this.el.dom;
47821 this.value = dom.options[dom.selectedIndex].value;
47827 * Clears any text/value currently set in the field
47829 clearValue : function(){
47831 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
47836 * Sets the specified value into the field. If the value finds a match, the corresponding record text
47837 * will be displayed in the field. If the value does not match the data value of an existing item,
47838 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
47839 * Otherwise the field will be blank (although the value will still be set).
47840 * @param {String} value The value to match
47842 setValue : function(v){
47843 var d = this.el.dom;
47844 for (var i =0; i < d.options.length;i++) {
47845 if (v == d.options[i].value) {
47846 d.selectedIndex = i;
47854 * @property {Object} the last set data for the element
47859 * Sets the value of the field based on a object which is related to the record format for the store.
47860 * @param {Object} value the value to set as. or false on reset?
47862 setFromData : function(o){
47863 Roo.log('setfrom data?');
47869 reset : function(){
47873 findRecord : function(prop, value){
47878 if(this.store.getCount() > 0){
47879 this.store.each(function(r){
47880 if(r.data[prop] == value){
47890 getName: function()
47892 // returns hidden if it's set..
47893 if (!this.rendered) {return ''};
47894 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
47902 onEmptyResults : function(){
47903 Roo.log('empty results');
47908 * Returns true if the dropdown list is expanded, else false.
47910 isExpanded : function(){
47915 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
47916 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47917 * @param {String} value The data value of the item to select
47918 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47919 * selected item if it is not currently in view (defaults to true)
47920 * @return {Boolean} True if the value matched an item in the list, else false
47922 selectByValue : function(v, scrollIntoView){
47923 Roo.log('select By Value');
47926 if(v !== undefined && v !== null){
47927 var r = this.findRecord(this.valueField || this.displayField, v);
47929 this.select(this.store.indexOf(r), scrollIntoView);
47937 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
47938 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47939 * @param {Number} index The zero-based index of the list item to select
47940 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47941 * selected item if it is not currently in view (defaults to true)
47943 select : function(index, scrollIntoView){
47944 Roo.log('select ');
47947 this.selectedIndex = index;
47948 this.view.select(index);
47949 if(scrollIntoView !== false){
47950 var el = this.view.getNode(index);
47952 this.innerList.scrollChildIntoView(el, false);
47960 validateBlur : function(){
47967 initQuery : function(){
47968 this.doQuery(this.getRawValue());
47972 doForce : function(){
47973 if(this.el.dom.value.length > 0){
47974 this.el.dom.value =
47975 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
47981 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
47982 * query allowing the query action to be canceled if needed.
47983 * @param {String} query The SQL query to execute
47984 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
47985 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
47986 * saved in the current store (defaults to false)
47988 doQuery : function(q, forceAll){
47990 Roo.log('doQuery?');
47991 if(q === undefined || q === null){
47996 forceAll: forceAll,
48000 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48004 forceAll = qe.forceAll;
48005 if(forceAll === true || (q.length >= this.minChars)){
48006 if(this.lastQuery != q || this.alwaysQuery){
48007 this.lastQuery = q;
48008 if(this.mode == 'local'){
48009 this.selectedIndex = -1;
48011 this.store.clearFilter();
48013 this.store.filter(this.displayField, q);
48017 this.store.baseParams[this.queryParam] = q;
48019 params: this.getParams(q)
48024 this.selectedIndex = -1;
48031 getParams : function(q){
48033 //p[this.queryParam] = q;
48036 p.limit = this.pageSize;
48042 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48044 collapse : function(){
48049 collapseIf : function(e){
48054 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48056 expand : function(){
48064 * @cfg {Boolean} grow
48068 * @cfg {Number} growMin
48072 * @cfg {Number} growMax
48080 setWidth : function()
48084 getResizeEl : function(){
48087 });//<script type="text/javasscript">
48091 * @class Roo.DDView
48092 * A DnD enabled version of Roo.View.
48093 * @param {Element/String} container The Element in which to create the View.
48094 * @param {String} tpl The template string used to create the markup for each element of the View
48095 * @param {Object} config The configuration properties. These include all the config options of
48096 * {@link Roo.View} plus some specific to this class.<br>
48098 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48099 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48101 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48102 .x-view-drag-insert-above {
48103 border-top:1px dotted #3366cc;
48105 .x-view-drag-insert-below {
48106 border-bottom:1px dotted #3366cc;
48112 Roo.DDView = function(container, tpl, config) {
48113 Roo.DDView.superclass.constructor.apply(this, arguments);
48114 this.getEl().setStyle("outline", "0px none");
48115 this.getEl().unselectable();
48116 if (this.dragGroup) {
48117 this.setDraggable(this.dragGroup.split(","));
48119 if (this.dropGroup) {
48120 this.setDroppable(this.dropGroup.split(","));
48122 if (this.deletable) {
48123 this.setDeletable();
48125 this.isDirtyFlag = false;
48131 Roo.extend(Roo.DDView, Roo.View, {
48132 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48133 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48134 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48135 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48139 reset: Roo.emptyFn,
48141 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48143 validate: function() {
48147 destroy: function() {
48148 this.purgeListeners();
48149 this.getEl.removeAllListeners();
48150 this.getEl().remove();
48151 if (this.dragZone) {
48152 if (this.dragZone.destroy) {
48153 this.dragZone.destroy();
48156 if (this.dropZone) {
48157 if (this.dropZone.destroy) {
48158 this.dropZone.destroy();
48163 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48164 getName: function() {
48168 /** Loads the View from a JSON string representing the Records to put into the Store. */
48169 setValue: function(v) {
48171 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48174 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48175 this.store.proxy = new Roo.data.MemoryProxy(data);
48179 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48180 getValue: function() {
48182 this.store.each(function(rec) {
48183 result += rec.id + ',';
48185 return result.substr(0, result.length - 1) + ')';
48188 getIds: function() {
48189 var i = 0, result = new Array(this.store.getCount());
48190 this.store.each(function(rec) {
48191 result[i++] = rec.id;
48196 isDirty: function() {
48197 return this.isDirtyFlag;
48201 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48202 * whole Element becomes the target, and this causes the drop gesture to append.
48204 getTargetFromEvent : function(e) {
48205 var target = e.getTarget();
48206 while ((target !== null) && (target.parentNode != this.el.dom)) {
48207 target = target.parentNode;
48210 target = this.el.dom.lastChild || this.el.dom;
48216 * Create the drag data which consists of an object which has the property "ddel" as
48217 * the drag proxy element.
48219 getDragData : function(e) {
48220 var target = this.findItemFromChild(e.getTarget());
48222 this.handleSelection(e);
48223 var selNodes = this.getSelectedNodes();
48226 copy: this.copy || (this.allowCopy && e.ctrlKey),
48230 var selectedIndices = this.getSelectedIndexes();
48231 for (var i = 0; i < selectedIndices.length; i++) {
48232 dragData.records.push(this.store.getAt(selectedIndices[i]));
48234 if (selNodes.length == 1) {
48235 dragData.ddel = target.cloneNode(true); // the div element
48237 var div = document.createElement('div'); // create the multi element drag "ghost"
48238 div.className = 'multi-proxy';
48239 for (var i = 0, len = selNodes.length; i < len; i++) {
48240 div.appendChild(selNodes[i].cloneNode(true));
48242 dragData.ddel = div;
48244 //console.log(dragData)
48245 //console.log(dragData.ddel.innerHTML)
48248 //console.log('nodragData')
48252 /** Specify to which ddGroup items in this DDView may be dragged. */
48253 setDraggable: function(ddGroup) {
48254 if (ddGroup instanceof Array) {
48255 Roo.each(ddGroup, this.setDraggable, this);
48258 if (this.dragZone) {
48259 this.dragZone.addToGroup(ddGroup);
48261 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48262 containerScroll: true,
48266 // Draggability implies selection. DragZone's mousedown selects the element.
48267 if (!this.multiSelect) { this.singleSelect = true; }
48269 // Wire the DragZone's handlers up to methods in *this*
48270 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48274 /** Specify from which ddGroup this DDView accepts drops. */
48275 setDroppable: function(ddGroup) {
48276 if (ddGroup instanceof Array) {
48277 Roo.each(ddGroup, this.setDroppable, this);
48280 if (this.dropZone) {
48281 this.dropZone.addToGroup(ddGroup);
48283 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48284 containerScroll: true,
48288 // Wire the DropZone's handlers up to methods in *this*
48289 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48290 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48291 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48292 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48293 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48297 /** Decide whether to drop above or below a View node. */
48298 getDropPoint : function(e, n, dd){
48299 if (n == this.el.dom) { return "above"; }
48300 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48301 var c = t + (b - t) / 2;
48302 var y = Roo.lib.Event.getPageY(e);
48310 onNodeEnter : function(n, dd, e, data){
48314 onNodeOver : function(n, dd, e, data){
48315 var pt = this.getDropPoint(e, n, dd);
48316 // set the insert point style on the target node
48317 var dragElClass = this.dropNotAllowed;
48320 if (pt == "above"){
48321 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48322 targetElClass = "x-view-drag-insert-above";
48324 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48325 targetElClass = "x-view-drag-insert-below";
48327 if (this.lastInsertClass != targetElClass){
48328 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48329 this.lastInsertClass = targetElClass;
48332 return dragElClass;
48335 onNodeOut : function(n, dd, e, data){
48336 this.removeDropIndicators(n);
48339 onNodeDrop : function(n, dd, e, data){
48340 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48343 var pt = this.getDropPoint(e, n, dd);
48344 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48345 if (pt == "below") { insertAt++; }
48346 for (var i = 0; i < data.records.length; i++) {
48347 var r = data.records[i];
48348 var dup = this.store.getById(r.id);
48349 if (dup && (dd != this.dragZone)) {
48350 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48353 this.store.insert(insertAt++, r.copy());
48355 data.source.isDirtyFlag = true;
48357 this.store.insert(insertAt++, r);
48359 this.isDirtyFlag = true;
48362 this.dragZone.cachedTarget = null;
48366 removeDropIndicators : function(n){
48368 Roo.fly(n).removeClass([
48369 "x-view-drag-insert-above",
48370 "x-view-drag-insert-below"]);
48371 this.lastInsertClass = "_noclass";
48376 * Utility method. Add a delete option to the DDView's context menu.
48377 * @param {String} imageUrl The URL of the "delete" icon image.
48379 setDeletable: function(imageUrl) {
48380 if (!this.singleSelect && !this.multiSelect) {
48381 this.singleSelect = true;
48383 var c = this.getContextMenu();
48384 this.contextMenu.on("itemclick", function(item) {
48387 this.remove(this.getSelectedIndexes());
48391 this.contextMenu.add({
48398 /** Return the context menu for this DDView. */
48399 getContextMenu: function() {
48400 if (!this.contextMenu) {
48401 // Create the View's context menu
48402 this.contextMenu = new Roo.menu.Menu({
48403 id: this.id + "-contextmenu"
48405 this.el.on("contextmenu", this.showContextMenu, this);
48407 return this.contextMenu;
48410 disableContextMenu: function() {
48411 if (this.contextMenu) {
48412 this.el.un("contextmenu", this.showContextMenu, this);
48416 showContextMenu: function(e, item) {
48417 item = this.findItemFromChild(e.getTarget());
48420 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
48421 this.contextMenu.showAt(e.getXY());
48426 * Remove {@link Roo.data.Record}s at the specified indices.
48427 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
48429 remove: function(selectedIndices) {
48430 selectedIndices = [].concat(selectedIndices);
48431 for (var i = 0; i < selectedIndices.length; i++) {
48432 var rec = this.store.getAt(selectedIndices[i]);
48433 this.store.remove(rec);
48438 * Double click fires the event, but also, if this is draggable, and there is only one other
48439 * related DropZone, it transfers the selected node.
48441 onDblClick : function(e){
48442 var item = this.findItemFromChild(e.getTarget());
48444 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
48447 if (this.dragGroup) {
48448 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
48449 while (targets.indexOf(this.dropZone) > -1) {
48450 targets.remove(this.dropZone);
48452 if (targets.length == 1) {
48453 this.dragZone.cachedTarget = null;
48454 var el = Roo.get(targets[0].getEl());
48455 var box = el.getBox(true);
48456 targets[0].onNodeDrop(el.dom, {
48458 xy: [box.x, box.y + box.height - 1]
48459 }, null, this.getDragData(e));
48465 handleSelection: function(e) {
48466 this.dragZone.cachedTarget = null;
48467 var item = this.findItemFromChild(e.getTarget());
48469 this.clearSelections(true);
48472 if (item && (this.multiSelect || this.singleSelect)){
48473 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
48474 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
48475 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
48476 this.unselect(item);
48478 this.select(item, this.multiSelect && e.ctrlKey);
48479 this.lastSelection = item;
48484 onItemClick : function(item, index, e){
48485 if(this.fireEvent("beforeclick", this, index, item, e) === false){
48491 unselect : function(nodeInfo, suppressEvent){
48492 var node = this.getNode(nodeInfo);
48493 if(node && this.isSelected(node)){
48494 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
48495 Roo.fly(node).removeClass(this.selectedClass);
48496 this.selections.remove(node);
48497 if(!suppressEvent){
48498 this.fireEvent("selectionchange", this, this.selections);
48506 * Ext JS Library 1.1.1
48507 * Copyright(c) 2006-2007, Ext JS, LLC.
48509 * Originally Released Under LGPL - original licence link has changed is not relivant.
48512 * <script type="text/javascript">
48516 * @class Roo.LayoutManager
48517 * @extends Roo.util.Observable
48518 * Base class for layout managers.
48520 Roo.LayoutManager = function(container, config){
48521 Roo.LayoutManager.superclass.constructor.call(this);
48522 this.el = Roo.get(container);
48523 // ie scrollbar fix
48524 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
48525 document.body.scroll = "no";
48526 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
48527 this.el.position('relative');
48529 this.id = this.el.id;
48530 this.el.addClass("x-layout-container");
48531 /** false to disable window resize monitoring @type Boolean */
48532 this.monitorWindowResize = true;
48537 * Fires when a layout is performed.
48538 * @param {Roo.LayoutManager} this
48542 * @event regionresized
48543 * Fires when the user resizes a region.
48544 * @param {Roo.LayoutRegion} region The resized region
48545 * @param {Number} newSize The new size (width for east/west, height for north/south)
48547 "regionresized" : true,
48549 * @event regioncollapsed
48550 * Fires when a region is collapsed.
48551 * @param {Roo.LayoutRegion} region The collapsed region
48553 "regioncollapsed" : true,
48555 * @event regionexpanded
48556 * Fires when a region is expanded.
48557 * @param {Roo.LayoutRegion} region The expanded region
48559 "regionexpanded" : true
48561 this.updating = false;
48562 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48565 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
48567 * Returns true if this layout is currently being updated
48568 * @return {Boolean}
48570 isUpdating : function(){
48571 return this.updating;
48575 * Suspend the LayoutManager from doing auto-layouts while
48576 * making multiple add or remove calls
48578 beginUpdate : function(){
48579 this.updating = true;
48583 * Restore auto-layouts and optionally disable the manager from performing a layout
48584 * @param {Boolean} noLayout true to disable a layout update
48586 endUpdate : function(noLayout){
48587 this.updating = false;
48593 layout: function(){
48597 onRegionResized : function(region, newSize){
48598 this.fireEvent("regionresized", region, newSize);
48602 onRegionCollapsed : function(region){
48603 this.fireEvent("regioncollapsed", region);
48606 onRegionExpanded : function(region){
48607 this.fireEvent("regionexpanded", region);
48611 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
48612 * performs box-model adjustments.
48613 * @return {Object} The size as an object {width: (the width), height: (the height)}
48615 getViewSize : function(){
48617 if(this.el.dom != document.body){
48618 size = this.el.getSize();
48620 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
48622 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
48623 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
48628 * Returns the Element this layout is bound to.
48629 * @return {Roo.Element}
48631 getEl : function(){
48636 * Returns the specified region.
48637 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
48638 * @return {Roo.LayoutRegion}
48640 getRegion : function(target){
48641 return this.regions[target.toLowerCase()];
48644 onWindowResize : function(){
48645 if(this.monitorWindowResize){
48651 * Ext JS Library 1.1.1
48652 * Copyright(c) 2006-2007, Ext JS, LLC.
48654 * Originally Released Under LGPL - original licence link has changed is not relivant.
48657 * <script type="text/javascript">
48660 * @class Roo.BorderLayout
48661 * @extends Roo.LayoutManager
48662 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
48663 * please see: <br><br>
48664 * <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>
48665 * <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>
48668 var layout = new Roo.BorderLayout(document.body, {
48702 preferredTabWidth: 150
48707 var CP = Roo.ContentPanel;
48709 layout.beginUpdate();
48710 layout.add("north", new CP("north", "North"));
48711 layout.add("south", new CP("south", {title: "South", closable: true}));
48712 layout.add("west", new CP("west", {title: "West"}));
48713 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
48714 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
48715 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
48716 layout.getRegion("center").showPanel("center1");
48717 layout.endUpdate();
48720 <b>The container the layout is rendered into can be either the body element or any other element.
48721 If it is not the body element, the container needs to either be an absolute positioned element,
48722 or you will need to add "position:relative" to the css of the container. You will also need to specify
48723 the container size if it is not the body element.</b>
48726 * Create a new BorderLayout
48727 * @param {String/HTMLElement/Element} container The container this layout is bound to
48728 * @param {Object} config Configuration options
48730 Roo.BorderLayout = function(container, config){
48731 config = config || {};
48732 Roo.BorderLayout.superclass.constructor.call(this, container, config);
48733 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
48734 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
48735 var target = this.factory.validRegions[i];
48736 if(config[target]){
48737 this.addRegion(target, config[target]);
48742 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
48744 * Creates and adds a new region if it doesn't already exist.
48745 * @param {String} target The target region key (north, south, east, west or center).
48746 * @param {Object} config The regions config object
48747 * @return {BorderLayoutRegion} The new region
48749 addRegion : function(target, config){
48750 if(!this.regions[target]){
48751 var r = this.factory.create(target, this, config);
48752 this.bindRegion(target, r);
48754 return this.regions[target];
48758 bindRegion : function(name, r){
48759 this.regions[name] = r;
48760 r.on("visibilitychange", this.layout, this);
48761 r.on("paneladded", this.layout, this);
48762 r.on("panelremoved", this.layout, this);
48763 r.on("invalidated", this.layout, this);
48764 r.on("resized", this.onRegionResized, this);
48765 r.on("collapsed", this.onRegionCollapsed, this);
48766 r.on("expanded", this.onRegionExpanded, this);
48770 * Performs a layout update.
48772 layout : function(){
48773 if(this.updating) return;
48774 var size = this.getViewSize();
48775 var w = size.width;
48776 var h = size.height;
48781 //var x = 0, y = 0;
48783 var rs = this.regions;
48784 var north = rs["north"];
48785 var south = rs["south"];
48786 var west = rs["west"];
48787 var east = rs["east"];
48788 var center = rs["center"];
48789 //if(this.hideOnLayout){ // not supported anymore
48790 //c.el.setStyle("display", "none");
48792 if(north && north.isVisible()){
48793 var b = north.getBox();
48794 var m = north.getMargins();
48795 b.width = w - (m.left+m.right);
48798 centerY = b.height + b.y + m.bottom;
48799 centerH -= centerY;
48800 north.updateBox(this.safeBox(b));
48802 if(south && south.isVisible()){
48803 var b = south.getBox();
48804 var m = south.getMargins();
48805 b.width = w - (m.left+m.right);
48807 var totalHeight = (b.height + m.top + m.bottom);
48808 b.y = h - totalHeight + m.top;
48809 centerH -= totalHeight;
48810 south.updateBox(this.safeBox(b));
48812 if(west && west.isVisible()){
48813 var b = west.getBox();
48814 var m = west.getMargins();
48815 b.height = centerH - (m.top+m.bottom);
48817 b.y = centerY + m.top;
48818 var totalWidth = (b.width + m.left + m.right);
48819 centerX += totalWidth;
48820 centerW -= totalWidth;
48821 west.updateBox(this.safeBox(b));
48823 if(east && east.isVisible()){
48824 var b = east.getBox();
48825 var m = east.getMargins();
48826 b.height = centerH - (m.top+m.bottom);
48827 var totalWidth = (b.width + m.left + m.right);
48828 b.x = w - totalWidth + m.left;
48829 b.y = centerY + m.top;
48830 centerW -= totalWidth;
48831 east.updateBox(this.safeBox(b));
48834 var m = center.getMargins();
48836 x: centerX + m.left,
48837 y: centerY + m.top,
48838 width: centerW - (m.left+m.right),
48839 height: centerH - (m.top+m.bottom)
48841 //if(this.hideOnLayout){
48842 //center.el.setStyle("display", "block");
48844 center.updateBox(this.safeBox(centerBox));
48847 this.fireEvent("layout", this);
48851 safeBox : function(box){
48852 box.width = Math.max(0, box.width);
48853 box.height = Math.max(0, box.height);
48858 * Adds a ContentPanel (or subclass) to this layout.
48859 * @param {String} target The target region key (north, south, east, west or center).
48860 * @param {Roo.ContentPanel} panel The panel to add
48861 * @return {Roo.ContentPanel} The added panel
48863 add : function(target, panel){
48865 target = target.toLowerCase();
48866 return this.regions[target].add(panel);
48870 * Remove a ContentPanel (or subclass) to this layout.
48871 * @param {String} target The target region key (north, south, east, west or center).
48872 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
48873 * @return {Roo.ContentPanel} The removed panel
48875 remove : function(target, panel){
48876 target = target.toLowerCase();
48877 return this.regions[target].remove(panel);
48881 * Searches all regions for a panel with the specified id
48882 * @param {String} panelId
48883 * @return {Roo.ContentPanel} The panel or null if it wasn't found
48885 findPanel : function(panelId){
48886 var rs = this.regions;
48887 for(var target in rs){
48888 if(typeof rs[target] != "function"){
48889 var p = rs[target].getPanel(panelId);
48899 * Searches all regions for a panel with the specified id and activates (shows) it.
48900 * @param {String/ContentPanel} panelId The panels id or the panel itself
48901 * @return {Roo.ContentPanel} The shown panel or null
48903 showPanel : function(panelId) {
48904 var rs = this.regions;
48905 for(var target in rs){
48906 var r = rs[target];
48907 if(typeof r != "function"){
48908 if(r.hasPanel(panelId)){
48909 return r.showPanel(panelId);
48917 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
48918 * @param {Roo.state.Provider} provider (optional) An alternate state provider
48920 restoreState : function(provider){
48922 provider = Roo.state.Manager;
48924 var sm = new Roo.LayoutStateManager();
48925 sm.init(this, provider);
48929 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
48930 * object should contain properties for each region to add ContentPanels to, and each property's value should be
48931 * a valid ContentPanel config object. Example:
48933 // Create the main layout
48934 var layout = new Roo.BorderLayout('main-ct', {
48945 // Create and add multiple ContentPanels at once via configs
48948 id: 'source-files',
48950 title:'Ext Source Files',
48963 * @param {Object} regions An object containing ContentPanel configs by region name
48965 batchAdd : function(regions){
48966 this.beginUpdate();
48967 for(var rname in regions){
48968 var lr = this.regions[rname];
48970 this.addTypedPanels(lr, regions[rname]);
48977 addTypedPanels : function(lr, ps){
48978 if(typeof ps == 'string'){
48979 lr.add(new Roo.ContentPanel(ps));
48981 else if(ps instanceof Array){
48982 for(var i =0, len = ps.length; i < len; i++){
48983 this.addTypedPanels(lr, ps[i]);
48986 else if(!ps.events){ // raw config?
48988 delete ps.el; // prevent conflict
48989 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
48991 else { // panel object assumed!
48996 * Adds a xtype elements to the layout.
49000 xtype : 'ContentPanel',
49007 xtype : 'NestedLayoutPanel',
49013 items : [ ... list of content panels or nested layout panels.. ]
49017 * @param {Object} cfg Xtype definition of item to add.
49019 addxtype : function(cfg)
49021 // basically accepts a pannel...
49022 // can accept a layout region..!?!?
49023 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49025 if (!cfg.xtype.match(/Panel$/)) {
49030 if (typeof(cfg.region) == 'undefined') {
49031 Roo.log("Failed to add Panel, region was not set");
49035 var region = cfg.region;
49041 xitems = cfg.items;
49048 case 'ContentPanel': // ContentPanel (el, cfg)
49049 case 'ScrollPanel': // ContentPanel (el, cfg)
49051 if(cfg.autoCreate) {
49052 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49054 var el = this.el.createChild();
49055 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49058 this.add(region, ret);
49062 case 'TreePanel': // our new panel!
49063 cfg.el = this.el.createChild();
49064 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49065 this.add(region, ret);
49068 case 'NestedLayoutPanel':
49069 // create a new Layout (which is a Border Layout...
49070 var el = this.el.createChild();
49071 var clayout = cfg.layout;
49073 clayout.items = clayout.items || [];
49074 // replace this exitems with the clayout ones..
49075 xitems = clayout.items;
49078 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49079 cfg.background = false;
49081 var layout = new Roo.BorderLayout(el, clayout);
49083 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49084 //console.log('adding nested layout panel ' + cfg.toSource());
49085 this.add(region, ret);
49086 nb = {}; /// find first...
49091 // needs grid and region
49093 //var el = this.getRegion(region).el.createChild();
49094 var el = this.el.createChild();
49095 // create the grid first...
49097 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49099 if (region == 'center' && this.active ) {
49100 cfg.background = false;
49102 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49104 this.add(region, ret);
49105 if (cfg.background) {
49106 ret.on('activate', function(gp) {
49107 if (!gp.grid.rendered) {
49122 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49124 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49125 this.add(region, ret);
49128 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49132 // GridPanel (grid, cfg)
49135 this.beginUpdate();
49139 Roo.each(xitems, function(i) {
49140 region = nb && i.region ? i.region : false;
49142 var add = ret.addxtype(i);
49145 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49146 if (!i.background) {
49147 abn[region] = nb[region] ;
49154 // make the last non-background panel active..
49155 //if (nb) { Roo.log(abn); }
49158 for(var r in abn) {
49159 region = this.getRegion(r);
49161 // tried using nb[r], but it does not work..
49163 region.showPanel(abn[r]);
49174 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49175 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49176 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49177 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49180 var CP = Roo.ContentPanel;
49182 var layout = Roo.BorderLayout.create({
49186 panels: [new CP("north", "North")]
49195 panels: [new CP("west", {title: "West"})]
49204 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49213 panels: [new CP("south", {title: "South", closable: true})]
49220 preferredTabWidth: 150,
49222 new CP("center1", {title: "Close Me", closable: true}),
49223 new CP("center2", {title: "Center Panel", closable: false})
49228 layout.getRegion("center").showPanel("center1");
49233 Roo.BorderLayout.create = function(config, targetEl){
49234 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49235 layout.beginUpdate();
49236 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49237 for(var j = 0, jlen = regions.length; j < jlen; j++){
49238 var lr = regions[j];
49239 if(layout.regions[lr] && config[lr].panels){
49240 var r = layout.regions[lr];
49241 var ps = config[lr].panels;
49242 layout.addTypedPanels(r, ps);
49245 layout.endUpdate();
49250 Roo.BorderLayout.RegionFactory = {
49252 validRegions : ["north","south","east","west","center"],
49255 create : function(target, mgr, config){
49256 target = target.toLowerCase();
49257 if(config.lightweight || config.basic){
49258 return new Roo.BasicLayoutRegion(mgr, config, target);
49262 return new Roo.NorthLayoutRegion(mgr, config);
49264 return new Roo.SouthLayoutRegion(mgr, config);
49266 return new Roo.EastLayoutRegion(mgr, config);
49268 return new Roo.WestLayoutRegion(mgr, config);
49270 return new Roo.CenterLayoutRegion(mgr, config);
49272 throw 'Layout region "'+target+'" not supported.';
49276 * Ext JS Library 1.1.1
49277 * Copyright(c) 2006-2007, Ext JS, LLC.
49279 * Originally Released Under LGPL - original licence link has changed is not relivant.
49282 * <script type="text/javascript">
49286 * @class Roo.BasicLayoutRegion
49287 * @extends Roo.util.Observable
49288 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49289 * and does not have a titlebar, tabs or any other features. All it does is size and position
49290 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49292 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49294 this.position = pos;
49297 * @scope Roo.BasicLayoutRegion
49301 * @event beforeremove
49302 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49303 * @param {Roo.LayoutRegion} this
49304 * @param {Roo.ContentPanel} panel The panel
49305 * @param {Object} e The cancel event object
49307 "beforeremove" : true,
49309 * @event invalidated
49310 * Fires when the layout for this region is changed.
49311 * @param {Roo.LayoutRegion} this
49313 "invalidated" : true,
49315 * @event visibilitychange
49316 * Fires when this region is shown or hidden
49317 * @param {Roo.LayoutRegion} this
49318 * @param {Boolean} visibility true or false
49320 "visibilitychange" : true,
49322 * @event paneladded
49323 * Fires when a panel is added.
49324 * @param {Roo.LayoutRegion} this
49325 * @param {Roo.ContentPanel} panel The panel
49327 "paneladded" : true,
49329 * @event panelremoved
49330 * Fires when a panel is removed.
49331 * @param {Roo.LayoutRegion} this
49332 * @param {Roo.ContentPanel} panel The panel
49334 "panelremoved" : true,
49337 * Fires when this region is collapsed.
49338 * @param {Roo.LayoutRegion} this
49340 "collapsed" : true,
49343 * Fires when this region is expanded.
49344 * @param {Roo.LayoutRegion} this
49349 * Fires when this region is slid into view.
49350 * @param {Roo.LayoutRegion} this
49352 "slideshow" : true,
49355 * Fires when this region slides out of view.
49356 * @param {Roo.LayoutRegion} this
49358 "slidehide" : true,
49360 * @event panelactivated
49361 * Fires when a panel is activated.
49362 * @param {Roo.LayoutRegion} this
49363 * @param {Roo.ContentPanel} panel The activated panel
49365 "panelactivated" : true,
49368 * Fires when the user resizes this region.
49369 * @param {Roo.LayoutRegion} this
49370 * @param {Number} newSize The new size (width for east/west, height for north/south)
49374 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49375 this.panels = new Roo.util.MixedCollection();
49376 this.panels.getKey = this.getPanelId.createDelegate(this);
49378 this.activePanel = null;
49379 // ensure listeners are added...
49381 if (config.listeners || config.events) {
49382 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49383 listeners : config.listeners || {},
49384 events : config.events || {}
49388 if(skipConfig !== true){
49389 this.applyConfig(config);
49393 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49394 getPanelId : function(p){
49398 applyConfig : function(config){
49399 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49400 this.config = config;
49405 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49406 * the width, for horizontal (north, south) the height.
49407 * @param {Number} newSize The new width or height
49409 resizeTo : function(newSize){
49410 var el = this.el ? this.el :
49411 (this.activePanel ? this.activePanel.getEl() : null);
49413 switch(this.position){
49416 el.setWidth(newSize);
49417 this.fireEvent("resized", this, newSize);
49421 el.setHeight(newSize);
49422 this.fireEvent("resized", this, newSize);
49428 getBox : function(){
49429 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
49432 getMargins : function(){
49433 return this.margins;
49436 updateBox : function(box){
49438 var el = this.activePanel.getEl();
49439 el.dom.style.left = box.x + "px";
49440 el.dom.style.top = box.y + "px";
49441 this.activePanel.setSize(box.width, box.height);
49445 * Returns the container element for this region.
49446 * @return {Roo.Element}
49448 getEl : function(){
49449 return this.activePanel;
49453 * Returns true if this region is currently visible.
49454 * @return {Boolean}
49456 isVisible : function(){
49457 return this.activePanel ? true : false;
49460 setActivePanel : function(panel){
49461 panel = this.getPanel(panel);
49462 if(this.activePanel && this.activePanel != panel){
49463 this.activePanel.setActiveState(false);
49464 this.activePanel.getEl().setLeftTop(-10000,-10000);
49466 this.activePanel = panel;
49467 panel.setActiveState(true);
49469 panel.setSize(this.box.width, this.box.height);
49471 this.fireEvent("panelactivated", this, panel);
49472 this.fireEvent("invalidated");
49476 * Show the specified panel.
49477 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
49478 * @return {Roo.ContentPanel} The shown panel or null
49480 showPanel : function(panel){
49481 if(panel = this.getPanel(panel)){
49482 this.setActivePanel(panel);
49488 * Get the active panel for this region.
49489 * @return {Roo.ContentPanel} The active panel or null
49491 getActivePanel : function(){
49492 return this.activePanel;
49496 * Add the passed ContentPanel(s)
49497 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49498 * @return {Roo.ContentPanel} The panel added (if only one was added)
49500 add : function(panel){
49501 if(arguments.length > 1){
49502 for(var i = 0, len = arguments.length; i < len; i++) {
49503 this.add(arguments[i]);
49507 if(this.hasPanel(panel)){
49508 this.showPanel(panel);
49511 var el = panel.getEl();
49512 if(el.dom.parentNode != this.mgr.el.dom){
49513 this.mgr.el.dom.appendChild(el.dom);
49515 if(panel.setRegion){
49516 panel.setRegion(this);
49518 this.panels.add(panel);
49519 el.setStyle("position", "absolute");
49520 if(!panel.background){
49521 this.setActivePanel(panel);
49522 if(this.config.initialSize && this.panels.getCount()==1){
49523 this.resizeTo(this.config.initialSize);
49526 this.fireEvent("paneladded", this, panel);
49531 * Returns true if the panel is in this region.
49532 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49533 * @return {Boolean}
49535 hasPanel : function(panel){
49536 if(typeof panel == "object"){ // must be panel obj
49537 panel = panel.getId();
49539 return this.getPanel(panel) ? true : false;
49543 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49544 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49545 * @param {Boolean} preservePanel Overrides the config preservePanel option
49546 * @return {Roo.ContentPanel} The panel that was removed
49548 remove : function(panel, preservePanel){
49549 panel = this.getPanel(panel);
49554 this.fireEvent("beforeremove", this, panel, e);
49555 if(e.cancel === true){
49558 var panelId = panel.getId();
49559 this.panels.removeKey(panelId);
49564 * Returns the panel specified or null if it's not in this region.
49565 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49566 * @return {Roo.ContentPanel}
49568 getPanel : function(id){
49569 if(typeof id == "object"){ // must be panel obj
49572 return this.panels.get(id);
49576 * Returns this regions position (north/south/east/west/center).
49579 getPosition: function(){
49580 return this.position;
49584 * Ext JS Library 1.1.1
49585 * Copyright(c) 2006-2007, Ext JS, LLC.
49587 * Originally Released Under LGPL - original licence link has changed is not relivant.
49590 * <script type="text/javascript">
49594 * @class Roo.LayoutRegion
49595 * @extends Roo.BasicLayoutRegion
49596 * This class represents a region in a layout manager.
49597 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
49598 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
49599 * @cfg {Boolean} floatable False to disable floating (defaults to true)
49600 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
49601 * @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})
49602 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
49603 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
49604 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
49605 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
49606 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
49607 * @cfg {String} title The title for the region (overrides panel titles)
49608 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
49609 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
49610 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
49611 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
49612 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
49613 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
49614 * the space available, similar to FireFox 1.5 tabs (defaults to false)
49615 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
49616 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
49617 * @cfg {Boolean} showPin True to show a pin button
49618 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
49619 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
49620 * @cfg {Boolean} disableTabTips True to disable tab tooltips
49621 * @cfg {Number} width For East/West panels
49622 * @cfg {Number} height For North/South panels
49623 * @cfg {Boolean} split To show the splitter
49624 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
49626 Roo.LayoutRegion = function(mgr, config, pos){
49627 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
49628 var dh = Roo.DomHelper;
49629 /** This region's container element
49630 * @type Roo.Element */
49631 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
49632 /** This region's title element
49633 * @type Roo.Element */
49635 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
49636 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
49637 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
49639 this.titleEl.enableDisplayMode();
49640 /** This region's title text element
49641 * @type HTMLElement */
49642 this.titleTextEl = this.titleEl.dom.firstChild;
49643 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
49644 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
49645 this.closeBtn.enableDisplayMode();
49646 this.closeBtn.on("click", this.closeClicked, this);
49647 this.closeBtn.hide();
49649 this.createBody(config);
49650 this.visible = true;
49651 this.collapsed = false;
49653 if(config.hideWhenEmpty){
49655 this.on("paneladded", this.validateVisibility, this);
49656 this.on("panelremoved", this.validateVisibility, this);
49658 this.applyConfig(config);
49661 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
49663 createBody : function(){
49664 /** This region's body element
49665 * @type Roo.Element */
49666 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
49669 applyConfig : function(c){
49670 if(c.collapsible && this.position != "center" && !this.collapsedEl){
49671 var dh = Roo.DomHelper;
49672 if(c.titlebar !== false){
49673 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
49674 this.collapseBtn.on("click", this.collapse, this);
49675 this.collapseBtn.enableDisplayMode();
49677 if(c.showPin === true || this.showPin){
49678 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
49679 this.stickBtn.enableDisplayMode();
49680 this.stickBtn.on("click", this.expand, this);
49681 this.stickBtn.hide();
49684 /** This region's collapsed element
49685 * @type Roo.Element */
49686 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
49687 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
49689 if(c.floatable !== false){
49690 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
49691 this.collapsedEl.on("click", this.collapseClick, this);
49694 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
49695 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
49696 id: "message", unselectable: "on", style:{"float":"left"}});
49697 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
49699 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
49700 this.expandBtn.on("click", this.expand, this);
49702 if(this.collapseBtn){
49703 this.collapseBtn.setVisible(c.collapsible == true);
49705 this.cmargins = c.cmargins || this.cmargins ||
49706 (this.position == "west" || this.position == "east" ?
49707 {top: 0, left: 2, right:2, bottom: 0} :
49708 {top: 2, left: 0, right:0, bottom: 2});
49709 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49710 this.bottomTabs = c.tabPosition != "top";
49711 this.autoScroll = c.autoScroll || false;
49712 if(this.autoScroll){
49713 this.bodyEl.setStyle("overflow", "auto");
49715 this.bodyEl.setStyle("overflow", "hidden");
49717 //if(c.titlebar !== false){
49718 if((!c.titlebar && !c.title) || c.titlebar === false){
49719 this.titleEl.hide();
49721 this.titleEl.show();
49723 this.titleTextEl.innerHTML = c.title;
49727 this.duration = c.duration || .30;
49728 this.slideDuration = c.slideDuration || .45;
49731 this.collapse(true);
49738 * Returns true if this region is currently visible.
49739 * @return {Boolean}
49741 isVisible : function(){
49742 return this.visible;
49746 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
49747 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
49749 setCollapsedTitle : function(title){
49750 title = title || " ";
49751 if(this.collapsedTitleTextEl){
49752 this.collapsedTitleTextEl.innerHTML = title;
49756 getBox : function(){
49758 if(!this.collapsed){
49759 b = this.el.getBox(false, true);
49761 b = this.collapsedEl.getBox(false, true);
49766 getMargins : function(){
49767 return this.collapsed ? this.cmargins : this.margins;
49770 highlight : function(){
49771 this.el.addClass("x-layout-panel-dragover");
49774 unhighlight : function(){
49775 this.el.removeClass("x-layout-panel-dragover");
49778 updateBox : function(box){
49780 if(!this.collapsed){
49781 this.el.dom.style.left = box.x + "px";
49782 this.el.dom.style.top = box.y + "px";
49783 this.updateBody(box.width, box.height);
49785 this.collapsedEl.dom.style.left = box.x + "px";
49786 this.collapsedEl.dom.style.top = box.y + "px";
49787 this.collapsedEl.setSize(box.width, box.height);
49790 this.tabs.autoSizeTabs();
49794 updateBody : function(w, h){
49796 this.el.setWidth(w);
49797 w -= this.el.getBorderWidth("rl");
49798 if(this.config.adjustments){
49799 w += this.config.adjustments[0];
49803 this.el.setHeight(h);
49804 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
49805 h -= this.el.getBorderWidth("tb");
49806 if(this.config.adjustments){
49807 h += this.config.adjustments[1];
49809 this.bodyEl.setHeight(h);
49811 h = this.tabs.syncHeight(h);
49814 if(this.panelSize){
49815 w = w !== null ? w : this.panelSize.width;
49816 h = h !== null ? h : this.panelSize.height;
49818 if(this.activePanel){
49819 var el = this.activePanel.getEl();
49820 w = w !== null ? w : el.getWidth();
49821 h = h !== null ? h : el.getHeight();
49822 this.panelSize = {width: w, height: h};
49823 this.activePanel.setSize(w, h);
49825 if(Roo.isIE && this.tabs){
49826 this.tabs.el.repaint();
49831 * Returns the container element for this region.
49832 * @return {Roo.Element}
49834 getEl : function(){
49839 * Hides this region.
49842 if(!this.collapsed){
49843 this.el.dom.style.left = "-2000px";
49846 this.collapsedEl.dom.style.left = "-2000px";
49847 this.collapsedEl.hide();
49849 this.visible = false;
49850 this.fireEvent("visibilitychange", this, false);
49854 * Shows this region if it was previously hidden.
49857 if(!this.collapsed){
49860 this.collapsedEl.show();
49862 this.visible = true;
49863 this.fireEvent("visibilitychange", this, true);
49866 closeClicked : function(){
49867 if(this.activePanel){
49868 this.remove(this.activePanel);
49872 collapseClick : function(e){
49874 e.stopPropagation();
49877 e.stopPropagation();
49883 * Collapses this region.
49884 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
49886 collapse : function(skipAnim){
49887 if(this.collapsed) return;
49888 this.collapsed = true;
49890 this.split.el.hide();
49892 if(this.config.animate && skipAnim !== true){
49893 this.fireEvent("invalidated", this);
49894 this.animateCollapse();
49896 this.el.setLocation(-20000,-20000);
49898 this.collapsedEl.show();
49899 this.fireEvent("collapsed", this);
49900 this.fireEvent("invalidated", this);
49904 animateCollapse : function(){
49909 * Expands this region if it was previously collapsed.
49910 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
49911 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
49913 expand : function(e, skipAnim){
49914 if(e) e.stopPropagation();
49915 if(!this.collapsed || this.el.hasActiveFx()) return;
49917 this.afterSlideIn();
49920 this.collapsed = false;
49921 if(this.config.animate && skipAnim !== true){
49922 this.animateExpand();
49926 this.split.el.show();
49928 this.collapsedEl.setLocation(-2000,-2000);
49929 this.collapsedEl.hide();
49930 this.fireEvent("invalidated", this);
49931 this.fireEvent("expanded", this);
49935 animateExpand : function(){
49939 initTabs : function()
49941 this.bodyEl.setStyle("overflow", "hidden");
49942 var ts = new Roo.TabPanel(
49945 tabPosition: this.bottomTabs ? 'bottom' : 'top',
49946 disableTooltips: this.config.disableTabTips,
49947 toolbar : this.config.toolbar
49950 if(this.config.hideTabs){
49951 ts.stripWrap.setDisplayed(false);
49954 ts.resizeTabs = this.config.resizeTabs === true;
49955 ts.minTabWidth = this.config.minTabWidth || 40;
49956 ts.maxTabWidth = this.config.maxTabWidth || 250;
49957 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
49958 ts.monitorResize = false;
49959 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49960 ts.bodyEl.addClass('x-layout-tabs-body');
49961 this.panels.each(this.initPanelAsTab, this);
49964 initPanelAsTab : function(panel){
49965 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
49966 this.config.closeOnTab && panel.isClosable());
49967 if(panel.tabTip !== undefined){
49968 ti.setTooltip(panel.tabTip);
49970 ti.on("activate", function(){
49971 this.setActivePanel(panel);
49973 if(this.config.closeOnTab){
49974 ti.on("beforeclose", function(t, e){
49976 this.remove(panel);
49982 updatePanelTitle : function(panel, title){
49983 if(this.activePanel == panel){
49984 this.updateTitle(title);
49987 var ti = this.tabs.getTab(panel.getEl().id);
49989 if(panel.tabTip !== undefined){
49990 ti.setTooltip(panel.tabTip);
49995 updateTitle : function(title){
49996 if(this.titleTextEl && !this.config.title){
49997 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50001 setActivePanel : function(panel){
50002 panel = this.getPanel(panel);
50003 if(this.activePanel && this.activePanel != panel){
50004 this.activePanel.setActiveState(false);
50006 this.activePanel = panel;
50007 panel.setActiveState(true);
50008 if(this.panelSize){
50009 panel.setSize(this.panelSize.width, this.panelSize.height);
50012 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50014 this.updateTitle(panel.getTitle());
50016 this.fireEvent("invalidated", this);
50018 this.fireEvent("panelactivated", this, panel);
50022 * Shows the specified panel.
50023 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50024 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50026 showPanel : function(panel){
50027 if(panel = this.getPanel(panel)){
50029 var tab = this.tabs.getTab(panel.getEl().id);
50030 if(tab.isHidden()){
50031 this.tabs.unhideTab(tab.id);
50035 this.setActivePanel(panel);
50042 * Get the active panel for this region.
50043 * @return {Roo.ContentPanel} The active panel or null
50045 getActivePanel : function(){
50046 return this.activePanel;
50049 validateVisibility : function(){
50050 if(this.panels.getCount() < 1){
50051 this.updateTitle(" ");
50052 this.closeBtn.hide();
50055 if(!this.isVisible()){
50062 * Adds the passed ContentPanel(s) to this region.
50063 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50064 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50066 add : function(panel){
50067 if(arguments.length > 1){
50068 for(var i = 0, len = arguments.length; i < len; i++) {
50069 this.add(arguments[i]);
50073 if(this.hasPanel(panel)){
50074 this.showPanel(panel);
50077 panel.setRegion(this);
50078 this.panels.add(panel);
50079 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50080 this.bodyEl.dom.appendChild(panel.getEl().dom);
50081 if(panel.background !== true){
50082 this.setActivePanel(panel);
50084 this.fireEvent("paneladded", this, panel);
50090 this.initPanelAsTab(panel);
50092 if(panel.background !== true){
50093 this.tabs.activate(panel.getEl().id);
50095 this.fireEvent("paneladded", this, panel);
50100 * Hides the tab for the specified panel.
50101 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50103 hidePanel : function(panel){
50104 if(this.tabs && (panel = this.getPanel(panel))){
50105 this.tabs.hideTab(panel.getEl().id);
50110 * Unhides the tab for a previously hidden panel.
50111 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50113 unhidePanel : function(panel){
50114 if(this.tabs && (panel = this.getPanel(panel))){
50115 this.tabs.unhideTab(panel.getEl().id);
50119 clearPanels : function(){
50120 while(this.panels.getCount() > 0){
50121 this.remove(this.panels.first());
50126 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50127 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50128 * @param {Boolean} preservePanel Overrides the config preservePanel option
50129 * @return {Roo.ContentPanel} The panel that was removed
50131 remove : function(panel, preservePanel){
50132 panel = this.getPanel(panel);
50137 this.fireEvent("beforeremove", this, panel, e);
50138 if(e.cancel === true){
50141 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50142 var panelId = panel.getId();
50143 this.panels.removeKey(panelId);
50145 document.body.appendChild(panel.getEl().dom);
50148 this.tabs.removeTab(panel.getEl().id);
50149 }else if (!preservePanel){
50150 this.bodyEl.dom.removeChild(panel.getEl().dom);
50152 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50153 var p = this.panels.first();
50154 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50155 tempEl.appendChild(p.getEl().dom);
50156 this.bodyEl.update("");
50157 this.bodyEl.dom.appendChild(p.getEl().dom);
50159 this.updateTitle(p.getTitle());
50161 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50162 this.setActivePanel(p);
50164 panel.setRegion(null);
50165 if(this.activePanel == panel){
50166 this.activePanel = null;
50168 if(this.config.autoDestroy !== false && preservePanel !== true){
50169 try{panel.destroy();}catch(e){}
50171 this.fireEvent("panelremoved", this, panel);
50176 * Returns the TabPanel component used by this region
50177 * @return {Roo.TabPanel}
50179 getTabs : function(){
50183 createTool : function(parentEl, className){
50184 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50185 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50186 btn.addClassOnOver("x-layout-tools-button-over");
50191 * Ext JS Library 1.1.1
50192 * Copyright(c) 2006-2007, Ext JS, LLC.
50194 * Originally Released Under LGPL - original licence link has changed is not relivant.
50197 * <script type="text/javascript">
50203 * @class Roo.SplitLayoutRegion
50204 * @extends Roo.LayoutRegion
50205 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50207 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50208 this.cursor = cursor;
50209 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50212 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50213 splitTip : "Drag to resize.",
50214 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50215 useSplitTips : false,
50217 applyConfig : function(config){
50218 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50221 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50222 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50223 /** The SplitBar for this region
50224 * @type Roo.SplitBar */
50225 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50226 this.split.on("moved", this.onSplitMove, this);
50227 this.split.useShim = config.useShim === true;
50228 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50229 if(this.useSplitTips){
50230 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50232 if(config.collapsible){
50233 this.split.el.on("dblclick", this.collapse, this);
50236 if(typeof config.minSize != "undefined"){
50237 this.split.minSize = config.minSize;
50239 if(typeof config.maxSize != "undefined"){
50240 this.split.maxSize = config.maxSize;
50242 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50243 this.hideSplitter();
50248 getHMaxSize : function(){
50249 var cmax = this.config.maxSize || 10000;
50250 var center = this.mgr.getRegion("center");
50251 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50254 getVMaxSize : function(){
50255 var cmax = this.config.maxSize || 10000;
50256 var center = this.mgr.getRegion("center");
50257 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50260 onSplitMove : function(split, newSize){
50261 this.fireEvent("resized", this, newSize);
50265 * Returns the {@link Roo.SplitBar} for this region.
50266 * @return {Roo.SplitBar}
50268 getSplitBar : function(){
50273 this.hideSplitter();
50274 Roo.SplitLayoutRegion.superclass.hide.call(this);
50277 hideSplitter : function(){
50279 this.split.el.setLocation(-2000,-2000);
50280 this.split.el.hide();
50286 this.split.el.show();
50288 Roo.SplitLayoutRegion.superclass.show.call(this);
50291 beforeSlide: function(){
50292 if(Roo.isGecko){// firefox overflow auto bug workaround
50293 this.bodyEl.clip();
50294 if(this.tabs) this.tabs.bodyEl.clip();
50295 if(this.activePanel){
50296 this.activePanel.getEl().clip();
50298 if(this.activePanel.beforeSlide){
50299 this.activePanel.beforeSlide();
50305 afterSlide : function(){
50306 if(Roo.isGecko){// firefox overflow auto bug workaround
50307 this.bodyEl.unclip();
50308 if(this.tabs) this.tabs.bodyEl.unclip();
50309 if(this.activePanel){
50310 this.activePanel.getEl().unclip();
50311 if(this.activePanel.afterSlide){
50312 this.activePanel.afterSlide();
50318 initAutoHide : function(){
50319 if(this.autoHide !== false){
50320 if(!this.autoHideHd){
50321 var st = new Roo.util.DelayedTask(this.slideIn, this);
50322 this.autoHideHd = {
50323 "mouseout": function(e){
50324 if(!e.within(this.el, true)){
50328 "mouseover" : function(e){
50334 this.el.on(this.autoHideHd);
50338 clearAutoHide : function(){
50339 if(this.autoHide !== false){
50340 this.el.un("mouseout", this.autoHideHd.mouseout);
50341 this.el.un("mouseover", this.autoHideHd.mouseover);
50345 clearMonitor : function(){
50346 Roo.get(document).un("click", this.slideInIf, this);
50349 // these names are backwards but not changed for compat
50350 slideOut : function(){
50351 if(this.isSlid || this.el.hasActiveFx()){
50354 this.isSlid = true;
50355 if(this.collapseBtn){
50356 this.collapseBtn.hide();
50358 this.closeBtnState = this.closeBtn.getStyle('display');
50359 this.closeBtn.hide();
50361 this.stickBtn.show();
50364 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50365 this.beforeSlide();
50366 this.el.setStyle("z-index", 10001);
50367 this.el.slideIn(this.getSlideAnchor(), {
50368 callback: function(){
50370 this.initAutoHide();
50371 Roo.get(document).on("click", this.slideInIf, this);
50372 this.fireEvent("slideshow", this);
50379 afterSlideIn : function(){
50380 this.clearAutoHide();
50381 this.isSlid = false;
50382 this.clearMonitor();
50383 this.el.setStyle("z-index", "");
50384 if(this.collapseBtn){
50385 this.collapseBtn.show();
50387 this.closeBtn.setStyle('display', this.closeBtnState);
50389 this.stickBtn.hide();
50391 this.fireEvent("slidehide", this);
50394 slideIn : function(cb){
50395 if(!this.isSlid || this.el.hasActiveFx()){
50399 this.isSlid = false;
50400 this.beforeSlide();
50401 this.el.slideOut(this.getSlideAnchor(), {
50402 callback: function(){
50403 this.el.setLeftTop(-10000, -10000);
50405 this.afterSlideIn();
50413 slideInIf : function(e){
50414 if(!e.within(this.el)){
50419 animateCollapse : function(){
50420 this.beforeSlide();
50421 this.el.setStyle("z-index", 20000);
50422 var anchor = this.getSlideAnchor();
50423 this.el.slideOut(anchor, {
50424 callback : function(){
50425 this.el.setStyle("z-index", "");
50426 this.collapsedEl.slideIn(anchor, {duration:.3});
50428 this.el.setLocation(-10000,-10000);
50430 this.fireEvent("collapsed", this);
50437 animateExpand : function(){
50438 this.beforeSlide();
50439 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
50440 this.el.setStyle("z-index", 20000);
50441 this.collapsedEl.hide({
50444 this.el.slideIn(this.getSlideAnchor(), {
50445 callback : function(){
50446 this.el.setStyle("z-index", "");
50449 this.split.el.show();
50451 this.fireEvent("invalidated", this);
50452 this.fireEvent("expanded", this);
50480 getAnchor : function(){
50481 return this.anchors[this.position];
50484 getCollapseAnchor : function(){
50485 return this.canchors[this.position];
50488 getSlideAnchor : function(){
50489 return this.sanchors[this.position];
50492 getAlignAdj : function(){
50493 var cm = this.cmargins;
50494 switch(this.position){
50510 getExpandAdj : function(){
50511 var c = this.collapsedEl, cm = this.cmargins;
50512 switch(this.position){
50514 return [-(cm.right+c.getWidth()+cm.left), 0];
50517 return [cm.right+c.getWidth()+cm.left, 0];
50520 return [0, -(cm.top+cm.bottom+c.getHeight())];
50523 return [0, cm.top+cm.bottom+c.getHeight()];
50529 * Ext JS Library 1.1.1
50530 * Copyright(c) 2006-2007, Ext JS, LLC.
50532 * Originally Released Under LGPL - original licence link has changed is not relivant.
50535 * <script type="text/javascript">
50538 * These classes are private internal classes
50540 Roo.CenterLayoutRegion = function(mgr, config){
50541 Roo.LayoutRegion.call(this, mgr, config, "center");
50542 this.visible = true;
50543 this.minWidth = config.minWidth || 20;
50544 this.minHeight = config.minHeight || 20;
50547 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
50549 // center panel can't be hidden
50553 // center panel can't be hidden
50556 getMinWidth: function(){
50557 return this.minWidth;
50560 getMinHeight: function(){
50561 return this.minHeight;
50566 Roo.NorthLayoutRegion = function(mgr, config){
50567 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
50569 this.split.placement = Roo.SplitBar.TOP;
50570 this.split.orientation = Roo.SplitBar.VERTICAL;
50571 this.split.el.addClass("x-layout-split-v");
50573 var size = config.initialSize || config.height;
50574 if(typeof size != "undefined"){
50575 this.el.setHeight(size);
50578 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
50579 orientation: Roo.SplitBar.VERTICAL,
50580 getBox : function(){
50581 if(this.collapsed){
50582 return this.collapsedEl.getBox();
50584 var box = this.el.getBox();
50586 box.height += this.split.el.getHeight();
50591 updateBox : function(box){
50592 if(this.split && !this.collapsed){
50593 box.height -= this.split.el.getHeight();
50594 this.split.el.setLeft(box.x);
50595 this.split.el.setTop(box.y+box.height);
50596 this.split.el.setWidth(box.width);
50598 if(this.collapsed){
50599 this.updateBody(box.width, null);
50601 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50605 Roo.SouthLayoutRegion = function(mgr, config){
50606 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
50608 this.split.placement = Roo.SplitBar.BOTTOM;
50609 this.split.orientation = Roo.SplitBar.VERTICAL;
50610 this.split.el.addClass("x-layout-split-v");
50612 var size = config.initialSize || config.height;
50613 if(typeof size != "undefined"){
50614 this.el.setHeight(size);
50617 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
50618 orientation: Roo.SplitBar.VERTICAL,
50619 getBox : function(){
50620 if(this.collapsed){
50621 return this.collapsedEl.getBox();
50623 var box = this.el.getBox();
50625 var sh = this.split.el.getHeight();
50632 updateBox : function(box){
50633 if(this.split && !this.collapsed){
50634 var sh = this.split.el.getHeight();
50637 this.split.el.setLeft(box.x);
50638 this.split.el.setTop(box.y-sh);
50639 this.split.el.setWidth(box.width);
50641 if(this.collapsed){
50642 this.updateBody(box.width, null);
50644 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50648 Roo.EastLayoutRegion = function(mgr, config){
50649 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
50651 this.split.placement = Roo.SplitBar.RIGHT;
50652 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50653 this.split.el.addClass("x-layout-split-h");
50655 var size = config.initialSize || config.width;
50656 if(typeof size != "undefined"){
50657 this.el.setWidth(size);
50660 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
50661 orientation: Roo.SplitBar.HORIZONTAL,
50662 getBox : function(){
50663 if(this.collapsed){
50664 return this.collapsedEl.getBox();
50666 var box = this.el.getBox();
50668 var sw = this.split.el.getWidth();
50675 updateBox : function(box){
50676 if(this.split && !this.collapsed){
50677 var sw = this.split.el.getWidth();
50679 this.split.el.setLeft(box.x);
50680 this.split.el.setTop(box.y);
50681 this.split.el.setHeight(box.height);
50684 if(this.collapsed){
50685 this.updateBody(null, box.height);
50687 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50691 Roo.WestLayoutRegion = function(mgr, config){
50692 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
50694 this.split.placement = Roo.SplitBar.LEFT;
50695 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50696 this.split.el.addClass("x-layout-split-h");
50698 var size = config.initialSize || config.width;
50699 if(typeof size != "undefined"){
50700 this.el.setWidth(size);
50703 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
50704 orientation: Roo.SplitBar.HORIZONTAL,
50705 getBox : function(){
50706 if(this.collapsed){
50707 return this.collapsedEl.getBox();
50709 var box = this.el.getBox();
50711 box.width += this.split.el.getWidth();
50716 updateBox : function(box){
50717 if(this.split && !this.collapsed){
50718 var sw = this.split.el.getWidth();
50720 this.split.el.setLeft(box.x+box.width);
50721 this.split.el.setTop(box.y);
50722 this.split.el.setHeight(box.height);
50724 if(this.collapsed){
50725 this.updateBody(null, box.height);
50727 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50732 * Ext JS Library 1.1.1
50733 * Copyright(c) 2006-2007, Ext JS, LLC.
50735 * Originally Released Under LGPL - original licence link has changed is not relivant.
50738 * <script type="text/javascript">
50743 * Private internal class for reading and applying state
50745 Roo.LayoutStateManager = function(layout){
50746 // default empty state
50755 Roo.LayoutStateManager.prototype = {
50756 init : function(layout, provider){
50757 this.provider = provider;
50758 var state = provider.get(layout.id+"-layout-state");
50760 var wasUpdating = layout.isUpdating();
50762 layout.beginUpdate();
50764 for(var key in state){
50765 if(typeof state[key] != "function"){
50766 var rstate = state[key];
50767 var r = layout.getRegion(key);
50770 r.resizeTo(rstate.size);
50772 if(rstate.collapsed == true){
50775 r.expand(null, true);
50781 layout.endUpdate();
50783 this.state = state;
50785 this.layout = layout;
50786 layout.on("regionresized", this.onRegionResized, this);
50787 layout.on("regioncollapsed", this.onRegionCollapsed, this);
50788 layout.on("regionexpanded", this.onRegionExpanded, this);
50791 storeState : function(){
50792 this.provider.set(this.layout.id+"-layout-state", this.state);
50795 onRegionResized : function(region, newSize){
50796 this.state[region.getPosition()].size = newSize;
50800 onRegionCollapsed : function(region){
50801 this.state[region.getPosition()].collapsed = true;
50805 onRegionExpanded : function(region){
50806 this.state[region.getPosition()].collapsed = false;
50811 * Ext JS Library 1.1.1
50812 * Copyright(c) 2006-2007, Ext JS, LLC.
50814 * Originally Released Under LGPL - original licence link has changed is not relivant.
50817 * <script type="text/javascript">
50820 * @class Roo.ContentPanel
50821 * @extends Roo.util.Observable
50822 * A basic ContentPanel element.
50823 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
50824 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
50825 * @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
50826 * @cfg {Boolean} closable True if the panel can be closed/removed
50827 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
50828 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
50829 * @cfg {Toolbar} toolbar A toolbar for this panel
50830 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
50831 * @cfg {String} title The title for this panel
50832 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
50833 * @cfg {String} url Calls {@link #setUrl} with this value
50834 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
50835 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
50836 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
50837 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
50840 * Create a new ContentPanel.
50841 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
50842 * @param {String/Object} config A string to set only the title or a config object
50843 * @param {String} content (optional) Set the HTML content for this panel
50844 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
50846 Roo.ContentPanel = function(el, config, content){
50850 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
50854 if (config && config.parentLayout) {
50855 el = config.parentLayout.el.createChild();
50858 if(el.autoCreate){ // xtype is available if this is called from factory
50862 this.el = Roo.get(el);
50863 if(!this.el && config && config.autoCreate){
50864 if(typeof config.autoCreate == "object"){
50865 if(!config.autoCreate.id){
50866 config.autoCreate.id = config.id||el;
50868 this.el = Roo.DomHelper.append(document.body,
50869 config.autoCreate, true);
50871 this.el = Roo.DomHelper.append(document.body,
50872 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
50875 this.closable = false;
50876 this.loaded = false;
50877 this.active = false;
50878 if(typeof config == "string"){
50879 this.title = config;
50881 Roo.apply(this, config);
50884 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
50885 this.wrapEl = this.el.wrap();
50886 this.toolbar.container = this.el.insertSibling(false, 'before');
50887 this.toolbar = new Roo.Toolbar(this.toolbar);
50890 // xtype created footer. - not sure if will work as we normally have to render first..
50891 if (this.footer && !this.footer.el && this.footer.xtype) {
50892 if (!this.wrapEl) {
50893 this.wrapEl = this.el.wrap();
50896 this.footer.container = this.wrapEl.createChild();
50898 this.footer = Roo.factory(this.footer, Roo);
50903 this.resizeEl = Roo.get(this.resizeEl, true);
50905 this.resizeEl = this.el;
50907 // handle view.xtype
50915 * Fires when this panel is activated.
50916 * @param {Roo.ContentPanel} this
50920 * @event deactivate
50921 * Fires when this panel is activated.
50922 * @param {Roo.ContentPanel} this
50924 "deactivate" : true,
50928 * Fires when this panel is resized if fitToFrame is true.
50929 * @param {Roo.ContentPanel} this
50930 * @param {Number} width The width after any component adjustments
50931 * @param {Number} height The height after any component adjustments
50937 * Fires when this tab is created
50938 * @param {Roo.ContentPanel} this
50949 if(this.autoScroll){
50950 this.resizeEl.setStyle("overflow", "auto");
50952 // fix randome scrolling
50953 this.el.on('scroll', function() {
50954 Roo.log('fix random scolling');
50955 this.scrollTo('top',0);
50958 content = content || this.content;
50960 this.setContent(content);
50962 if(config && config.url){
50963 this.setUrl(this.url, this.params, this.loadOnce);
50968 Roo.ContentPanel.superclass.constructor.call(this);
50970 if (this.view && typeof(this.view.xtype) != 'undefined') {
50971 this.view.el = this.el.appendChild(document.createElement("div"));
50972 this.view = Roo.factory(this.view);
50973 this.view.render && this.view.render(false, '');
50977 this.fireEvent('render', this);
50980 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
50982 setRegion : function(region){
50983 this.region = region;
50985 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
50987 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
50992 * Returns the toolbar for this Panel if one was configured.
50993 * @return {Roo.Toolbar}
50995 getToolbar : function(){
50996 return this.toolbar;
50999 setActiveState : function(active){
51000 this.active = active;
51002 this.fireEvent("deactivate", this);
51004 this.fireEvent("activate", this);
51008 * Updates this panel's element
51009 * @param {String} content The new content
51010 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51012 setContent : function(content, loadScripts){
51013 this.el.update(content, loadScripts);
51016 ignoreResize : function(w, h){
51017 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51020 this.lastSize = {width: w, height: h};
51025 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51026 * @return {Roo.UpdateManager} The UpdateManager
51028 getUpdateManager : function(){
51029 return this.el.getUpdateManager();
51032 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51033 * @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:
51036 url: "your-url.php",
51037 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51038 callback: yourFunction,
51039 scope: yourObject, //(optional scope)
51042 text: "Loading...",
51047 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51048 * 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.
51049 * @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}
51050 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51051 * @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.
51052 * @return {Roo.ContentPanel} this
51055 var um = this.el.getUpdateManager();
51056 um.update.apply(um, arguments);
51062 * 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.
51063 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51064 * @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)
51065 * @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)
51066 * @return {Roo.UpdateManager} The UpdateManager
51068 setUrl : function(url, params, loadOnce){
51069 if(this.refreshDelegate){
51070 this.removeListener("activate", this.refreshDelegate);
51072 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51073 this.on("activate", this.refreshDelegate);
51074 return this.el.getUpdateManager();
51077 _handleRefresh : function(url, params, loadOnce){
51078 if(!loadOnce || !this.loaded){
51079 var updater = this.el.getUpdateManager();
51080 updater.update(url, params, this._setLoaded.createDelegate(this));
51084 _setLoaded : function(){
51085 this.loaded = true;
51089 * Returns this panel's id
51092 getId : function(){
51097 * Returns this panel's element - used by regiosn to add.
51098 * @return {Roo.Element}
51100 getEl : function(){
51101 return this.wrapEl || this.el;
51104 adjustForComponents : function(width, height)
51106 //Roo.log('adjustForComponents ');
51107 if(this.resizeEl != this.el){
51108 width -= this.el.getFrameWidth('lr');
51109 height -= this.el.getFrameWidth('tb');
51112 var te = this.toolbar.getEl();
51113 height -= te.getHeight();
51114 te.setWidth(width);
51117 var te = this.footer.getEl();
51118 Roo.log("footer:" + te.getHeight());
51120 height -= te.getHeight();
51121 te.setWidth(width);
51125 if(this.adjustments){
51126 width += this.adjustments[0];
51127 height += this.adjustments[1];
51129 return {"width": width, "height": height};
51132 setSize : function(width, height){
51133 if(this.fitToFrame && !this.ignoreResize(width, height)){
51134 if(this.fitContainer && this.resizeEl != this.el){
51135 this.el.setSize(width, height);
51137 var size = this.adjustForComponents(width, height);
51138 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51139 this.fireEvent('resize', this, size.width, size.height);
51144 * Returns this panel's title
51147 getTitle : function(){
51152 * Set this panel's title
51153 * @param {String} title
51155 setTitle : function(title){
51156 this.title = title;
51158 this.region.updatePanelTitle(this, title);
51163 * Returns true is this panel was configured to be closable
51164 * @return {Boolean}
51166 isClosable : function(){
51167 return this.closable;
51170 beforeSlide : function(){
51172 this.resizeEl.clip();
51175 afterSlide : function(){
51177 this.resizeEl.unclip();
51181 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51182 * Will fail silently if the {@link #setUrl} method has not been called.
51183 * This does not activate the panel, just updates its content.
51185 refresh : function(){
51186 if(this.refreshDelegate){
51187 this.loaded = false;
51188 this.refreshDelegate();
51193 * Destroys this panel
51195 destroy : function(){
51196 this.el.removeAllListeners();
51197 var tempEl = document.createElement("span");
51198 tempEl.appendChild(this.el.dom);
51199 tempEl.innerHTML = "";
51205 * form - if the content panel contains a form - this is a reference to it.
51206 * @type {Roo.form.Form}
51210 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51211 * This contains a reference to it.
51217 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51227 * @param {Object} cfg Xtype definition of item to add.
51230 addxtype : function(cfg) {
51232 if (cfg.xtype.match(/^Form$/)) {
51235 //if (this.footer) {
51236 // el = this.footer.container.insertSibling(false, 'before');
51238 el = this.el.createChild();
51241 this.form = new Roo.form.Form(cfg);
51244 if ( this.form.allItems.length) this.form.render(el.dom);
51247 // should only have one of theses..
51248 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51249 // views.. should not be just added - used named prop 'view''
51251 cfg.el = this.el.appendChild(document.createElement("div"));
51254 var ret = new Roo.factory(cfg);
51256 ret.render && ret.render(false, ''); // render blank..
51265 * @class Roo.GridPanel
51266 * @extends Roo.ContentPanel
51268 * Create a new GridPanel.
51269 * @param {Roo.grid.Grid} grid The grid for this panel
51270 * @param {String/Object} config A string to set only the panel's title, or a config object
51272 Roo.GridPanel = function(grid, config){
51275 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51276 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51278 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51280 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51283 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51285 // xtype created footer. - not sure if will work as we normally have to render first..
51286 if (this.footer && !this.footer.el && this.footer.xtype) {
51288 this.footer.container = this.grid.getView().getFooterPanel(true);
51289 this.footer.dataSource = this.grid.dataSource;
51290 this.footer = Roo.factory(this.footer, Roo);
51294 grid.monitorWindowResize = false; // turn off autosizing
51295 grid.autoHeight = false;
51296 grid.autoWidth = false;
51298 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51301 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51302 getId : function(){
51303 return this.grid.id;
51307 * Returns the grid for this panel
51308 * @return {Roo.grid.Grid}
51310 getGrid : function(){
51314 setSize : function(width, height){
51315 if(!this.ignoreResize(width, height)){
51316 var grid = this.grid;
51317 var size = this.adjustForComponents(width, height);
51318 grid.getGridEl().setSize(size.width, size.height);
51323 beforeSlide : function(){
51324 this.grid.getView().scroller.clip();
51327 afterSlide : function(){
51328 this.grid.getView().scroller.unclip();
51331 destroy : function(){
51332 this.grid.destroy();
51334 Roo.GridPanel.superclass.destroy.call(this);
51340 * @class Roo.NestedLayoutPanel
51341 * @extends Roo.ContentPanel
51343 * Create a new NestedLayoutPanel.
51346 * @param {Roo.BorderLayout} layout The layout for this panel
51347 * @param {String/Object} config A string to set only the title or a config object
51349 Roo.NestedLayoutPanel = function(layout, config)
51351 // construct with only one argument..
51352 /* FIXME - implement nicer consturctors
51353 if (layout.layout) {
51355 layout = config.layout;
51356 delete config.layout;
51358 if (layout.xtype && !layout.getEl) {
51359 // then layout needs constructing..
51360 layout = Roo.factory(layout, Roo);
51365 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51367 layout.monitorWindowResize = false; // turn off autosizing
51368 this.layout = layout;
51369 this.layout.getEl().addClass("x-layout-nested-layout");
51376 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51378 setSize : function(width, height){
51379 if(!this.ignoreResize(width, height)){
51380 var size = this.adjustForComponents(width, height);
51381 var el = this.layout.getEl();
51382 el.setSize(size.width, size.height);
51383 var touch = el.dom.offsetWidth;
51384 this.layout.layout();
51385 // ie requires a double layout on the first pass
51386 if(Roo.isIE && !this.initialized){
51387 this.initialized = true;
51388 this.layout.layout();
51393 // activate all subpanels if not currently active..
51395 setActiveState : function(active){
51396 this.active = active;
51398 this.fireEvent("deactivate", this);
51402 this.fireEvent("activate", this);
51403 // not sure if this should happen before or after..
51404 if (!this.layout) {
51405 return; // should not happen..
51408 for (var r in this.layout.regions) {
51409 reg = this.layout.getRegion(r);
51410 if (reg.getActivePanel()) {
51411 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51412 reg.setActivePanel(reg.getActivePanel());
51415 if (!reg.panels.length) {
51418 reg.showPanel(reg.getPanel(0));
51427 * Returns the nested BorderLayout for this panel
51428 * @return {Roo.BorderLayout}
51430 getLayout : function(){
51431 return this.layout;
51435 * Adds a xtype elements to the layout of the nested panel
51439 xtype : 'ContentPanel',
51446 xtype : 'NestedLayoutPanel',
51452 items : [ ... list of content panels or nested layout panels.. ]
51456 * @param {Object} cfg Xtype definition of item to add.
51458 addxtype : function(cfg) {
51459 return this.layout.addxtype(cfg);
51464 Roo.ScrollPanel = function(el, config, content){
51465 config = config || {};
51466 config.fitToFrame = true;
51467 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
51469 this.el.dom.style.overflow = "hidden";
51470 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
51471 this.el.removeClass("x-layout-inactive-content");
51472 this.el.on("mousewheel", this.onWheel, this);
51474 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
51475 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
51476 up.unselectable(); down.unselectable();
51477 up.on("click", this.scrollUp, this);
51478 down.on("click", this.scrollDown, this);
51479 up.addClassOnOver("x-scroller-btn-over");
51480 down.addClassOnOver("x-scroller-btn-over");
51481 up.addClassOnClick("x-scroller-btn-click");
51482 down.addClassOnClick("x-scroller-btn-click");
51483 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
51485 this.resizeEl = this.el;
51486 this.el = wrap; this.up = up; this.down = down;
51489 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
51491 wheelIncrement : 5,
51492 scrollUp : function(){
51493 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
51496 scrollDown : function(){
51497 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
51500 afterScroll : function(){
51501 var el = this.resizeEl;
51502 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
51503 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51504 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51507 setSize : function(){
51508 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
51509 this.afterScroll();
51512 onWheel : function(e){
51513 var d = e.getWheelDelta();
51514 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
51515 this.afterScroll();
51519 setContent : function(content, loadScripts){
51520 this.resizeEl.update(content, loadScripts);
51534 * @class Roo.TreePanel
51535 * @extends Roo.ContentPanel
51537 * Create a new TreePanel. - defaults to fit/scoll contents.
51538 * @param {String/Object} config A string to set only the panel's title, or a config object
51539 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
51541 Roo.TreePanel = function(config){
51542 var el = config.el;
51543 var tree = config.tree;
51544 delete config.tree;
51545 delete config.el; // hopefull!
51547 // wrapper for IE7 strict & safari scroll issue
51549 var treeEl = el.createChild();
51550 config.resizeEl = treeEl;
51554 Roo.TreePanel.superclass.constructor.call(this, el, config);
51557 this.tree = new Roo.tree.TreePanel(treeEl , tree);
51558 //console.log(tree);
51559 this.on('activate', function()
51561 if (this.tree.rendered) {
51564 //console.log('render tree');
51565 this.tree.render();
51567 // this should not be needed.. - it's actually the 'el' that resizes?
51568 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
51570 //this.on('resize', function (cp, w, h) {
51571 // this.tree.innerCt.setWidth(w);
51572 // this.tree.innerCt.setHeight(h);
51573 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
51580 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
51597 * Ext JS Library 1.1.1
51598 * Copyright(c) 2006-2007, Ext JS, LLC.
51600 * Originally Released Under LGPL - original licence link has changed is not relivant.
51603 * <script type="text/javascript">
51608 * @class Roo.ReaderLayout
51609 * @extends Roo.BorderLayout
51610 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
51611 * center region containing two nested regions (a top one for a list view and one for item preview below),
51612 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
51613 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
51614 * expedites the setup of the overall layout and regions for this common application style.
51617 var reader = new Roo.ReaderLayout();
51618 var CP = Roo.ContentPanel; // shortcut for adding
51620 reader.beginUpdate();
51621 reader.add("north", new CP("north", "North"));
51622 reader.add("west", new CP("west", {title: "West"}));
51623 reader.add("east", new CP("east", {title: "East"}));
51625 reader.regions.listView.add(new CP("listView", "List"));
51626 reader.regions.preview.add(new CP("preview", "Preview"));
51627 reader.endUpdate();
51630 * Create a new ReaderLayout
51631 * @param {Object} config Configuration options
51632 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
51633 * document.body if omitted)
51635 Roo.ReaderLayout = function(config, renderTo){
51636 var c = config || {size:{}};
51637 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
51638 north: c.north !== false ? Roo.apply({
51642 }, c.north) : false,
51643 west: c.west !== false ? Roo.apply({
51651 margins:{left:5,right:0,bottom:5,top:5},
51652 cmargins:{left:5,right:5,bottom:5,top:5}
51653 }, c.west) : false,
51654 east: c.east !== false ? Roo.apply({
51662 margins:{left:0,right:5,bottom:5,top:5},
51663 cmargins:{left:5,right:5,bottom:5,top:5}
51664 }, c.east) : false,
51665 center: Roo.apply({
51666 tabPosition: 'top',
51670 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
51674 this.el.addClass('x-reader');
51676 this.beginUpdate();
51678 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
51679 south: c.preview !== false ? Roo.apply({
51686 cmargins:{top:5,left:0, right:0, bottom:0}
51687 }, c.preview) : false,
51688 center: Roo.apply({
51694 this.add('center', new Roo.NestedLayoutPanel(inner,
51695 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
51699 this.regions.preview = inner.getRegion('south');
51700 this.regions.listView = inner.getRegion('center');
51703 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
51705 * Ext JS Library 1.1.1
51706 * Copyright(c) 2006-2007, Ext JS, LLC.
51708 * Originally Released Under LGPL - original licence link has changed is not relivant.
51711 * <script type="text/javascript">
51715 * @class Roo.grid.Grid
51716 * @extends Roo.util.Observable
51717 * This class represents the primary interface of a component based grid control.
51718 * <br><br>Usage:<pre><code>
51719 var grid = new Roo.grid.Grid("my-container-id", {
51722 selModel: mySelectionModel,
51723 autoSizeColumns: true,
51724 monitorWindowResize: false,
51725 trackMouseOver: true
51730 * <b>Common Problems:</b><br/>
51731 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
51732 * element will correct this<br/>
51733 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
51734 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
51735 * are unpredictable.<br/>
51736 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
51737 * grid to calculate dimensions/offsets.<br/>
51739 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51740 * The container MUST have some type of size defined for the grid to fill. The container will be
51741 * automatically set to position relative if it isn't already.
51742 * @param {Object} config A config object that sets properties on this grid.
51744 Roo.grid.Grid = function(container, config){
51745 // initialize the container
51746 this.container = Roo.get(container);
51747 this.container.update("");
51748 this.container.setStyle("overflow", "hidden");
51749 this.container.addClass('x-grid-container');
51751 this.id = this.container.id;
51753 Roo.apply(this, config);
51754 // check and correct shorthanded configs
51756 this.dataSource = this.ds;
51760 this.colModel = this.cm;
51764 this.selModel = this.sm;
51768 if (this.selModel) {
51769 this.selModel = Roo.factory(this.selModel, Roo.grid);
51770 this.sm = this.selModel;
51771 this.sm.xmodule = this.xmodule || false;
51773 if (typeof(this.colModel.config) == 'undefined') {
51774 this.colModel = new Roo.grid.ColumnModel(this.colModel);
51775 this.cm = this.colModel;
51776 this.cm.xmodule = this.xmodule || false;
51778 if (this.dataSource) {
51779 this.dataSource= Roo.factory(this.dataSource, Roo.data);
51780 this.ds = this.dataSource;
51781 this.ds.xmodule = this.xmodule || false;
51788 this.container.setWidth(this.width);
51792 this.container.setHeight(this.height);
51799 * The raw click event for the entire grid.
51800 * @param {Roo.EventObject} e
51805 * The raw dblclick event for the entire grid.
51806 * @param {Roo.EventObject} e
51810 * @event contextmenu
51811 * The raw contextmenu event for the entire grid.
51812 * @param {Roo.EventObject} e
51814 "contextmenu" : true,
51817 * The raw mousedown event for the entire grid.
51818 * @param {Roo.EventObject} e
51820 "mousedown" : true,
51823 * The raw mouseup event for the entire grid.
51824 * @param {Roo.EventObject} e
51829 * The raw mouseover event for the entire grid.
51830 * @param {Roo.EventObject} e
51832 "mouseover" : true,
51835 * The raw mouseout event for the entire grid.
51836 * @param {Roo.EventObject} e
51841 * The raw keypress event for the entire grid.
51842 * @param {Roo.EventObject} e
51847 * The raw keydown event for the entire grid.
51848 * @param {Roo.EventObject} e
51856 * Fires when a cell is clicked
51857 * @param {Grid} this
51858 * @param {Number} rowIndex
51859 * @param {Number} columnIndex
51860 * @param {Roo.EventObject} e
51862 "cellclick" : true,
51864 * @event celldblclick
51865 * Fires when a cell is double clicked
51866 * @param {Grid} this
51867 * @param {Number} rowIndex
51868 * @param {Number} columnIndex
51869 * @param {Roo.EventObject} e
51871 "celldblclick" : true,
51874 * Fires when a row is clicked
51875 * @param {Grid} this
51876 * @param {Number} rowIndex
51877 * @param {Roo.EventObject} e
51881 * @event rowdblclick
51882 * Fires when a row is double clicked
51883 * @param {Grid} this
51884 * @param {Number} rowIndex
51885 * @param {Roo.EventObject} e
51887 "rowdblclick" : true,
51889 * @event headerclick
51890 * Fires when a header is clicked
51891 * @param {Grid} this
51892 * @param {Number} columnIndex
51893 * @param {Roo.EventObject} e
51895 "headerclick" : true,
51897 * @event headerdblclick
51898 * Fires when a header cell is double clicked
51899 * @param {Grid} this
51900 * @param {Number} columnIndex
51901 * @param {Roo.EventObject} e
51903 "headerdblclick" : true,
51905 * @event rowcontextmenu
51906 * Fires when a row is right clicked
51907 * @param {Grid} this
51908 * @param {Number} rowIndex
51909 * @param {Roo.EventObject} e
51911 "rowcontextmenu" : true,
51913 * @event cellcontextmenu
51914 * Fires when a cell is right clicked
51915 * @param {Grid} this
51916 * @param {Number} rowIndex
51917 * @param {Number} cellIndex
51918 * @param {Roo.EventObject} e
51920 "cellcontextmenu" : true,
51922 * @event headercontextmenu
51923 * Fires when a header is right clicked
51924 * @param {Grid} this
51925 * @param {Number} columnIndex
51926 * @param {Roo.EventObject} e
51928 "headercontextmenu" : true,
51930 * @event bodyscroll
51931 * Fires when the body element is scrolled
51932 * @param {Number} scrollLeft
51933 * @param {Number} scrollTop
51935 "bodyscroll" : true,
51937 * @event columnresize
51938 * Fires when the user resizes a column
51939 * @param {Number} columnIndex
51940 * @param {Number} newSize
51942 "columnresize" : true,
51944 * @event columnmove
51945 * Fires when the user moves a column
51946 * @param {Number} oldIndex
51947 * @param {Number} newIndex
51949 "columnmove" : true,
51952 * Fires when row(s) start being dragged
51953 * @param {Grid} this
51954 * @param {Roo.GridDD} dd The drag drop object
51955 * @param {event} e The raw browser event
51957 "startdrag" : true,
51960 * Fires when a drag operation is complete
51961 * @param {Grid} this
51962 * @param {Roo.GridDD} dd The drag drop object
51963 * @param {event} e The raw browser event
51968 * Fires when dragged row(s) are dropped on a valid DD target
51969 * @param {Grid} this
51970 * @param {Roo.GridDD} dd The drag drop object
51971 * @param {String} targetId The target drag drop object
51972 * @param {event} e The raw browser event
51977 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
51978 * @param {Grid} this
51979 * @param {Roo.GridDD} dd The drag drop object
51980 * @param {String} targetId The target drag drop object
51981 * @param {event} e The raw browser event
51986 * Fires when the dragged row(s) first cross another DD target while being dragged
51987 * @param {Grid} this
51988 * @param {Roo.GridDD} dd The drag drop object
51989 * @param {String} targetId The target drag drop object
51990 * @param {event} e The raw browser event
51992 "dragenter" : true,
51995 * Fires when the dragged row(s) leave another DD target while being dragged
51996 * @param {Grid} this
51997 * @param {Roo.GridDD} dd The drag drop object
51998 * @param {String} targetId The target drag drop object
51999 * @param {event} e The raw browser event
52004 * Fires when a row is rendered, so you can change add a style to it.
52005 * @param {GridView} gridview The grid view
52006 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52012 * Fires when the grid is rendered
52013 * @param {Grid} grid
52018 Roo.grid.Grid.superclass.constructor.call(this);
52020 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52023 * @cfg {String} ddGroup - drag drop group.
52027 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52029 minColumnWidth : 25,
52032 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52033 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52034 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52036 autoSizeColumns : false,
52039 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52041 autoSizeHeaders : true,
52044 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52046 monitorWindowResize : true,
52049 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52050 * rows measured to get a columns size. Default is 0 (all rows).
52052 maxRowsToMeasure : 0,
52055 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52057 trackMouseOver : true,
52060 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52064 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52066 enableDragDrop : false,
52069 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52071 enableColumnMove : true,
52074 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52076 enableColumnHide : true,
52079 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52081 enableRowHeightSync : false,
52084 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52089 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52091 autoHeight : false,
52094 * @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.
52096 autoExpandColumn : false,
52099 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52102 autoExpandMin : 50,
52105 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52107 autoExpandMax : 1000,
52110 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52115 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52119 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52129 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52130 * of a fixed width. Default is false.
52133 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52136 * Called once after all setup has been completed and the grid is ready to be rendered.
52137 * @return {Roo.grid.Grid} this
52139 render : function()
52141 var c = this.container;
52142 // try to detect autoHeight/width mode
52143 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52144 this.autoHeight = true;
52146 var view = this.getView();
52149 c.on("click", this.onClick, this);
52150 c.on("dblclick", this.onDblClick, this);
52151 c.on("contextmenu", this.onContextMenu, this);
52152 c.on("keydown", this.onKeyDown, this);
52154 c.on("touchstart", this.onTouchStart, this);
52157 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52159 this.getSelectionModel().init(this);
52164 this.loadMask = new Roo.LoadMask(this.container,
52165 Roo.apply({store:this.dataSource}, this.loadMask));
52169 if (this.toolbar && this.toolbar.xtype) {
52170 this.toolbar.container = this.getView().getHeaderPanel(true);
52171 this.toolbar = new Roo.Toolbar(this.toolbar);
52173 if (this.footer && this.footer.xtype) {
52174 this.footer.dataSource = this.getDataSource();
52175 this.footer.container = this.getView().getFooterPanel(true);
52176 this.footer = Roo.factory(this.footer, Roo);
52178 if (this.dropTarget && this.dropTarget.xtype) {
52179 delete this.dropTarget.xtype;
52180 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52184 this.rendered = true;
52185 this.fireEvent('render', this);
52190 * Reconfigures the grid to use a different Store and Column Model.
52191 * The View will be bound to the new objects and refreshed.
52192 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52193 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52195 reconfigure : function(dataSource, colModel){
52197 this.loadMask.destroy();
52198 this.loadMask = new Roo.LoadMask(this.container,
52199 Roo.apply({store:dataSource}, this.loadMask));
52201 this.view.bind(dataSource, colModel);
52202 this.dataSource = dataSource;
52203 this.colModel = colModel;
52204 this.view.refresh(true);
52208 onKeyDown : function(e){
52209 this.fireEvent("keydown", e);
52213 * Destroy this grid.
52214 * @param {Boolean} removeEl True to remove the element
52216 destroy : function(removeEl, keepListeners){
52218 this.loadMask.destroy();
52220 var c = this.container;
52221 c.removeAllListeners();
52222 this.view.destroy();
52223 this.colModel.purgeListeners();
52224 if(!keepListeners){
52225 this.purgeListeners();
52228 if(removeEl === true){
52234 processEvent : function(name, e){
52235 // does this fire select???
52236 Roo.log('grid:processEvent ' + name);
52238 if (name != 'touchstart' ) {
52239 this.fireEvent(name, e);
52242 var t = e.getTarget();
52244 var header = v.findHeaderIndex(t);
52245 if(header !== false){
52246 var ename = name == 'touchstart' ? 'click' : name;
52248 this.fireEvent("header" + ename, this, header, e);
52250 var row = v.findRowIndex(t);
52251 var cell = v.findCellIndex(t);
52252 if (name == 'touchstart') {
52253 // first touch is always a click.
52254 // hopefull this happens after selection is updated.?
52257 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52258 var cs = this.selModel.getSelectedCell();
52259 if (row == cs[0] && cell == cs[1]){
52263 if (typeof(this.selModel.getSelections) != 'undefined') {
52264 var cs = this.selModel.getSelections();
52265 var ds = this.dataSource;
52266 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52277 this.fireEvent("row" + name, this, row, e);
52278 if(cell !== false){
52279 this.fireEvent("cell" + name, this, row, cell, e);
52286 onClick : function(e){
52287 this.processEvent("click", e);
52290 onTouchStart : function(e){
52291 this.processEvent("touchstart", e);
52295 onContextMenu : function(e, t){
52296 this.processEvent("contextmenu", e);
52300 onDblClick : function(e){
52301 this.processEvent("dblclick", e);
52305 walkCells : function(row, col, step, fn, scope){
52306 var cm = this.colModel, clen = cm.getColumnCount();
52307 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52319 if(fn.call(scope || this, row, col, cm) === true){
52337 if(fn.call(scope || this, row, col, cm) === true){
52349 getSelections : function(){
52350 return this.selModel.getSelections();
52354 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52355 * but if manual update is required this method will initiate it.
52357 autoSize : function(){
52359 this.view.layout();
52360 if(this.view.adjustForScroll){
52361 this.view.adjustForScroll();
52367 * Returns the grid's underlying element.
52368 * @return {Element} The element
52370 getGridEl : function(){
52371 return this.container;
52374 // private for compatibility, overridden by editor grid
52375 stopEditing : function(){},
52378 * Returns the grid's SelectionModel.
52379 * @return {SelectionModel}
52381 getSelectionModel : function(){
52382 if(!this.selModel){
52383 this.selModel = new Roo.grid.RowSelectionModel();
52385 return this.selModel;
52389 * Returns the grid's DataSource.
52390 * @return {DataSource}
52392 getDataSource : function(){
52393 return this.dataSource;
52397 * Returns the grid's ColumnModel.
52398 * @return {ColumnModel}
52400 getColumnModel : function(){
52401 return this.colModel;
52405 * Returns the grid's GridView object.
52406 * @return {GridView}
52408 getView : function(){
52410 this.view = new Roo.grid.GridView(this.viewConfig);
52415 * Called to get grid's drag proxy text, by default returns this.ddText.
52418 getDragDropText : function(){
52419 var count = this.selModel.getCount();
52420 return String.format(this.ddText, count, count == 1 ? '' : 's');
52424 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
52425 * %0 is replaced with the number of selected rows.
52428 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
52430 * Ext JS Library 1.1.1
52431 * Copyright(c) 2006-2007, Ext JS, LLC.
52433 * Originally Released Under LGPL - original licence link has changed is not relivant.
52436 * <script type="text/javascript">
52439 Roo.grid.AbstractGridView = function(){
52443 "beforerowremoved" : true,
52444 "beforerowsinserted" : true,
52445 "beforerefresh" : true,
52446 "rowremoved" : true,
52447 "rowsinserted" : true,
52448 "rowupdated" : true,
52451 Roo.grid.AbstractGridView.superclass.constructor.call(this);
52454 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
52455 rowClass : "x-grid-row",
52456 cellClass : "x-grid-cell",
52457 tdClass : "x-grid-td",
52458 hdClass : "x-grid-hd",
52459 splitClass : "x-grid-hd-split",
52461 init: function(grid){
52463 var cid = this.grid.getGridEl().id;
52464 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
52465 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
52466 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
52467 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
52470 getColumnRenderers : function(){
52471 var renderers = [];
52472 var cm = this.grid.colModel;
52473 var colCount = cm.getColumnCount();
52474 for(var i = 0; i < colCount; i++){
52475 renderers[i] = cm.getRenderer(i);
52480 getColumnIds : function(){
52482 var cm = this.grid.colModel;
52483 var colCount = cm.getColumnCount();
52484 for(var i = 0; i < colCount; i++){
52485 ids[i] = cm.getColumnId(i);
52490 getDataIndexes : function(){
52491 if(!this.indexMap){
52492 this.indexMap = this.buildIndexMap();
52494 return this.indexMap.colToData;
52497 getColumnIndexByDataIndex : function(dataIndex){
52498 if(!this.indexMap){
52499 this.indexMap = this.buildIndexMap();
52501 return this.indexMap.dataToCol[dataIndex];
52505 * Set a css style for a column dynamically.
52506 * @param {Number} colIndex The index of the column
52507 * @param {String} name The css property name
52508 * @param {String} value The css value
52510 setCSSStyle : function(colIndex, name, value){
52511 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
52512 Roo.util.CSS.updateRule(selector, name, value);
52515 generateRules : function(cm){
52516 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
52517 Roo.util.CSS.removeStyleSheet(rulesId);
52518 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52519 var cid = cm.getColumnId(i);
52520 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
52521 this.tdSelector, cid, " {\n}\n",
52522 this.hdSelector, cid, " {\n}\n",
52523 this.splitSelector, cid, " {\n}\n");
52525 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52529 * Ext JS Library 1.1.1
52530 * Copyright(c) 2006-2007, Ext JS, LLC.
52532 * Originally Released Under LGPL - original licence link has changed is not relivant.
52535 * <script type="text/javascript">
52539 // This is a support class used internally by the Grid components
52540 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
52542 this.view = grid.getView();
52543 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52544 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
52546 this.setHandleElId(Roo.id(hd));
52547 this.setOuterHandleElId(Roo.id(hd2));
52549 this.scroll = false;
52551 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
52553 getDragData : function(e){
52554 var t = Roo.lib.Event.getTarget(e);
52555 var h = this.view.findHeaderCell(t);
52557 return {ddel: h.firstChild, header:h};
52562 onInitDrag : function(e){
52563 this.view.headersDisabled = true;
52564 var clone = this.dragData.ddel.cloneNode(true);
52565 clone.id = Roo.id();
52566 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
52567 this.proxy.update(clone);
52571 afterValidDrop : function(){
52573 setTimeout(function(){
52574 v.headersDisabled = false;
52578 afterInvalidDrop : function(){
52580 setTimeout(function(){
52581 v.headersDisabled = false;
52587 * Ext JS Library 1.1.1
52588 * Copyright(c) 2006-2007, Ext JS, LLC.
52590 * Originally Released Under LGPL - original licence link has changed is not relivant.
52593 * <script type="text/javascript">
52596 // This is a support class used internally by the Grid components
52597 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
52599 this.view = grid.getView();
52600 // split the proxies so they don't interfere with mouse events
52601 this.proxyTop = Roo.DomHelper.append(document.body, {
52602 cls:"col-move-top", html:" "
52604 this.proxyBottom = Roo.DomHelper.append(document.body, {
52605 cls:"col-move-bottom", html:" "
52607 this.proxyTop.hide = this.proxyBottom.hide = function(){
52608 this.setLeftTop(-100,-100);
52609 this.setStyle("visibility", "hidden");
52611 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52612 // temporarily disabled
52613 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
52614 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
52616 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
52617 proxyOffsets : [-4, -9],
52618 fly: Roo.Element.fly,
52620 getTargetFromEvent : function(e){
52621 var t = Roo.lib.Event.getTarget(e);
52622 var cindex = this.view.findCellIndex(t);
52623 if(cindex !== false){
52624 return this.view.getHeaderCell(cindex);
52629 nextVisible : function(h){
52630 var v = this.view, cm = this.grid.colModel;
52633 if(!cm.isHidden(v.getCellIndex(h))){
52641 prevVisible : function(h){
52642 var v = this.view, cm = this.grid.colModel;
52645 if(!cm.isHidden(v.getCellIndex(h))){
52653 positionIndicator : function(h, n, e){
52654 var x = Roo.lib.Event.getPageX(e);
52655 var r = Roo.lib.Dom.getRegion(n.firstChild);
52656 var px, pt, py = r.top + this.proxyOffsets[1];
52657 if((r.right - x) <= (r.right-r.left)/2){
52658 px = r.right+this.view.borderWidth;
52664 var oldIndex = this.view.getCellIndex(h);
52665 var newIndex = this.view.getCellIndex(n);
52667 if(this.grid.colModel.isFixed(newIndex)){
52671 var locked = this.grid.colModel.isLocked(newIndex);
52676 if(oldIndex < newIndex){
52679 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
52682 px += this.proxyOffsets[0];
52683 this.proxyTop.setLeftTop(px, py);
52684 this.proxyTop.show();
52685 if(!this.bottomOffset){
52686 this.bottomOffset = this.view.mainHd.getHeight();
52688 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
52689 this.proxyBottom.show();
52693 onNodeEnter : function(n, dd, e, data){
52694 if(data.header != n){
52695 this.positionIndicator(data.header, n, e);
52699 onNodeOver : function(n, dd, e, data){
52700 var result = false;
52701 if(data.header != n){
52702 result = this.positionIndicator(data.header, n, e);
52705 this.proxyTop.hide();
52706 this.proxyBottom.hide();
52708 return result ? this.dropAllowed : this.dropNotAllowed;
52711 onNodeOut : function(n, dd, e, data){
52712 this.proxyTop.hide();
52713 this.proxyBottom.hide();
52716 onNodeDrop : function(n, dd, e, data){
52717 var h = data.header;
52719 var cm = this.grid.colModel;
52720 var x = Roo.lib.Event.getPageX(e);
52721 var r = Roo.lib.Dom.getRegion(n.firstChild);
52722 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
52723 var oldIndex = this.view.getCellIndex(h);
52724 var newIndex = this.view.getCellIndex(n);
52725 var locked = cm.isLocked(newIndex);
52729 if(oldIndex < newIndex){
52732 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
52735 cm.setLocked(oldIndex, locked, true);
52736 cm.moveColumn(oldIndex, newIndex);
52737 this.grid.fireEvent("columnmove", oldIndex, newIndex);
52745 * Ext JS Library 1.1.1
52746 * Copyright(c) 2006-2007, Ext JS, LLC.
52748 * Originally Released Under LGPL - original licence link has changed is not relivant.
52751 * <script type="text/javascript">
52755 * @class Roo.grid.GridView
52756 * @extends Roo.util.Observable
52759 * @param {Object} config
52761 Roo.grid.GridView = function(config){
52762 Roo.grid.GridView.superclass.constructor.call(this);
52765 Roo.apply(this, config);
52768 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
52770 unselectable : 'unselectable="on"',
52771 unselectableCls : 'x-unselectable',
52774 rowClass : "x-grid-row",
52776 cellClass : "x-grid-col",
52778 tdClass : "x-grid-td",
52780 hdClass : "x-grid-hd",
52782 splitClass : "x-grid-split",
52784 sortClasses : ["sort-asc", "sort-desc"],
52786 enableMoveAnim : false,
52790 dh : Roo.DomHelper,
52792 fly : Roo.Element.fly,
52794 css : Roo.util.CSS,
52800 scrollIncrement : 22,
52802 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
52804 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
52806 bind : function(ds, cm){
52808 this.ds.un("load", this.onLoad, this);
52809 this.ds.un("datachanged", this.onDataChange, this);
52810 this.ds.un("add", this.onAdd, this);
52811 this.ds.un("remove", this.onRemove, this);
52812 this.ds.un("update", this.onUpdate, this);
52813 this.ds.un("clear", this.onClear, this);
52816 ds.on("load", this.onLoad, this);
52817 ds.on("datachanged", this.onDataChange, this);
52818 ds.on("add", this.onAdd, this);
52819 ds.on("remove", this.onRemove, this);
52820 ds.on("update", this.onUpdate, this);
52821 ds.on("clear", this.onClear, this);
52826 this.cm.un("widthchange", this.onColWidthChange, this);
52827 this.cm.un("headerchange", this.onHeaderChange, this);
52828 this.cm.un("hiddenchange", this.onHiddenChange, this);
52829 this.cm.un("columnmoved", this.onColumnMove, this);
52830 this.cm.un("columnlockchange", this.onColumnLock, this);
52833 this.generateRules(cm);
52834 cm.on("widthchange", this.onColWidthChange, this);
52835 cm.on("headerchange", this.onHeaderChange, this);
52836 cm.on("hiddenchange", this.onHiddenChange, this);
52837 cm.on("columnmoved", this.onColumnMove, this);
52838 cm.on("columnlockchange", this.onColumnLock, this);
52843 init: function(grid){
52844 Roo.grid.GridView.superclass.init.call(this, grid);
52846 this.bind(grid.dataSource, grid.colModel);
52848 grid.on("headerclick", this.handleHeaderClick, this);
52850 if(grid.trackMouseOver){
52851 grid.on("mouseover", this.onRowOver, this);
52852 grid.on("mouseout", this.onRowOut, this);
52854 grid.cancelTextSelection = function(){};
52855 this.gridId = grid.id;
52857 var tpls = this.templates || {};
52860 tpls.master = new Roo.Template(
52861 '<div class="x-grid" hidefocus="true">',
52862 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
52863 '<div class="x-grid-topbar"></div>',
52864 '<div class="x-grid-scroller"><div></div></div>',
52865 '<div class="x-grid-locked">',
52866 '<div class="x-grid-header">{lockedHeader}</div>',
52867 '<div class="x-grid-body">{lockedBody}</div>',
52869 '<div class="x-grid-viewport">',
52870 '<div class="x-grid-header">{header}</div>',
52871 '<div class="x-grid-body">{body}</div>',
52873 '<div class="x-grid-bottombar"></div>',
52875 '<div class="x-grid-resize-proxy"> </div>',
52878 tpls.master.disableformats = true;
52882 tpls.header = new Roo.Template(
52883 '<table border="0" cellspacing="0" cellpadding="0">',
52884 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
52887 tpls.header.disableformats = true;
52889 tpls.header.compile();
52892 tpls.hcell = new Roo.Template(
52893 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
52894 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
52897 tpls.hcell.disableFormats = true;
52899 tpls.hcell.compile();
52902 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
52903 this.unselectableCls + '" ' + this.unselectable +'> </div>');
52904 tpls.hsplit.disableFormats = true;
52906 tpls.hsplit.compile();
52909 tpls.body = new Roo.Template(
52910 '<table border="0" cellspacing="0" cellpadding="0">',
52911 "<tbody>{rows}</tbody>",
52914 tpls.body.disableFormats = true;
52916 tpls.body.compile();
52919 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
52920 tpls.row.disableFormats = true;
52922 tpls.row.compile();
52925 tpls.cell = new Roo.Template(
52926 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
52927 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
52928 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
52931 tpls.cell.disableFormats = true;
52933 tpls.cell.compile();
52935 this.templates = tpls;
52938 // remap these for backwards compat
52939 onColWidthChange : function(){
52940 this.updateColumns.apply(this, arguments);
52942 onHeaderChange : function(){
52943 this.updateHeaders.apply(this, arguments);
52945 onHiddenChange : function(){
52946 this.handleHiddenChange.apply(this, arguments);
52948 onColumnMove : function(){
52949 this.handleColumnMove.apply(this, arguments);
52951 onColumnLock : function(){
52952 this.handleLockChange.apply(this, arguments);
52955 onDataChange : function(){
52957 this.updateHeaderSortState();
52960 onClear : function(){
52964 onUpdate : function(ds, record){
52965 this.refreshRow(record);
52968 refreshRow : function(record){
52969 var ds = this.ds, index;
52970 if(typeof record == 'number'){
52972 record = ds.getAt(index);
52974 index = ds.indexOf(record);
52976 this.insertRows(ds, index, index, true);
52977 this.onRemove(ds, record, index+1, true);
52978 this.syncRowHeights(index, index);
52980 this.fireEvent("rowupdated", this, index, record);
52983 onAdd : function(ds, records, index){
52984 this.insertRows(ds, index, index + (records.length-1));
52987 onRemove : function(ds, record, index, isUpdate){
52988 if(isUpdate !== true){
52989 this.fireEvent("beforerowremoved", this, index, record);
52991 var bt = this.getBodyTable(), lt = this.getLockedTable();
52992 if(bt.rows[index]){
52993 bt.firstChild.removeChild(bt.rows[index]);
52995 if(lt.rows[index]){
52996 lt.firstChild.removeChild(lt.rows[index]);
52998 if(isUpdate !== true){
52999 this.stripeRows(index);
53000 this.syncRowHeights(index, index);
53002 this.fireEvent("rowremoved", this, index, record);
53006 onLoad : function(){
53007 this.scrollToTop();
53011 * Scrolls the grid to the top
53013 scrollToTop : function(){
53015 this.scroller.dom.scrollTop = 0;
53021 * Gets a panel in the header of the grid that can be used for toolbars etc.
53022 * After modifying the contents of this panel a call to grid.autoSize() may be
53023 * required to register any changes in size.
53024 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53025 * @return Roo.Element
53027 getHeaderPanel : function(doShow){
53029 this.headerPanel.show();
53031 return this.headerPanel;
53035 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53036 * After modifying the contents of this panel a call to grid.autoSize() may be
53037 * required to register any changes in size.
53038 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53039 * @return Roo.Element
53041 getFooterPanel : function(doShow){
53043 this.footerPanel.show();
53045 return this.footerPanel;
53048 initElements : function(){
53049 var E = Roo.Element;
53050 var el = this.grid.getGridEl().dom.firstChild;
53051 var cs = el.childNodes;
53053 this.el = new E(el);
53055 this.focusEl = new E(el.firstChild);
53056 this.focusEl.swallowEvent("click", true);
53058 this.headerPanel = new E(cs[1]);
53059 this.headerPanel.enableDisplayMode("block");
53061 this.scroller = new E(cs[2]);
53062 this.scrollSizer = new E(this.scroller.dom.firstChild);
53064 this.lockedWrap = new E(cs[3]);
53065 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53066 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53068 this.mainWrap = new E(cs[4]);
53069 this.mainHd = new E(this.mainWrap.dom.firstChild);
53070 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53072 this.footerPanel = new E(cs[5]);
53073 this.footerPanel.enableDisplayMode("block");
53075 this.resizeProxy = new E(cs[6]);
53077 this.headerSelector = String.format(
53078 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53079 this.lockedHd.id, this.mainHd.id
53082 this.splitterSelector = String.format(
53083 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53084 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53087 idToCssName : function(s)
53089 return s.replace(/[^a-z0-9]+/ig, '-');
53092 getHeaderCell : function(index){
53093 return Roo.DomQuery.select(this.headerSelector)[index];
53096 getHeaderCellMeasure : function(index){
53097 return this.getHeaderCell(index).firstChild;
53100 getHeaderCellText : function(index){
53101 return this.getHeaderCell(index).firstChild.firstChild;
53104 getLockedTable : function(){
53105 return this.lockedBody.dom.firstChild;
53108 getBodyTable : function(){
53109 return this.mainBody.dom.firstChild;
53112 getLockedRow : function(index){
53113 return this.getLockedTable().rows[index];
53116 getRow : function(index){
53117 return this.getBodyTable().rows[index];
53120 getRowComposite : function(index){
53122 this.rowEl = new Roo.CompositeElementLite();
53124 var els = [], lrow, mrow;
53125 if(lrow = this.getLockedRow(index)){
53128 if(mrow = this.getRow(index)){
53131 this.rowEl.elements = els;
53135 * Gets the 'td' of the cell
53137 * @param {Integer} rowIndex row to select
53138 * @param {Integer} colIndex column to select
53142 getCell : function(rowIndex, colIndex){
53143 var locked = this.cm.getLockedCount();
53145 if(colIndex < locked){
53146 source = this.lockedBody.dom.firstChild;
53148 source = this.mainBody.dom.firstChild;
53149 colIndex -= locked;
53151 return source.rows[rowIndex].childNodes[colIndex];
53154 getCellText : function(rowIndex, colIndex){
53155 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53158 getCellBox : function(cell){
53159 var b = this.fly(cell).getBox();
53160 if(Roo.isOpera){ // opera fails to report the Y
53161 b.y = cell.offsetTop + this.mainBody.getY();
53166 getCellIndex : function(cell){
53167 var id = String(cell.className).match(this.cellRE);
53169 return parseInt(id[1], 10);
53174 findHeaderIndex : function(n){
53175 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53176 return r ? this.getCellIndex(r) : false;
53179 findHeaderCell : function(n){
53180 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53181 return r ? r : false;
53184 findRowIndex : function(n){
53188 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53189 return r ? r.rowIndex : false;
53192 findCellIndex : function(node){
53193 var stop = this.el.dom;
53194 while(node && node != stop){
53195 if(this.findRE.test(node.className)){
53196 return this.getCellIndex(node);
53198 node = node.parentNode;
53203 getColumnId : function(index){
53204 return this.cm.getColumnId(index);
53207 getSplitters : function()
53209 if(this.splitterSelector){
53210 return Roo.DomQuery.select(this.splitterSelector);
53216 getSplitter : function(index){
53217 return this.getSplitters()[index];
53220 onRowOver : function(e, t){
53222 if((row = this.findRowIndex(t)) !== false){
53223 this.getRowComposite(row).addClass("x-grid-row-over");
53227 onRowOut : function(e, t){
53229 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53230 this.getRowComposite(row).removeClass("x-grid-row-over");
53234 renderHeaders : function(){
53236 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53237 var cb = [], lb = [], sb = [], lsb = [], p = {};
53238 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53239 p.cellId = "x-grid-hd-0-" + i;
53240 p.splitId = "x-grid-csplit-0-" + i;
53241 p.id = cm.getColumnId(i);
53242 p.title = cm.getColumnTooltip(i) || "";
53243 p.value = cm.getColumnHeader(i) || "";
53244 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53245 if(!cm.isLocked(i)){
53246 cb[cb.length] = ct.apply(p);
53247 sb[sb.length] = st.apply(p);
53249 lb[lb.length] = ct.apply(p);
53250 lsb[lsb.length] = st.apply(p);
53253 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53254 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53257 updateHeaders : function(){
53258 var html = this.renderHeaders();
53259 this.lockedHd.update(html[0]);
53260 this.mainHd.update(html[1]);
53264 * Focuses the specified row.
53265 * @param {Number} row The row index
53267 focusRow : function(row)
53269 //Roo.log('GridView.focusRow');
53270 var x = this.scroller.dom.scrollLeft;
53271 this.focusCell(row, 0, false);
53272 this.scroller.dom.scrollLeft = x;
53276 * Focuses the specified cell.
53277 * @param {Number} row The row index
53278 * @param {Number} col The column index
53279 * @param {Boolean} hscroll false to disable horizontal scrolling
53281 focusCell : function(row, col, hscroll)
53283 //Roo.log('GridView.focusCell');
53284 var el = this.ensureVisible(row, col, hscroll);
53285 this.focusEl.alignTo(el, "tl-tl");
53287 this.focusEl.focus();
53289 this.focusEl.focus.defer(1, this.focusEl);
53294 * Scrolls the specified cell into view
53295 * @param {Number} row The row index
53296 * @param {Number} col The column index
53297 * @param {Boolean} hscroll false to disable horizontal scrolling
53299 ensureVisible : function(row, col, hscroll)
53301 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53302 //return null; //disable for testing.
53303 if(typeof row != "number"){
53304 row = row.rowIndex;
53306 if(row < 0 && row >= this.ds.getCount()){
53309 col = (col !== undefined ? col : 0);
53310 var cm = this.grid.colModel;
53311 while(cm.isHidden(col)){
53315 var el = this.getCell(row, col);
53319 var c = this.scroller.dom;
53321 var ctop = parseInt(el.offsetTop, 10);
53322 var cleft = parseInt(el.offsetLeft, 10);
53323 var cbot = ctop + el.offsetHeight;
53324 var cright = cleft + el.offsetWidth;
53326 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53327 var stop = parseInt(c.scrollTop, 10);
53328 var sleft = parseInt(c.scrollLeft, 10);
53329 var sbot = stop + ch;
53330 var sright = sleft + c.clientWidth;
53332 Roo.log('GridView.ensureVisible:' +
53334 ' c.clientHeight:' + c.clientHeight +
53335 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53343 c.scrollTop = ctop;
53344 //Roo.log("set scrolltop to ctop DISABLE?");
53345 }else if(cbot > sbot){
53346 //Roo.log("set scrolltop to cbot-ch");
53347 c.scrollTop = cbot-ch;
53350 if(hscroll !== false){
53352 c.scrollLeft = cleft;
53353 }else if(cright > sright){
53354 c.scrollLeft = cright-c.clientWidth;
53361 updateColumns : function(){
53362 this.grid.stopEditing();
53363 var cm = this.grid.colModel, colIds = this.getColumnIds();
53364 //var totalWidth = cm.getTotalWidth();
53366 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53367 //if(cm.isHidden(i)) continue;
53368 var w = cm.getColumnWidth(i);
53369 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53370 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53372 this.updateSplitters();
53375 generateRules : function(cm){
53376 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53377 Roo.util.CSS.removeStyleSheet(rulesId);
53378 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53379 var cid = cm.getColumnId(i);
53381 if(cm.config[i].align){
53382 align = 'text-align:'+cm.config[i].align+';';
53385 if(cm.isHidden(i)){
53386 hidden = 'display:none;';
53388 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53390 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53391 this.hdSelector, cid, " {\n", align, width, "}\n",
53392 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53393 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53395 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53398 updateSplitters : function(){
53399 var cm = this.cm, s = this.getSplitters();
53400 if(s){ // splitters not created yet
53401 var pos = 0, locked = true;
53402 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53403 if(cm.isHidden(i)) continue;
53404 var w = cm.getColumnWidth(i); // make sure it's a number
53405 if(!cm.isLocked(i) && locked){
53410 s[i].style.left = (pos-this.splitOffset) + "px";
53415 handleHiddenChange : function(colModel, colIndex, hidden){
53417 this.hideColumn(colIndex);
53419 this.unhideColumn(colIndex);
53423 hideColumn : function(colIndex){
53424 var cid = this.getColumnId(colIndex);
53425 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
53426 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
53428 this.updateHeaders();
53430 this.updateSplitters();
53434 unhideColumn : function(colIndex){
53435 var cid = this.getColumnId(colIndex);
53436 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
53437 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
53440 this.updateHeaders();
53442 this.updateSplitters();
53446 insertRows : function(dm, firstRow, lastRow, isUpdate){
53447 if(firstRow == 0 && lastRow == dm.getCount()-1){
53451 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
53453 var s = this.getScrollState();
53454 var markup = this.renderRows(firstRow, lastRow);
53455 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
53456 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
53457 this.restoreScroll(s);
53459 this.fireEvent("rowsinserted", this, firstRow, lastRow);
53460 this.syncRowHeights(firstRow, lastRow);
53461 this.stripeRows(firstRow);
53467 bufferRows : function(markup, target, index){
53468 var before = null, trows = target.rows, tbody = target.tBodies[0];
53469 if(index < trows.length){
53470 before = trows[index];
53472 var b = document.createElement("div");
53473 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
53474 var rows = b.firstChild.rows;
53475 for(var i = 0, len = rows.length; i < len; i++){
53477 tbody.insertBefore(rows[0], before);
53479 tbody.appendChild(rows[0]);
53486 deleteRows : function(dm, firstRow, lastRow){
53487 if(dm.getRowCount()<1){
53488 this.fireEvent("beforerefresh", this);
53489 this.mainBody.update("");
53490 this.lockedBody.update("");
53491 this.fireEvent("refresh", this);
53493 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
53494 var bt = this.getBodyTable();
53495 var tbody = bt.firstChild;
53496 var rows = bt.rows;
53497 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
53498 tbody.removeChild(rows[firstRow]);
53500 this.stripeRows(firstRow);
53501 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
53505 updateRows : function(dataSource, firstRow, lastRow){
53506 var s = this.getScrollState();
53508 this.restoreScroll(s);
53511 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
53515 this.updateHeaderSortState();
53518 getScrollState : function(){
53520 var sb = this.scroller.dom;
53521 return {left: sb.scrollLeft, top: sb.scrollTop};
53524 stripeRows : function(startRow){
53525 if(!this.grid.stripeRows || this.ds.getCount() < 1){
53528 startRow = startRow || 0;
53529 var rows = this.getBodyTable().rows;
53530 var lrows = this.getLockedTable().rows;
53531 var cls = ' x-grid-row-alt ';
53532 for(var i = startRow, len = rows.length; i < len; i++){
53533 var row = rows[i], lrow = lrows[i];
53534 var isAlt = ((i+1) % 2 == 0);
53535 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
53536 if(isAlt == hasAlt){
53540 row.className += " x-grid-row-alt";
53542 row.className = row.className.replace("x-grid-row-alt", "");
53545 lrow.className = row.className;
53550 restoreScroll : function(state){
53551 //Roo.log('GridView.restoreScroll');
53552 var sb = this.scroller.dom;
53553 sb.scrollLeft = state.left;
53554 sb.scrollTop = state.top;
53558 syncScroll : function(){
53559 //Roo.log('GridView.syncScroll');
53560 var sb = this.scroller.dom;
53561 var sh = this.mainHd.dom;
53562 var bs = this.mainBody.dom;
53563 var lv = this.lockedBody.dom;
53564 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
53565 lv.scrollTop = bs.scrollTop = sb.scrollTop;
53568 handleScroll : function(e){
53570 var sb = this.scroller.dom;
53571 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
53575 handleWheel : function(e){
53576 var d = e.getWheelDelta();
53577 this.scroller.dom.scrollTop -= d*22;
53578 // set this here to prevent jumpy scrolling on large tables
53579 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
53583 renderRows : function(startRow, endRow){
53584 // pull in all the crap needed to render rows
53585 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
53586 var colCount = cm.getColumnCount();
53588 if(ds.getCount() < 1){
53592 // build a map for all the columns
53594 for(var i = 0; i < colCount; i++){
53595 var name = cm.getDataIndex(i);
53597 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
53598 renderer : cm.getRenderer(i),
53599 id : cm.getColumnId(i),
53600 locked : cm.isLocked(i)
53604 startRow = startRow || 0;
53605 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
53607 // records to render
53608 var rs = ds.getRange(startRow, endRow);
53610 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
53613 // As much as I hate to duplicate code, this was branched because FireFox really hates
53614 // [].join("") on strings. The performance difference was substantial enough to
53615 // branch this function
53616 doRender : Roo.isGecko ?
53617 function(cs, rs, ds, startRow, colCount, stripe){
53618 var ts = this.templates, ct = ts.cell, rt = ts.row;
53620 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53622 var hasListener = this.grid.hasListener('rowclass');
53624 for(var j = 0, len = rs.length; j < len; j++){
53625 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
53626 for(var i = 0; i < colCount; i++){
53628 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53630 p.css = p.attr = "";
53631 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53632 if(p.value == undefined || p.value === "") p.value = " ";
53633 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53634 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53636 var markup = ct.apply(p);
53644 if(stripe && ((rowIndex+1) % 2 == 0)){
53645 alt.push("x-grid-row-alt")
53648 alt.push( " x-grid-dirty-row");
53651 if(this.getRowClass){
53652 alt.push(this.getRowClass(r, rowIndex));
53658 rowIndex : rowIndex,
53661 this.grid.fireEvent('rowclass', this, rowcfg);
53662 alt.push(rowcfg.rowClass);
53664 rp.alt = alt.join(" ");
53665 lbuf+= rt.apply(rp);
53667 buf+= rt.apply(rp);
53669 return [lbuf, buf];
53671 function(cs, rs, ds, startRow, colCount, stripe){
53672 var ts = this.templates, ct = ts.cell, rt = ts.row;
53674 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53675 var hasListener = this.grid.hasListener('rowclass');
53678 for(var j = 0, len = rs.length; j < len; j++){
53679 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
53680 for(var i = 0; i < colCount; i++){
53682 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53684 p.css = p.attr = "";
53685 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53686 if(p.value == undefined || p.value === "") p.value = " ";
53687 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53688 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53691 var markup = ct.apply(p);
53693 cb[cb.length] = markup;
53695 lcb[lcb.length] = markup;
53699 if(stripe && ((rowIndex+1) % 2 == 0)){
53700 alt.push( "x-grid-row-alt");
53703 alt.push(" x-grid-dirty-row");
53706 if(this.getRowClass){
53707 alt.push( this.getRowClass(r, rowIndex));
53713 rowIndex : rowIndex,
53716 this.grid.fireEvent('rowclass', this, rowcfg);
53717 alt.push(rowcfg.rowClass);
53719 rp.alt = alt.join(" ");
53720 rp.cells = lcb.join("");
53721 lbuf[lbuf.length] = rt.apply(rp);
53722 rp.cells = cb.join("");
53723 buf[buf.length] = rt.apply(rp);
53725 return [lbuf.join(""), buf.join("")];
53728 renderBody : function(){
53729 var markup = this.renderRows();
53730 var bt = this.templates.body;
53731 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
53735 * Refreshes the grid
53736 * @param {Boolean} headersToo
53738 refresh : function(headersToo){
53739 this.fireEvent("beforerefresh", this);
53740 this.grid.stopEditing();
53741 var result = this.renderBody();
53742 this.lockedBody.update(result[0]);
53743 this.mainBody.update(result[1]);
53744 if(headersToo === true){
53745 this.updateHeaders();
53746 this.updateColumns();
53747 this.updateSplitters();
53748 this.updateHeaderSortState();
53750 this.syncRowHeights();
53752 this.fireEvent("refresh", this);
53755 handleColumnMove : function(cm, oldIndex, newIndex){
53756 this.indexMap = null;
53757 var s = this.getScrollState();
53758 this.refresh(true);
53759 this.restoreScroll(s);
53760 this.afterMove(newIndex);
53763 afterMove : function(colIndex){
53764 if(this.enableMoveAnim && Roo.enableFx){
53765 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
53767 // if multisort - fix sortOrder, and reload..
53768 if (this.grid.dataSource.multiSort) {
53769 // the we can call sort again..
53770 var dm = this.grid.dataSource;
53771 var cm = this.grid.colModel;
53773 for(var i = 0; i < cm.config.length; i++ ) {
53775 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
53776 continue; // dont' bother, it's not in sort list or being set.
53779 so.push(cm.config[i].dataIndex);
53782 dm.load(dm.lastOptions);
53789 updateCell : function(dm, rowIndex, dataIndex){
53790 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
53791 if(typeof colIndex == "undefined"){ // not present in grid
53794 var cm = this.grid.colModel;
53795 var cell = this.getCell(rowIndex, colIndex);
53796 var cellText = this.getCellText(rowIndex, colIndex);
53799 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
53800 id : cm.getColumnId(colIndex),
53801 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
53803 var renderer = cm.getRenderer(colIndex);
53804 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
53805 if(typeof val == "undefined" || val === "") val = " ";
53806 cellText.innerHTML = val;
53807 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
53808 this.syncRowHeights(rowIndex, rowIndex);
53811 calcColumnWidth : function(colIndex, maxRowsToMeasure){
53813 if(this.grid.autoSizeHeaders){
53814 var h = this.getHeaderCellMeasure(colIndex);
53815 maxWidth = Math.max(maxWidth, h.scrollWidth);
53818 if(this.cm.isLocked(colIndex)){
53819 tb = this.getLockedTable();
53822 tb = this.getBodyTable();
53823 index = colIndex - this.cm.getLockedCount();
53826 var rows = tb.rows;
53827 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
53828 for(var i = 0; i < stopIndex; i++){
53829 var cell = rows[i].childNodes[index].firstChild;
53830 maxWidth = Math.max(maxWidth, cell.scrollWidth);
53833 return maxWidth + /*margin for error in IE*/ 5;
53836 * Autofit a column to its content.
53837 * @param {Number} colIndex
53838 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
53840 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
53841 if(this.cm.isHidden(colIndex)){
53842 return; // can't calc a hidden column
53845 var cid = this.cm.getColumnId(colIndex);
53846 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
53847 if(this.grid.autoSizeHeaders){
53848 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
53851 var newWidth = this.calcColumnWidth(colIndex);
53852 this.cm.setColumnWidth(colIndex,
53853 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
53854 if(!suppressEvent){
53855 this.grid.fireEvent("columnresize", colIndex, newWidth);
53860 * Autofits all columns to their content and then expands to fit any extra space in the grid
53862 autoSizeColumns : function(){
53863 var cm = this.grid.colModel;
53864 var colCount = cm.getColumnCount();
53865 for(var i = 0; i < colCount; i++){
53866 this.autoSizeColumn(i, true, true);
53868 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
53871 this.updateColumns();
53877 * Autofits all columns to the grid's width proportionate with their current size
53878 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
53880 fitColumns : function(reserveScrollSpace){
53881 var cm = this.grid.colModel;
53882 var colCount = cm.getColumnCount();
53886 for (i = 0; i < colCount; i++){
53887 if(!cm.isHidden(i) && !cm.isFixed(i)){
53888 w = cm.getColumnWidth(i);
53894 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
53895 if(reserveScrollSpace){
53898 var frac = (avail - cm.getTotalWidth())/width;
53899 while (cols.length){
53902 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
53904 this.updateColumns();
53908 onRowSelect : function(rowIndex){
53909 var row = this.getRowComposite(rowIndex);
53910 row.addClass("x-grid-row-selected");
53913 onRowDeselect : function(rowIndex){
53914 var row = this.getRowComposite(rowIndex);
53915 row.removeClass("x-grid-row-selected");
53918 onCellSelect : function(row, col){
53919 var cell = this.getCell(row, col);
53921 Roo.fly(cell).addClass("x-grid-cell-selected");
53925 onCellDeselect : function(row, col){
53926 var cell = this.getCell(row, col);
53928 Roo.fly(cell).removeClass("x-grid-cell-selected");
53932 updateHeaderSortState : function(){
53934 // sort state can be single { field: xxx, direction : yyy}
53935 // or { xxx=>ASC , yyy : DESC ..... }
53938 if (!this.ds.multiSort) {
53939 var state = this.ds.getSortState();
53943 mstate[state.field] = state.direction;
53944 // FIXME... - this is not used here.. but might be elsewhere..
53945 this.sortState = state;
53948 mstate = this.ds.sortToggle;
53950 //remove existing sort classes..
53952 var sc = this.sortClasses;
53953 var hds = this.el.select(this.headerSelector).removeClass(sc);
53955 for(var f in mstate) {
53957 var sortColumn = this.cm.findColumnIndex(f);
53959 if(sortColumn != -1){
53960 var sortDir = mstate[f];
53961 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
53970 handleHeaderClick : function(g, index,e){
53972 Roo.log("header click");
53975 // touch events on header are handled by context
53976 this.handleHdCtx(g,index,e);
53981 if(this.headersDisabled){
53984 var dm = g.dataSource, cm = g.colModel;
53985 if(!cm.isSortable(index)){
53990 if (dm.multiSort) {
53991 // update the sortOrder
53993 for(var i = 0; i < cm.config.length; i++ ) {
53995 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
53996 continue; // dont' bother, it's not in sort list or being set.
53999 so.push(cm.config[i].dataIndex);
54005 dm.sort(cm.getDataIndex(index));
54009 destroy : function(){
54011 this.colMenu.removeAll();
54012 Roo.menu.MenuMgr.unregister(this.colMenu);
54013 this.colMenu.getEl().remove();
54014 delete this.colMenu;
54017 this.hmenu.removeAll();
54018 Roo.menu.MenuMgr.unregister(this.hmenu);
54019 this.hmenu.getEl().remove();
54022 if(this.grid.enableColumnMove){
54023 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54025 for(var dd in dds){
54026 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54027 var elid = dds[dd].dragElId;
54029 Roo.get(elid).remove();
54030 } else if(dds[dd].config.isTarget){
54031 dds[dd].proxyTop.remove();
54032 dds[dd].proxyBottom.remove();
54035 if(Roo.dd.DDM.locationCache[dd]){
54036 delete Roo.dd.DDM.locationCache[dd];
54039 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54042 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54043 this.bind(null, null);
54044 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54047 handleLockChange : function(){
54048 this.refresh(true);
54051 onDenyColumnLock : function(){
54055 onDenyColumnHide : function(){
54059 handleHdMenuClick : function(item){
54060 var index = this.hdCtxIndex;
54061 var cm = this.cm, ds = this.ds;
54064 ds.sort(cm.getDataIndex(index), "ASC");
54067 ds.sort(cm.getDataIndex(index), "DESC");
54070 var lc = cm.getLockedCount();
54071 if(cm.getColumnCount(true) <= lc+1){
54072 this.onDenyColumnLock();
54076 cm.setLocked(index, true, true);
54077 cm.moveColumn(index, lc);
54078 this.grid.fireEvent("columnmove", index, lc);
54080 cm.setLocked(index, true);
54084 var lc = cm.getLockedCount();
54085 if((lc-1) != index){
54086 cm.setLocked(index, false, true);
54087 cm.moveColumn(index, lc-1);
54088 this.grid.fireEvent("columnmove", index, lc-1);
54090 cm.setLocked(index, false);
54093 case 'wider': // used to expand cols on touch..
54095 var cw = cm.getColumnWidth(index);
54096 cw += (item.id == 'wider' ? 1 : -1) * 50;
54097 cw = Math.max(0, cw);
54098 cw = Math.min(cw,4000);
54099 cm.setColumnWidth(index, cw);
54103 index = cm.getIndexById(item.id.substr(4));
54105 if(item.checked && cm.getColumnCount(true) <= 1){
54106 this.onDenyColumnHide();
54109 cm.setHidden(index, item.checked);
54115 beforeColMenuShow : function(){
54116 var cm = this.cm, colCount = cm.getColumnCount();
54117 this.colMenu.removeAll();
54118 for(var i = 0; i < colCount; i++){
54119 this.colMenu.add(new Roo.menu.CheckItem({
54120 id: "col-"+cm.getColumnId(i),
54121 text: cm.getColumnHeader(i),
54122 checked: !cm.isHidden(i),
54128 handleHdCtx : function(g, index, e){
54130 var hd = this.getHeaderCell(index);
54131 this.hdCtxIndex = index;
54132 var ms = this.hmenu.items, cm = this.cm;
54133 ms.get("asc").setDisabled(!cm.isSortable(index));
54134 ms.get("desc").setDisabled(!cm.isSortable(index));
54135 if(this.grid.enableColLock !== false){
54136 ms.get("lock").setDisabled(cm.isLocked(index));
54137 ms.get("unlock").setDisabled(!cm.isLocked(index));
54139 this.hmenu.show(hd, "tl-bl");
54142 handleHdOver : function(e){
54143 var hd = this.findHeaderCell(e.getTarget());
54144 if(hd && !this.headersDisabled){
54145 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54146 this.fly(hd).addClass("x-grid-hd-over");
54151 handleHdOut : function(e){
54152 var hd = this.findHeaderCell(e.getTarget());
54154 this.fly(hd).removeClass("x-grid-hd-over");
54158 handleSplitDblClick : function(e, t){
54159 var i = this.getCellIndex(t);
54160 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54161 this.autoSizeColumn(i, true);
54166 render : function(){
54169 var colCount = cm.getColumnCount();
54171 if(this.grid.monitorWindowResize === true){
54172 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54174 var header = this.renderHeaders();
54175 var body = this.templates.body.apply({rows:""});
54176 var html = this.templates.master.apply({
54179 lockedHeader: header[0],
54183 //this.updateColumns();
54185 this.grid.getGridEl().dom.innerHTML = html;
54187 this.initElements();
54189 // a kludge to fix the random scolling effect in webkit
54190 this.el.on("scroll", function() {
54191 this.el.dom.scrollTop=0; // hopefully not recursive..
54194 this.scroller.on("scroll", this.handleScroll, this);
54195 this.lockedBody.on("mousewheel", this.handleWheel, this);
54196 this.mainBody.on("mousewheel", this.handleWheel, this);
54198 this.mainHd.on("mouseover", this.handleHdOver, this);
54199 this.mainHd.on("mouseout", this.handleHdOut, this);
54200 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54201 {delegate: "."+this.splitClass});
54203 this.lockedHd.on("mouseover", this.handleHdOver, this);
54204 this.lockedHd.on("mouseout", this.handleHdOut, this);
54205 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54206 {delegate: "."+this.splitClass});
54208 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54209 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54212 this.updateSplitters();
54214 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54215 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54216 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54219 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54220 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54222 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54223 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54225 if(this.grid.enableColLock !== false){
54226 this.hmenu.add('-',
54227 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54228 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54232 this.hmenu.add('-',
54233 {id:"wider", text: this.columnsWiderText},
54234 {id:"narrow", text: this.columnsNarrowText }
54240 if(this.grid.enableColumnHide !== false){
54242 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54243 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54244 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54246 this.hmenu.add('-',
54247 {id:"columns", text: this.columnsText, menu: this.colMenu}
54250 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54252 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54255 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54256 this.dd = new Roo.grid.GridDragZone(this.grid, {
54257 ddGroup : this.grid.ddGroup || 'GridDD'
54263 for(var i = 0; i < colCount; i++){
54264 if(cm.isHidden(i)){
54265 this.hideColumn(i);
54267 if(cm.config[i].align){
54268 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54269 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54273 this.updateHeaderSortState();
54275 this.beforeInitialResize();
54278 // two part rendering gives faster view to the user
54279 this.renderPhase2.defer(1, this);
54282 renderPhase2 : function(){
54283 // render the rows now
54285 if(this.grid.autoSizeColumns){
54286 this.autoSizeColumns();
54290 beforeInitialResize : function(){
54294 onColumnSplitterMoved : function(i, w){
54295 this.userResized = true;
54296 var cm = this.grid.colModel;
54297 cm.setColumnWidth(i, w, true);
54298 var cid = cm.getColumnId(i);
54299 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54300 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54301 this.updateSplitters();
54303 this.grid.fireEvent("columnresize", i, w);
54306 syncRowHeights : function(startIndex, endIndex){
54307 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54308 startIndex = startIndex || 0;
54309 var mrows = this.getBodyTable().rows;
54310 var lrows = this.getLockedTable().rows;
54311 var len = mrows.length-1;
54312 endIndex = Math.min(endIndex || len, len);
54313 for(var i = startIndex; i <= endIndex; i++){
54314 var m = mrows[i], l = lrows[i];
54315 var h = Math.max(m.offsetHeight, l.offsetHeight);
54316 m.style.height = l.style.height = h + "px";
54321 layout : function(initialRender, is2ndPass){
54323 var auto = g.autoHeight;
54324 var scrollOffset = 16;
54325 var c = g.getGridEl(), cm = this.cm,
54326 expandCol = g.autoExpandColumn,
54328 //c.beginMeasure();
54330 if(!c.dom.offsetWidth){ // display:none?
54332 this.lockedWrap.show();
54333 this.mainWrap.show();
54338 var hasLock = this.cm.isLocked(0);
54340 var tbh = this.headerPanel.getHeight();
54341 var bbh = this.footerPanel.getHeight();
54344 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54345 var newHeight = ch + c.getBorderWidth("tb");
54347 newHeight = Math.min(g.maxHeight, newHeight);
54349 c.setHeight(newHeight);
54353 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54356 var s = this.scroller;
54358 var csize = c.getSize(true);
54360 this.el.setSize(csize.width, csize.height);
54362 this.headerPanel.setWidth(csize.width);
54363 this.footerPanel.setWidth(csize.width);
54365 var hdHeight = this.mainHd.getHeight();
54366 var vw = csize.width;
54367 var vh = csize.height - (tbh + bbh);
54371 var bt = this.getBodyTable();
54372 var ltWidth = hasLock ?
54373 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54375 var scrollHeight = bt.offsetHeight;
54376 var scrollWidth = ltWidth + bt.offsetWidth;
54377 var vscroll = false, hscroll = false;
54379 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54381 var lw = this.lockedWrap, mw = this.mainWrap;
54382 var lb = this.lockedBody, mb = this.mainBody;
54384 setTimeout(function(){
54385 var t = s.dom.offsetTop;
54386 var w = s.dom.clientWidth,
54387 h = s.dom.clientHeight;
54390 lw.setSize(ltWidth, h);
54392 mw.setLeftTop(ltWidth, t);
54393 mw.setSize(w-ltWidth, h);
54395 lb.setHeight(h-hdHeight);
54396 mb.setHeight(h-hdHeight);
54398 if(is2ndPass !== true && !gv.userResized && expandCol){
54399 // high speed resize without full column calculation
54401 var ci = cm.getIndexById(expandCol);
54403 ci = cm.findColumnIndex(expandCol);
54405 ci = Math.max(0, ci); // make sure it's got at least the first col.
54406 var expandId = cm.getColumnId(ci);
54407 var tw = cm.getTotalWidth(false);
54408 var currentWidth = cm.getColumnWidth(ci);
54409 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54410 if(currentWidth != cw){
54411 cm.setColumnWidth(ci, cw, true);
54412 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54413 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54414 gv.updateSplitters();
54415 gv.layout(false, true);
54427 onWindowResize : function(){
54428 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
54434 appendFooter : function(parentEl){
54438 sortAscText : "Sort Ascending",
54439 sortDescText : "Sort Descending",
54440 lockText : "Lock Column",
54441 unlockText : "Unlock Column",
54442 columnsText : "Columns",
54444 columnsWiderText : "Wider",
54445 columnsNarrowText : "Thinner"
54449 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
54450 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
54451 this.proxy.el.addClass('x-grid3-col-dd');
54454 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
54455 handleMouseDown : function(e){
54459 callHandleMouseDown : function(e){
54460 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
54465 * Ext JS Library 1.1.1
54466 * Copyright(c) 2006-2007, Ext JS, LLC.
54468 * Originally Released Under LGPL - original licence link has changed is not relivant.
54471 * <script type="text/javascript">
54475 // This is a support class used internally by the Grid components
54476 Roo.grid.SplitDragZone = function(grid, hd, hd2){
54478 this.view = grid.getView();
54479 this.proxy = this.view.resizeProxy;
54480 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
54481 "gridSplitters" + this.grid.getGridEl().id, {
54482 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
54484 this.setHandleElId(Roo.id(hd));
54485 this.setOuterHandleElId(Roo.id(hd2));
54486 this.scroll = false;
54488 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
54489 fly: Roo.Element.fly,
54491 b4StartDrag : function(x, y){
54492 this.view.headersDisabled = true;
54493 this.proxy.setHeight(this.view.mainWrap.getHeight());
54494 var w = this.cm.getColumnWidth(this.cellIndex);
54495 var minw = Math.max(w-this.grid.minColumnWidth, 0);
54496 this.resetConstraints();
54497 this.setXConstraint(minw, 1000);
54498 this.setYConstraint(0, 0);
54499 this.minX = x - minw;
54500 this.maxX = x + 1000;
54502 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
54506 handleMouseDown : function(e){
54507 ev = Roo.EventObject.setEvent(e);
54508 var t = this.fly(ev.getTarget());
54509 if(t.hasClass("x-grid-split")){
54510 this.cellIndex = this.view.getCellIndex(t.dom);
54511 this.split = t.dom;
54512 this.cm = this.grid.colModel;
54513 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
54514 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
54519 endDrag : function(e){
54520 this.view.headersDisabled = false;
54521 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
54522 var diff = endX - this.startPos;
54523 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
54526 autoOffset : function(){
54527 this.setDelta(0,0);
54531 * Ext JS Library 1.1.1
54532 * Copyright(c) 2006-2007, Ext JS, LLC.
54534 * Originally Released Under LGPL - original licence link has changed is not relivant.
54537 * <script type="text/javascript">
54541 // This is a support class used internally by the Grid components
54542 Roo.grid.GridDragZone = function(grid, config){
54543 this.view = grid.getView();
54544 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
54545 if(this.view.lockedBody){
54546 this.setHandleElId(Roo.id(this.view.mainBody.dom));
54547 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
54549 this.scroll = false;
54551 this.ddel = document.createElement('div');
54552 this.ddel.className = 'x-grid-dd-wrap';
54555 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
54556 ddGroup : "GridDD",
54558 getDragData : function(e){
54559 var t = Roo.lib.Event.getTarget(e);
54560 var rowIndex = this.view.findRowIndex(t);
54561 var sm = this.grid.selModel;
54563 //Roo.log(rowIndex);
54565 if (sm.getSelectedCell) {
54566 // cell selection..
54567 if (!sm.getSelectedCell()) {
54570 if (rowIndex != sm.getSelectedCell()[0]) {
54576 if(rowIndex !== false){
54581 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
54583 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
54586 if (e.hasModifier()){
54587 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
54590 Roo.log("getDragData");
54595 rowIndex: rowIndex,
54596 selections:sm.getSelections ? sm.getSelections() : (
54597 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
54604 onInitDrag : function(e){
54605 var data = this.dragData;
54606 this.ddel.innerHTML = this.grid.getDragDropText();
54607 this.proxy.update(this.ddel);
54608 // fire start drag?
54611 afterRepair : function(){
54612 this.dragging = false;
54615 getRepairXY : function(e, data){
54619 onEndDrag : function(data, e){
54623 onValidDrop : function(dd, e, id){
54628 beforeInvalidDrop : function(e, id){
54633 * Ext JS Library 1.1.1
54634 * Copyright(c) 2006-2007, Ext JS, LLC.
54636 * Originally Released Under LGPL - original licence link has changed is not relivant.
54639 * <script type="text/javascript">
54644 * @class Roo.grid.ColumnModel
54645 * @extends Roo.util.Observable
54646 * This is the default implementation of a ColumnModel used by the Grid. It defines
54647 * the columns in the grid.
54650 var colModel = new Roo.grid.ColumnModel([
54651 {header: "Ticker", width: 60, sortable: true, locked: true},
54652 {header: "Company Name", width: 150, sortable: true},
54653 {header: "Market Cap.", width: 100, sortable: true},
54654 {header: "$ Sales", width: 100, sortable: true, renderer: money},
54655 {header: "Employees", width: 100, sortable: true, resizable: false}
54660 * The config options listed for this class are options which may appear in each
54661 * individual column definition.
54662 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
54664 * @param {Object} config An Array of column config objects. See this class's
54665 * config objects for details.
54667 Roo.grid.ColumnModel = function(config){
54669 * The config passed into the constructor
54671 this.config = config;
54674 // if no id, create one
54675 // if the column does not have a dataIndex mapping,
54676 // map it to the order it is in the config
54677 for(var i = 0, len = config.length; i < len; i++){
54679 if(typeof c.dataIndex == "undefined"){
54682 if(typeof c.renderer == "string"){
54683 c.renderer = Roo.util.Format[c.renderer];
54685 if(typeof c.id == "undefined"){
54688 if(c.editor && c.editor.xtype){
54689 c.editor = Roo.factory(c.editor, Roo.grid);
54691 if(c.editor && c.editor.isFormField){
54692 c.editor = new Roo.grid.GridEditor(c.editor);
54694 this.lookup[c.id] = c;
54698 * The width of columns which have no width specified (defaults to 100)
54701 this.defaultWidth = 100;
54704 * Default sortable of columns which have no sortable specified (defaults to false)
54707 this.defaultSortable = false;
54711 * @event widthchange
54712 * Fires when the width of a column changes.
54713 * @param {ColumnModel} this
54714 * @param {Number} columnIndex The column index
54715 * @param {Number} newWidth The new width
54717 "widthchange": true,
54719 * @event headerchange
54720 * Fires when the text of a header changes.
54721 * @param {ColumnModel} this
54722 * @param {Number} columnIndex The column index
54723 * @param {Number} newText The new header text
54725 "headerchange": true,
54727 * @event hiddenchange
54728 * Fires when a column is hidden or "unhidden".
54729 * @param {ColumnModel} this
54730 * @param {Number} columnIndex The column index
54731 * @param {Boolean} hidden true if hidden, false otherwise
54733 "hiddenchange": true,
54735 * @event columnmoved
54736 * Fires when a column is moved.
54737 * @param {ColumnModel} this
54738 * @param {Number} oldIndex
54739 * @param {Number} newIndex
54741 "columnmoved" : true,
54743 * @event columlockchange
54744 * Fires when a column's locked state is changed
54745 * @param {ColumnModel} this
54746 * @param {Number} colIndex
54747 * @param {Boolean} locked true if locked
54749 "columnlockchange" : true
54751 Roo.grid.ColumnModel.superclass.constructor.call(this);
54753 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
54755 * @cfg {String} header The header text to display in the Grid view.
54758 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
54759 * {@link Roo.data.Record} definition from which to draw the column's value. If not
54760 * specified, the column's index is used as an index into the Record's data Array.
54763 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
54764 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
54767 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
54768 * Defaults to the value of the {@link #defaultSortable} property.
54769 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
54772 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
54775 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
54778 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
54781 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
54784 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
54785 * given the cell's data value. See {@link #setRenderer}. If not specified, the
54786 * default renderer uses the raw data value.
54789 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
54792 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
54796 * Returns the id of the column at the specified index.
54797 * @param {Number} index The column index
54798 * @return {String} the id
54800 getColumnId : function(index){
54801 return this.config[index].id;
54805 * Returns the column for a specified id.
54806 * @param {String} id The column id
54807 * @return {Object} the column
54809 getColumnById : function(id){
54810 return this.lookup[id];
54815 * Returns the column for a specified dataIndex.
54816 * @param {String} dataIndex The column dataIndex
54817 * @return {Object|Boolean} the column or false if not found
54819 getColumnByDataIndex: function(dataIndex){
54820 var index = this.findColumnIndex(dataIndex);
54821 return index > -1 ? this.config[index] : false;
54825 * Returns the index for a specified column id.
54826 * @param {String} id The column id
54827 * @return {Number} the index, or -1 if not found
54829 getIndexById : function(id){
54830 for(var i = 0, len = this.config.length; i < len; i++){
54831 if(this.config[i].id == id){
54839 * Returns the index for a specified column dataIndex.
54840 * @param {String} dataIndex The column dataIndex
54841 * @return {Number} the index, or -1 if not found
54844 findColumnIndex : function(dataIndex){
54845 for(var i = 0, len = this.config.length; i < len; i++){
54846 if(this.config[i].dataIndex == dataIndex){
54854 moveColumn : function(oldIndex, newIndex){
54855 var c = this.config[oldIndex];
54856 this.config.splice(oldIndex, 1);
54857 this.config.splice(newIndex, 0, c);
54858 this.dataMap = null;
54859 this.fireEvent("columnmoved", this, oldIndex, newIndex);
54862 isLocked : function(colIndex){
54863 return this.config[colIndex].locked === true;
54866 setLocked : function(colIndex, value, suppressEvent){
54867 if(this.isLocked(colIndex) == value){
54870 this.config[colIndex].locked = value;
54871 if(!suppressEvent){
54872 this.fireEvent("columnlockchange", this, colIndex, value);
54876 getTotalLockedWidth : function(){
54877 var totalWidth = 0;
54878 for(var i = 0; i < this.config.length; i++){
54879 if(this.isLocked(i) && !this.isHidden(i)){
54880 this.totalWidth += this.getColumnWidth(i);
54886 getLockedCount : function(){
54887 for(var i = 0, len = this.config.length; i < len; i++){
54888 if(!this.isLocked(i)){
54895 * Returns the number of columns.
54898 getColumnCount : function(visibleOnly){
54899 if(visibleOnly === true){
54901 for(var i = 0, len = this.config.length; i < len; i++){
54902 if(!this.isHidden(i)){
54908 return this.config.length;
54912 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
54913 * @param {Function} fn
54914 * @param {Object} scope (optional)
54915 * @return {Array} result
54917 getColumnsBy : function(fn, scope){
54919 for(var i = 0, len = this.config.length; i < len; i++){
54920 var c = this.config[i];
54921 if(fn.call(scope||this, c, i) === true){
54929 * Returns true if the specified column is sortable.
54930 * @param {Number} col The column index
54931 * @return {Boolean}
54933 isSortable : function(col){
54934 if(typeof this.config[col].sortable == "undefined"){
54935 return this.defaultSortable;
54937 return this.config[col].sortable;
54941 * Returns the rendering (formatting) function defined for the column.
54942 * @param {Number} col The column index.
54943 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
54945 getRenderer : function(col){
54946 if(!this.config[col].renderer){
54947 return Roo.grid.ColumnModel.defaultRenderer;
54949 return this.config[col].renderer;
54953 * Sets the rendering (formatting) function for a column.
54954 * @param {Number} col The column index
54955 * @param {Function} fn The function to use to process the cell's raw data
54956 * to return HTML markup for the grid view. The render function is called with
54957 * the following parameters:<ul>
54958 * <li>Data value.</li>
54959 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
54960 * <li>css A CSS style string to apply to the table cell.</li>
54961 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
54962 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
54963 * <li>Row index</li>
54964 * <li>Column index</li>
54965 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
54967 setRenderer : function(col, fn){
54968 this.config[col].renderer = fn;
54972 * Returns the width for the specified column.
54973 * @param {Number} col The column index
54976 getColumnWidth : function(col){
54977 return this.config[col].width * 1 || this.defaultWidth;
54981 * Sets the width for a column.
54982 * @param {Number} col The column index
54983 * @param {Number} width The new width
54985 setColumnWidth : function(col, width, suppressEvent){
54986 this.config[col].width = width;
54987 this.totalWidth = null;
54988 if(!suppressEvent){
54989 this.fireEvent("widthchange", this, col, width);
54994 * Returns the total width of all columns.
54995 * @param {Boolean} includeHidden True to include hidden column widths
54998 getTotalWidth : function(includeHidden){
54999 if(!this.totalWidth){
55000 this.totalWidth = 0;
55001 for(var i = 0, len = this.config.length; i < len; i++){
55002 if(includeHidden || !this.isHidden(i)){
55003 this.totalWidth += this.getColumnWidth(i);
55007 return this.totalWidth;
55011 * Returns the header for the specified column.
55012 * @param {Number} col The column index
55015 getColumnHeader : function(col){
55016 return this.config[col].header;
55020 * Sets the header for a column.
55021 * @param {Number} col The column index
55022 * @param {String} header The new header
55024 setColumnHeader : function(col, header){
55025 this.config[col].header = header;
55026 this.fireEvent("headerchange", this, col, header);
55030 * Returns the tooltip for the specified column.
55031 * @param {Number} col The column index
55034 getColumnTooltip : function(col){
55035 return this.config[col].tooltip;
55038 * Sets the tooltip for a column.
55039 * @param {Number} col The column index
55040 * @param {String} tooltip The new tooltip
55042 setColumnTooltip : function(col, tooltip){
55043 this.config[col].tooltip = tooltip;
55047 * Returns the dataIndex for the specified column.
55048 * @param {Number} col The column index
55051 getDataIndex : function(col){
55052 return this.config[col].dataIndex;
55056 * Sets the dataIndex for a column.
55057 * @param {Number} col The column index
55058 * @param {Number} dataIndex The new dataIndex
55060 setDataIndex : function(col, dataIndex){
55061 this.config[col].dataIndex = dataIndex;
55067 * Returns true if the cell is editable.
55068 * @param {Number} colIndex The column index
55069 * @param {Number} rowIndex The row index
55070 * @return {Boolean}
55072 isCellEditable : function(colIndex, rowIndex){
55073 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55077 * Returns the editor defined for the cell/column.
55078 * return false or null to disable editing.
55079 * @param {Number} colIndex The column index
55080 * @param {Number} rowIndex The row index
55083 getCellEditor : function(colIndex, rowIndex){
55084 return this.config[colIndex].editor;
55088 * Sets if a column is editable.
55089 * @param {Number} col The column index
55090 * @param {Boolean} editable True if the column is editable
55092 setEditable : function(col, editable){
55093 this.config[col].editable = editable;
55098 * Returns true if the column is hidden.
55099 * @param {Number} colIndex The column index
55100 * @return {Boolean}
55102 isHidden : function(colIndex){
55103 return this.config[colIndex].hidden;
55108 * Returns true if the column width cannot be changed
55110 isFixed : function(colIndex){
55111 return this.config[colIndex].fixed;
55115 * Returns true if the column can be resized
55116 * @return {Boolean}
55118 isResizable : function(colIndex){
55119 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55122 * Sets if a column is hidden.
55123 * @param {Number} colIndex The column index
55124 * @param {Boolean} hidden True if the column is hidden
55126 setHidden : function(colIndex, hidden){
55127 this.config[colIndex].hidden = hidden;
55128 this.totalWidth = null;
55129 this.fireEvent("hiddenchange", this, colIndex, hidden);
55133 * Sets the editor for a column.
55134 * @param {Number} col The column index
55135 * @param {Object} editor The editor object
55137 setEditor : function(col, editor){
55138 this.config[col].editor = editor;
55142 Roo.grid.ColumnModel.defaultRenderer = function(value){
55143 if(typeof value == "string" && value.length < 1){
55149 // Alias for backwards compatibility
55150 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55153 * Ext JS Library 1.1.1
55154 * Copyright(c) 2006-2007, Ext JS, LLC.
55156 * Originally Released Under LGPL - original licence link has changed is not relivant.
55159 * <script type="text/javascript">
55163 * @class Roo.grid.AbstractSelectionModel
55164 * @extends Roo.util.Observable
55165 * Abstract base class for grid SelectionModels. It provides the interface that should be
55166 * implemented by descendant classes. This class should not be directly instantiated.
55169 Roo.grid.AbstractSelectionModel = function(){
55170 this.locked = false;
55171 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55174 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55175 /** @ignore Called by the grid automatically. Do not call directly. */
55176 init : function(grid){
55182 * Locks the selections.
55185 this.locked = true;
55189 * Unlocks the selections.
55191 unlock : function(){
55192 this.locked = false;
55196 * Returns true if the selections are locked.
55197 * @return {Boolean}
55199 isLocked : function(){
55200 return this.locked;
55204 * Ext JS Library 1.1.1
55205 * Copyright(c) 2006-2007, Ext JS, LLC.
55207 * Originally Released Under LGPL - original licence link has changed is not relivant.
55210 * <script type="text/javascript">
55213 * @extends Roo.grid.AbstractSelectionModel
55214 * @class Roo.grid.RowSelectionModel
55215 * The default SelectionModel used by {@link Roo.grid.Grid}.
55216 * It supports multiple selections and keyboard selection/navigation.
55218 * @param {Object} config
55220 Roo.grid.RowSelectionModel = function(config){
55221 Roo.apply(this, config);
55222 this.selections = new Roo.util.MixedCollection(false, function(o){
55227 this.lastActive = false;
55231 * @event selectionchange
55232 * Fires when the selection changes
55233 * @param {SelectionModel} this
55235 "selectionchange" : true,
55237 * @event afterselectionchange
55238 * Fires after the selection changes (eg. by key press or clicking)
55239 * @param {SelectionModel} this
55241 "afterselectionchange" : true,
55243 * @event beforerowselect
55244 * Fires when a row is selected being selected, return false to cancel.
55245 * @param {SelectionModel} this
55246 * @param {Number} rowIndex The selected index
55247 * @param {Boolean} keepExisting False if other selections will be cleared
55249 "beforerowselect" : true,
55252 * Fires when a row is selected.
55253 * @param {SelectionModel} this
55254 * @param {Number} rowIndex The selected index
55255 * @param {Roo.data.Record} r The record
55257 "rowselect" : true,
55259 * @event rowdeselect
55260 * Fires when a row is deselected.
55261 * @param {SelectionModel} this
55262 * @param {Number} rowIndex The selected index
55264 "rowdeselect" : true
55266 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55267 this.locked = false;
55270 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55272 * @cfg {Boolean} singleSelect
55273 * True to allow selection of only one row at a time (defaults to false)
55275 singleSelect : false,
55278 initEvents : function(){
55280 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55281 this.grid.on("mousedown", this.handleMouseDown, this);
55282 }else{ // allow click to work like normal
55283 this.grid.on("rowclick", this.handleDragableRowClick, this);
55286 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55287 "up" : function(e){
55289 this.selectPrevious(e.shiftKey);
55290 }else if(this.last !== false && this.lastActive !== false){
55291 var last = this.last;
55292 this.selectRange(this.last, this.lastActive-1);
55293 this.grid.getView().focusRow(this.lastActive);
55294 if(last !== false){
55298 this.selectFirstRow();
55300 this.fireEvent("afterselectionchange", this);
55302 "down" : function(e){
55304 this.selectNext(e.shiftKey);
55305 }else if(this.last !== false && this.lastActive !== false){
55306 var last = this.last;
55307 this.selectRange(this.last, this.lastActive+1);
55308 this.grid.getView().focusRow(this.lastActive);
55309 if(last !== false){
55313 this.selectFirstRow();
55315 this.fireEvent("afterselectionchange", this);
55320 var view = this.grid.view;
55321 view.on("refresh", this.onRefresh, this);
55322 view.on("rowupdated", this.onRowUpdated, this);
55323 view.on("rowremoved", this.onRemove, this);
55327 onRefresh : function(){
55328 var ds = this.grid.dataSource, i, v = this.grid.view;
55329 var s = this.selections;
55330 s.each(function(r){
55331 if((i = ds.indexOfId(r.id)) != -1){
55340 onRemove : function(v, index, r){
55341 this.selections.remove(r);
55345 onRowUpdated : function(v, index, r){
55346 if(this.isSelected(r)){
55347 v.onRowSelect(index);
55353 * @param {Array} records The records to select
55354 * @param {Boolean} keepExisting (optional) True to keep existing selections
55356 selectRecords : function(records, keepExisting){
55358 this.clearSelections();
55360 var ds = this.grid.dataSource;
55361 for(var i = 0, len = records.length; i < len; i++){
55362 this.selectRow(ds.indexOf(records[i]), true);
55367 * Gets the number of selected rows.
55370 getCount : function(){
55371 return this.selections.length;
55375 * Selects the first row in the grid.
55377 selectFirstRow : function(){
55382 * Select the last row.
55383 * @param {Boolean} keepExisting (optional) True to keep existing selections
55385 selectLastRow : function(keepExisting){
55386 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55390 * Selects the row immediately following the last selected row.
55391 * @param {Boolean} keepExisting (optional) True to keep existing selections
55393 selectNext : function(keepExisting){
55394 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55395 this.selectRow(this.last+1, keepExisting);
55396 this.grid.getView().focusRow(this.last);
55401 * Selects the row that precedes the last selected row.
55402 * @param {Boolean} keepExisting (optional) True to keep existing selections
55404 selectPrevious : function(keepExisting){
55406 this.selectRow(this.last-1, keepExisting);
55407 this.grid.getView().focusRow(this.last);
55412 * Returns the selected records
55413 * @return {Array} Array of selected records
55415 getSelections : function(){
55416 return [].concat(this.selections.items);
55420 * Returns the first selected record.
55423 getSelected : function(){
55424 return this.selections.itemAt(0);
55429 * Clears all selections.
55431 clearSelections : function(fast){
55432 if(this.locked) return;
55434 var ds = this.grid.dataSource;
55435 var s = this.selections;
55436 s.each(function(r){
55437 this.deselectRow(ds.indexOfId(r.id));
55441 this.selections.clear();
55448 * Selects all rows.
55450 selectAll : function(){
55451 if(this.locked) return;
55452 this.selections.clear();
55453 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
55454 this.selectRow(i, true);
55459 * Returns True if there is a selection.
55460 * @return {Boolean}
55462 hasSelection : function(){
55463 return this.selections.length > 0;
55467 * Returns True if the specified row is selected.
55468 * @param {Number/Record} record The record or index of the record to check
55469 * @return {Boolean}
55471 isSelected : function(index){
55472 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
55473 return (r && this.selections.key(r.id) ? true : false);
55477 * Returns True if the specified record id is selected.
55478 * @param {String} id The id of record to check
55479 * @return {Boolean}
55481 isIdSelected : function(id){
55482 return (this.selections.key(id) ? true : false);
55486 handleMouseDown : function(e, t){
55487 var view = this.grid.getView(), rowIndex;
55488 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
55491 if(e.shiftKey && this.last !== false){
55492 var last = this.last;
55493 this.selectRange(last, rowIndex, e.ctrlKey);
55494 this.last = last; // reset the last
55495 view.focusRow(rowIndex);
55497 var isSelected = this.isSelected(rowIndex);
55498 if(e.button !== 0 && isSelected){
55499 view.focusRow(rowIndex);
55500 }else if(e.ctrlKey && isSelected){
55501 this.deselectRow(rowIndex);
55502 }else if(!isSelected){
55503 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
55504 view.focusRow(rowIndex);
55507 this.fireEvent("afterselectionchange", this);
55510 handleDragableRowClick : function(grid, rowIndex, e)
55512 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
55513 this.selectRow(rowIndex, false);
55514 grid.view.focusRow(rowIndex);
55515 this.fireEvent("afterselectionchange", this);
55520 * Selects multiple rows.
55521 * @param {Array} rows Array of the indexes of the row to select
55522 * @param {Boolean} keepExisting (optional) True to keep existing selections
55524 selectRows : function(rows, keepExisting){
55526 this.clearSelections();
55528 for(var i = 0, len = rows.length; i < len; i++){
55529 this.selectRow(rows[i], true);
55534 * Selects a range of rows. All rows in between startRow and endRow are also selected.
55535 * @param {Number} startRow The index of the first row in the range
55536 * @param {Number} endRow The index of the last row in the range
55537 * @param {Boolean} keepExisting (optional) True to retain existing selections
55539 selectRange : function(startRow, endRow, keepExisting){
55540 if(this.locked) return;
55542 this.clearSelections();
55544 if(startRow <= endRow){
55545 for(var i = startRow; i <= endRow; i++){
55546 this.selectRow(i, true);
55549 for(var i = startRow; i >= endRow; i--){
55550 this.selectRow(i, true);
55556 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
55557 * @param {Number} startRow The index of the first row in the range
55558 * @param {Number} endRow The index of the last row in the range
55560 deselectRange : function(startRow, endRow, preventViewNotify){
55561 if(this.locked) return;
55562 for(var i = startRow; i <= endRow; i++){
55563 this.deselectRow(i, preventViewNotify);
55569 * @param {Number} row The index of the row to select
55570 * @param {Boolean} keepExisting (optional) True to keep existing selections
55572 selectRow : function(index, keepExisting, preventViewNotify){
55573 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
55574 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
55575 if(!keepExisting || this.singleSelect){
55576 this.clearSelections();
55578 var r = this.grid.dataSource.getAt(index);
55579 this.selections.add(r);
55580 this.last = this.lastActive = index;
55581 if(!preventViewNotify){
55582 this.grid.getView().onRowSelect(index);
55584 this.fireEvent("rowselect", this, index, r);
55585 this.fireEvent("selectionchange", this);
55591 * @param {Number} row The index of the row to deselect
55593 deselectRow : function(index, preventViewNotify){
55594 if(this.locked) return;
55595 if(this.last == index){
55598 if(this.lastActive == index){
55599 this.lastActive = false;
55601 var r = this.grid.dataSource.getAt(index);
55602 this.selections.remove(r);
55603 if(!preventViewNotify){
55604 this.grid.getView().onRowDeselect(index);
55606 this.fireEvent("rowdeselect", this, index);
55607 this.fireEvent("selectionchange", this);
55611 restoreLast : function(){
55613 this.last = this._last;
55618 acceptsNav : function(row, col, cm){
55619 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55623 onEditorKey : function(field, e){
55624 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
55629 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55631 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55633 }else if(k == e.ENTER && !e.ctrlKey){
55637 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
55639 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
55641 }else if(k == e.ESC){
55645 g.startEditing(newCell[0], newCell[1]);
55650 * Ext JS Library 1.1.1
55651 * Copyright(c) 2006-2007, Ext JS, LLC.
55653 * Originally Released Under LGPL - original licence link has changed is not relivant.
55656 * <script type="text/javascript">
55659 * @class Roo.grid.CellSelectionModel
55660 * @extends Roo.grid.AbstractSelectionModel
55661 * This class provides the basic implementation for cell selection in a grid.
55663 * @param {Object} config The object containing the configuration of this model.
55664 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
55666 Roo.grid.CellSelectionModel = function(config){
55667 Roo.apply(this, config);
55669 this.selection = null;
55673 * @event beforerowselect
55674 * Fires before a cell is selected.
55675 * @param {SelectionModel} this
55676 * @param {Number} rowIndex The selected row index
55677 * @param {Number} colIndex The selected cell index
55679 "beforecellselect" : true,
55681 * @event cellselect
55682 * Fires when a cell is selected.
55683 * @param {SelectionModel} this
55684 * @param {Number} rowIndex The selected row index
55685 * @param {Number} colIndex The selected cell index
55687 "cellselect" : true,
55689 * @event selectionchange
55690 * Fires when the active selection changes.
55691 * @param {SelectionModel} this
55692 * @param {Object} selection null for no selection or an object (o) with two properties
55694 <li>o.record: the record object for the row the selection is in</li>
55695 <li>o.cell: An array of [rowIndex, columnIndex]</li>
55698 "selectionchange" : true,
55701 * Fires when the tab (or enter) was pressed on the last editable cell
55702 * You can use this to trigger add new row.
55703 * @param {SelectionModel} this
55707 * @event beforeeditnext
55708 * Fires before the next editable sell is made active
55709 * You can use this to skip to another cell or fire the tabend
55710 * if you set cell to false
55711 * @param {Object} eventdata object : { cell : [ row, col ] }
55713 "beforeeditnext" : true
55715 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
55718 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
55720 enter_is_tab: false,
55723 initEvents : function(){
55724 this.grid.on("mousedown", this.handleMouseDown, this);
55725 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
55726 var view = this.grid.view;
55727 view.on("refresh", this.onViewChange, this);
55728 view.on("rowupdated", this.onRowUpdated, this);
55729 view.on("beforerowremoved", this.clearSelections, this);
55730 view.on("beforerowsinserted", this.clearSelections, this);
55731 if(this.grid.isEditor){
55732 this.grid.on("beforeedit", this.beforeEdit, this);
55737 beforeEdit : function(e){
55738 this.select(e.row, e.column, false, true, e.record);
55742 onRowUpdated : function(v, index, r){
55743 if(this.selection && this.selection.record == r){
55744 v.onCellSelect(index, this.selection.cell[1]);
55749 onViewChange : function(){
55750 this.clearSelections(true);
55754 * Returns the currently selected cell,.
55755 * @return {Array} The selected cell (row, column) or null if none selected.
55757 getSelectedCell : function(){
55758 return this.selection ? this.selection.cell : null;
55762 * Clears all selections.
55763 * @param {Boolean} true to prevent the gridview from being notified about the change.
55765 clearSelections : function(preventNotify){
55766 var s = this.selection;
55768 if(preventNotify !== true){
55769 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
55771 this.selection = null;
55772 this.fireEvent("selectionchange", this, null);
55777 * Returns true if there is a selection.
55778 * @return {Boolean}
55780 hasSelection : function(){
55781 return this.selection ? true : false;
55785 handleMouseDown : function(e, t){
55786 var v = this.grid.getView();
55787 if(this.isLocked()){
55790 var row = v.findRowIndex(t);
55791 var cell = v.findCellIndex(t);
55792 if(row !== false && cell !== false){
55793 this.select(row, cell);
55799 * @param {Number} rowIndex
55800 * @param {Number} collIndex
55802 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
55803 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
55804 this.clearSelections();
55805 r = r || this.grid.dataSource.getAt(rowIndex);
55808 cell : [rowIndex, colIndex]
55810 if(!preventViewNotify){
55811 var v = this.grid.getView();
55812 v.onCellSelect(rowIndex, colIndex);
55813 if(preventFocus !== true){
55814 v.focusCell(rowIndex, colIndex);
55817 this.fireEvent("cellselect", this, rowIndex, colIndex);
55818 this.fireEvent("selectionchange", this, this.selection);
55823 isSelectable : function(rowIndex, colIndex, cm){
55824 return !cm.isHidden(colIndex);
55828 handleKeyDown : function(e){
55829 //Roo.log('Cell Sel Model handleKeyDown');
55830 if(!e.isNavKeyPress()){
55833 var g = this.grid, s = this.selection;
55836 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
55838 this.select(cell[0], cell[1]);
55843 var walk = function(row, col, step){
55844 return g.walkCells(row, col, step, sm.isSelectable, sm);
55846 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
55853 // handled by onEditorKey
55854 if (g.isEditor && g.editing) {
55858 newCell = walk(r, c-1, -1);
55860 newCell = walk(r, c+1, 1);
55865 newCell = walk(r+1, c, 1);
55869 newCell = walk(r-1, c, -1);
55873 newCell = walk(r, c+1, 1);
55877 newCell = walk(r, c-1, -1);
55882 if(g.isEditor && !g.editing){
55883 g.startEditing(r, c);
55892 this.select(newCell[0], newCell[1]);
55898 acceptsNav : function(row, col, cm){
55899 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55903 * @param {Number} field (not used) - as it's normally used as a listener
55904 * @param {Number} e - event - fake it by using
55906 * var e = Roo.EventObjectImpl.prototype;
55907 * e.keyCode = e.TAB
55911 onEditorKey : function(field, e){
55913 var k = e.getKey(),
55916 ed = g.activeEditor,
55918 ///Roo.log('onEditorKey' + k);
55921 if (this.enter_is_tab && k == e.ENTER) {
55927 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55929 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55935 } else if(k == e.ENTER && !e.ctrlKey){
55938 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55940 } else if(k == e.ESC){
55945 var ecall = { cell : newCell, forward : forward };
55946 this.fireEvent('beforeeditnext', ecall );
55947 newCell = ecall.cell;
55948 forward = ecall.forward;
55952 //Roo.log('next cell after edit');
55953 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
55954 } else if (forward) {
55955 // tabbed past last
55956 this.fireEvent.defer(100, this, ['tabend',this]);
55961 * Ext JS Library 1.1.1
55962 * Copyright(c) 2006-2007, Ext JS, LLC.
55964 * Originally Released Under LGPL - original licence link has changed is not relivant.
55967 * <script type="text/javascript">
55971 * @class Roo.grid.EditorGrid
55972 * @extends Roo.grid.Grid
55973 * Class for creating and editable grid.
55974 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55975 * The container MUST have some type of size defined for the grid to fill. The container will be
55976 * automatically set to position relative if it isn't already.
55977 * @param {Object} dataSource The data model to bind to
55978 * @param {Object} colModel The column model with info about this grid's columns
55980 Roo.grid.EditorGrid = function(container, config){
55981 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
55982 this.getGridEl().addClass("xedit-grid");
55984 if(!this.selModel){
55985 this.selModel = new Roo.grid.CellSelectionModel();
55988 this.activeEditor = null;
55992 * @event beforeedit
55993 * Fires before cell editing is triggered. The edit event object has the following properties <br />
55994 * <ul style="padding:5px;padding-left:16px;">
55995 * <li>grid - This grid</li>
55996 * <li>record - The record being edited</li>
55997 * <li>field - The field name being edited</li>
55998 * <li>value - The value for the field being edited.</li>
55999 * <li>row - The grid row index</li>
56000 * <li>column - The grid column index</li>
56001 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56003 * @param {Object} e An edit event (see above for description)
56005 "beforeedit" : true,
56008 * Fires after a cell is edited. <br />
56009 * <ul style="padding:5px;padding-left:16px;">
56010 * <li>grid - This grid</li>
56011 * <li>record - The record being edited</li>
56012 * <li>field - The field name being edited</li>
56013 * <li>value - The value being set</li>
56014 * <li>originalValue - The original value for the field, before the edit.</li>
56015 * <li>row - The grid row index</li>
56016 * <li>column - The grid column index</li>
56018 * @param {Object} e An edit event (see above for description)
56020 "afteredit" : true,
56022 * @event validateedit
56023 * Fires after a cell is edited, but before the value is set in the record.
56024 * You can use this to modify the value being set in the field, Return false
56025 * to cancel the change. The edit event object has the following properties <br />
56026 * <ul style="padding:5px;padding-left:16px;">
56027 * <li>editor - This editor</li>
56028 * <li>grid - This grid</li>
56029 * <li>record - The record being edited</li>
56030 * <li>field - The field name being edited</li>
56031 * <li>value - The value being set</li>
56032 * <li>originalValue - The original value for the field, before the edit.</li>
56033 * <li>row - The grid row index</li>
56034 * <li>column - The grid column index</li>
56035 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56037 * @param {Object} e An edit event (see above for description)
56039 "validateedit" : true
56041 this.on("bodyscroll", this.stopEditing, this);
56042 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56045 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56047 * @cfg {Number} clicksToEdit
56048 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56055 trackMouseOver: false, // causes very odd FF errors
56057 onCellDblClick : function(g, row, col){
56058 this.startEditing(row, col);
56061 onEditComplete : function(ed, value, startValue){
56062 this.editing = false;
56063 this.activeEditor = null;
56064 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56066 var field = this.colModel.getDataIndex(ed.col);
56071 originalValue: startValue,
56078 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56081 if(String(value) !== String(startValue)){
56083 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56084 r.set(field, e.value);
56085 // if we are dealing with a combo box..
56086 // then we also set the 'name' colum to be the displayField
56087 if (ed.field.displayField && ed.field.name) {
56088 r.set(ed.field.name, ed.field.el.dom.value);
56091 delete e.cancel; //?? why!!!
56092 this.fireEvent("afteredit", e);
56095 this.fireEvent("afteredit", e); // always fire it!
56097 this.view.focusCell(ed.row, ed.col);
56101 * Starts editing the specified for the specified row/column
56102 * @param {Number} rowIndex
56103 * @param {Number} colIndex
56105 startEditing : function(row, col){
56106 this.stopEditing();
56107 if(this.colModel.isCellEditable(col, row)){
56108 this.view.ensureVisible(row, col, true);
56110 var r = this.dataSource.getAt(row);
56111 var field = this.colModel.getDataIndex(col);
56112 var cell = Roo.get(this.view.getCell(row,col));
56117 value: r.data[field],
56122 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56123 this.editing = true;
56124 var ed = this.colModel.getCellEditor(col, row);
56130 ed.render(ed.parentEl || document.body);
56136 (function(){ // complex but required for focus issues in safari, ie and opera
56140 ed.on("complete", this.onEditComplete, this, {single: true});
56141 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56142 this.activeEditor = ed;
56143 var v = r.data[field];
56144 ed.startEdit(this.view.getCell(row, col), v);
56145 // combo's with 'displayField and name set
56146 if (ed.field.displayField && ed.field.name) {
56147 ed.field.el.dom.value = r.data[ed.field.name];
56151 }).defer(50, this);
56157 * Stops any active editing
56159 stopEditing : function(){
56160 if(this.activeEditor){
56161 this.activeEditor.completeEdit();
56163 this.activeEditor = null;
56167 * Called to get grid's drag proxy text, by default returns this.ddText.
56170 getDragDropText : function(){
56171 var count = this.selModel.getSelectedCell() ? 1 : 0;
56172 return String.format(this.ddText, count, count == 1 ? '' : 's');
56177 * Ext JS Library 1.1.1
56178 * Copyright(c) 2006-2007, Ext JS, LLC.
56180 * Originally Released Under LGPL - original licence link has changed is not relivant.
56183 * <script type="text/javascript">
56186 // private - not really -- you end up using it !
56187 // This is a support class used internally by the Grid components
56190 * @class Roo.grid.GridEditor
56191 * @extends Roo.Editor
56192 * Class for creating and editable grid elements.
56193 * @param {Object} config any settings (must include field)
56195 Roo.grid.GridEditor = function(field, config){
56196 if (!config && field.field) {
56198 field = Roo.factory(config.field, Roo.form);
56200 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56201 field.monitorTab = false;
56204 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56207 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56210 alignment: "tl-tl",
56213 cls: "x-small-editor x-grid-editor",
56218 * Ext JS Library 1.1.1
56219 * Copyright(c) 2006-2007, Ext JS, LLC.
56221 * Originally Released Under LGPL - original licence link has changed is not relivant.
56224 * <script type="text/javascript">
56229 Roo.grid.PropertyRecord = Roo.data.Record.create([
56230 {name:'name',type:'string'}, 'value'
56234 Roo.grid.PropertyStore = function(grid, source){
56236 this.store = new Roo.data.Store({
56237 recordType : Roo.grid.PropertyRecord
56239 this.store.on('update', this.onUpdate, this);
56241 this.setSource(source);
56243 Roo.grid.PropertyStore.superclass.constructor.call(this);
56248 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56249 setSource : function(o){
56251 this.store.removeAll();
56254 if(this.isEditableValue(o[k])){
56255 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56258 this.store.loadRecords({records: data}, {}, true);
56261 onUpdate : function(ds, record, type){
56262 if(type == Roo.data.Record.EDIT){
56263 var v = record.data['value'];
56264 var oldValue = record.modified['value'];
56265 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56266 this.source[record.id] = v;
56268 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56275 getProperty : function(row){
56276 return this.store.getAt(row);
56279 isEditableValue: function(val){
56280 if(val && val instanceof Date){
56282 }else if(typeof val == 'object' || typeof val == 'function'){
56288 setValue : function(prop, value){
56289 this.source[prop] = value;
56290 this.store.getById(prop).set('value', value);
56293 getSource : function(){
56294 return this.source;
56298 Roo.grid.PropertyColumnModel = function(grid, store){
56301 g.PropertyColumnModel.superclass.constructor.call(this, [
56302 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56303 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56305 this.store = store;
56306 this.bselect = Roo.DomHelper.append(document.body, {
56307 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56308 {tag: 'option', value: 'true', html: 'true'},
56309 {tag: 'option', value: 'false', html: 'false'}
56312 Roo.id(this.bselect);
56315 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56316 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56317 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56318 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56319 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56321 this.renderCellDelegate = this.renderCell.createDelegate(this);
56322 this.renderPropDelegate = this.renderProp.createDelegate(this);
56325 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56329 valueText : 'Value',
56331 dateFormat : 'm/j/Y',
56334 renderDate : function(dateVal){
56335 return dateVal.dateFormat(this.dateFormat);
56338 renderBool : function(bVal){
56339 return bVal ? 'true' : 'false';
56342 isCellEditable : function(colIndex, rowIndex){
56343 return colIndex == 1;
56346 getRenderer : function(col){
56348 this.renderCellDelegate : this.renderPropDelegate;
56351 renderProp : function(v){
56352 return this.getPropertyName(v);
56355 renderCell : function(val){
56357 if(val instanceof Date){
56358 rv = this.renderDate(val);
56359 }else if(typeof val == 'boolean'){
56360 rv = this.renderBool(val);
56362 return Roo.util.Format.htmlEncode(rv);
56365 getPropertyName : function(name){
56366 var pn = this.grid.propertyNames;
56367 return pn && pn[name] ? pn[name] : name;
56370 getCellEditor : function(colIndex, rowIndex){
56371 var p = this.store.getProperty(rowIndex);
56372 var n = p.data['name'], val = p.data['value'];
56374 if(typeof(this.grid.customEditors[n]) == 'string'){
56375 return this.editors[this.grid.customEditors[n]];
56377 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56378 return this.grid.customEditors[n];
56380 if(val instanceof Date){
56381 return this.editors['date'];
56382 }else if(typeof val == 'number'){
56383 return this.editors['number'];
56384 }else if(typeof val == 'boolean'){
56385 return this.editors['boolean'];
56387 return this.editors['string'];
56393 * @class Roo.grid.PropertyGrid
56394 * @extends Roo.grid.EditorGrid
56395 * This class represents the interface of a component based property grid control.
56396 * <br><br>Usage:<pre><code>
56397 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56405 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56406 * The container MUST have some type of size defined for the grid to fill. The container will be
56407 * automatically set to position relative if it isn't already.
56408 * @param {Object} config A config object that sets properties on this grid.
56410 Roo.grid.PropertyGrid = function(container, config){
56411 config = config || {};
56412 var store = new Roo.grid.PropertyStore(this);
56413 this.store = store;
56414 var cm = new Roo.grid.PropertyColumnModel(this, store);
56415 store.store.sort('name', 'ASC');
56416 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
56419 enableColLock:false,
56420 enableColumnMove:false,
56422 trackMouseOver: false,
56425 this.getGridEl().addClass('x-props-grid');
56426 this.lastEditRow = null;
56427 this.on('columnresize', this.onColumnResize, this);
56430 * @event beforepropertychange
56431 * Fires before a property changes (return false to stop?)
56432 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56433 * @param {String} id Record Id
56434 * @param {String} newval New Value
56435 * @param {String} oldval Old Value
56437 "beforepropertychange": true,
56439 * @event propertychange
56440 * Fires after a property changes
56441 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56442 * @param {String} id Record Id
56443 * @param {String} newval New Value
56444 * @param {String} oldval Old Value
56446 "propertychange": true
56448 this.customEditors = this.customEditors || {};
56450 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
56453 * @cfg {Object} customEditors map of colnames=> custom editors.
56454 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
56455 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
56456 * false disables editing of the field.
56460 * @cfg {Object} propertyNames map of property Names to their displayed value
56463 render : function(){
56464 Roo.grid.PropertyGrid.superclass.render.call(this);
56465 this.autoSize.defer(100, this);
56468 autoSize : function(){
56469 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
56471 this.view.fitColumns();
56475 onColumnResize : function(){
56476 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
56480 * Sets the data for the Grid
56481 * accepts a Key => Value object of all the elements avaiable.
56482 * @param {Object} data to appear in grid.
56484 setSource : function(source){
56485 this.store.setSource(source);
56489 * Gets all the data from the grid.
56490 * @return {Object} data data stored in grid
56492 getSource : function(){
56493 return this.store.getSource();
56502 * @class Roo.grid.Calendar
56503 * @extends Roo.util.Grid
56504 * This class extends the Grid to provide a calendar widget
56505 * <br><br>Usage:<pre><code>
56506 var grid = new Roo.grid.Calendar("my-container-id", {
56509 selModel: mySelectionModel,
56510 autoSizeColumns: true,
56511 monitorWindowResize: false,
56512 trackMouseOver: true
56513 eventstore : real data store..
56519 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56520 * The container MUST have some type of size defined for the grid to fill. The container will be
56521 * automatically set to position relative if it isn't already.
56522 * @param {Object} config A config object that sets properties on this grid.
56524 Roo.grid.Calendar = function(container, config){
56525 // initialize the container
56526 this.container = Roo.get(container);
56527 this.container.update("");
56528 this.container.setStyle("overflow", "hidden");
56529 this.container.addClass('x-grid-container');
56531 this.id = this.container.id;
56533 Roo.apply(this, config);
56534 // check and correct shorthanded configs
56538 for (var r = 0;r < 6;r++) {
56541 for (var c =0;c < 7;c++) {
56545 if (this.eventStore) {
56546 this.eventStore= Roo.factory(this.eventStore, Roo.data);
56547 this.eventStore.on('load',this.onLoad, this);
56548 this.eventStore.on('beforeload',this.clearEvents, this);
56552 this.dataSource = new Roo.data.Store({
56553 proxy: new Roo.data.MemoryProxy(rows),
56554 reader: new Roo.data.ArrayReader({}, [
56555 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
56558 this.dataSource.load();
56559 this.ds = this.dataSource;
56560 this.ds.xmodule = this.xmodule || false;
56563 var cellRender = function(v,x,r)
56565 return String.format(
56566 '<div class="fc-day fc-widget-content"><div>' +
56567 '<div class="fc-event-container"></div>' +
56568 '<div class="fc-day-number">{0}</div>'+
56570 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
56571 '</div></div>', v);
56576 this.colModel = new Roo.grid.ColumnModel( [
56578 xtype: 'ColumnModel',
56580 dataIndex : 'weekday0',
56582 renderer : cellRender
56585 xtype: 'ColumnModel',
56587 dataIndex : 'weekday1',
56589 renderer : cellRender
56592 xtype: 'ColumnModel',
56594 dataIndex : 'weekday2',
56595 header : 'Tuesday',
56596 renderer : cellRender
56599 xtype: 'ColumnModel',
56601 dataIndex : 'weekday3',
56602 header : 'Wednesday',
56603 renderer : cellRender
56606 xtype: 'ColumnModel',
56608 dataIndex : 'weekday4',
56609 header : 'Thursday',
56610 renderer : cellRender
56613 xtype: 'ColumnModel',
56615 dataIndex : 'weekday5',
56617 renderer : cellRender
56620 xtype: 'ColumnModel',
56622 dataIndex : 'weekday6',
56623 header : 'Saturday',
56624 renderer : cellRender
56627 this.cm = this.colModel;
56628 this.cm.xmodule = this.xmodule || false;
56632 //this.selModel = new Roo.grid.CellSelectionModel();
56633 //this.sm = this.selModel;
56634 //this.selModel.init(this);
56638 this.container.setWidth(this.width);
56642 this.container.setHeight(this.height);
56649 * The raw click event for the entire grid.
56650 * @param {Roo.EventObject} e
56655 * The raw dblclick event for the entire grid.
56656 * @param {Roo.EventObject} e
56660 * @event contextmenu
56661 * The raw contextmenu event for the entire grid.
56662 * @param {Roo.EventObject} e
56664 "contextmenu" : true,
56667 * The raw mousedown event for the entire grid.
56668 * @param {Roo.EventObject} e
56670 "mousedown" : true,
56673 * The raw mouseup event for the entire grid.
56674 * @param {Roo.EventObject} e
56679 * The raw mouseover event for the entire grid.
56680 * @param {Roo.EventObject} e
56682 "mouseover" : true,
56685 * The raw mouseout event for the entire grid.
56686 * @param {Roo.EventObject} e
56691 * The raw keypress event for the entire grid.
56692 * @param {Roo.EventObject} e
56697 * The raw keydown event for the entire grid.
56698 * @param {Roo.EventObject} e
56706 * Fires when a cell is clicked
56707 * @param {Grid} this
56708 * @param {Number} rowIndex
56709 * @param {Number} columnIndex
56710 * @param {Roo.EventObject} e
56712 "cellclick" : true,
56714 * @event celldblclick
56715 * Fires when a cell is double clicked
56716 * @param {Grid} this
56717 * @param {Number} rowIndex
56718 * @param {Number} columnIndex
56719 * @param {Roo.EventObject} e
56721 "celldblclick" : true,
56724 * Fires when a row is clicked
56725 * @param {Grid} this
56726 * @param {Number} rowIndex
56727 * @param {Roo.EventObject} e
56731 * @event rowdblclick
56732 * Fires when a row is double clicked
56733 * @param {Grid} this
56734 * @param {Number} rowIndex
56735 * @param {Roo.EventObject} e
56737 "rowdblclick" : true,
56739 * @event headerclick
56740 * Fires when a header is clicked
56741 * @param {Grid} this
56742 * @param {Number} columnIndex
56743 * @param {Roo.EventObject} e
56745 "headerclick" : true,
56747 * @event headerdblclick
56748 * Fires when a header cell is double clicked
56749 * @param {Grid} this
56750 * @param {Number} columnIndex
56751 * @param {Roo.EventObject} e
56753 "headerdblclick" : true,
56755 * @event rowcontextmenu
56756 * Fires when a row is right clicked
56757 * @param {Grid} this
56758 * @param {Number} rowIndex
56759 * @param {Roo.EventObject} e
56761 "rowcontextmenu" : true,
56763 * @event cellcontextmenu
56764 * Fires when a cell is right clicked
56765 * @param {Grid} this
56766 * @param {Number} rowIndex
56767 * @param {Number} cellIndex
56768 * @param {Roo.EventObject} e
56770 "cellcontextmenu" : true,
56772 * @event headercontextmenu
56773 * Fires when a header is right clicked
56774 * @param {Grid} this
56775 * @param {Number} columnIndex
56776 * @param {Roo.EventObject} e
56778 "headercontextmenu" : true,
56780 * @event bodyscroll
56781 * Fires when the body element is scrolled
56782 * @param {Number} scrollLeft
56783 * @param {Number} scrollTop
56785 "bodyscroll" : true,
56787 * @event columnresize
56788 * Fires when the user resizes a column
56789 * @param {Number} columnIndex
56790 * @param {Number} newSize
56792 "columnresize" : true,
56794 * @event columnmove
56795 * Fires when the user moves a column
56796 * @param {Number} oldIndex
56797 * @param {Number} newIndex
56799 "columnmove" : true,
56802 * Fires when row(s) start being dragged
56803 * @param {Grid} this
56804 * @param {Roo.GridDD} dd The drag drop object
56805 * @param {event} e The raw browser event
56807 "startdrag" : true,
56810 * Fires when a drag operation is complete
56811 * @param {Grid} this
56812 * @param {Roo.GridDD} dd The drag drop object
56813 * @param {event} e The raw browser event
56818 * Fires when dragged row(s) are dropped on a valid DD target
56819 * @param {Grid} this
56820 * @param {Roo.GridDD} dd The drag drop object
56821 * @param {String} targetId The target drag drop object
56822 * @param {event} e The raw browser event
56827 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
56828 * @param {Grid} this
56829 * @param {Roo.GridDD} dd The drag drop object
56830 * @param {String} targetId The target drag drop object
56831 * @param {event} e The raw browser event
56836 * Fires when the dragged row(s) first cross another DD target while being dragged
56837 * @param {Grid} this
56838 * @param {Roo.GridDD} dd The drag drop object
56839 * @param {String} targetId The target drag drop object
56840 * @param {event} e The raw browser event
56842 "dragenter" : true,
56845 * Fires when the dragged row(s) leave another DD target while being dragged
56846 * @param {Grid} this
56847 * @param {Roo.GridDD} dd The drag drop object
56848 * @param {String} targetId The target drag drop object
56849 * @param {event} e The raw browser event
56854 * Fires when a row is rendered, so you can change add a style to it.
56855 * @param {GridView} gridview The grid view
56856 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
56862 * Fires when the grid is rendered
56863 * @param {Grid} grid
56868 * Fires when a date is selected
56869 * @param {DatePicker} this
56870 * @param {Date} date The selected date
56874 * @event monthchange
56875 * Fires when the displayed month changes
56876 * @param {DatePicker} this
56877 * @param {Date} date The selected month
56879 'monthchange': true,
56881 * @event evententer
56882 * Fires when mouse over an event
56883 * @param {Calendar} this
56884 * @param {event} Event
56886 'evententer': true,
56888 * @event eventleave
56889 * Fires when the mouse leaves an
56890 * @param {Calendar} this
56893 'eventleave': true,
56895 * @event eventclick
56896 * Fires when the mouse click an
56897 * @param {Calendar} this
56900 'eventclick': true,
56902 * @event eventrender
56903 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
56904 * @param {Calendar} this
56905 * @param {data} data to be modified
56907 'eventrender': true
56911 Roo.grid.Grid.superclass.constructor.call(this);
56912 this.on('render', function() {
56913 this.view.el.addClass('x-grid-cal');
56915 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
56919 if (!Roo.grid.Calendar.style) {
56920 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
56923 '.x-grid-cal .x-grid-col' : {
56924 height: 'auto !important',
56925 'vertical-align': 'top'
56927 '.x-grid-cal .fc-event-hori' : {
56938 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
56940 * @cfg {Store} eventStore The store that loads events.
56945 activeDate : false,
56948 monitorWindowResize : false,
56951 resizeColumns : function() {
56952 var col = (this.view.el.getWidth() / 7) - 3;
56953 // loop through cols, and setWidth
56954 for(var i =0 ; i < 7 ; i++){
56955 this.cm.setColumnWidth(i, col);
56958 setDate :function(date) {
56960 Roo.log('setDate?');
56962 this.resizeColumns();
56963 var vd = this.activeDate;
56964 this.activeDate = date;
56965 // if(vd && this.el){
56966 // var t = date.getTime();
56967 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
56968 // Roo.log('using add remove');
56970 // this.fireEvent('monthchange', this, date);
56972 // this.cells.removeClass("fc-state-highlight");
56973 // this.cells.each(function(c){
56974 // if(c.dateValue == t){
56975 // c.addClass("fc-state-highlight");
56976 // setTimeout(function(){
56977 // try{c.dom.firstChild.focus();}catch(e){}
56987 var days = date.getDaysInMonth();
56989 var firstOfMonth = date.getFirstDateOfMonth();
56990 var startingPos = firstOfMonth.getDay()-this.startDay;
56992 if(startingPos < this.startDay){
56996 var pm = date.add(Date.MONTH, -1);
56997 var prevStart = pm.getDaysInMonth()-startingPos;
57001 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57003 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57004 //this.cells.addClassOnOver('fc-state-hover');
57006 var cells = this.cells.elements;
57007 var textEls = this.textNodes;
57009 //Roo.each(cells, function(cell){
57010 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57013 days += startingPos;
57015 // convert everything to numbers so it's fast
57016 var day = 86400000;
57017 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57020 //Roo.log(prevStart);
57022 var today = new Date().clearTime().getTime();
57023 var sel = date.clearTime().getTime();
57024 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57025 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57026 var ddMatch = this.disabledDatesRE;
57027 var ddText = this.disabledDatesText;
57028 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57029 var ddaysText = this.disabledDaysText;
57030 var format = this.format;
57032 var setCellClass = function(cal, cell){
57034 //Roo.log('set Cell Class');
57036 var t = d.getTime();
57041 cell.dateValue = t;
57043 cell.className += " fc-today";
57044 cell.className += " fc-state-highlight";
57045 cell.title = cal.todayText;
57048 // disable highlight in other month..
57049 cell.className += " fc-state-highlight";
57054 //cell.className = " fc-state-disabled";
57055 cell.title = cal.minText;
57059 //cell.className = " fc-state-disabled";
57060 cell.title = cal.maxText;
57064 if(ddays.indexOf(d.getDay()) != -1){
57065 // cell.title = ddaysText;
57066 // cell.className = " fc-state-disabled";
57069 if(ddMatch && format){
57070 var fvalue = d.dateFormat(format);
57071 if(ddMatch.test(fvalue)){
57072 cell.title = ddText.replace("%0", fvalue);
57073 cell.className = " fc-state-disabled";
57077 if (!cell.initialClassName) {
57078 cell.initialClassName = cell.dom.className;
57081 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57086 for(; i < startingPos; i++) {
57087 cells[i].dayName = (++prevStart);
57088 Roo.log(textEls[i]);
57089 d.setDate(d.getDate()+1);
57091 //cells[i].className = "fc-past fc-other-month";
57092 setCellClass(this, cells[i]);
57097 for(; i < days; i++){
57098 intDay = i - startingPos + 1;
57099 cells[i].dayName = (intDay);
57100 d.setDate(d.getDate()+1);
57102 cells[i].className = ''; // "x-date-active";
57103 setCellClass(this, cells[i]);
57107 for(; i < 42; i++) {
57108 //textEls[i].innerHTML = (++extraDays);
57110 d.setDate(d.getDate()+1);
57111 cells[i].dayName = (++extraDays);
57112 cells[i].className = "fc-future fc-other-month";
57113 setCellClass(this, cells[i]);
57116 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57118 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57120 // this will cause all the cells to mis
57123 for (var r = 0;r < 6;r++) {
57124 for (var c =0;c < 7;c++) {
57125 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57129 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57130 for(i=0;i<cells.length;i++) {
57132 this.cells.elements[i].dayName = cells[i].dayName ;
57133 this.cells.elements[i].className = cells[i].className;
57134 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57135 this.cells.elements[i].title = cells[i].title ;
57136 this.cells.elements[i].dateValue = cells[i].dateValue ;
57142 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57143 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57145 ////if(totalRows != 6){
57146 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57147 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57150 this.fireEvent('monthchange', this, date);
57155 * Returns the grid's SelectionModel.
57156 * @return {SelectionModel}
57158 getSelectionModel : function(){
57159 if(!this.selModel){
57160 this.selModel = new Roo.grid.CellSelectionModel();
57162 return this.selModel;
57166 this.eventStore.load()
57172 findCell : function(dt) {
57173 dt = dt.clearTime().getTime();
57175 this.cells.each(function(c){
57176 //Roo.log("check " +c.dateValue + '?=' + dt);
57177 if(c.dateValue == dt){
57187 findCells : function(rec) {
57188 var s = rec.data.start_dt.clone().clearTime().getTime();
57190 var e= rec.data.end_dt.clone().clearTime().getTime();
57193 this.cells.each(function(c){
57194 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57196 if(c.dateValue > e){
57199 if(c.dateValue < s){
57208 findBestRow: function(cells)
57212 for (var i =0 ; i < cells.length;i++) {
57213 ret = Math.max(cells[i].rows || 0,ret);
57220 addItem : function(rec)
57222 // look for vertical location slot in
57223 var cells = this.findCells(rec);
57225 rec.row = this.findBestRow(cells);
57227 // work out the location.
57231 for(var i =0; i < cells.length; i++) {
57239 if (crow.start.getY() == cells[i].getY()) {
57241 crow.end = cells[i];
57257 for (var i = 0; i < cells.length;i++) {
57258 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57265 clearEvents: function() {
57267 if (!this.eventStore.getCount()) {
57270 // reset number of rows in cells.
57271 Roo.each(this.cells.elements, function(c){
57275 this.eventStore.each(function(e) {
57276 this.clearEvent(e);
57281 clearEvent : function(ev)
57284 Roo.each(ev.els, function(el) {
57285 el.un('mouseenter' ,this.onEventEnter, this);
57286 el.un('mouseleave' ,this.onEventLeave, this);
57294 renderEvent : function(ev,ctr) {
57296 ctr = this.view.el.select('.fc-event-container',true).first();
57300 this.clearEvent(ev);
57306 var cells = ev.cells;
57307 var rows = ev.rows;
57308 this.fireEvent('eventrender', this, ev);
57310 for(var i =0; i < rows.length; i++) {
57314 cls += ' fc-event-start';
57316 if ((i+1) == rows.length) {
57317 cls += ' fc-event-end';
57320 //Roo.log(ev.data);
57321 // how many rows should it span..
57322 var cg = this.eventTmpl.append(ctr,Roo.apply({
57325 }, ev.data) , true);
57328 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57329 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57330 cg.on('click', this.onEventClick, this, ev);
57334 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57335 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57338 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57339 cg.setWidth(ebox.right - sbox.x -2);
57343 renderEvents: function()
57345 // first make sure there is enough space..
57347 if (!this.eventTmpl) {
57348 this.eventTmpl = new Roo.Template(
57349 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57350 '<div class="fc-event-inner">' +
57351 '<span class="fc-event-time">{time}</span>' +
57352 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57354 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57362 this.cells.each(function(c) {
57363 //Roo.log(c.select('.fc-day-content div',true).first());
57364 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57367 var ctr = this.view.el.select('.fc-event-container',true).first();
57370 this.eventStore.each(function(ev){
57372 this.renderEvent(ev);
57376 this.view.layout();
57380 onEventEnter: function (e, el,event,d) {
57381 this.fireEvent('evententer', this, el, event);
57384 onEventLeave: function (e, el,event,d) {
57385 this.fireEvent('eventleave', this, el, event);
57388 onEventClick: function (e, el,event,d) {
57389 this.fireEvent('eventclick', this, el, event);
57392 onMonthChange: function () {
57396 onLoad: function () {
57398 //Roo.log('calendar onload');
57400 if(this.eventStore.getCount() > 0){
57404 this.eventStore.each(function(d){
57409 if (typeof(add.end_dt) == 'undefined') {
57410 Roo.log("Missing End time in calendar data: ");
57414 if (typeof(add.start_dt) == 'undefined') {
57415 Roo.log("Missing Start time in calendar data: ");
57419 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
57420 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
57421 add.id = add.id || d.id;
57422 add.title = add.title || '??';
57430 this.renderEvents();
57440 render : function ()
57444 if (!this.view.el.hasClass('course-timesheet')) {
57445 this.view.el.addClass('course-timesheet');
57447 if (this.tsStyle) {
57452 Roo.log(_this.grid.view.el.getWidth());
57455 this.tsStyle = Roo.util.CSS.createStyleSheet({
57456 '.course-timesheet .x-grid-row' : {
57459 '.x-grid-row td' : {
57460 'vertical-align' : 0
57462 '.course-edit-link' : {
57464 'text-overflow' : 'ellipsis',
57465 'overflow' : 'hidden',
57466 'white-space' : 'nowrap',
57467 'cursor' : 'pointer'
57472 '.de-act-sup-link' : {
57473 'color' : 'purple',
57474 'text-decoration' : 'line-through'
57478 'text-decoration' : 'line-through'
57480 '.course-timesheet .course-highlight' : {
57481 'border-top-style': 'dashed !important',
57482 'border-bottom-bottom': 'dashed !important'
57484 '.course-timesheet .course-item' : {
57485 'font-family' : 'tahoma, arial, helvetica',
57486 'font-size' : '11px',
57487 'overflow' : 'hidden',
57488 'padding-left' : '10px',
57489 'padding-right' : '10px',
57490 'padding-top' : '10px'
57498 monitorWindowResize : false,
57499 cellrenderer : function(v,x,r)
57504 xtype: 'CellSelectionModel',
57511 beforeload : function (_self, options)
57513 options.params = options.params || {};
57514 options.params._month = _this.monthField.getValue();
57515 options.params.limit = 9999;
57516 options.params['sort'] = 'when_dt';
57517 options.params['dir'] = 'ASC';
57518 this.proxy.loadResponse = this.loadResponse;
57520 //this.addColumns();
57522 load : function (_self, records, options)
57524 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
57525 // if you click on the translation.. you can edit it...
57526 var el = Roo.get(this);
57527 var id = el.dom.getAttribute('data-id');
57528 var d = el.dom.getAttribute('data-date');
57529 var t = el.dom.getAttribute('data-time');
57530 //var id = this.child('span').dom.textContent;
57533 Pman.Dialog.CourseCalendar.show({
57537 productitem_active : id ? 1 : 0
57539 _this.grid.ds.load({});
57544 _this.panel.fireEvent('resize', [ '', '' ]);
57547 loadResponse : function(o, success, response){
57548 // this is overridden on before load..
57550 Roo.log("our code?");
57551 //Roo.log(success);
57552 //Roo.log(response)
57553 delete this.activeRequest;
57555 this.fireEvent("loadexception", this, o, response);
57556 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57561 result = o.reader.read(response);
57563 Roo.log("load exception?");
57564 this.fireEvent("loadexception", this, o, response, e);
57565 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57568 Roo.log("ready...");
57569 // loop through result.records;
57570 // and set this.tdate[date] = [] << array of records..
57572 Roo.each(result.records, function(r){
57574 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
57575 _this.tdata[r.data.when_dt.format('j')] = [];
57577 _this.tdata[r.data.when_dt.format('j')].push(r.data);
57580 //Roo.log(_this.tdata);
57582 result.records = [];
57583 result.totalRecords = 6;
57585 // let's generate some duumy records for the rows.
57586 //var st = _this.dateField.getValue();
57588 // work out monday..
57589 //st = st.add(Date.DAY, -1 * st.format('w'));
57591 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57593 var firstOfMonth = date.getFirstDayOfMonth();
57594 var days = date.getDaysInMonth();
57596 var firstAdded = false;
57597 for (var i = 0; i < result.totalRecords ; i++) {
57598 //var d= st.add(Date.DAY, i);
57601 for(var w = 0 ; w < 7 ; w++){
57602 if(!firstAdded && firstOfMonth != w){
57609 var dd = (d > 0 && d < 10) ? "0"+d : d;
57610 row['weekday'+w] = String.format(
57611 '<span style="font-size: 16px;"><b>{0}</b></span>'+
57612 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
57614 date.format('Y-m-')+dd
57617 if(typeof(_this.tdata[d]) != 'undefined'){
57618 Roo.each(_this.tdata[d], function(r){
57622 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
57623 if(r.parent_id*1>0){
57624 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
57627 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
57628 deactive = 'de-act-link';
57631 row['weekday'+w] += String.format(
57632 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
57634 r.product_id_name, //1
57635 r.when_dt.format('h:ia'), //2
57645 // only do this if something added..
57647 result.records.push(_this.grid.dataSource.reader.newRow(row));
57651 // push it twice. (second one with an hour..
57655 this.fireEvent("load", this, o, o.request.arg);
57656 o.request.callback.call(o.request.scope, result, o.request.arg, true);
57658 sortInfo : {field: 'when_dt', direction : 'ASC' },
57660 xtype: 'HttpProxy',
57663 url : baseURL + '/Roo/Shop_course.php'
57666 xtype: 'JsonReader',
57683 'name': 'parent_id',
57687 'name': 'product_id',
57691 'name': 'productitem_id',
57709 click : function (_self, e)
57711 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57712 sd.setMonth(sd.getMonth()-1);
57713 _this.monthField.setValue(sd.format('Y-m-d'));
57714 _this.grid.ds.load({});
57720 xtype: 'Separator',
57724 xtype: 'MonthField',
57727 render : function (_self)
57729 _this.monthField = _self;
57730 // _this.monthField.set today
57732 select : function (combo, date)
57734 _this.grid.ds.load({});
57737 value : (function() { return new Date(); })()
57740 xtype: 'Separator',
57746 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
57756 click : function (_self, e)
57758 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57759 sd.setMonth(sd.getMonth()+1);
57760 _this.monthField.setValue(sd.format('Y-m-d'));
57761 _this.grid.ds.load({});
57774 * Ext JS Library 1.1.1
57775 * Copyright(c) 2006-2007, Ext JS, LLC.
57777 * Originally Released Under LGPL - original licence link has changed is not relivant.
57780 * <script type="text/javascript">
57784 * @class Roo.LoadMask
57785 * A simple utility class for generically masking elements while loading data. If the element being masked has
57786 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
57787 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
57788 * element's UpdateManager load indicator and will be destroyed after the initial load.
57790 * Create a new LoadMask
57791 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
57792 * @param {Object} config The config object
57794 Roo.LoadMask = function(el, config){
57795 this.el = Roo.get(el);
57796 Roo.apply(this, config);
57798 this.store.on('beforeload', this.onBeforeLoad, this);
57799 this.store.on('load', this.onLoad, this);
57800 this.store.on('loadexception', this.onLoadException, this);
57801 this.removeMask = false;
57803 var um = this.el.getUpdateManager();
57804 um.showLoadIndicator = false; // disable the default indicator
57805 um.on('beforeupdate', this.onBeforeLoad, this);
57806 um.on('update', this.onLoad, this);
57807 um.on('failure', this.onLoad, this);
57808 this.removeMask = true;
57812 Roo.LoadMask.prototype = {
57814 * @cfg {Boolean} removeMask
57815 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
57816 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
57819 * @cfg {String} msg
57820 * The text to display in a centered loading message box (defaults to 'Loading...')
57822 msg : 'Loading...',
57824 * @cfg {String} msgCls
57825 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
57827 msgCls : 'x-mask-loading',
57830 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
57836 * Disables the mask to prevent it from being displayed
57838 disable : function(){
57839 this.disabled = true;
57843 * Enables the mask so that it can be displayed
57845 enable : function(){
57846 this.disabled = false;
57849 onLoadException : function()
57851 Roo.log(arguments);
57853 if (typeof(arguments[3]) != 'undefined') {
57854 Roo.MessageBox.alert("Error loading",arguments[3]);
57858 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
57859 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
57868 this.el.unmask(this.removeMask);
57871 onLoad : function()
57873 this.el.unmask(this.removeMask);
57877 onBeforeLoad : function(){
57878 if(!this.disabled){
57879 this.el.mask(this.msg, this.msgCls);
57884 destroy : function(){
57886 this.store.un('beforeload', this.onBeforeLoad, this);
57887 this.store.un('load', this.onLoad, this);
57888 this.store.un('loadexception', this.onLoadException, this);
57890 var um = this.el.getUpdateManager();
57891 um.un('beforeupdate', this.onBeforeLoad, this);
57892 um.un('update', this.onLoad, this);
57893 um.un('failure', this.onLoad, this);
57898 * Ext JS Library 1.1.1
57899 * Copyright(c) 2006-2007, Ext JS, LLC.
57901 * Originally Released Under LGPL - original licence link has changed is not relivant.
57904 * <script type="text/javascript">
57909 * @class Roo.XTemplate
57910 * @extends Roo.Template
57911 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
57913 var t = new Roo.XTemplate(
57914 '<select name="{name}">',
57915 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
57919 // then append, applying the master template values
57922 * Supported features:
57927 {a_variable} - output encoded.
57928 {a_variable.format:("Y-m-d")} - call a method on the variable
57929 {a_variable:raw} - unencoded output
57930 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
57931 {a_variable:this.method_on_template(...)} - call a method on the template object.
57936 <tpl for="a_variable or condition.."></tpl>
57937 <tpl if="a_variable or condition"></tpl>
57938 <tpl exec="some javascript"></tpl>
57939 <tpl name="named_template"></tpl> (experimental)
57941 <tpl for="."></tpl> - just iterate the property..
57942 <tpl for=".."></tpl> - iterates with the parent (probably the template)
57946 Roo.XTemplate = function()
57948 Roo.XTemplate.superclass.constructor.apply(this, arguments);
57955 Roo.extend(Roo.XTemplate, Roo.Template, {
57958 * The various sub templates
57963 * basic tag replacing syntax
57966 * // you can fake an object call by doing this
57970 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
57973 * compile the template
57975 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
57978 compile: function()
57982 s = ['<tpl>', s, '</tpl>'].join('');
57984 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
57985 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
57986 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
57987 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
57988 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
57993 while(true == !!(m = s.match(re))){
57994 var forMatch = m[0].match(nameRe),
57995 ifMatch = m[0].match(ifRe),
57996 execMatch = m[0].match(execRe),
57997 namedMatch = m[0].match(namedRe),
58002 name = forMatch && forMatch[1] ? forMatch[1] : '';
58005 // if - puts fn into test..
58006 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58008 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58013 // exec - calls a function... returns empty if true is returned.
58014 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58016 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58024 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58025 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58026 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58029 var uid = namedMatch ? namedMatch[1] : id;
58033 id: namedMatch ? namedMatch[1] : id,
58040 s = s.replace(m[0], '');
58042 s = s.replace(m[0], '{xtpl'+ id + '}');
58047 for(var i = tpls.length-1; i >= 0; --i){
58048 this.compileTpl(tpls[i]);
58049 this.tpls[tpls[i].id] = tpls[i];
58051 this.master = tpls[tpls.length-1];
58055 * same as applyTemplate, except it's done to one of the subTemplates
58056 * when using named templates, you can do:
58058 * var str = pl.applySubTemplate('your-name', values);
58061 * @param {Number} id of the template
58062 * @param {Object} values to apply to template
58063 * @param {Object} parent (normaly the instance of this object)
58065 applySubTemplate : function(id, values, parent)
58069 var t = this.tpls[id];
58073 if(t.test && !t.test.call(this, values, parent)){
58077 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58078 Roo.log(e.toString());
58084 if(t.exec && t.exec.call(this, values, parent)){
58088 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58089 Roo.log(e.toString());
58094 var vs = t.target ? t.target.call(this, values, parent) : values;
58095 parent = t.target ? values : parent;
58096 if(t.target && vs instanceof Array){
58098 for(var i = 0, len = vs.length; i < len; i++){
58099 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58101 return buf.join('');
58103 return t.compiled.call(this, vs, parent);
58105 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58106 Roo.log(e.toString());
58107 Roo.log(t.compiled);
58112 compileTpl : function(tpl)
58114 var fm = Roo.util.Format;
58115 var useF = this.disableFormats !== true;
58116 var sep = Roo.isGecko ? "+" : ",";
58117 var undef = function(str) {
58118 Roo.log("Property not found :" + str);
58122 var fn = function(m, name, format, args)
58124 //Roo.log(arguments);
58125 args = args ? args.replace(/\\'/g,"'") : args;
58126 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58127 if (typeof(format) == 'undefined') {
58128 format= 'htmlEncode';
58130 if (format == 'raw' ) {
58134 if(name.substr(0, 4) == 'xtpl'){
58135 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58138 // build an array of options to determine if value is undefined..
58140 // basically get 'xxxx.yyyy' then do
58141 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58142 // (function () { Roo.log("Property not found"); return ''; })() :
58147 Roo.each(name.split('.'), function(st) {
58148 lookfor += (lookfor.length ? '.': '') + st;
58149 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58152 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58155 if(format && useF){
58157 args = args ? ',' + args : "";
58159 if(format.substr(0, 5) != "this."){
58160 format = "fm." + format + '(';
58162 format = 'this.call("'+ format.substr(5) + '", ';
58166 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58170 // called with xxyx.yuu:(test,test)
58172 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58174 // raw.. - :raw modifier..
58175 return "'"+ sep + udef_st + name + ")"+sep+"'";
58179 // branched to use + in gecko and [].join() in others
58181 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58182 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58185 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58186 body.push(tpl.body.replace(/(\r\n|\n)/g,
58187 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58188 body.push("'].join('');};};");
58189 body = body.join('');
58192 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58194 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58200 applyTemplate : function(values){
58201 return this.master.compiled.call(this, values, {});
58202 //var s = this.subs;
58205 apply : function(){
58206 return this.applyTemplate.apply(this, arguments);
58211 Roo.XTemplate.from = function(el){
58212 el = Roo.getDom(el);
58213 return new Roo.XTemplate(el.value || el.innerHTML);