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..
304 if (c.constructor == ns[c.xtype]) {// already created...
308 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
309 var ret = new ns[c.xtype](c);
313 c.xns = false; // prevent recursion..
317 * Logs to console if it can.
319 * @param {String|Object} string
324 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
331 * 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.
335 urlEncode : function(o){
341 var ov = o[key], k = Roo.encodeURIComponent(key);
342 var type = typeof ov;
343 if(type == 'undefined'){
345 }else if(type != "function" && type != "object"){
346 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
347 }else if(ov instanceof Array){
349 for(var i = 0, len = ov.length; i < len; i++) {
350 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
361 * Safe version of encodeURIComponent
362 * @param {String} data
366 encodeURIComponent : function (data)
369 return encodeURIComponent(data);
370 } catch(e) {} // should be an uri encode error.
372 if (data == '' || data == null){
375 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
376 function nibble_to_hex(nibble){
377 var chars = '0123456789ABCDEF';
378 return chars.charAt(nibble);
380 data = data.toString();
382 for(var i=0; i<data.length; i++){
383 var c = data.charCodeAt(i);
384 var bs = new Array();
387 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
388 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
389 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
390 bs[3] = 0x80 | (c & 0x3F);
391 }else if (c > 0x800){
393 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
394 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
395 bs[2] = 0x80 | (c & 0x3F);
398 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
399 bs[1] = 0x80 | (c & 0x3F);
404 for(var j=0; j<bs.length; j++){
406 var hex = nibble_to_hex((b & 0xF0) >>> 4)
407 + nibble_to_hex(b &0x0F);
416 * 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]}.
417 * @param {String} string
418 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
419 * @return {Object} A literal with members
421 urlDecode : function(string, overwrite){
422 if(!string || !string.length){
426 var pairs = string.split('&');
427 var pair, name, value;
428 for(var i = 0, len = pairs.length; i < len; i++){
429 pair = pairs[i].split('=');
430 name = decodeURIComponent(pair[0]);
431 value = decodeURIComponent(pair[1]);
432 if(overwrite !== true){
433 if(typeof obj[name] == "undefined"){
435 }else if(typeof obj[name] == "string"){
436 obj[name] = [obj[name]];
437 obj[name].push(value);
439 obj[name].push(value);
449 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
450 * passed array is not really an array, your function is called once with it.
451 * The supplied function is called with (Object item, Number index, Array allItems).
452 * @param {Array/NodeList/Mixed} array
453 * @param {Function} fn
454 * @param {Object} scope
456 each : function(array, fn, scope){
457 if(typeof array.length == "undefined" || typeof array == "string"){
460 for(var i = 0, len = array.length; i < len; i++){
461 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
466 combine : function(){
467 var as = arguments, l = as.length, r = [];
468 for(var i = 0; i < l; i++){
470 if(a instanceof Array){
472 }else if(a.length !== undefined && !a.substr){
473 r = r.concat(Array.prototype.slice.call(a, 0));
482 * Escapes the passed string for use in a regular expression
483 * @param {String} str
486 escapeRe : function(s) {
487 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
491 callback : function(cb, scope, args, delay){
492 if(typeof cb == "function"){
494 cb.defer(delay, scope, args || []);
496 cb.apply(scope, args || []);
502 * Return the dom node for the passed string (id), dom node, or Roo.Element
503 * @param {String/HTMLElement/Roo.Element} el
504 * @return HTMLElement
506 getDom : function(el){
510 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
514 * Shorthand for {@link Roo.ComponentMgr#get}
516 * @return Roo.Component
518 getCmp : function(id){
519 return Roo.ComponentMgr.get(id);
522 num : function(v, defaultValue){
523 if(typeof v != 'number'){
529 destroy : function(){
530 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
534 as.removeAllListeners();
538 if(typeof as.purgeListeners == 'function'){
541 if(typeof as.destroy == 'function'){
548 // inpired by a similar function in mootools library
550 * Returns the type of object that is passed in. If the object passed in is null or undefined it
551 * return false otherwise it returns one of the following values:<ul>
552 * <li><b>string</b>: If the object passed is a string</li>
553 * <li><b>number</b>: If the object passed is a number</li>
554 * <li><b>boolean</b>: If the object passed is a boolean value</li>
555 * <li><b>function</b>: If the object passed is a function reference</li>
556 * <li><b>object</b>: If the object passed is an object</li>
557 * <li><b>array</b>: If the object passed is an array</li>
558 * <li><b>regexp</b>: If the object passed is a regular expression</li>
559 * <li><b>element</b>: If the object passed is a DOM Element</li>
560 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
561 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
562 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
563 * @param {Mixed} object
567 if(o === undefined || o === null){
574 if(t == 'object' && o.nodeName) {
576 case 1: return 'element';
577 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
580 if(t == 'object' || t == 'function') {
581 switch(o.constructor) {
582 case Array: return 'array';
583 case RegExp: return 'regexp';
585 if(typeof o.length == 'number' && typeof o.item == 'function') {
593 * Returns true if the passed value is null, undefined or an empty string (optional).
594 * @param {Mixed} value The value to test
595 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
598 isEmpty : function(v, allowBlank){
599 return v === null || v === undefined || (!allowBlank ? v === '' : false);
613 isBorderBox : isBorderBox,
615 isWindows : isWindows,
624 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
625 * you may want to set this to true.
628 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
633 * Selects a single element as a Roo Element
634 * This is about as close as you can get to jQuery's $('do crazy stuff')
635 * @param {String} selector The selector/xpath query
636 * @param {Node} root (optional) The start of the query (defaults to document).
637 * @return {Roo.Element}
639 selectNode : function(selector, root)
641 var node = Roo.DomQuery.selectNode(selector,root);
642 return node ? Roo.get(node) : new Roo.Element(false);
650 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
651 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
654 * Ext JS Library 1.1.1
655 * Copyright(c) 2006-2007, Ext JS, LLC.
657 * Originally Released Under LGPL - original licence link has changed is not relivant.
660 * <script type="text/javascript">
664 // wrappedn so fnCleanup is not in global scope...
666 function fnCleanUp() {
667 var p = Function.prototype;
668 delete p.createSequence;
670 delete p.createDelegate;
671 delete p.createCallback;
672 delete p.createInterceptor;
674 window.detachEvent("onunload", fnCleanUp);
676 window.attachEvent("onunload", fnCleanUp);
683 * These functions are available on every Function object (any JavaScript function).
685 Roo.apply(Function.prototype, {
687 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
688 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
689 * Will create a function that is bound to those 2 args.
690 * @return {Function} The new function
692 createCallback : function(/*args...*/){
693 // make args available, in function below
694 var args = arguments;
697 return method.apply(window, args);
702 * Creates a delegate (callback) that sets the scope to obj.
703 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
704 * Will create a function that is automatically scoped to this.
705 * @param {Object} obj (optional) The object for which the scope is set
706 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
707 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
708 * if a number the args are inserted at the specified position
709 * @return {Function} The new function
711 createDelegate : function(obj, args, appendArgs){
714 var callArgs = args || arguments;
715 if(appendArgs === true){
716 callArgs = Array.prototype.slice.call(arguments, 0);
717 callArgs = callArgs.concat(args);
718 }else if(typeof appendArgs == "number"){
719 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
720 var applyArgs = [appendArgs, 0].concat(args); // create method call params
721 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
723 return method.apply(obj || window, callArgs);
728 * Calls this function after the number of millseconds specified.
729 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
730 * @param {Object} obj (optional) The object for which the scope is set
731 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
732 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
733 * if a number the args are inserted at the specified position
734 * @return {Number} The timeout id that can be used with clearTimeout
736 defer : function(millis, obj, args, appendArgs){
737 var fn = this.createDelegate(obj, args, appendArgs);
739 return setTimeout(fn, millis);
745 * Create a combined function call sequence of the original function + the passed function.
746 * The resulting function returns the results of the original function.
747 * The passed fcn is called with the parameters of the original function
748 * @param {Function} fcn The function to sequence
749 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
750 * @return {Function} The new function
752 createSequence : function(fcn, scope){
753 if(typeof fcn != "function"){
758 var retval = method.apply(this || window, arguments);
759 fcn.apply(scope || this || window, arguments);
765 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
766 * The resulting function returns the results of the original function.
767 * The passed fcn is called with the parameters of the original function.
769 * @param {Function} fcn The function to call before the original
770 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
771 * @return {Function} The new function
773 createInterceptor : function(fcn, scope){
774 if(typeof fcn != "function"){
781 if(fcn.apply(scope || this || window, arguments) === false){
784 return method.apply(this || window, arguments);
790 * Ext JS Library 1.1.1
791 * Copyright(c) 2006-2007, Ext JS, LLC.
793 * Originally Released Under LGPL - original licence link has changed is not relivant.
796 * <script type="text/javascript">
799 Roo.applyIf(String, {
804 * Escapes the passed string for ' and \
805 * @param {String} string The string to escape
806 * @return {String} The escaped string
809 escape : function(string) {
810 return string.replace(/('|\\)/g, "\\$1");
814 * Pads the left side of a string with a specified character. This is especially useful
815 * for normalizing number and date strings. Example usage:
817 var s = String.leftPad('123', 5, '0');
818 // s now contains the string: '00123'
820 * @param {String} string The original string
821 * @param {Number} size The total length of the output string
822 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
823 * @return {String} The padded string
826 leftPad : function (val, size, ch) {
827 var result = new String(val);
828 if(ch === null || ch === undefined || ch === '') {
831 while (result.length < size) {
832 result = ch + result;
838 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
839 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
841 var cls = 'my-class', text = 'Some text';
842 var s = String.format('<div class="{0}">{1}</div>', cls, text);
843 // s now contains the string: '<div class="my-class">Some text</div>'
845 * @param {String} string The tokenized string to be formatted
846 * @param {String} value1 The value to replace token {0}
847 * @param {String} value2 Etc...
848 * @return {String} The formatted string
851 format : function(format){
852 var args = Array.prototype.slice.call(arguments, 1);
853 return format.replace(/\{(\d+)\}/g, function(m, i){
854 return Roo.util.Format.htmlEncode(args[i]);
860 * Utility function that allows you to easily switch a string between two alternating values. The passed value
861 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
862 * they are already different, the first value passed in is returned. Note that this method returns the new value
863 * but does not change the current string.
865 // alternate sort directions
866 sort = sort.toggle('ASC', 'DESC');
868 // instead of conditional logic:
869 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
871 * @param {String} value The value to compare to the current string
872 * @param {String} other The new value to use if the string already equals the first value passed in
873 * @return {String} The new value
876 String.prototype.toggle = function(value, other){
877 return this == value ? other : value;
880 * Ext JS Library 1.1.1
881 * Copyright(c) 2006-2007, Ext JS, LLC.
883 * Originally Released Under LGPL - original licence link has changed is not relivant.
886 * <script type="text/javascript">
892 Roo.applyIf(Number.prototype, {
894 * Checks whether or not the current number is within a desired range. If the number is already within the
895 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
896 * exceeded. Note that this method returns the constrained value but does not change the current number.
897 * @param {Number} min The minimum number in the range
898 * @param {Number} max The maximum number in the range
899 * @return {Number} The constrained value if outside the range, otherwise the current value
901 constrain : function(min, max){
902 return Math.min(Math.max(this, min), max);
906 * Ext JS Library 1.1.1
907 * Copyright(c) 2006-2007, Ext JS, LLC.
909 * Originally Released Under LGPL - original licence link has changed is not relivant.
912 * <script type="text/javascript">
917 Roo.applyIf(Array.prototype, {
919 * Checks whether or not the specified object exists in the array.
920 * @param {Object} o The object to check for
921 * @return {Number} The index of o in the array (or -1 if it is not found)
923 indexOf : function(o){
924 for (var i = 0, len = this.length; i < len; i++){
925 if(this[i] == o) return i;
931 * Removes the specified object from the array. If the object is not found nothing happens.
932 * @param {Object} o The object to remove
934 remove : function(o){
935 var index = this.indexOf(o);
937 this.splice(index, 1);
941 * Map (JS 1.6 compatibility)
942 * @param {Function} function to call
946 var len = this.length >>> 0;
947 if (typeof fun != "function")
948 throw new TypeError();
950 var res = new Array(len);
951 var thisp = arguments[1];
952 for (var i = 0; i < len; i++)
955 res[i] = fun.call(thisp, this[i], i, this);
966 * Ext JS Library 1.1.1
967 * Copyright(c) 2006-2007, Ext JS, LLC.
969 * Originally Released Under LGPL - original licence link has changed is not relivant.
972 * <script type="text/javascript">
978 * The date parsing and format syntax is a subset of
979 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
980 * supported will provide results equivalent to their PHP versions.
982 * Following is the list of all currently supported formats:
985 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
987 Format Output Description
988 ------ ---------- --------------------------------------------------------------
989 d 10 Day of the month, 2 digits with leading zeros
990 D Wed A textual representation of a day, three letters
991 j 10 Day of the month without leading zeros
992 l Wednesday A full textual representation of the day of the week
993 S th English ordinal day of month suffix, 2 chars (use with j)
994 w 3 Numeric representation of the day of the week
995 z 9 The julian date, or day of the year (0-365)
996 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
997 F January A full textual representation of the month
998 m 01 Numeric representation of a month, with leading zeros
999 M Jan Month name abbreviation, three letters
1000 n 1 Numeric representation of a month, without leading zeros
1001 t 31 Number of days in the given month
1002 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1003 Y 2007 A full numeric representation of a year, 4 digits
1004 y 07 A two digit representation of a year
1005 a pm Lowercase Ante meridiem and Post meridiem
1006 A PM Uppercase Ante meridiem and Post meridiem
1007 g 3 12-hour format of an hour without leading zeros
1008 G 15 24-hour format of an hour without leading zeros
1009 h 03 12-hour format of an hour with leading zeros
1010 H 15 24-hour format of an hour with leading zeros
1011 i 05 Minutes with leading zeros
1012 s 01 Seconds, with leading zeros
1013 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1014 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1015 T CST Timezone setting of the machine running the code
1016 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1019 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1021 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1022 document.write(dt.format('Y-m-d')); //2007-01-10
1023 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1024 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
1027 * Here are some standard date/time patterns that you might find helpful. They
1028 * are not part of the source of Date.js, but to use them you can simply copy this
1029 * block of code into any script that is included after Date.js and they will also become
1030 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1033 ISO8601Long:"Y-m-d H:i:s",
1034 ISO8601Short:"Y-m-d",
1036 LongDate: "l, F d, Y",
1037 FullDateTime: "l, F d, Y g:i:s A",
1040 LongTime: "g:i:s A",
1041 SortableDateTime: "Y-m-d\\TH:i:s",
1042 UniversalSortableDateTime: "Y-m-d H:i:sO",
1049 var dt = new Date();
1050 document.write(dt.format(Date.patterns.ShortDate));
1055 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1056 * They generate precompiled functions from date formats instead of parsing and
1057 * processing the pattern every time you format a date. These functions are available
1058 * on every Date object (any javascript function).
1060 * The original article and download are here:
1061 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1068 Returns the number of milliseconds between this date and date
1069 @param {Date} date (optional) Defaults to now
1070 @return {Number} The diff in milliseconds
1071 @member Date getElapsed
1073 Date.prototype.getElapsed = function(date) {
1074 return Math.abs((date || new Date()).getTime()-this.getTime());
1076 // was in date file..
1080 Date.parseFunctions = {count:0};
1082 Date.parseRegexes = [];
1084 Date.formatFunctions = {count:0};
1087 Date.prototype.dateFormat = function(format) {
1088 if (Date.formatFunctions[format] == null) {
1089 Date.createNewFormat(format);
1091 var func = Date.formatFunctions[format];
1092 return this[func]();
1097 * Formats a date given the supplied format string
1098 * @param {String} format The format string
1099 * @return {String} The formatted date
1102 Date.prototype.format = Date.prototype.dateFormat;
1105 Date.createNewFormat = function(format) {
1106 var funcName = "format" + Date.formatFunctions.count++;
1107 Date.formatFunctions[format] = funcName;
1108 var code = "Date.prototype." + funcName + " = function(){return ";
1109 var special = false;
1111 for (var i = 0; i < format.length; ++i) {
1112 ch = format.charAt(i);
1113 if (!special && ch == "\\") {
1118 code += "'" + String.escape(ch) + "' + ";
1121 code += Date.getFormatCode(ch);
1124 /** eval:var:zzzzzzzzzzzzz */
1125 eval(code.substring(0, code.length - 3) + ";}");
1129 Date.getFormatCode = function(character) {
1130 switch (character) {
1132 return "String.leftPad(this.getDate(), 2, '0') + ";
1134 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1136 return "this.getDate() + ";
1138 return "Date.dayNames[this.getDay()] + ";
1140 return "this.getSuffix() + ";
1142 return "this.getDay() + ";
1144 return "this.getDayOfYear() + ";
1146 return "this.getWeekOfYear() + ";
1148 return "Date.monthNames[this.getMonth()] + ";
1150 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1152 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1154 return "(this.getMonth() + 1) + ";
1156 return "this.getDaysInMonth() + ";
1158 return "(this.isLeapYear() ? 1 : 0) + ";
1160 return "this.getFullYear() + ";
1162 return "('' + this.getFullYear()).substring(2, 4) + ";
1164 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1166 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1168 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1170 return "this.getHours() + ";
1172 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1174 return "String.leftPad(this.getHours(), 2, '0') + ";
1176 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1178 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1180 return "this.getGMTOffset() + ";
1182 return "this.getGMTColonOffset() + ";
1184 return "this.getTimezone() + ";
1186 return "(this.getTimezoneOffset() * -60) + ";
1188 return "'" + String.escape(character) + "' + ";
1193 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1194 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1195 * the date format that is not specified will default to the current date value for that part. Time parts can also
1196 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1197 * string or the parse operation will fail.
1200 //dt = Fri May 25 2007 (current date)
1201 var dt = new Date();
1203 //dt = Thu May 25 2006 (today's month/day in 2006)
1204 dt = Date.parseDate("2006", "Y");
1206 //dt = Sun Jan 15 2006 (all date parts specified)
1207 dt = Date.parseDate("2006-1-15", "Y-m-d");
1209 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1210 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1212 * @param {String} input The unparsed date as a string
1213 * @param {String} format The format the date is in
1214 * @return {Date} The parsed date
1217 Date.parseDate = function(input, format) {
1218 if (Date.parseFunctions[format] == null) {
1219 Date.createParser(format);
1221 var func = Date.parseFunctions[format];
1222 return Date[func](input);
1227 Date.createParser = function(format) {
1228 var funcName = "parse" + Date.parseFunctions.count++;
1229 var regexNum = Date.parseRegexes.length;
1230 var currentGroup = 1;
1231 Date.parseFunctions[format] = funcName;
1233 var code = "Date." + funcName + " = function(input){\n"
1234 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1235 + "var d = new Date();\n"
1236 + "y = d.getFullYear();\n"
1237 + "m = d.getMonth();\n"
1238 + "d = d.getDate();\n"
1239 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1240 + "if (results && results.length > 0) {";
1243 var special = false;
1245 for (var i = 0; i < format.length; ++i) {
1246 ch = format.charAt(i);
1247 if (!special && ch == "\\") {
1252 regex += String.escape(ch);
1255 var obj = Date.formatCodeToRegex(ch, currentGroup);
1256 currentGroup += obj.g;
1258 if (obj.g && obj.c) {
1264 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1265 + "{v = new Date(y, m, d, h, i, s);}\n"
1266 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1267 + "{v = new Date(y, m, d, h, i);}\n"
1268 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1269 + "{v = new Date(y, m, d, h);}\n"
1270 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1271 + "{v = new Date(y, m, d);}\n"
1272 + "else if (y >= 0 && m >= 0)\n"
1273 + "{v = new Date(y, m);}\n"
1274 + "else if (y >= 0)\n"
1275 + "{v = new Date(y);}\n"
1276 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1277 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1278 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1281 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1282 /** eval:var:zzzzzzzzzzzzz */
1287 Date.formatCodeToRegex = function(character, currentGroup) {
1288 switch (character) {
1292 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1295 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1296 s:"(\\d{1,2})"}; // day of month without leading zeroes
1299 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1300 s:"(\\d{2})"}; // day of month with leading zeroes
1304 s:"(?:" + Date.dayNames.join("|") + ")"};
1308 s:"(?:st|nd|rd|th)"};
1323 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1324 s:"(" + Date.monthNames.join("|") + ")"};
1327 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1328 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1331 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1332 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1335 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1336 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1347 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1351 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1352 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1356 c:"if (results[" + currentGroup + "] == 'am') {\n"
1357 + "if (h == 12) { h = 0; }\n"
1358 + "} else { if (h < 12) { h += 12; }}",
1362 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1363 + "if (h == 12) { h = 0; }\n"
1364 + "} else { if (h < 12) { h += 12; }}",
1369 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1370 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1374 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1375 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1378 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1382 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1387 "o = results[", currentGroup, "];\n",
1388 "var sn = o.substring(0,1);\n", // get + / - sign
1389 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1390 "var mn = o.substring(3,5) % 60;\n", // get minutes
1391 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1392 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1394 s:"([+\-]\\d{2,4})"};
1400 "o = results[", currentGroup, "];\n",
1401 "var sn = o.substring(0,1);\n",
1402 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1403 "var mn = o.substring(4,6) % 60;\n",
1404 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1405 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1411 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1414 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1415 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1416 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1420 s:String.escape(character)};
1425 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1426 * @return {String} The abbreviated timezone name (e.g. 'CST')
1428 Date.prototype.getTimezone = function() {
1429 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1433 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1434 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1436 Date.prototype.getGMTOffset = function() {
1437 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1438 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1439 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1443 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1444 * @return {String} 2-characters representing hours and 2-characters representing minutes
1445 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1447 Date.prototype.getGMTColonOffset = function() {
1448 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1449 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1451 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1455 * Get the numeric day number of the year, adjusted for leap year.
1456 * @return {Number} 0 through 364 (365 in leap years)
1458 Date.prototype.getDayOfYear = function() {
1460 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1461 for (var i = 0; i < this.getMonth(); ++i) {
1462 num += Date.daysInMonth[i];
1464 return num + this.getDate() - 1;
1468 * Get the string representation of the numeric week number of the year
1469 * (equivalent to the format specifier 'W').
1470 * @return {String} '00' through '52'
1472 Date.prototype.getWeekOfYear = function() {
1473 // Skip to Thursday of this week
1474 var now = this.getDayOfYear() + (4 - this.getDay());
1475 // Find the first Thursday of the year
1476 var jan1 = new Date(this.getFullYear(), 0, 1);
1477 var then = (7 - jan1.getDay() + 4);
1478 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1482 * Whether or not the current date is in a leap year.
1483 * @return {Boolean} True if the current date is in a leap year, else false
1485 Date.prototype.isLeapYear = function() {
1486 var year = this.getFullYear();
1487 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1491 * Get the first day of the current month, adjusted for leap year. The returned value
1492 * is the numeric day index within the week (0-6) which can be used in conjunction with
1493 * the {@link #monthNames} array to retrieve the textual day name.
1496 var dt = new Date('1/10/2007');
1497 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1499 * @return {Number} The day number (0-6)
1501 Date.prototype.getFirstDayOfMonth = function() {
1502 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1503 return (day < 0) ? (day + 7) : day;
1507 * Get the last day of the current month, adjusted for leap year. The returned value
1508 * is the numeric day index within the week (0-6) which can be used in conjunction with
1509 * the {@link #monthNames} array to retrieve the textual day name.
1512 var dt = new Date('1/10/2007');
1513 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1515 * @return {Number} The day number (0-6)
1517 Date.prototype.getLastDayOfMonth = function() {
1518 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1519 return (day < 0) ? (day + 7) : day;
1524 * Get the first date of this date's month
1527 Date.prototype.getFirstDateOfMonth = function() {
1528 return new Date(this.getFullYear(), this.getMonth(), 1);
1532 * Get the last date of this date's month
1535 Date.prototype.getLastDateOfMonth = function() {
1536 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1539 * Get the number of days in the current month, adjusted for leap year.
1540 * @return {Number} The number of days in the month
1542 Date.prototype.getDaysInMonth = function() {
1543 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1544 return Date.daysInMonth[this.getMonth()];
1548 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1549 * @return {String} 'st, 'nd', 'rd' or 'th'
1551 Date.prototype.getSuffix = function() {
1552 switch (this.getDate()) {
1569 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1572 * An array of textual month names.
1573 * Override these values for international dates, for example...
1574 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1593 * An array of textual day names.
1594 * Override these values for international dates, for example...
1595 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1611 Date.monthNumbers = {
1626 * Creates and returns a new Date instance with the exact same date value as the called instance.
1627 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1628 * variable will also be changed. When the intention is to create a new variable that will not
1629 * modify the original instance, you should create a clone.
1631 * Example of correctly cloning a date:
1634 var orig = new Date('10/1/2006');
1637 document.write(orig); //returns 'Thu Oct 05 2006'!
1640 var orig = new Date('10/1/2006');
1641 var copy = orig.clone();
1643 document.write(orig); //returns 'Thu Oct 01 2006'
1645 * @return {Date} The new Date instance
1647 Date.prototype.clone = function() {
1648 return new Date(this.getTime());
1652 * Clears any time information from this date
1653 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1654 @return {Date} this or the clone
1656 Date.prototype.clearTime = function(clone){
1658 return this.clone().clearTime();
1663 this.setMilliseconds(0);
1668 // safari setMonth is broken
1670 Date.brokenSetMonth = Date.prototype.setMonth;
1671 Date.prototype.setMonth = function(num){
1673 var n = Math.ceil(-num);
1674 var back_year = Math.ceil(n/12);
1675 var month = (n % 12) ? 12 - n % 12 : 0 ;
1676 this.setFullYear(this.getFullYear() - back_year);
1677 return Date.brokenSetMonth.call(this, month);
1679 return Date.brokenSetMonth.apply(this, arguments);
1684 /** Date interval constant
1688 /** Date interval constant
1692 /** Date interval constant
1696 /** Date interval constant
1700 /** Date interval constant
1704 /** Date interval constant
1708 /** Date interval constant
1714 * Provides a convenient method of performing basic date arithmetic. This method
1715 * does not modify the Date instance being called - it creates and returns
1716 * a new Date instance containing the resulting date value.
1721 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1722 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1724 //Negative values will subtract correctly:
1725 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1726 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1728 //You can even chain several calls together in one line!
1729 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1730 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1733 * @param {String} interval A valid date interval enum value
1734 * @param {Number} value The amount to add to the current date
1735 * @return {Date} The new Date instance
1737 Date.prototype.add = function(interval, value){
1738 var d = this.clone();
1739 if (!interval || value === 0) return d;
1740 switch(interval.toLowerCase()){
1742 d.setMilliseconds(this.getMilliseconds() + value);
1745 d.setSeconds(this.getSeconds() + value);
1748 d.setMinutes(this.getMinutes() + value);
1751 d.setHours(this.getHours() + value);
1754 d.setDate(this.getDate() + value);
1757 var day = this.getDate();
1759 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1762 d.setMonth(this.getMonth() + value);
1765 d.setFullYear(this.getFullYear() + value);
1772 * Ext JS Library 1.1.1
1773 * Copyright(c) 2006-2007, Ext JS, LLC.
1775 * Originally Released Under LGPL - original licence link has changed is not relivant.
1778 * <script type="text/javascript">
1782 * @class Roo.lib.Dom
1785 * Dom utils (from YIU afaik)
1790 * Get the view width
1791 * @param {Boolean} full True will get the full document, otherwise it's the view width
1792 * @return {Number} The width
1795 getViewWidth : function(full) {
1796 return full ? this.getDocumentWidth() : this.getViewportWidth();
1799 * Get the view height
1800 * @param {Boolean} full True will get the full document, otherwise it's the view height
1801 * @return {Number} The height
1803 getViewHeight : function(full) {
1804 return full ? this.getDocumentHeight() : this.getViewportHeight();
1807 getDocumentHeight: function() {
1808 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1809 return Math.max(scrollHeight, this.getViewportHeight());
1812 getDocumentWidth: function() {
1813 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1814 return Math.max(scrollWidth, this.getViewportWidth());
1817 getViewportHeight: function() {
1818 var height = self.innerHeight;
1819 var mode = document.compatMode;
1821 if ((mode || Roo.isIE) && !Roo.isOpera) {
1822 height = (mode == "CSS1Compat") ?
1823 document.documentElement.clientHeight :
1824 document.body.clientHeight;
1830 getViewportWidth: function() {
1831 var width = self.innerWidth;
1832 var mode = document.compatMode;
1834 if (mode || Roo.isIE) {
1835 width = (mode == "CSS1Compat") ?
1836 document.documentElement.clientWidth :
1837 document.body.clientWidth;
1842 isAncestor : function(p, c) {
1849 if (p.contains && !Roo.isSafari) {
1850 return p.contains(c);
1851 } else if (p.compareDocumentPosition) {
1852 return !!(p.compareDocumentPosition(c) & 16);
1854 var parent = c.parentNode;
1859 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1862 parent = parent.parentNode;
1868 getRegion : function(el) {
1869 return Roo.lib.Region.getRegion(el);
1872 getY : function(el) {
1873 return this.getXY(el)[1];
1876 getX : function(el) {
1877 return this.getXY(el)[0];
1880 getXY : function(el) {
1881 var p, pe, b, scroll, bd = document.body;
1882 el = Roo.getDom(el);
1883 var fly = Roo.lib.AnimBase.fly;
1884 if (el.getBoundingClientRect) {
1885 b = el.getBoundingClientRect();
1886 scroll = fly(document).getScroll();
1887 return [b.left + scroll.left, b.top + scroll.top];
1893 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1900 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1907 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1908 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1915 if (p != el && pe.getStyle('overflow') != 'visible') {
1923 if (Roo.isSafari && hasAbsolute) {
1928 if (Roo.isGecko && !hasAbsolute) {
1930 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1931 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1935 while (p && p != bd) {
1936 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1948 setXY : function(el, xy) {
1949 el = Roo.fly(el, '_setXY');
1951 var pts = el.translatePoints(xy);
1952 if (xy[0] !== false) {
1953 el.dom.style.left = pts.left + "px";
1955 if (xy[1] !== false) {
1956 el.dom.style.top = pts.top + "px";
1960 setX : function(el, x) {
1961 this.setXY(el, [x, false]);
1964 setY : function(el, y) {
1965 this.setXY(el, [false, y]);
1969 * Portions of this file are based on pieces of Yahoo User Interface Library
1970 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1971 * YUI licensed under the BSD License:
1972 * http://developer.yahoo.net/yui/license.txt
1973 * <script type="text/javascript">
1977 Roo.lib.Event = function() {
1978 var loadComplete = false;
1980 var unloadListeners = [];
1982 var onAvailStack = [];
1984 var lastError = null;
1997 startInterval: function() {
1998 if (!this._interval) {
2000 var callback = function() {
2001 self._tryPreloadAttach();
2003 this._interval = setInterval(callback, this.POLL_INTERVAL);
2008 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2009 onAvailStack.push({ id: p_id,
2012 override: p_override,
2013 checkReady: false });
2015 retryCount = this.POLL_RETRYS;
2016 this.startInterval();
2020 addListener: function(el, eventName, fn) {
2021 el = Roo.getDom(el);
2026 if ("unload" == eventName) {
2027 unloadListeners[unloadListeners.length] =
2028 [el, eventName, fn];
2032 var wrappedFn = function(e) {
2033 return fn(Roo.lib.Event.getEvent(e));
2036 var li = [el, eventName, fn, wrappedFn];
2038 var index = listeners.length;
2039 listeners[index] = li;
2041 this.doAdd(el, eventName, wrappedFn, false);
2047 removeListener: function(el, eventName, fn) {
2050 el = Roo.getDom(el);
2053 return this.purgeElement(el, false, eventName);
2057 if ("unload" == eventName) {
2059 for (i = 0,len = unloadListeners.length; i < len; i++) {
2060 var li = unloadListeners[i];
2063 li[1] == eventName &&
2065 unloadListeners.splice(i, 1);
2073 var cacheItem = null;
2076 var index = arguments[3];
2078 if ("undefined" == typeof index) {
2079 index = this._getCacheIndex(el, eventName, fn);
2083 cacheItem = listeners[index];
2086 if (!el || !cacheItem) {
2090 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2092 delete listeners[index][this.WFN];
2093 delete listeners[index][this.FN];
2094 listeners.splice(index, 1);
2101 getTarget: function(ev, resolveTextNode) {
2102 ev = ev.browserEvent || ev;
2103 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2104 var t = ev.target || ev.srcElement;
2105 return this.resolveTextNode(t);
2109 resolveTextNode: function(node) {
2110 if (Roo.isSafari && node && 3 == node.nodeType) {
2111 return node.parentNode;
2118 getPageX: function(ev) {
2119 ev = ev.browserEvent || ev;
2120 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2122 if (!x && 0 !== x) {
2123 x = ev.clientX || 0;
2126 x += this.getScroll()[1];
2134 getPageY: function(ev) {
2135 ev = ev.browserEvent || ev;
2136 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2138 if (!y && 0 !== y) {
2139 y = ev.clientY || 0;
2142 y += this.getScroll()[0];
2151 getXY: function(ev) {
2152 ev = ev.browserEvent || ev;
2153 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2154 return [this.getPageX(ev), this.getPageY(ev)];
2158 getRelatedTarget: function(ev) {
2159 ev = ev.browserEvent || ev;
2160 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2161 var t = ev.relatedTarget;
2163 if (ev.type == "mouseout") {
2165 } else if (ev.type == "mouseover") {
2170 return this.resolveTextNode(t);
2174 getTime: function(ev) {
2175 ev = ev.browserEvent || ev;
2176 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2178 var t = new Date().getTime();
2182 this.lastError = ex;
2191 stopEvent: function(ev) {
2192 this.stopPropagation(ev);
2193 this.preventDefault(ev);
2197 stopPropagation: function(ev) {
2198 ev = ev.browserEvent || ev;
2199 if (ev.stopPropagation) {
2200 ev.stopPropagation();
2202 ev.cancelBubble = true;
2207 preventDefault: function(ev) {
2208 ev = ev.browserEvent || ev;
2209 if(ev.preventDefault) {
2210 ev.preventDefault();
2212 ev.returnValue = false;
2217 getEvent: function(e) {
2218 var ev = e || window.event;
2220 var c = this.getEvent.caller;
2222 ev = c.arguments[0];
2223 if (ev && Event == ev.constructor) {
2233 getCharCode: function(ev) {
2234 ev = ev.browserEvent || ev;
2235 return ev.charCode || ev.keyCode || 0;
2239 _getCacheIndex: function(el, eventName, fn) {
2240 for (var i = 0,len = listeners.length; i < len; ++i) {
2241 var li = listeners[i];
2243 li[this.FN] == fn &&
2244 li[this.EL] == el &&
2245 li[this.TYPE] == eventName) {
2257 getEl: function(id) {
2258 return document.getElementById(id);
2262 clearCache: function() {
2266 _load: function(e) {
2267 loadComplete = true;
2268 var EU = Roo.lib.Event;
2272 EU.doRemove(window, "load", EU._load);
2277 _tryPreloadAttach: function() {
2286 var tryAgain = !loadComplete;
2288 tryAgain = (retryCount > 0);
2293 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2294 var item = onAvailStack[i];
2296 var el = this.getEl(item.id);
2299 if (!item.checkReady ||
2302 (document && document.body)) {
2305 if (item.override) {
2306 if (item.override === true) {
2309 scope = item.override;
2312 item.fn.call(scope, item.obj);
2313 onAvailStack[i] = null;
2316 notAvail.push(item);
2321 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2325 this.startInterval();
2327 clearInterval(this._interval);
2328 this._interval = null;
2331 this.locked = false;
2338 purgeElement: function(el, recurse, eventName) {
2339 var elListeners = this.getListeners(el, eventName);
2341 for (var i = 0,len = elListeners.length; i < len; ++i) {
2342 var l = elListeners[i];
2343 this.removeListener(el, l.type, l.fn);
2347 if (recurse && el && el.childNodes) {
2348 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2349 this.purgeElement(el.childNodes[i], recurse, eventName);
2355 getListeners: function(el, eventName) {
2356 var results = [], searchLists;
2358 searchLists = [listeners, unloadListeners];
2359 } else if (eventName == "unload") {
2360 searchLists = [unloadListeners];
2362 searchLists = [listeners];
2365 for (var j = 0; j < searchLists.length; ++j) {
2366 var searchList = searchLists[j];
2367 if (searchList && searchList.length > 0) {
2368 for (var i = 0,len = searchList.length; i < len; ++i) {
2369 var l = searchList[i];
2370 if (l && l[this.EL] === el &&
2371 (!eventName || eventName === l[this.TYPE])) {
2376 adjust: l[this.ADJ_SCOPE],
2384 return (results.length) ? results : null;
2388 _unload: function(e) {
2390 var EU = Roo.lib.Event, i, j, l, len, index;
2392 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2393 l = unloadListeners[i];
2396 if (l[EU.ADJ_SCOPE]) {
2397 if (l[EU.ADJ_SCOPE] === true) {
2400 scope = l[EU.ADJ_SCOPE];
2403 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2404 unloadListeners[i] = null;
2410 unloadListeners = null;
2412 if (listeners && listeners.length > 0) {
2413 j = listeners.length;
2416 l = listeners[index];
2418 EU.removeListener(l[EU.EL], l[EU.TYPE],
2428 EU.doRemove(window, "unload", EU._unload);
2433 getScroll: function() {
2434 var dd = document.documentElement, db = document.body;
2435 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2436 return [dd.scrollTop, dd.scrollLeft];
2438 return [db.scrollTop, db.scrollLeft];
2445 doAdd: function () {
2446 if (window.addEventListener) {
2447 return function(el, eventName, fn, capture) {
2448 el.addEventListener(eventName, fn, (capture));
2450 } else if (window.attachEvent) {
2451 return function(el, eventName, fn, capture) {
2452 el.attachEvent("on" + eventName, fn);
2461 doRemove: function() {
2462 if (window.removeEventListener) {
2463 return function (el, eventName, fn, capture) {
2464 el.removeEventListener(eventName, fn, (capture));
2466 } else if (window.detachEvent) {
2467 return function (el, eventName, fn) {
2468 el.detachEvent("on" + eventName, fn);
2480 var E = Roo.lib.Event;
2481 E.on = E.addListener;
2482 E.un = E.removeListener;
2484 if (document && document.body) {
2487 E.doAdd(window, "load", E._load);
2489 E.doAdd(window, "unload", E._unload);
2490 E._tryPreloadAttach();
2494 * Portions of this file are based on pieces of Yahoo User Interface Library
2495 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2496 * YUI licensed under the BSD License:
2497 * http://developer.yahoo.net/yui/license.txt
2498 * <script type="text/javascript">
2504 * @class Roo.lib.Ajax
2511 request : function(method, uri, cb, data, options) {
2513 var hs = options.headers;
2516 if(hs.hasOwnProperty(h)){
2517 this.initHeader(h, hs[h], false);
2521 if(options.xmlData){
2522 this.initHeader('Content-Type', 'text/xml', false);
2524 data = options.xmlData;
2528 return this.asyncRequest(method, uri, cb, data);
2531 serializeForm : function(form) {
2532 if(typeof form == 'string') {
2533 form = (document.getElementById(form) || document.forms[form]);
2536 var el, name, val, disabled, data = '', hasSubmit = false;
2537 for (var i = 0; i < form.elements.length; i++) {
2538 el = form.elements[i];
2539 disabled = form.elements[i].disabled;
2540 name = form.elements[i].name;
2541 val = form.elements[i].value;
2543 if (!disabled && name){
2547 case 'select-multiple':
2548 for (var j = 0; j < el.options.length; j++) {
2549 if (el.options[j].selected) {
2551 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2554 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2562 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2575 if(hasSubmit == false) {
2576 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2581 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2586 data = data.substr(0, data.length - 1);
2594 useDefaultHeader:true,
2596 defaultPostHeader:'application/x-www-form-urlencoded',
2598 useDefaultXhrHeader:true,
2600 defaultXhrHeader:'XMLHttpRequest',
2602 hasDefaultHeaders:true,
2614 setProgId:function(id)
2616 this.activeX.unshift(id);
2619 setDefaultPostHeader:function(b)
2621 this.useDefaultHeader = b;
2624 setDefaultXhrHeader:function(b)
2626 this.useDefaultXhrHeader = b;
2629 setPollingInterval:function(i)
2631 if (typeof i == 'number' && isFinite(i)) {
2632 this.pollInterval = i;
2636 createXhrObject:function(transactionId)
2642 http = new XMLHttpRequest();
2644 obj = { conn:http, tId:transactionId };
2648 for (var i = 0; i < this.activeX.length; ++i) {
2652 http = new ActiveXObject(this.activeX[i]);
2654 obj = { conn:http, tId:transactionId };
2667 getConnectionObject:function()
2670 var tId = this.transactionId;
2674 o = this.createXhrObject(tId);
2676 this.transactionId++;
2687 asyncRequest:function(method, uri, callback, postData)
2689 var o = this.getConnectionObject();
2695 o.conn.open(method, uri, true);
2697 if (this.useDefaultXhrHeader) {
2698 if (!this.defaultHeaders['X-Requested-With']) {
2699 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2703 if(postData && this.useDefaultHeader){
2704 this.initHeader('Content-Type', this.defaultPostHeader);
2707 if (this.hasDefaultHeaders || this.hasHeaders) {
2711 this.handleReadyState(o, callback);
2712 o.conn.send(postData || null);
2718 handleReadyState:function(o, callback)
2722 if (callback && callback.timeout) {
2724 this.timeout[o.tId] = window.setTimeout(function() {
2725 oConn.abort(o, callback, true);
2726 }, callback.timeout);
2729 this.poll[o.tId] = window.setInterval(
2731 if (o.conn && o.conn.readyState == 4) {
2732 window.clearInterval(oConn.poll[o.tId]);
2733 delete oConn.poll[o.tId];
2735 if(callback && callback.timeout) {
2736 window.clearTimeout(oConn.timeout[o.tId]);
2737 delete oConn.timeout[o.tId];
2740 oConn.handleTransactionResponse(o, callback);
2743 , this.pollInterval);
2746 handleTransactionResponse:function(o, callback, isAbort)
2750 this.releaseObject(o);
2754 var httpStatus, responseObject;
2758 if (o.conn.status !== undefined && o.conn.status != 0) {
2759 httpStatus = o.conn.status;
2771 if (httpStatus >= 200 && httpStatus < 300) {
2772 responseObject = this.createResponseObject(o, callback.argument);
2773 if (callback.success) {
2774 if (!callback.scope) {
2775 callback.success(responseObject);
2780 callback.success.apply(callback.scope, [responseObject]);
2785 switch (httpStatus) {
2793 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2794 if (callback.failure) {
2795 if (!callback.scope) {
2796 callback.failure(responseObject);
2799 callback.failure.apply(callback.scope, [responseObject]);
2804 responseObject = this.createResponseObject(o, callback.argument);
2805 if (callback.failure) {
2806 if (!callback.scope) {
2807 callback.failure(responseObject);
2810 callback.failure.apply(callback.scope, [responseObject]);
2816 this.releaseObject(o);
2817 responseObject = null;
2820 createResponseObject:function(o, callbackArg)
2827 var headerStr = o.conn.getAllResponseHeaders();
2828 var header = headerStr.split('\n');
2829 for (var i = 0; i < header.length; i++) {
2830 var delimitPos = header[i].indexOf(':');
2831 if (delimitPos != -1) {
2832 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2840 obj.status = o.conn.status;
2841 obj.statusText = o.conn.statusText;
2842 obj.getResponseHeader = headerObj;
2843 obj.getAllResponseHeaders = headerStr;
2844 obj.responseText = o.conn.responseText;
2845 obj.responseXML = o.conn.responseXML;
2847 if (typeof callbackArg !== undefined) {
2848 obj.argument = callbackArg;
2854 createExceptionObject:function(tId, callbackArg, isAbort)
2857 var COMM_ERROR = 'communication failure';
2858 var ABORT_CODE = -1;
2859 var ABORT_ERROR = 'transaction aborted';
2865 obj.status = ABORT_CODE;
2866 obj.statusText = ABORT_ERROR;
2869 obj.status = COMM_CODE;
2870 obj.statusText = COMM_ERROR;
2874 obj.argument = callbackArg;
2880 initHeader:function(label, value, isDefault)
2882 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2884 if (headerObj[label] === undefined) {
2885 headerObj[label] = value;
2890 headerObj[label] = value + "," + headerObj[label];
2894 this.hasDefaultHeaders = true;
2897 this.hasHeaders = true;
2902 setHeader:function(o)
2904 if (this.hasDefaultHeaders) {
2905 for (var prop in this.defaultHeaders) {
2906 if (this.defaultHeaders.hasOwnProperty(prop)) {
2907 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2912 if (this.hasHeaders) {
2913 for (var prop in this.headers) {
2914 if (this.headers.hasOwnProperty(prop)) {
2915 o.conn.setRequestHeader(prop, this.headers[prop]);
2919 this.hasHeaders = false;
2923 resetDefaultHeaders:function() {
2924 delete this.defaultHeaders;
2925 this.defaultHeaders = {};
2926 this.hasDefaultHeaders = false;
2929 abort:function(o, callback, isTimeout)
2931 if(this.isCallInProgress(o)) {
2933 window.clearInterval(this.poll[o.tId]);
2934 delete this.poll[o.tId];
2936 delete this.timeout[o.tId];
2939 this.handleTransactionResponse(o, callback, true);
2949 isCallInProgress:function(o)
2952 return o.conn.readyState != 4 && o.conn.readyState != 0;
2961 releaseObject:function(o)
2970 'MSXML2.XMLHTTP.3.0',
2978 * Portions of this file are based on pieces of Yahoo User Interface Library
2979 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2980 * YUI licensed under the BSD License:
2981 * http://developer.yahoo.net/yui/license.txt
2982 * <script type="text/javascript">
2986 Roo.lib.Region = function(t, r, b, l) {
2996 Roo.lib.Region.prototype = {
2997 contains : function(region) {
2998 return ( region.left >= this.left &&
2999 region.right <= this.right &&
3000 region.top >= this.top &&
3001 region.bottom <= this.bottom );
3005 getArea : function() {
3006 return ( (this.bottom - this.top) * (this.right - this.left) );
3009 intersect : function(region) {
3010 var t = Math.max(this.top, region.top);
3011 var r = Math.min(this.right, region.right);
3012 var b = Math.min(this.bottom, region.bottom);
3013 var l = Math.max(this.left, region.left);
3015 if (b >= t && r >= l) {
3016 return new Roo.lib.Region(t, r, b, l);
3021 union : function(region) {
3022 var t = Math.min(this.top, region.top);
3023 var r = Math.max(this.right, region.right);
3024 var b = Math.max(this.bottom, region.bottom);
3025 var l = Math.min(this.left, region.left);
3027 return new Roo.lib.Region(t, r, b, l);
3030 adjust : function(t, l, b, r) {
3039 Roo.lib.Region.getRegion = function(el) {
3040 var p = Roo.lib.Dom.getXY(el);
3043 var r = p[0] + el.offsetWidth;
3044 var b = p[1] + el.offsetHeight;
3047 return new Roo.lib.Region(t, r, b, l);
3050 * Portions of this file are based on pieces of Yahoo User Interface Library
3051 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3052 * YUI licensed under the BSD License:
3053 * http://developer.yahoo.net/yui/license.txt
3054 * <script type="text/javascript">
3057 //@@dep Roo.lib.Region
3060 Roo.lib.Point = function(x, y) {
3061 if (x instanceof Array) {
3065 this.x = this.right = this.left = this[0] = x;
3066 this.y = this.top = this.bottom = this[1] = y;
3069 Roo.lib.Point.prototype = new Roo.lib.Region();
3071 * Portions of this file are based on pieces of Yahoo User Interface Library
3072 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3073 * YUI licensed under the BSD License:
3074 * http://developer.yahoo.net/yui/license.txt
3075 * <script type="text/javascript">
3082 scroll : function(el, args, duration, easing, cb, scope) {
3083 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3086 motion : function(el, args, duration, easing, cb, scope) {
3087 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3090 color : function(el, args, duration, easing, cb, scope) {
3091 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3094 run : function(el, args, duration, easing, cb, scope, type) {
3095 type = type || Roo.lib.AnimBase;
3096 if (typeof easing == "string") {
3097 easing = Roo.lib.Easing[easing];
3099 var anim = new type(el, args, duration, easing);
3100 anim.animateX(function() {
3101 Roo.callback(cb, scope);
3107 * Portions of this file are based on pieces of Yahoo User Interface Library
3108 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3109 * YUI licensed under the BSD License:
3110 * http://developer.yahoo.net/yui/license.txt
3111 * <script type="text/javascript">
3119 if (!libFlyweight) {
3120 libFlyweight = new Roo.Element.Flyweight();
3122 libFlyweight.dom = el;
3123 return libFlyweight;
3126 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3130 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3132 this.init(el, attributes, duration, method);
3136 Roo.lib.AnimBase.fly = fly;
3140 Roo.lib.AnimBase.prototype = {
3142 toString: function() {
3143 var el = this.getEl();
3144 var id = el.id || el.tagName;
3145 return ("Anim " + id);
3149 noNegatives: /width|height|opacity|padding/i,
3150 offsetAttribute: /^((width|height)|(top|left))$/,
3151 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3152 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3156 doMethod: function(attr, start, end) {
3157 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3161 setAttribute: function(attr, val, unit) {
3162 if (this.patterns.noNegatives.test(attr)) {
3163 val = (val > 0) ? val : 0;
3166 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3170 getAttribute: function(attr) {
3171 var el = this.getEl();
3172 var val = fly(el).getStyle(attr);
3174 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3175 return parseFloat(val);
3178 var a = this.patterns.offsetAttribute.exec(attr) || [];
3179 var pos = !!( a[3] );
3180 var box = !!( a[2] );
3183 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3184 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3193 getDefaultUnit: function(attr) {
3194 if (this.patterns.defaultUnit.test(attr)) {
3201 animateX : function(callback, scope) {
3202 var f = function() {
3203 this.onComplete.removeListener(f);
3204 if (typeof callback == "function") {
3205 callback.call(scope || this, this);
3208 this.onComplete.addListener(f, this);
3213 setRuntimeAttribute: function(attr) {
3216 var attributes = this.attributes;
3218 this.runtimeAttributes[attr] = {};
3220 var isset = function(prop) {
3221 return (typeof prop !== 'undefined');
3224 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3228 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3231 if (isset(attributes[attr]['to'])) {
3232 end = attributes[attr]['to'];
3233 } else if (isset(attributes[attr]['by'])) {
3234 if (start.constructor == Array) {
3236 for (var i = 0, len = start.length; i < len; ++i) {
3237 end[i] = start[i] + attributes[attr]['by'][i];
3240 end = start + attributes[attr]['by'];
3244 this.runtimeAttributes[attr].start = start;
3245 this.runtimeAttributes[attr].end = end;
3248 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3252 init: function(el, attributes, duration, method) {
3254 var isAnimated = false;
3257 var startTime = null;
3260 var actualFrames = 0;
3263 el = Roo.getDom(el);
3266 this.attributes = attributes || {};
3269 this.duration = duration || 1;
3272 this.method = method || Roo.lib.Easing.easeNone;
3275 this.useSeconds = true;
3278 this.currentFrame = 0;
3281 this.totalFrames = Roo.lib.AnimMgr.fps;
3284 this.getEl = function() {
3289 this.isAnimated = function() {
3294 this.getStartTime = function() {
3298 this.runtimeAttributes = {};
3301 this.animate = function() {
3302 if (this.isAnimated()) {
3306 this.currentFrame = 0;
3308 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3310 Roo.lib.AnimMgr.registerElement(this);
3314 this.stop = function(finish) {
3316 this.currentFrame = this.totalFrames;
3317 this._onTween.fire();
3319 Roo.lib.AnimMgr.stop(this);
3322 var onStart = function() {
3323 this.onStart.fire();
3325 this.runtimeAttributes = {};
3326 for (var attr in this.attributes) {
3327 this.setRuntimeAttribute(attr);
3332 startTime = new Date();
3336 var onTween = function() {
3338 duration: new Date() - this.getStartTime(),
3339 currentFrame: this.currentFrame
3342 data.toString = function() {
3344 'duration: ' + data.duration +
3345 ', currentFrame: ' + data.currentFrame
3349 this.onTween.fire(data);
3351 var runtimeAttributes = this.runtimeAttributes;
3353 for (var attr in runtimeAttributes) {
3354 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3360 var onComplete = function() {
3361 var actual_duration = (new Date() - startTime) / 1000 ;
3364 duration: actual_duration,
3365 frames: actualFrames,
3366 fps: actualFrames / actual_duration
3369 data.toString = function() {
3371 'duration: ' + data.duration +
3372 ', frames: ' + data.frames +
3373 ', fps: ' + data.fps
3379 this.onComplete.fire(data);
3383 this._onStart = new Roo.util.Event(this);
3384 this.onStart = new Roo.util.Event(this);
3385 this.onTween = new Roo.util.Event(this);
3386 this._onTween = new Roo.util.Event(this);
3387 this.onComplete = new Roo.util.Event(this);
3388 this._onComplete = new Roo.util.Event(this);
3389 this._onStart.addListener(onStart);
3390 this._onTween.addListener(onTween);
3391 this._onComplete.addListener(onComplete);
3396 * Portions of this file are based on pieces of Yahoo User Interface Library
3397 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3398 * YUI licensed under the BSD License:
3399 * http://developer.yahoo.net/yui/license.txt
3400 * <script type="text/javascript">
3404 Roo.lib.AnimMgr = new function() {
3421 this.registerElement = function(tween) {
3422 queue[queue.length] = tween;
3424 tween._onStart.fire();
3429 this.unRegister = function(tween, index) {
3430 tween._onComplete.fire();
3431 index = index || getIndex(tween);
3433 queue.splice(index, 1);
3437 if (tweenCount <= 0) {
3443 this.start = function() {
3444 if (thread === null) {
3445 thread = setInterval(this.run, this.delay);
3450 this.stop = function(tween) {
3452 clearInterval(thread);
3454 for (var i = 0, len = queue.length; i < len; ++i) {
3455 if (queue[0].isAnimated()) {
3456 this.unRegister(queue[0], 0);
3465 this.unRegister(tween);
3470 this.run = function() {
3471 for (var i = 0, len = queue.length; i < len; ++i) {
3472 var tween = queue[i];
3473 if (!tween || !tween.isAnimated()) {
3477 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3479 tween.currentFrame += 1;
3481 if (tween.useSeconds) {
3482 correctFrame(tween);
3484 tween._onTween.fire();
3487 Roo.lib.AnimMgr.stop(tween, i);
3492 var getIndex = function(anim) {
3493 for (var i = 0, len = queue.length; i < len; ++i) {
3494 if (queue[i] == anim) {
3502 var correctFrame = function(tween) {
3503 var frames = tween.totalFrames;
3504 var frame = tween.currentFrame;
3505 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3506 var elapsed = (new Date() - tween.getStartTime());
3509 if (elapsed < tween.duration * 1000) {
3510 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3512 tweak = frames - (frame + 1);
3514 if (tweak > 0 && isFinite(tweak)) {
3515 if (tween.currentFrame + tweak >= frames) {
3516 tweak = frames - (frame + 1);
3519 tween.currentFrame += tweak;
3525 * Portions of this file are based on pieces of Yahoo User Interface Library
3526 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3527 * YUI licensed under the BSD License:
3528 * http://developer.yahoo.net/yui/license.txt
3529 * <script type="text/javascript">
3532 Roo.lib.Bezier = new function() {
3534 this.getPosition = function(points, t) {
3535 var n = points.length;
3538 for (var i = 0; i < n; ++i) {
3539 tmp[i] = [points[i][0], points[i][1]];
3542 for (var j = 1; j < n; ++j) {
3543 for (i = 0; i < n - j; ++i) {
3544 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3545 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3549 return [ tmp[0][0], tmp[0][1] ];
3553 * Portions of this file are based on pieces of Yahoo User Interface Library
3554 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3555 * YUI licensed under the BSD License:
3556 * http://developer.yahoo.net/yui/license.txt
3557 * <script type="text/javascript">
3562 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3563 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3566 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3568 var fly = Roo.lib.AnimBase.fly;
3570 var superclass = Y.ColorAnim.superclass;
3571 var proto = Y.ColorAnim.prototype;
3573 proto.toString = function() {
3574 var el = this.getEl();
3575 var id = el.id || el.tagName;
3576 return ("ColorAnim " + id);
3579 proto.patterns.color = /color$/i;
3580 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3581 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3582 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3583 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3586 proto.parseColor = function(s) {
3587 if (s.length == 3) {
3591 var c = this.patterns.hex.exec(s);
3592 if (c && c.length == 4) {
3593 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3596 c = this.patterns.rgb.exec(s);
3597 if (c && c.length == 4) {
3598 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3601 c = this.patterns.hex3.exec(s);
3602 if (c && c.length == 4) {
3603 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3608 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3609 proto.getAttribute = function(attr) {
3610 var el = this.getEl();
3611 if (this.patterns.color.test(attr)) {
3612 var val = fly(el).getStyle(attr);
3614 if (this.patterns.transparent.test(val)) {
3615 var parent = el.parentNode;
3616 val = fly(parent).getStyle(attr);
3618 while (parent && this.patterns.transparent.test(val)) {
3619 parent = parent.parentNode;
3620 val = fly(parent).getStyle(attr);
3621 if (parent.tagName.toUpperCase() == 'HTML') {
3627 val = superclass.getAttribute.call(this, attr);
3632 proto.getAttribute = function(attr) {
3633 var el = this.getEl();
3634 if (this.patterns.color.test(attr)) {
3635 var val = fly(el).getStyle(attr);
3637 if (this.patterns.transparent.test(val)) {
3638 var parent = el.parentNode;
3639 val = fly(parent).getStyle(attr);
3641 while (parent && this.patterns.transparent.test(val)) {
3642 parent = parent.parentNode;
3643 val = fly(parent).getStyle(attr);
3644 if (parent.tagName.toUpperCase() == 'HTML') {
3650 val = superclass.getAttribute.call(this, attr);
3656 proto.doMethod = function(attr, start, end) {
3659 if (this.patterns.color.test(attr)) {
3661 for (var i = 0, len = start.length; i < len; ++i) {
3662 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3665 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3668 val = superclass.doMethod.call(this, attr, start, end);
3674 proto.setRuntimeAttribute = function(attr) {
3675 superclass.setRuntimeAttribute.call(this, attr);
3677 if (this.patterns.color.test(attr)) {
3678 var attributes = this.attributes;
3679 var start = this.parseColor(this.runtimeAttributes[attr].start);
3680 var end = this.parseColor(this.runtimeAttributes[attr].end);
3682 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3683 end = this.parseColor(attributes[attr].by);
3685 for (var i = 0, len = start.length; i < len; ++i) {
3686 end[i] = start[i] + end[i];
3690 this.runtimeAttributes[attr].start = start;
3691 this.runtimeAttributes[attr].end = end;
3697 * Portions of this file are based on pieces of Yahoo User Interface Library
3698 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3699 * YUI licensed under the BSD License:
3700 * http://developer.yahoo.net/yui/license.txt
3701 * <script type="text/javascript">
3707 easeNone: function (t, b, c, d) {
3708 return c * t / d + b;
3712 easeIn: function (t, b, c, d) {
3713 return c * (t /= d) * t + b;
3717 easeOut: function (t, b, c, d) {
3718 return -c * (t /= d) * (t - 2) + b;
3722 easeBoth: function (t, b, c, d) {
3723 if ((t /= d / 2) < 1) {
3724 return c / 2 * t * t + b;
3727 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3731 easeInStrong: function (t, b, c, d) {
3732 return c * (t /= d) * t * t * t + b;
3736 easeOutStrong: function (t, b, c, d) {
3737 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3741 easeBothStrong: function (t, b, c, d) {
3742 if ((t /= d / 2) < 1) {
3743 return c / 2 * t * t * t * t + b;
3746 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3751 elasticIn: function (t, b, c, d, a, p) {
3755 if ((t /= d) == 1) {
3762 if (!a || a < Math.abs(c)) {
3767 var s = p / (2 * Math.PI) * Math.asin(c / a);
3770 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3774 elasticOut: function (t, b, c, d, a, p) {
3778 if ((t /= d) == 1) {
3785 if (!a || a < Math.abs(c)) {
3790 var s = p / (2 * Math.PI) * Math.asin(c / a);
3793 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3797 elasticBoth: function (t, b, c, d, a, p) {
3802 if ((t /= d / 2) == 2) {
3810 if (!a || a < Math.abs(c)) {
3815 var s = p / (2 * Math.PI) * Math.asin(c / a);
3819 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3820 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3822 return a * Math.pow(2, -10 * (t -= 1)) *
3823 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3828 backIn: function (t, b, c, d, s) {
3829 if (typeof s == 'undefined') {
3832 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3836 backOut: function (t, b, c, d, s) {
3837 if (typeof s == 'undefined') {
3840 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3844 backBoth: function (t, b, c, d, s) {
3845 if (typeof s == 'undefined') {
3849 if ((t /= d / 2 ) < 1) {
3850 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3852 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3856 bounceIn: function (t, b, c, d) {
3857 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3861 bounceOut: function (t, b, c, d) {
3862 if ((t /= d) < (1 / 2.75)) {
3863 return c * (7.5625 * t * t) + b;
3864 } else if (t < (2 / 2.75)) {
3865 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3866 } else if (t < (2.5 / 2.75)) {
3867 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3869 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3873 bounceBoth: function (t, b, c, d) {
3875 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3877 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3880 * Portions of this file are based on pieces of Yahoo User Interface Library
3881 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3882 * YUI licensed under the BSD License:
3883 * http://developer.yahoo.net/yui/license.txt
3884 * <script type="text/javascript">
3888 Roo.lib.Motion = function(el, attributes, duration, method) {
3890 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3894 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3898 var superclass = Y.Motion.superclass;
3899 var proto = Y.Motion.prototype;
3901 proto.toString = function() {
3902 var el = this.getEl();
3903 var id = el.id || el.tagName;
3904 return ("Motion " + id);
3907 proto.patterns.points = /^points$/i;
3909 proto.setAttribute = function(attr, val, unit) {
3910 if (this.patterns.points.test(attr)) {
3911 unit = unit || 'px';
3912 superclass.setAttribute.call(this, 'left', val[0], unit);
3913 superclass.setAttribute.call(this, 'top', val[1], unit);
3915 superclass.setAttribute.call(this, attr, val, unit);
3919 proto.getAttribute = function(attr) {
3920 if (this.patterns.points.test(attr)) {
3922 superclass.getAttribute.call(this, 'left'),
3923 superclass.getAttribute.call(this, 'top')
3926 val = superclass.getAttribute.call(this, attr);
3932 proto.doMethod = function(attr, start, end) {
3935 if (this.patterns.points.test(attr)) {
3936 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3937 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3939 val = superclass.doMethod.call(this, attr, start, end);
3944 proto.setRuntimeAttribute = function(attr) {
3945 if (this.patterns.points.test(attr)) {
3946 var el = this.getEl();
3947 var attributes = this.attributes;
3949 var control = attributes['points']['control'] || [];
3953 if (control.length > 0 && !(control[0] instanceof Array)) {
3954 control = [control];
3957 for (i = 0,len = control.length; i < len; ++i) {
3958 tmp[i] = control[i];
3963 Roo.fly(el).position();
3965 if (isset(attributes['points']['from'])) {
3966 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3969 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3972 start = this.getAttribute('points');
3975 if (isset(attributes['points']['to'])) {
3976 end = translateValues.call(this, attributes['points']['to'], start);
3978 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3979 for (i = 0,len = control.length; i < len; ++i) {
3980 control[i] = translateValues.call(this, control[i], start);
3984 } else if (isset(attributes['points']['by'])) {
3985 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3987 for (i = 0,len = control.length; i < len; ++i) {
3988 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3992 this.runtimeAttributes[attr] = [start];
3994 if (control.length > 0) {
3995 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3998 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4001 superclass.setRuntimeAttribute.call(this, attr);
4005 var translateValues = function(val, start) {
4006 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4007 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4012 var isset = function(prop) {
4013 return (typeof prop !== 'undefined');
4017 * Portions of this file are based on pieces of Yahoo User Interface Library
4018 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4019 * YUI licensed under the BSD License:
4020 * http://developer.yahoo.net/yui/license.txt
4021 * <script type="text/javascript">
4025 Roo.lib.Scroll = function(el, attributes, duration, method) {
4027 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4031 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4035 var superclass = Y.Scroll.superclass;
4036 var proto = Y.Scroll.prototype;
4038 proto.toString = function() {
4039 var el = this.getEl();
4040 var id = el.id || el.tagName;
4041 return ("Scroll " + id);
4044 proto.doMethod = function(attr, start, end) {
4047 if (attr == 'scroll') {
4049 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4050 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4054 val = superclass.doMethod.call(this, attr, start, end);
4059 proto.getAttribute = function(attr) {
4061 var el = this.getEl();
4063 if (attr == 'scroll') {
4064 val = [ el.scrollLeft, el.scrollTop ];
4066 val = superclass.getAttribute.call(this, attr);
4072 proto.setAttribute = function(attr, val, unit) {
4073 var el = this.getEl();
4075 if (attr == 'scroll') {
4076 el.scrollLeft = val[0];
4077 el.scrollTop = val[1];
4079 superclass.setAttribute.call(this, attr, val, unit);
4085 * Ext JS Library 1.1.1
4086 * Copyright(c) 2006-2007, Ext JS, LLC.
4088 * Originally Released Under LGPL - original licence link has changed is not relivant.
4091 * <script type="text/javascript">
4095 // nasty IE9 hack - what a pile of crap that is..
4097 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4098 Range.prototype.createContextualFragment = function (html) {
4099 var doc = window.document;
4100 var container = doc.createElement("div");
4101 container.innerHTML = html;
4102 var frag = doc.createDocumentFragment(), n;
4103 while ((n = container.firstChild)) {
4104 frag.appendChild(n);
4111 * @class Roo.DomHelper
4112 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4113 * 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>.
4116 Roo.DomHelper = function(){
4117 var tempTableEl = null;
4118 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4119 var tableRe = /^table|tbody|tr|td$/i;
4121 // build as innerHTML where available
4123 var createHtml = function(o){
4124 if(typeof o == 'string'){
4133 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4134 if(attr == "style"){
4136 if(typeof s == "function"){
4139 if(typeof s == "string"){
4140 b += ' style="' + s + '"';
4141 }else if(typeof s == "object"){
4144 if(typeof s[key] != "function"){
4145 b += key + ":" + s[key] + ";";
4152 b += ' class="' + o["cls"] + '"';
4153 }else if(attr == "htmlFor"){
4154 b += ' for="' + o["htmlFor"] + '"';
4156 b += " " + attr + '="' + o[attr] + '"';
4160 if(emptyTags.test(o.tag)){
4164 var cn = o.children || o.cn;
4166 //http://bugs.kde.org/show_bug.cgi?id=71506
4167 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4168 for(var i = 0, len = cn.length; i < len; i++) {
4169 b += createHtml(cn[i], b);
4172 b += createHtml(cn, b);
4178 b += "</" + o.tag + ">";
4185 var createDom = function(o, parentNode){
4187 // defininition craeted..
4189 if (o.ns && o.ns != 'html') {
4191 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4192 xmlns[o.ns] = o.xmlns;
4195 if (typeof(xmlns[o.ns]) == 'undefined') {
4196 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4202 if (typeof(o) == 'string') {
4203 return parentNode.appendChild(document.createTextNode(o));
4205 o.tag = o.tag || div;
4206 if (o.ns && Roo.isIE) {
4208 o.tag = o.ns + ':' + o.tag;
4211 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4212 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4215 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4216 attr == "style" || typeof o[attr] == "function") continue;
4218 if(attr=="cls" && Roo.isIE){
4219 el.className = o["cls"];
4221 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4222 else el[attr] = o[attr];
4225 Roo.DomHelper.applyStyles(el, o.style);
4226 var cn = o.children || o.cn;
4228 //http://bugs.kde.org/show_bug.cgi?id=71506
4229 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4230 for(var i = 0, len = cn.length; i < len; i++) {
4231 createDom(cn[i], el);
4238 el.innerHTML = o.html;
4241 parentNode.appendChild(el);
4246 var ieTable = function(depth, s, h, e){
4247 tempTableEl.innerHTML = [s, h, e].join('');
4248 var i = -1, el = tempTableEl;
4255 // kill repeat to save bytes
4259 tbe = '</tbody>'+te,
4265 * Nasty code for IE's broken table implementation
4267 var insertIntoTable = function(tag, where, el, html){
4269 tempTableEl = document.createElement('div');
4274 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4277 if(where == 'beforebegin'){
4281 before = el.nextSibling;
4284 node = ieTable(4, trs, html, tre);
4286 else if(tag == 'tr'){
4287 if(where == 'beforebegin'){
4290 node = ieTable(3, tbs, html, tbe);
4291 } else if(where == 'afterend'){
4292 before = el.nextSibling;
4294 node = ieTable(3, tbs, html, tbe);
4295 } else{ // INTO a TR
4296 if(where == 'afterbegin'){
4297 before = el.firstChild;
4299 node = ieTable(4, trs, html, tre);
4301 } else if(tag == 'tbody'){
4302 if(where == 'beforebegin'){
4305 node = ieTable(2, ts, html, te);
4306 } else if(where == 'afterend'){
4307 before = el.nextSibling;
4309 node = ieTable(2, ts, html, te);
4311 if(where == 'afterbegin'){
4312 before = el.firstChild;
4314 node = ieTable(3, tbs, html, tbe);
4317 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4320 if(where == 'afterbegin'){
4321 before = el.firstChild;
4323 node = ieTable(2, ts, html, te);
4325 el.insertBefore(node, before);
4330 /** True to force the use of DOM instead of html fragments @type Boolean */
4334 * Returns the markup for the passed Element(s) config
4335 * @param {Object} o The Dom object spec (and children)
4338 markup : function(o){
4339 return createHtml(o);
4343 * Applies a style specification to an element
4344 * @param {String/HTMLElement} el The element to apply styles to
4345 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4346 * a function which returns such a specification.
4348 applyStyles : function(el, styles){
4351 if(typeof styles == "string"){
4352 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4354 while ((matches = re.exec(styles)) != null){
4355 el.setStyle(matches[1], matches[2]);
4357 }else if (typeof styles == "object"){
4358 for (var style in styles){
4359 el.setStyle(style, styles[style]);
4361 }else if (typeof styles == "function"){
4362 Roo.DomHelper.applyStyles(el, styles.call());
4368 * Inserts an HTML fragment into the Dom
4369 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4370 * @param {HTMLElement} el The context element
4371 * @param {String} html The HTML fragmenet
4372 * @return {HTMLElement} The new node
4374 insertHtml : function(where, el, html){
4375 where = where.toLowerCase();
4376 if(el.insertAdjacentHTML){
4377 if(tableRe.test(el.tagName)){
4379 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4385 el.insertAdjacentHTML('BeforeBegin', html);
4386 return el.previousSibling;
4388 el.insertAdjacentHTML('AfterBegin', html);
4389 return el.firstChild;
4391 el.insertAdjacentHTML('BeforeEnd', html);
4392 return el.lastChild;
4394 el.insertAdjacentHTML('AfterEnd', html);
4395 return el.nextSibling;
4397 throw 'Illegal insertion point -> "' + where + '"';
4399 var range = el.ownerDocument.createRange();
4403 range.setStartBefore(el);
4404 frag = range.createContextualFragment(html);
4405 el.parentNode.insertBefore(frag, el);
4406 return el.previousSibling;
4409 range.setStartBefore(el.firstChild);
4410 frag = range.createContextualFragment(html);
4411 el.insertBefore(frag, el.firstChild);
4412 return el.firstChild;
4414 el.innerHTML = html;
4415 return el.firstChild;
4419 range.setStartAfter(el.lastChild);
4420 frag = range.createContextualFragment(html);
4421 el.appendChild(frag);
4422 return el.lastChild;
4424 el.innerHTML = html;
4425 return el.lastChild;
4428 range.setStartAfter(el);
4429 frag = range.createContextualFragment(html);
4430 el.parentNode.insertBefore(frag, el.nextSibling);
4431 return el.nextSibling;
4433 throw 'Illegal insertion point -> "' + where + '"';
4437 * Creates new Dom element(s) and inserts them before el
4438 * @param {String/HTMLElement/Element} el The context element
4439 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4440 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4441 * @return {HTMLElement/Roo.Element} The new node
4443 insertBefore : function(el, o, returnElement){
4444 return this.doInsert(el, o, returnElement, "beforeBegin");
4448 * Creates new Dom element(s) and inserts them after el
4449 * @param {String/HTMLElement/Element} el The context element
4450 * @param {Object} o The Dom object spec (and children)
4451 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4452 * @return {HTMLElement/Roo.Element} The new node
4454 insertAfter : function(el, o, returnElement){
4455 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4459 * Creates new Dom element(s) and inserts them as the first child of el
4460 * @param {String/HTMLElement/Element} el The context element
4461 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4462 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4463 * @return {HTMLElement/Roo.Element} The new node
4465 insertFirst : function(el, o, returnElement){
4466 return this.doInsert(el, o, returnElement, "afterBegin");
4470 doInsert : function(el, o, returnElement, pos, sibling){
4471 el = Roo.getDom(el);
4473 if(this.useDom || o.ns){
4474 newNode = createDom(o, null);
4475 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4477 var html = createHtml(o);
4478 newNode = this.insertHtml(pos, el, html);
4480 return returnElement ? Roo.get(newNode, true) : newNode;
4484 * Creates new Dom element(s) and appends them to el
4485 * @param {String/HTMLElement/Element} el The context element
4486 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4487 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4488 * @return {HTMLElement/Roo.Element} The new node
4490 append : function(el, o, returnElement){
4491 el = Roo.getDom(el);
4493 if(this.useDom || o.ns){
4494 newNode = createDom(o, null);
4495 el.appendChild(newNode);
4497 var html = createHtml(o);
4498 newNode = this.insertHtml("beforeEnd", el, html);
4500 return returnElement ? Roo.get(newNode, true) : newNode;
4504 * Creates new Dom element(s) and overwrites the contents of el with them
4505 * @param {String/HTMLElement/Element} el The context element
4506 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4507 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4508 * @return {HTMLElement/Roo.Element} The new node
4510 overwrite : function(el, o, returnElement){
4511 el = Roo.getDom(el);
4514 while (el.childNodes.length) {
4515 el.removeChild(el.firstChild);
4519 el.innerHTML = createHtml(o);
4522 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4526 * Creates a new Roo.DomHelper.Template from the Dom object spec
4527 * @param {Object} o The Dom object spec (and children)
4528 * @return {Roo.DomHelper.Template} The new template
4530 createTemplate : function(o){
4531 var html = createHtml(o);
4532 return new Roo.Template(html);
4538 * Ext JS Library 1.1.1
4539 * Copyright(c) 2006-2007, Ext JS, LLC.
4541 * Originally Released Under LGPL - original licence link has changed is not relivant.
4544 * <script type="text/javascript">
4548 * @class Roo.Template
4549 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4550 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4553 var t = new Roo.Template({
4554 html : '<div name="{id}">' +
4555 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4557 myformat: function (value, allValues) {
4558 return 'XX' + value;
4561 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4563 * For more information see this blog post with examples:
4564 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4565 - Create Elements using DOM, HTML fragments and Templates</a>.
4567 * @param {Object} cfg - Configuration object.
4569 Roo.Template = function(cfg){
4571 if(cfg instanceof Array){
4573 }else if(arguments.length > 1){
4574 cfg = Array.prototype.join.call(arguments, "");
4578 if (typeof(cfg) == 'object') {
4589 Roo.Template.prototype = {
4592 * @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..
4593 * it should be fixed so that template is observable...
4597 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4601 * Returns an HTML fragment of this template with the specified values applied.
4602 * @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'})
4603 * @return {String} The HTML fragment
4605 applyTemplate : function(values){
4609 return this.compiled(values);
4611 var useF = this.disableFormats !== true;
4612 var fm = Roo.util.Format, tpl = this;
4613 var fn = function(m, name, format, args){
4615 if(format.substr(0, 5) == "this."){
4616 return tpl.call(format.substr(5), values[name], values);
4619 // quoted values are required for strings in compiled templates,
4620 // but for non compiled we need to strip them
4621 // quoted reversed for jsmin
4622 var re = /^\s*['"](.*)["']\s*$/;
4623 args = args.split(',');
4624 for(var i = 0, len = args.length; i < len; i++){
4625 args[i] = args[i].replace(re, "$1");
4627 args = [values[name]].concat(args);
4629 args = [values[name]];
4631 return fm[format].apply(fm, args);
4634 return values[name] !== undefined ? values[name] : "";
4637 return this.html.replace(this.re, fn);
4655 this.loading = true;
4656 this.compiled = false;
4658 var cx = new Roo.data.Connection();
4662 success : function (response) {
4664 _t.html = response.responseText;
4668 failure : function(response) {
4669 Roo.log("Template failed to load from " + _t.url);
4676 * Sets the HTML used as the template and optionally compiles it.
4677 * @param {String} html
4678 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4679 * @return {Roo.Template} this
4681 set : function(html, compile){
4683 this.compiled = null;
4691 * True to disable format functions (defaults to false)
4694 disableFormats : false,
4697 * The regular expression used to match template variables
4701 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4704 * Compiles the template into an internal function, eliminating the RegEx overhead.
4705 * @return {Roo.Template} this
4707 compile : function(){
4708 var fm = Roo.util.Format;
4709 var useF = this.disableFormats !== true;
4710 var sep = Roo.isGecko ? "+" : ",";
4711 var fn = function(m, name, format, args){
4713 args = args ? ',' + args : "";
4714 if(format.substr(0, 5) != "this."){
4715 format = "fm." + format + '(';
4717 format = 'this.call("'+ format.substr(5) + '", ';
4721 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4723 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4726 // branched to use + in gecko and [].join() in others
4728 body = "this.compiled = function(values){ return '" +
4729 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4732 body = ["this.compiled = function(values){ return ['"];
4733 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4734 body.push("'].join('');};");
4735 body = body.join('');
4745 // private function used to call members
4746 call : function(fnName, value, allValues){
4747 return this[fnName](value, allValues);
4751 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4752 * @param {String/HTMLElement/Roo.Element} el The context element
4753 * @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'})
4754 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4755 * @return {HTMLElement/Roo.Element} The new node or Element
4757 insertFirst: function(el, values, returnElement){
4758 return this.doInsert('afterBegin', el, values, returnElement);
4762 * Applies the supplied values to the template and inserts the new node(s) before el.
4763 * @param {String/HTMLElement/Roo.Element} el The context element
4764 * @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'})
4765 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4766 * @return {HTMLElement/Roo.Element} The new node or Element
4768 insertBefore: function(el, values, returnElement){
4769 return this.doInsert('beforeBegin', el, values, returnElement);
4773 * Applies the supplied values to the template and inserts the new node(s) after el.
4774 * @param {String/HTMLElement/Roo.Element} el The context element
4775 * @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'})
4776 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4777 * @return {HTMLElement/Roo.Element} The new node or Element
4779 insertAfter : function(el, values, returnElement){
4780 return this.doInsert('afterEnd', el, values, returnElement);
4784 * Applies the supplied values to the template and appends the new node(s) to el.
4785 * @param {String/HTMLElement/Roo.Element} el The context element
4786 * @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'})
4787 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4788 * @return {HTMLElement/Roo.Element} The new node or Element
4790 append : function(el, values, returnElement){
4791 return this.doInsert('beforeEnd', el, values, returnElement);
4794 doInsert : function(where, el, values, returnEl){
4795 el = Roo.getDom(el);
4796 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4797 return returnEl ? Roo.get(newNode, true) : newNode;
4801 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4802 * @param {String/HTMLElement/Roo.Element} el The context element
4803 * @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'})
4804 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4805 * @return {HTMLElement/Roo.Element} The new node or Element
4807 overwrite : function(el, values, returnElement){
4808 el = Roo.getDom(el);
4809 el.innerHTML = this.applyTemplate(values);
4810 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4814 * Alias for {@link #applyTemplate}
4817 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4820 Roo.DomHelper.Template = Roo.Template;
4823 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4824 * @param {String/HTMLElement} el A DOM element or its id
4825 * @returns {Roo.Template} The created template
4828 Roo.Template.from = function(el){
4829 el = Roo.getDom(el);
4830 return new Roo.Template(el.value || el.innerHTML);
4833 * Ext JS Library 1.1.1
4834 * Copyright(c) 2006-2007, Ext JS, LLC.
4836 * Originally Released Under LGPL - original licence link has changed is not relivant.
4839 * <script type="text/javascript">
4844 * This is code is also distributed under MIT license for use
4845 * with jQuery and prototype JavaScript libraries.
4848 * @class Roo.DomQuery
4849 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).
4851 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>
4854 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.
4856 <h4>Element Selectors:</h4>
4858 <li> <b>*</b> any element</li>
4859 <li> <b>E</b> an element with the tag E</li>
4860 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4861 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4862 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4863 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4865 <h4>Attribute Selectors:</h4>
4866 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4868 <li> <b>E[foo]</b> has an attribute "foo"</li>
4869 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4870 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4871 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4872 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4873 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4874 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4876 <h4>Pseudo Classes:</h4>
4878 <li> <b>E:first-child</b> E is the first child of its parent</li>
4879 <li> <b>E:last-child</b> E is the last child of its parent</li>
4880 <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>
4881 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4882 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4883 <li> <b>E:only-child</b> E is the only child of its parent</li>
4884 <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>
4885 <li> <b>E:first</b> the first E in the resultset</li>
4886 <li> <b>E:last</b> the last E in the resultset</li>
4887 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4888 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4889 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4890 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4891 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4892 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4893 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4894 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4895 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4897 <h4>CSS Value Selectors:</h4>
4899 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4900 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4901 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4902 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4903 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4904 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4908 Roo.DomQuery = function(){
4909 var cache = {}, simpleCache = {}, valueCache = {};
4910 var nonSpace = /\S/;
4911 var trimRe = /^\s+|\s+$/g;
4912 var tplRe = /\{(\d+)\}/g;
4913 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4914 var tagTokenRe = /^(#)?([\w-\*]+)/;
4915 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4917 function child(p, index){
4919 var n = p.firstChild;
4921 if(n.nodeType == 1){
4932 while((n = n.nextSibling) && n.nodeType != 1);
4937 while((n = n.previousSibling) && n.nodeType != 1);
4941 function children(d){
4942 var n = d.firstChild, ni = -1;
4944 var nx = n.nextSibling;
4945 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4955 function byClassName(c, a, v){
4959 var r = [], ri = -1, cn;
4960 for(var i = 0, ci; ci = c[i]; i++){
4961 if((' '+ci.className+' ').indexOf(v) != -1){
4968 function attrValue(n, attr){
4969 if(!n.tagName && typeof n.length != "undefined"){
4978 if(attr == "class" || attr == "className"){
4981 return n.getAttribute(attr) || n[attr];
4985 function getNodes(ns, mode, tagName){
4986 var result = [], ri = -1, cs;
4990 tagName = tagName || "*";
4991 if(typeof ns.getElementsByTagName != "undefined"){
4995 for(var i = 0, ni; ni = ns[i]; i++){
4996 cs = ni.getElementsByTagName(tagName);
4997 for(var j = 0, ci; ci = cs[j]; j++){
5001 }else if(mode == "/" || mode == ">"){
5002 var utag = tagName.toUpperCase();
5003 for(var i = 0, ni, cn; ni = ns[i]; i++){
5004 cn = ni.children || ni.childNodes;
5005 for(var j = 0, cj; cj = cn[j]; j++){
5006 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5011 }else if(mode == "+"){
5012 var utag = tagName.toUpperCase();
5013 for(var i = 0, n; n = ns[i]; i++){
5014 while((n = n.nextSibling) && n.nodeType != 1);
5015 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5019 }else if(mode == "~"){
5020 for(var i = 0, n; n = ns[i]; i++){
5021 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5030 function concat(a, b){
5034 for(var i = 0, l = b.length; i < l; i++){
5040 function byTag(cs, tagName){
5041 if(cs.tagName || cs == document){
5047 var r = [], ri = -1;
5048 tagName = tagName.toLowerCase();
5049 for(var i = 0, ci; ci = cs[i]; i++){
5050 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5057 function byId(cs, attr, id){
5058 if(cs.tagName || cs == document){
5064 var r = [], ri = -1;
5065 for(var i = 0,ci; ci = cs[i]; i++){
5066 if(ci && ci.id == id){
5074 function byAttribute(cs, attr, value, op, custom){
5075 var r = [], ri = -1, st = custom=="{";
5076 var f = Roo.DomQuery.operators[op];
5077 for(var i = 0, ci; ci = cs[i]; i++){
5080 a = Roo.DomQuery.getStyle(ci, attr);
5082 else if(attr == "class" || attr == "className"){
5084 }else if(attr == "for"){
5086 }else if(attr == "href"){
5087 a = ci.getAttribute("href", 2);
5089 a = ci.getAttribute(attr);
5091 if((f && f(a, value)) || (!f && a)){
5098 function byPseudo(cs, name, value){
5099 return Roo.DomQuery.pseudos[name](cs, value);
5102 // This is for IE MSXML which does not support expandos.
5103 // IE runs the same speed using setAttribute, however FF slows way down
5104 // and Safari completely fails so they need to continue to use expandos.
5105 var isIE = window.ActiveXObject ? true : false;
5107 // this eval is stop the compressor from
5108 // renaming the variable to something shorter
5110 /** eval:var:batch */
5115 function nodupIEXml(cs){
5117 cs[0].setAttribute("_nodup", d);
5119 for(var i = 1, len = cs.length; i < len; i++){
5121 if(!c.getAttribute("_nodup") != d){
5122 c.setAttribute("_nodup", d);
5126 for(var i = 0, len = cs.length; i < len; i++){
5127 cs[i].removeAttribute("_nodup");
5136 var len = cs.length, c, i, r = cs, cj, ri = -1;
5137 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5140 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5141 return nodupIEXml(cs);
5145 for(i = 1; c = cs[i]; i++){
5150 for(var j = 0; j < i; j++){
5153 for(j = i+1; cj = cs[j]; j++){
5165 function quickDiffIEXml(c1, c2){
5167 for(var i = 0, len = c1.length; i < len; i++){
5168 c1[i].setAttribute("_qdiff", d);
5171 for(var i = 0, len = c2.length; i < len; i++){
5172 if(c2[i].getAttribute("_qdiff") != d){
5173 r[r.length] = c2[i];
5176 for(var i = 0, len = c1.length; i < len; i++){
5177 c1[i].removeAttribute("_qdiff");
5182 function quickDiff(c1, c2){
5183 var len1 = c1.length;
5187 if(isIE && c1[0].selectSingleNode){
5188 return quickDiffIEXml(c1, c2);
5191 for(var i = 0; i < len1; i++){
5195 for(var i = 0, len = c2.length; i < len; i++){
5196 if(c2[i]._qdiff != d){
5197 r[r.length] = c2[i];
5203 function quickId(ns, mode, root, id){
5205 var d = root.ownerDocument || root;
5206 return d.getElementById(id);
5208 ns = getNodes(ns, mode, "*");
5209 return byId(ns, null, id);
5213 getStyle : function(el, name){
5214 return Roo.fly(el).getStyle(name);
5217 * Compiles a selector/xpath query into a reusable function. The returned function
5218 * takes one parameter "root" (optional), which is the context node from where the query should start.
5219 * @param {String} selector The selector/xpath query
5220 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5221 * @return {Function}
5223 compile : function(path, type){
5224 type = type || "select";
5226 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5227 var q = path, mode, lq;
5228 var tk = Roo.DomQuery.matchers;
5229 var tklen = tk.length;
5232 // accept leading mode switch
5233 var lmode = q.match(modeRe);
5234 if(lmode && lmode[1]){
5235 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5236 q = q.replace(lmode[1], "");
5238 // strip leading slashes
5239 while(path.substr(0, 1)=="/"){
5240 path = path.substr(1);
5243 while(q && lq != q){
5245 var tm = q.match(tagTokenRe);
5246 if(type == "select"){
5249 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5251 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5253 q = q.replace(tm[0], "");
5254 }else if(q.substr(0, 1) != '@'){
5255 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5260 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5262 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5264 q = q.replace(tm[0], "");
5267 while(!(mm = q.match(modeRe))){
5268 var matched = false;
5269 for(var j = 0; j < tklen; j++){
5271 var m = q.match(t.re);
5273 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5276 q = q.replace(m[0], "");
5281 // prevent infinite loop on bad selector
5283 throw 'Error parsing selector, parsing failed at "' + q + '"';
5287 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5288 q = q.replace(mm[1], "");
5291 fn[fn.length] = "return nodup(n);\n}";
5294 * list of variables that need from compression as they are used by eval.
5304 * eval:var:byClassName
5306 * eval:var:byAttribute
5307 * eval:var:attrValue
5315 * Selects a group of elements.
5316 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5317 * @param {Node} root (optional) The start of the query (defaults to document).
5320 select : function(path, root, type){
5321 if(!root || root == document){
5324 if(typeof root == "string"){
5325 root = document.getElementById(root);
5327 var paths = path.split(",");
5329 for(var i = 0, len = paths.length; i < len; i++){
5330 var p = paths[i].replace(trimRe, "");
5332 cache[p] = Roo.DomQuery.compile(p);
5334 throw p + " is not a valid selector";
5337 var result = cache[p](root);
5338 if(result && result != document){
5339 results = results.concat(result);
5342 if(paths.length > 1){
5343 return nodup(results);
5349 * Selects a single element.
5350 * @param {String} selector The selector/xpath query
5351 * @param {Node} root (optional) The start of the query (defaults to document).
5354 selectNode : function(path, root){
5355 return Roo.DomQuery.select(path, root)[0];
5359 * Selects the value of a node, optionally replacing null with the defaultValue.
5360 * @param {String} selector The selector/xpath query
5361 * @param {Node} root (optional) The start of the query (defaults to document).
5362 * @param {String} defaultValue
5364 selectValue : function(path, root, defaultValue){
5365 path = path.replace(trimRe, "");
5366 if(!valueCache[path]){
5367 valueCache[path] = Roo.DomQuery.compile(path, "select");
5369 var n = valueCache[path](root);
5370 n = n[0] ? n[0] : n;
5371 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5372 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5376 * Selects the value of a node, parsing integers and floats.
5377 * @param {String} selector The selector/xpath query
5378 * @param {Node} root (optional) The start of the query (defaults to document).
5379 * @param {Number} defaultValue
5382 selectNumber : function(path, root, defaultValue){
5383 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5384 return parseFloat(v);
5388 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5389 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5390 * @param {String} selector The simple selector to test
5393 is : function(el, ss){
5394 if(typeof el == "string"){
5395 el = document.getElementById(el);
5397 var isArray = (el instanceof Array);
5398 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5399 return isArray ? (result.length == el.length) : (result.length > 0);
5403 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5404 * @param {Array} el An array of elements to filter
5405 * @param {String} selector The simple selector to test
5406 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5407 * the selector instead of the ones that match
5410 filter : function(els, ss, nonMatches){
5411 ss = ss.replace(trimRe, "");
5412 if(!simpleCache[ss]){
5413 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5415 var result = simpleCache[ss](els);
5416 return nonMatches ? quickDiff(result, els) : result;
5420 * Collection of matching regular expressions and code snippets.
5424 select: 'n = byClassName(n, null, " {1} ");'
5426 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5427 select: 'n = byPseudo(n, "{1}", "{2}");'
5429 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5430 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5433 select: 'n = byId(n, null, "{1}");'
5436 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5441 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5442 * 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, > <.
5445 "=" : function(a, v){
5448 "!=" : function(a, v){
5451 "^=" : function(a, v){
5452 return a && a.substr(0, v.length) == v;
5454 "$=" : function(a, v){
5455 return a && a.substr(a.length-v.length) == v;
5457 "*=" : function(a, v){
5458 return a && a.indexOf(v) !== -1;
5460 "%=" : function(a, v){
5461 return (a % v) == 0;
5463 "|=" : function(a, v){
5464 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5466 "~=" : function(a, v){
5467 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5472 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5473 * and the argument (if any) supplied in the selector.
5476 "first-child" : function(c){
5477 var r = [], ri = -1, n;
5478 for(var i = 0, ci; ci = n = c[i]; i++){
5479 while((n = n.previousSibling) && n.nodeType != 1);
5487 "last-child" : function(c){
5488 var r = [], ri = -1, n;
5489 for(var i = 0, ci; ci = n = c[i]; i++){
5490 while((n = n.nextSibling) && n.nodeType != 1);
5498 "nth-child" : function(c, a) {
5499 var r = [], ri = -1;
5500 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5501 var f = (m[1] || 1) - 0, l = m[2] - 0;
5502 for(var i = 0, n; n = c[i]; i++){
5503 var pn = n.parentNode;
5504 if (batch != pn._batch) {
5506 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5507 if(cn.nodeType == 1){
5514 if (l == 0 || n.nodeIndex == l){
5517 } else if ((n.nodeIndex + l) % f == 0){
5525 "only-child" : function(c){
5526 var r = [], ri = -1;;
5527 for(var i = 0, ci; ci = c[i]; i++){
5528 if(!prev(ci) && !next(ci)){
5535 "empty" : function(c){
5536 var r = [], ri = -1;
5537 for(var i = 0, ci; ci = c[i]; i++){
5538 var cns = ci.childNodes, j = 0, cn, empty = true;
5541 if(cn.nodeType == 1 || cn.nodeType == 3){
5553 "contains" : function(c, v){
5554 var r = [], ri = -1;
5555 for(var i = 0, ci; ci = c[i]; i++){
5556 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5563 "nodeValue" : function(c, v){
5564 var r = [], ri = -1;
5565 for(var i = 0, ci; ci = c[i]; i++){
5566 if(ci.firstChild && ci.firstChild.nodeValue == v){
5573 "checked" : function(c){
5574 var r = [], ri = -1;
5575 for(var i = 0, ci; ci = c[i]; i++){
5576 if(ci.checked == true){
5583 "not" : function(c, ss){
5584 return Roo.DomQuery.filter(c, ss, true);
5587 "odd" : function(c){
5588 return this["nth-child"](c, "odd");
5591 "even" : function(c){
5592 return this["nth-child"](c, "even");
5595 "nth" : function(c, a){
5596 return c[a-1] || [];
5599 "first" : function(c){
5603 "last" : function(c){
5604 return c[c.length-1] || [];
5607 "has" : function(c, ss){
5608 var s = Roo.DomQuery.select;
5609 var r = [], ri = -1;
5610 for(var i = 0, ci; ci = c[i]; i++){
5611 if(s(ss, ci).length > 0){
5618 "next" : function(c, ss){
5619 var is = Roo.DomQuery.is;
5620 var r = [], ri = -1;
5621 for(var i = 0, ci; ci = c[i]; i++){
5630 "prev" : function(c, ss){
5631 var is = Roo.DomQuery.is;
5632 var r = [], ri = -1;
5633 for(var i = 0, ci; ci = c[i]; i++){
5646 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5647 * @param {String} path The selector/xpath query
5648 * @param {Node} root (optional) The start of the query (defaults to document).
5653 Roo.query = Roo.DomQuery.select;
5656 * Ext JS Library 1.1.1
5657 * Copyright(c) 2006-2007, Ext JS, LLC.
5659 * Originally Released Under LGPL - original licence link has changed is not relivant.
5662 * <script type="text/javascript">
5666 * @class Roo.util.Observable
5667 * Base class that provides a common interface for publishing events. Subclasses are expected to
5668 * to have a property "events" with all the events defined.<br>
5671 Employee = function(name){
5678 Roo.extend(Employee, Roo.util.Observable);
5680 * @param {Object} config properties to use (incuding events / listeners)
5683 Roo.util.Observable = function(cfg){
5686 this.addEvents(cfg.events || {});
5688 delete cfg.events; // make sure
5691 Roo.apply(this, cfg);
5694 this.on(this.listeners);
5695 delete this.listeners;
5698 Roo.util.Observable.prototype = {
5700 * @cfg {Object} listeners list of events and functions to call for this object,
5704 'click' : function(e) {
5714 * Fires the specified event with the passed parameters (minus the event name).
5715 * @param {String} eventName
5716 * @param {Object...} args Variable number of parameters are passed to handlers
5717 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5719 fireEvent : function(){
5720 var ce = this.events[arguments[0].toLowerCase()];
5721 if(typeof ce == "object"){
5722 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5729 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5732 * Appends an event handler to this component
5733 * @param {String} eventName The type of event to listen for
5734 * @param {Function} handler The method the event invokes
5735 * @param {Object} scope (optional) The scope in which to execute the handler
5736 * function. The handler function's "this" context.
5737 * @param {Object} options (optional) An object containing handler configuration
5738 * properties. This may contain any of the following properties:<ul>
5739 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5740 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5741 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5742 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5743 * by the specified number of milliseconds. If the event fires again within that time, the original
5744 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5747 * <b>Combining Options</b><br>
5748 * Using the options argument, it is possible to combine different types of listeners:<br>
5750 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5752 el.on('click', this.onClick, this, {
5759 * <b>Attaching multiple handlers in 1 call</b><br>
5760 * The method also allows for a single argument to be passed which is a config object containing properties
5761 * which specify multiple handlers.
5770 fn: this.onMouseOver,
5774 fn: this.onMouseOut,
5780 * Or a shorthand syntax which passes the same scope object to all handlers:
5783 'click': this.onClick,
5784 'mouseover': this.onMouseOver,
5785 'mouseout': this.onMouseOut,
5790 addListener : function(eventName, fn, scope, o){
5791 if(typeof eventName == "object"){
5794 if(this.filterOptRe.test(e)){
5797 if(typeof o[e] == "function"){
5799 this.addListener(e, o[e], o.scope, o);
5801 // individual options
5802 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5807 o = (!o || typeof o == "boolean") ? {} : o;
5808 eventName = eventName.toLowerCase();
5809 var ce = this.events[eventName] || true;
5810 if(typeof ce == "boolean"){
5811 ce = new Roo.util.Event(this, eventName);
5812 this.events[eventName] = ce;
5814 ce.addListener(fn, scope, o);
5818 * Removes a listener
5819 * @param {String} eventName The type of event to listen for
5820 * @param {Function} handler The handler to remove
5821 * @param {Object} scope (optional) The scope (this object) for the handler
5823 removeListener : function(eventName, fn, scope){
5824 var ce = this.events[eventName.toLowerCase()];
5825 if(typeof ce == "object"){
5826 ce.removeListener(fn, scope);
5831 * Removes all listeners for this object
5833 purgeListeners : function(){
5834 for(var evt in this.events){
5835 if(typeof this.events[evt] == "object"){
5836 this.events[evt].clearListeners();
5841 relayEvents : function(o, events){
5842 var createHandler = function(ename){
5844 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5847 for(var i = 0, len = events.length; i < len; i++){
5848 var ename = events[i];
5849 if(!this.events[ename]){ this.events[ename] = true; };
5850 o.on(ename, createHandler(ename), this);
5855 * Used to define events on this Observable
5856 * @param {Object} object The object with the events defined
5858 addEvents : function(o){
5862 Roo.applyIf(this.events, o);
5866 * Checks to see if this object has any listeners for a specified event
5867 * @param {String} eventName The name of the event to check for
5868 * @return {Boolean} True if the event is being listened for, else false
5870 hasListener : function(eventName){
5871 var e = this.events[eventName];
5872 return typeof e == "object" && e.listeners.length > 0;
5876 * Appends an event handler to this element (shorthand for addListener)
5877 * @param {String} eventName The type of event to listen for
5878 * @param {Function} handler The method the event invokes
5879 * @param {Object} scope (optional) The scope in which to execute the handler
5880 * function. The handler function's "this" context.
5881 * @param {Object} options (optional)
5884 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5886 * Removes a listener (shorthand for removeListener)
5887 * @param {String} eventName The type of event to listen for
5888 * @param {Function} handler The handler to remove
5889 * @param {Object} scope (optional) The scope (this object) for the handler
5892 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5895 * Starts capture on the specified Observable. All events will be passed
5896 * to the supplied function with the event name + standard signature of the event
5897 * <b>before</b> the event is fired. If the supplied function returns false,
5898 * the event will not fire.
5899 * @param {Observable} o The Observable to capture
5900 * @param {Function} fn The function to call
5901 * @param {Object} scope (optional) The scope (this object) for the fn
5904 Roo.util.Observable.capture = function(o, fn, scope){
5905 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5909 * Removes <b>all</b> added captures from the Observable.
5910 * @param {Observable} o The Observable to release
5913 Roo.util.Observable.releaseCapture = function(o){
5914 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5919 var createBuffered = function(h, o, scope){
5920 var task = new Roo.util.DelayedTask();
5922 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5926 var createSingle = function(h, e, fn, scope){
5928 e.removeListener(fn, scope);
5929 return h.apply(scope, arguments);
5933 var createDelayed = function(h, o, scope){
5935 var args = Array.prototype.slice.call(arguments, 0);
5936 setTimeout(function(){
5937 h.apply(scope, args);
5942 Roo.util.Event = function(obj, name){
5945 this.listeners = [];
5948 Roo.util.Event.prototype = {
5949 addListener : function(fn, scope, options){
5950 var o = options || {};
5951 scope = scope || this.obj;
5952 if(!this.isListening(fn, scope)){
5953 var l = {fn: fn, scope: scope, options: o};
5956 h = createDelayed(h, o, scope);
5959 h = createSingle(h, this, fn, scope);
5962 h = createBuffered(h, o, scope);
5965 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5966 this.listeners.push(l);
5968 this.listeners = this.listeners.slice(0);
5969 this.listeners.push(l);
5974 findListener : function(fn, scope){
5975 scope = scope || this.obj;
5976 var ls = this.listeners;
5977 for(var i = 0, len = ls.length; i < len; i++){
5979 if(l.fn == fn && l.scope == scope){
5986 isListening : function(fn, scope){
5987 return this.findListener(fn, scope) != -1;
5990 removeListener : function(fn, scope){
5992 if((index = this.findListener(fn, scope)) != -1){
5994 this.listeners.splice(index, 1);
5996 this.listeners = this.listeners.slice(0);
5997 this.listeners.splice(index, 1);
6004 clearListeners : function(){
6005 this.listeners = [];
6009 var ls = this.listeners, scope, len = ls.length;
6012 var args = Array.prototype.slice.call(arguments, 0);
6013 for(var i = 0; i < len; i++){
6015 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6016 this.firing = false;
6020 this.firing = false;
6027 * Ext JS Library 1.1.1
6028 * Copyright(c) 2006-2007, Ext JS, LLC.
6030 * Originally Released Under LGPL - original licence link has changed is not relivant.
6033 * <script type="text/javascript">
6037 * @class Roo.EventManager
6038 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6039 * several useful events directly.
6040 * See {@link Roo.EventObject} for more details on normalized event objects.
6043 Roo.EventManager = function(){
6044 var docReadyEvent, docReadyProcId, docReadyState = false;
6045 var resizeEvent, resizeTask, textEvent, textSize;
6046 var E = Roo.lib.Event;
6047 var D = Roo.lib.Dom;
6050 var fireDocReady = function(){
6052 docReadyState = true;
6055 clearInterval(docReadyProcId);
6057 if(Roo.isGecko || Roo.isOpera) {
6058 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6061 var defer = document.getElementById("ie-deferred-loader");
6063 defer.onreadystatechange = null;
6064 defer.parentNode.removeChild(defer);
6068 docReadyEvent.fire();
6069 docReadyEvent.clearListeners();
6074 var initDocReady = function(){
6075 docReadyEvent = new Roo.util.Event();
6076 if(Roo.isGecko || Roo.isOpera) {
6077 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6079 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6080 var defer = document.getElementById("ie-deferred-loader");
6081 defer.onreadystatechange = function(){
6082 if(this.readyState == "complete"){
6086 }else if(Roo.isSafari){
6087 docReadyProcId = setInterval(function(){
6088 var rs = document.readyState;
6089 if(rs == "complete") {
6094 // no matter what, make sure it fires on load
6095 E.on(window, "load", fireDocReady);
6098 var createBuffered = function(h, o){
6099 var task = new Roo.util.DelayedTask(h);
6101 // create new event object impl so new events don't wipe out properties
6102 e = new Roo.EventObjectImpl(e);
6103 task.delay(o.buffer, h, null, [e]);
6107 var createSingle = function(h, el, ename, fn){
6109 Roo.EventManager.removeListener(el, ename, fn);
6114 var createDelayed = function(h, o){
6116 // create new event object impl so new events don't wipe out properties
6117 e = new Roo.EventObjectImpl(e);
6118 setTimeout(function(){
6124 var listen = function(element, ename, opt, fn, scope){
6125 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6126 fn = fn || o.fn; scope = scope || o.scope;
6127 var el = Roo.getDom(element);
6129 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6131 var h = function(e){
6132 e = Roo.EventObject.setEvent(e);
6135 t = e.getTarget(o.delegate, el);
6142 if(o.stopEvent === true){
6145 if(o.preventDefault === true){
6148 if(o.stopPropagation === true){
6149 e.stopPropagation();
6152 if(o.normalized === false){
6156 fn.call(scope || el, e, t, o);
6159 h = createDelayed(h, o);
6162 h = createSingle(h, el, ename, fn);
6165 h = createBuffered(h, o);
6167 fn._handlers = fn._handlers || [];
6168 fn._handlers.push([Roo.id(el), ename, h]);
6171 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6172 el.addEventListener("DOMMouseScroll", h, false);
6173 E.on(window, 'unload', function(){
6174 el.removeEventListener("DOMMouseScroll", h, false);
6177 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6178 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6183 var stopListening = function(el, ename, fn){
6184 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6186 for(var i = 0, len = hds.length; i < len; i++){
6188 if(h[0] == id && h[1] == ename){
6195 E.un(el, ename, hd);
6196 el = Roo.getDom(el);
6197 if(ename == "mousewheel" && el.addEventListener){
6198 el.removeEventListener("DOMMouseScroll", hd, false);
6200 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6201 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6205 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6212 * @scope Roo.EventManager
6217 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6218 * object with a Roo.EventObject
6219 * @param {Function} fn The method the event invokes
6220 * @param {Object} scope An object that becomes the scope of the handler
6221 * @param {boolean} override If true, the obj passed in becomes
6222 * the execution scope of the listener
6223 * @return {Function} The wrapped function
6226 wrap : function(fn, scope, override){
6228 Roo.EventObject.setEvent(e);
6229 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6234 * Appends an event handler to an element (shorthand for addListener)
6235 * @param {String/HTMLElement} element The html element or id to assign the
6236 * @param {String} eventName The type of event to listen for
6237 * @param {Function} handler The method the event invokes
6238 * @param {Object} scope (optional) The scope in which to execute the handler
6239 * function. The handler function's "this" context.
6240 * @param {Object} options (optional) An object containing handler configuration
6241 * properties. This may contain any of the following properties:<ul>
6242 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6243 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6244 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6245 * <li>preventDefault {Boolean} True to prevent the default action</li>
6246 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6247 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6248 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6249 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6250 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6251 * by the specified number of milliseconds. If the event fires again within that time, the original
6252 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6255 * <b>Combining Options</b><br>
6256 * Using the options argument, it is possible to combine different types of listeners:<br>
6258 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6260 el.on('click', this.onClick, this, {
6267 * <b>Attaching multiple handlers in 1 call</b><br>
6268 * The method also allows for a single argument to be passed which is a config object containing properties
6269 * which specify multiple handlers.
6279 fn: this.onMouseOver
6288 * Or a shorthand syntax:<br>
6291 'click' : this.onClick,
6292 'mouseover' : this.onMouseOver,
6293 'mouseout' : this.onMouseOut
6297 addListener : function(element, eventName, fn, scope, options){
6298 if(typeof eventName == "object"){
6304 if(typeof o[e] == "function"){
6306 listen(element, e, o, o[e], o.scope);
6308 // individual options
6309 listen(element, e, o[e]);
6314 return listen(element, eventName, options, fn, scope);
6318 * Removes an event handler
6320 * @param {String/HTMLElement} element The id or html element to remove the
6322 * @param {String} eventName The type of event
6323 * @param {Function} fn
6324 * @return {Boolean} True if a listener was actually removed
6326 removeListener : function(element, eventName, fn){
6327 return stopListening(element, eventName, fn);
6331 * Fires when the document is ready (before onload and before images are loaded). Can be
6332 * accessed shorthanded Roo.onReady().
6333 * @param {Function} fn The method the event invokes
6334 * @param {Object} scope An object that becomes the scope of the handler
6335 * @param {boolean} options
6337 onDocumentReady : function(fn, scope, options){
6338 if(docReadyState){ // if it already fired
6339 docReadyEvent.addListener(fn, scope, options);
6340 docReadyEvent.fire();
6341 docReadyEvent.clearListeners();
6347 docReadyEvent.addListener(fn, scope, options);
6351 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6352 * @param {Function} fn The method the event invokes
6353 * @param {Object} scope An object that becomes the scope of the handler
6354 * @param {boolean} options
6356 onWindowResize : function(fn, scope, options){
6358 resizeEvent = new Roo.util.Event();
6359 resizeTask = new Roo.util.DelayedTask(function(){
6360 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6362 E.on(window, "resize", function(){
6364 resizeTask.delay(50);
6366 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6370 resizeEvent.addListener(fn, scope, options);
6374 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6375 * @param {Function} fn The method the event invokes
6376 * @param {Object} scope An object that becomes the scope of the handler
6377 * @param {boolean} options
6379 onTextResize : function(fn, scope, options){
6381 textEvent = new Roo.util.Event();
6382 var textEl = new Roo.Element(document.createElement('div'));
6383 textEl.dom.className = 'x-text-resize';
6384 textEl.dom.innerHTML = 'X';
6385 textEl.appendTo(document.body);
6386 textSize = textEl.dom.offsetHeight;
6387 setInterval(function(){
6388 if(textEl.dom.offsetHeight != textSize){
6389 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6391 }, this.textResizeInterval);
6393 textEvent.addListener(fn, scope, options);
6397 * Removes the passed window resize listener.
6398 * @param {Function} fn The method the event invokes
6399 * @param {Object} scope The scope of handler
6401 removeResizeListener : function(fn, scope){
6403 resizeEvent.removeListener(fn, scope);
6408 fireResize : function(){
6410 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6414 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6418 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6420 textResizeInterval : 50
6425 * @scopeAlias pub=Roo.EventManager
6429 * Appends an event handler to an element (shorthand for addListener)
6430 * @param {String/HTMLElement} element The html element or id to assign the
6431 * @param {String} eventName The type of event to listen for
6432 * @param {Function} handler The method the event invokes
6433 * @param {Object} scope (optional) The scope in which to execute the handler
6434 * function. The handler function's "this" context.
6435 * @param {Object} options (optional) An object containing handler configuration
6436 * properties. This may contain any of the following properties:<ul>
6437 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6438 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6439 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6440 * <li>preventDefault {Boolean} True to prevent the default action</li>
6441 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6442 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6443 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6444 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6445 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6446 * by the specified number of milliseconds. If the event fires again within that time, the original
6447 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6450 * <b>Combining Options</b><br>
6451 * Using the options argument, it is possible to combine different types of listeners:<br>
6453 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6455 el.on('click', this.onClick, this, {
6462 * <b>Attaching multiple handlers in 1 call</b><br>
6463 * The method also allows for a single argument to be passed which is a config object containing properties
6464 * which specify multiple handlers.
6474 fn: this.onMouseOver
6483 * Or a shorthand syntax:<br>
6486 'click' : this.onClick,
6487 'mouseover' : this.onMouseOver,
6488 'mouseout' : this.onMouseOut
6492 pub.on = pub.addListener;
6493 pub.un = pub.removeListener;
6495 pub.stoppedMouseDownEvent = new Roo.util.Event();
6499 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6500 * @param {Function} fn The method the event invokes
6501 * @param {Object} scope An object that becomes the scope of the handler
6502 * @param {boolean} override If true, the obj passed in becomes
6503 * the execution scope of the listener
6507 Roo.onReady = Roo.EventManager.onDocumentReady;
6509 Roo.onReady(function(){
6510 var bd = Roo.get(document.body);
6515 : Roo.isGecko ? "roo-gecko"
6516 : Roo.isOpera ? "roo-opera"
6517 : Roo.isSafari ? "roo-safari" : ""];
6520 cls.push("roo-mac");
6523 cls.push("roo-linux");
6525 if(Roo.isBorderBox){
6526 cls.push('roo-border-box');
6528 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6529 var p = bd.dom.parentNode;
6531 p.className += ' roo-strict';
6534 bd.addClass(cls.join(' '));
6538 * @class Roo.EventObject
6539 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6540 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6543 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6545 var target = e.getTarget();
6548 var myDiv = Roo.get("myDiv");
6549 myDiv.on("click", handleClick);
6551 Roo.EventManager.on("myDiv", 'click', handleClick);
6552 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6556 Roo.EventObject = function(){
6558 var E = Roo.lib.Event;
6560 // safari keypress events for special keys return bad keycodes
6563 63235 : 39, // right
6566 63276 : 33, // page up
6567 63277 : 34, // page down
6568 63272 : 46, // delete
6573 // normalize button clicks
6574 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6575 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6577 Roo.EventObjectImpl = function(e){
6579 this.setEvent(e.browserEvent || e);
6582 Roo.EventObjectImpl.prototype = {
6584 * Used to fix doc tools.
6585 * @scope Roo.EventObject.prototype
6591 /** The normal browser event */
6592 browserEvent : null,
6593 /** The button pressed in a mouse event */
6595 /** True if the shift key was down during the event */
6597 /** True if the control key was down during the event */
6599 /** True if the alt key was down during the event */
6658 setEvent : function(e){
6659 if(e == this || (e && e.browserEvent)){ // already wrapped
6662 this.browserEvent = e;
6664 // normalize buttons
6665 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6666 if(e.type == 'click' && this.button == -1){
6670 this.shiftKey = e.shiftKey;
6671 // mac metaKey behaves like ctrlKey
6672 this.ctrlKey = e.ctrlKey || e.metaKey;
6673 this.altKey = e.altKey;
6674 // in getKey these will be normalized for the mac
6675 this.keyCode = e.keyCode;
6676 // keyup warnings on firefox.
6677 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6678 // cache the target for the delayed and or buffered events
6679 this.target = E.getTarget(e);
6681 this.xy = E.getXY(e);
6684 this.shiftKey = false;
6685 this.ctrlKey = false;
6686 this.altKey = false;
6696 * Stop the event (preventDefault and stopPropagation)
6698 stopEvent : function(){
6699 if(this.browserEvent){
6700 if(this.browserEvent.type == 'mousedown'){
6701 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6703 E.stopEvent(this.browserEvent);
6708 * Prevents the browsers default handling of the event.
6710 preventDefault : function(){
6711 if(this.browserEvent){
6712 E.preventDefault(this.browserEvent);
6717 isNavKeyPress : function(){
6718 var k = this.keyCode;
6719 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6720 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6723 isSpecialKey : function(){
6724 var k = this.keyCode;
6725 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6726 (k == 16) || (k == 17) ||
6727 (k >= 18 && k <= 20) ||
6728 (k >= 33 && k <= 35) ||
6729 (k >= 36 && k <= 39) ||
6730 (k >= 44 && k <= 45);
6733 * Cancels bubbling of the event.
6735 stopPropagation : function(){
6736 if(this.browserEvent){
6737 if(this.type == 'mousedown'){
6738 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6740 E.stopPropagation(this.browserEvent);
6745 * Gets the key code for the event.
6748 getCharCode : function(){
6749 return this.charCode || this.keyCode;
6753 * Returns a normalized keyCode for the event.
6754 * @return {Number} The key code
6756 getKey : function(){
6757 var k = this.keyCode || this.charCode;
6758 return Roo.isSafari ? (safariKeys[k] || k) : k;
6762 * Gets the x coordinate of the event.
6765 getPageX : function(){
6770 * Gets the y coordinate of the event.
6773 getPageY : function(){
6778 * Gets the time of the event.
6781 getTime : function(){
6782 if(this.browserEvent){
6783 return E.getTime(this.browserEvent);
6789 * Gets the page coordinates of the event.
6790 * @return {Array} The xy values like [x, y]
6797 * Gets the target for the event.
6798 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6799 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6800 search as a number or element (defaults to 10 || document.body)
6801 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6802 * @return {HTMLelement}
6804 getTarget : function(selector, maxDepth, returnEl){
6805 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6808 * Gets the related target.
6809 * @return {HTMLElement}
6811 getRelatedTarget : function(){
6812 if(this.browserEvent){
6813 return E.getRelatedTarget(this.browserEvent);
6819 * Normalizes mouse wheel delta across browsers
6820 * @return {Number} The delta
6822 getWheelDelta : function(){
6823 var e = this.browserEvent;
6825 if(e.wheelDelta){ /* IE/Opera. */
6826 delta = e.wheelDelta/120;
6827 }else if(e.detail){ /* Mozilla case. */
6828 delta = -e.detail/3;
6834 * Returns true if the control, meta, shift or alt key was pressed during this event.
6837 hasModifier : function(){
6838 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6842 * Returns true if the target of this event equals el or is a child of el
6843 * @param {String/HTMLElement/Element} el
6844 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6847 within : function(el, related){
6848 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6849 return t && Roo.fly(el).contains(t);
6852 getPoint : function(){
6853 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6857 return new Roo.EventObjectImpl();
6862 * Ext JS Library 1.1.1
6863 * Copyright(c) 2006-2007, Ext JS, LLC.
6865 * Originally Released Under LGPL - original licence link has changed is not relivant.
6868 * <script type="text/javascript">
6872 // was in Composite Element!??!?!
6875 var D = Roo.lib.Dom;
6876 var E = Roo.lib.Event;
6877 var A = Roo.lib.Anim;
6879 // local style camelizing for speed
6881 var camelRe = /(-[a-z])/gi;
6882 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6883 var view = document.defaultView;
6886 * @class Roo.Element
6887 * Represents an Element in the DOM.<br><br>
6890 var el = Roo.get("my-div");
6893 var el = getEl("my-div");
6895 // or with a DOM element
6896 var el = Roo.get(myDivElement);
6898 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6899 * each call instead of constructing a new one.<br><br>
6900 * <b>Animations</b><br />
6901 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6902 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6904 Option Default Description
6905 --------- -------- ---------------------------------------------
6906 duration .35 The duration of the animation in seconds
6907 easing easeOut The YUI easing method
6908 callback none A function to execute when the anim completes
6909 scope this The scope (this) of the callback function
6911 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6912 * manipulate the animation. Here's an example:
6914 var el = Roo.get("my-div");
6919 // default animation
6920 el.setWidth(100, true);
6922 // animation with some options set
6929 // using the "anim" property to get the Anim object
6935 el.setWidth(100, opt);
6937 if(opt.anim.isAnimated()){
6941 * <b> Composite (Collections of) Elements</b><br />
6942 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6943 * @constructor Create a new Element directly.
6944 * @param {String/HTMLElement} element
6945 * @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).
6947 Roo.Element = function(element, forceNew){
6948 var dom = typeof element == "string" ?
6949 document.getElementById(element) : element;
6950 if(!dom){ // invalid id/element
6954 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6955 return Roo.Element.cache[id];
6965 * The DOM element ID
6968 this.id = id || Roo.id(dom);
6971 var El = Roo.Element;
6975 * The element's default display mode (defaults to "")
6978 originalDisplay : "",
6982 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6987 * Sets the element's visibility mode. When setVisible() is called it
6988 * will use this to determine whether to set the visibility or the display property.
6989 * @param visMode Element.VISIBILITY or Element.DISPLAY
6990 * @return {Roo.Element} this
6992 setVisibilityMode : function(visMode){
6993 this.visibilityMode = visMode;
6997 * Convenience method for setVisibilityMode(Element.DISPLAY)
6998 * @param {String} display (optional) What to set display to when visible
6999 * @return {Roo.Element} this
7001 enableDisplayMode : function(display){
7002 this.setVisibilityMode(El.DISPLAY);
7003 if(typeof display != "undefined") this.originalDisplay = display;
7008 * 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)
7009 * @param {String} selector The simple selector to test
7010 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7011 search as a number or element (defaults to 10 || document.body)
7012 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7013 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7015 findParent : function(simpleSelector, maxDepth, returnEl){
7016 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7017 maxDepth = maxDepth || 50;
7018 if(typeof maxDepth != "number"){
7019 stopEl = Roo.getDom(maxDepth);
7022 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7023 if(dq.is(p, simpleSelector)){
7024 return returnEl ? Roo.get(p) : p;
7034 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7035 * @param {String} selector The simple selector to test
7036 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7037 search as a number or element (defaults to 10 || document.body)
7038 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7039 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7041 findParentNode : function(simpleSelector, maxDepth, returnEl){
7042 var p = Roo.fly(this.dom.parentNode, '_internal');
7043 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7047 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7048 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7049 * @param {String} selector The simple selector to test
7050 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7051 search as a number or element (defaults to 10 || document.body)
7052 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7054 up : function(simpleSelector, maxDepth){
7055 return this.findParentNode(simpleSelector, maxDepth, true);
7061 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7062 * @param {String} selector The simple selector to test
7063 * @return {Boolean} True if this element matches the selector, else false
7065 is : function(simpleSelector){
7066 return Roo.DomQuery.is(this.dom, simpleSelector);
7070 * Perform animation on this element.
7071 * @param {Object} args The YUI animation control args
7072 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7073 * @param {Function} onComplete (optional) Function to call when animation completes
7074 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7075 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7076 * @return {Roo.Element} this
7078 animate : function(args, duration, onComplete, easing, animType){
7079 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7084 * @private Internal animation call
7086 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7087 animType = animType || 'run';
7089 var anim = Roo.lib.Anim[animType](
7091 (opt.duration || defaultDur) || .35,
7092 (opt.easing || defaultEase) || 'easeOut',
7094 Roo.callback(cb, this);
7095 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7103 // private legacy anim prep
7104 preanim : function(a, i){
7105 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7109 * Removes worthless text nodes
7110 * @param {Boolean} forceReclean (optional) By default the element
7111 * keeps track if it has been cleaned already so
7112 * you can call this over and over. However, if you update the element and
7113 * need to force a reclean, you can pass true.
7115 clean : function(forceReclean){
7116 if(this.isCleaned && forceReclean !== true){
7120 var d = this.dom, n = d.firstChild, ni = -1;
7122 var nx = n.nextSibling;
7123 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7130 this.isCleaned = true;
7135 calcOffsetsTo : function(el){
7138 var restorePos = false;
7139 if(el.getStyle('position') == 'static'){
7140 el.position('relative');
7145 while(op && op != d && op.tagName != 'HTML'){
7148 op = op.offsetParent;
7151 el.position('static');
7157 * Scrolls this element into view within the passed container.
7158 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7159 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7160 * @return {Roo.Element} this
7162 scrollIntoView : function(container, hscroll){
7163 var c = Roo.getDom(container) || document.body;
7166 var o = this.calcOffsetsTo(c),
7169 b = t+el.offsetHeight,
7170 r = l+el.offsetWidth;
7172 var ch = c.clientHeight;
7173 var ct = parseInt(c.scrollTop, 10);
7174 var cl = parseInt(c.scrollLeft, 10);
7176 var cr = cl + c.clientWidth;
7184 if(hscroll !== false){
7188 c.scrollLeft = r-c.clientWidth;
7195 scrollChildIntoView : function(child, hscroll){
7196 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7200 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7201 * the new height may not be available immediately.
7202 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7203 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7204 * @param {Function} onComplete (optional) Function to call when animation completes
7205 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7206 * @return {Roo.Element} this
7208 autoHeight : function(animate, duration, onComplete, easing){
7209 var oldHeight = this.getHeight();
7211 this.setHeight(1); // force clipping
7212 setTimeout(function(){
7213 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7215 this.setHeight(height);
7217 if(typeof onComplete == "function"){
7221 this.setHeight(oldHeight); // restore original height
7222 this.setHeight(height, animate, duration, function(){
7224 if(typeof onComplete == "function") onComplete();
7225 }.createDelegate(this), easing);
7227 }.createDelegate(this), 0);
7232 * Returns true if this element is an ancestor of the passed element
7233 * @param {HTMLElement/String} el The element to check
7234 * @return {Boolean} True if this element is an ancestor of el, else false
7236 contains : function(el){
7237 if(!el){return false;}
7238 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7242 * Checks whether the element is currently visible using both visibility and display properties.
7243 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7244 * @return {Boolean} True if the element is currently visible, else false
7246 isVisible : function(deep) {
7247 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7248 if(deep !== true || !vis){
7251 var p = this.dom.parentNode;
7252 while(p && p.tagName.toLowerCase() != "body"){
7253 if(!Roo.fly(p, '_isVisible').isVisible()){
7262 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7263 * @param {String} selector The CSS selector
7264 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7265 * @return {CompositeElement/CompositeElementLite} The composite element
7267 select : function(selector, unique){
7268 return El.select(selector, unique, this.dom);
7272 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7273 * @param {String} selector The CSS selector
7274 * @return {Array} An array of the matched nodes
7276 query : function(selector, unique){
7277 return Roo.DomQuery.select(selector, this.dom);
7281 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7282 * @param {String} selector The CSS selector
7283 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7284 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7286 child : function(selector, returnDom){
7287 var n = Roo.DomQuery.selectNode(selector, this.dom);
7288 return returnDom ? n : Roo.get(n);
7292 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7293 * @param {String} selector The CSS selector
7294 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7295 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7297 down : function(selector, returnDom){
7298 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7299 return returnDom ? n : Roo.get(n);
7303 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7304 * @param {String} group The group the DD object is member of
7305 * @param {Object} config The DD config object
7306 * @param {Object} overrides An object containing methods to override/implement on the DD object
7307 * @return {Roo.dd.DD} The DD object
7309 initDD : function(group, config, overrides){
7310 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7311 return Roo.apply(dd, overrides);
7315 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7316 * @param {String} group The group the DDProxy object is member of
7317 * @param {Object} config The DDProxy config object
7318 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7319 * @return {Roo.dd.DDProxy} The DDProxy object
7321 initDDProxy : function(group, config, overrides){
7322 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7323 return Roo.apply(dd, overrides);
7327 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7328 * @param {String} group The group the DDTarget object is member of
7329 * @param {Object} config The DDTarget config object
7330 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7331 * @return {Roo.dd.DDTarget} The DDTarget object
7333 initDDTarget : function(group, config, overrides){
7334 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7335 return Roo.apply(dd, overrides);
7339 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7340 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7341 * @param {Boolean} visible Whether the element is visible
7342 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7343 * @return {Roo.Element} this
7345 setVisible : function(visible, animate){
7347 if(this.visibilityMode == El.DISPLAY){
7348 this.setDisplayed(visible);
7351 this.dom.style.visibility = visible ? "visible" : "hidden";
7354 // closure for composites
7356 var visMode = this.visibilityMode;
7358 this.setOpacity(.01);
7359 this.setVisible(true);
7361 this.anim({opacity: { to: (visible?1:0) }},
7362 this.preanim(arguments, 1),
7363 null, .35, 'easeIn', function(){
7365 if(visMode == El.DISPLAY){
7366 dom.style.display = "none";
7368 dom.style.visibility = "hidden";
7370 Roo.get(dom).setOpacity(1);
7378 * Returns true if display is not "none"
7381 isDisplayed : function() {
7382 return this.getStyle("display") != "none";
7386 * Toggles the element's visibility or display, depending on visibility mode.
7387 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7388 * @return {Roo.Element} this
7390 toggle : function(animate){
7391 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7396 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7397 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7398 * @return {Roo.Element} this
7400 setDisplayed : function(value) {
7401 if(typeof value == "boolean"){
7402 value = value ? this.originalDisplay : "none";
7404 this.setStyle("display", value);
7409 * Tries to focus the element. Any exceptions are caught and ignored.
7410 * @return {Roo.Element} this
7412 focus : function() {
7420 * Tries to blur the element. Any exceptions are caught and ignored.
7421 * @return {Roo.Element} this
7431 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7432 * @param {String/Array} className The CSS class to add, or an array of classes
7433 * @return {Roo.Element} this
7435 addClass : function(className){
7436 if(className instanceof Array){
7437 for(var i = 0, len = className.length; i < len; i++) {
7438 this.addClass(className[i]);
7441 if(className && !this.hasClass(className)){
7442 this.dom.className = this.dom.className + " " + className;
7449 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7450 * @param {String/Array} className The CSS class to add, or an array of classes
7451 * @return {Roo.Element} this
7453 radioClass : function(className){
7454 var siblings = this.dom.parentNode.childNodes;
7455 for(var i = 0; i < siblings.length; i++) {
7456 var s = siblings[i];
7457 if(s.nodeType == 1){
7458 Roo.get(s).removeClass(className);
7461 this.addClass(className);
7466 * Removes one or more CSS classes from the element.
7467 * @param {String/Array} className The CSS class to remove, or an array of classes
7468 * @return {Roo.Element} this
7470 removeClass : function(className){
7471 if(!className || !this.dom.className){
7474 if(className instanceof Array){
7475 for(var i = 0, len = className.length; i < len; i++) {
7476 this.removeClass(className[i]);
7479 if(this.hasClass(className)){
7480 var re = this.classReCache[className];
7482 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7483 this.classReCache[className] = re;
7485 this.dom.className =
7486 this.dom.className.replace(re, " ");
7496 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7497 * @param {String} className The CSS class to toggle
7498 * @return {Roo.Element} this
7500 toggleClass : function(className){
7501 if(this.hasClass(className)){
7502 this.removeClass(className);
7504 this.addClass(className);
7510 * Checks if the specified CSS class exists on this element's DOM node.
7511 * @param {String} className The CSS class to check for
7512 * @return {Boolean} True if the class exists, else false
7514 hasClass : function(className){
7515 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7519 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7520 * @param {String} oldClassName The CSS class to replace
7521 * @param {String} newClassName The replacement CSS class
7522 * @return {Roo.Element} this
7524 replaceClass : function(oldClassName, newClassName){
7525 this.removeClass(oldClassName);
7526 this.addClass(newClassName);
7531 * Returns an object with properties matching the styles requested.
7532 * For example, el.getStyles('color', 'font-size', 'width') might return
7533 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7534 * @param {String} style1 A style name
7535 * @param {String} style2 A style name
7536 * @param {String} etc.
7537 * @return {Object} The style object
7539 getStyles : function(){
7540 var a = arguments, len = a.length, r = {};
7541 for(var i = 0; i < len; i++){
7542 r[a[i]] = this.getStyle(a[i]);
7548 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7549 * @param {String} property The style property whose value is returned.
7550 * @return {String} The current value of the style property for this element.
7552 getStyle : function(){
7553 return view && view.getComputedStyle ?
7555 var el = this.dom, v, cs, camel;
7556 if(prop == 'float'){
7559 if(el.style && (v = el.style[prop])){
7562 if(cs = view.getComputedStyle(el, "")){
7563 if(!(camel = propCache[prop])){
7564 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7571 var el = this.dom, v, cs, camel;
7572 if(prop == 'opacity'){
7573 if(typeof el.style.filter == 'string'){
7574 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7576 var fv = parseFloat(m[1]);
7578 return fv ? fv / 100 : 0;
7583 }else if(prop == 'float'){
7584 prop = "styleFloat";
7586 if(!(camel = propCache[prop])){
7587 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7589 if(v = el.style[camel]){
7592 if(cs = el.currentStyle){
7600 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7601 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7602 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7603 * @return {Roo.Element} this
7605 setStyle : function(prop, value){
7606 if(typeof prop == "string"){
7608 if (prop == 'float') {
7609 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7614 if(!(camel = propCache[prop])){
7615 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7618 if(camel == 'opacity') {
7619 this.setOpacity(value);
7621 this.dom.style[camel] = value;
7624 for(var style in prop){
7625 if(typeof prop[style] != "function"){
7626 this.setStyle(style, prop[style]);
7634 * More flexible version of {@link #setStyle} for setting style properties.
7635 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7636 * a function which returns such a specification.
7637 * @return {Roo.Element} this
7639 applyStyles : function(style){
7640 Roo.DomHelper.applyStyles(this.dom, style);
7645 * 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).
7646 * @return {Number} The X position of the element
7649 return D.getX(this.dom);
7653 * 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).
7654 * @return {Number} The Y position of the element
7657 return D.getY(this.dom);
7661 * 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).
7662 * @return {Array} The XY position of the element
7665 return D.getXY(this.dom);
7669 * 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).
7670 * @param {Number} The X position of the element
7671 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7672 * @return {Roo.Element} this
7674 setX : function(x, animate){
7676 D.setX(this.dom, x);
7678 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7684 * 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).
7685 * @param {Number} The Y position of the element
7686 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7687 * @return {Roo.Element} this
7689 setY : function(y, animate){
7691 D.setY(this.dom, y);
7693 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7699 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7700 * @param {String} left The left CSS property value
7701 * @return {Roo.Element} this
7703 setLeft : function(left){
7704 this.setStyle("left", this.addUnits(left));
7709 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7710 * @param {String} top The top CSS property value
7711 * @return {Roo.Element} this
7713 setTop : function(top){
7714 this.setStyle("top", this.addUnits(top));
7719 * Sets the element's CSS right style.
7720 * @param {String} right The right CSS property value
7721 * @return {Roo.Element} this
7723 setRight : function(right){
7724 this.setStyle("right", this.addUnits(right));
7729 * Sets the element's CSS bottom style.
7730 * @param {String} bottom The bottom CSS property value
7731 * @return {Roo.Element} this
7733 setBottom : function(bottom){
7734 this.setStyle("bottom", this.addUnits(bottom));
7739 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7740 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7741 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7742 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7743 * @return {Roo.Element} this
7745 setXY : function(pos, animate){
7747 D.setXY(this.dom, pos);
7749 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7755 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7756 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7757 * @param {Number} x X value for new position (coordinates are page-based)
7758 * @param {Number} y Y value for new position (coordinates are page-based)
7759 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7760 * @return {Roo.Element} this
7762 setLocation : function(x, y, animate){
7763 this.setXY([x, y], this.preanim(arguments, 2));
7768 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7769 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7770 * @param {Number} x X value for new position (coordinates are page-based)
7771 * @param {Number} y Y value for new position (coordinates are page-based)
7772 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7773 * @return {Roo.Element} this
7775 moveTo : function(x, y, animate){
7776 this.setXY([x, y], this.preanim(arguments, 2));
7781 * Returns the region of the given element.
7782 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7783 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7785 getRegion : function(){
7786 return D.getRegion(this.dom);
7790 * Returns the offset height of the element
7791 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7792 * @return {Number} The element's height
7794 getHeight : function(contentHeight){
7795 var h = this.dom.offsetHeight || 0;
7796 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7800 * Returns the offset width of the element
7801 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7802 * @return {Number} The element's width
7804 getWidth : function(contentWidth){
7805 var w = this.dom.offsetWidth || 0;
7806 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7810 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7811 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7812 * if a height has not been set using CSS.
7815 getComputedHeight : function(){
7816 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7818 h = parseInt(this.getStyle('height'), 10) || 0;
7819 if(!this.isBorderBox()){
7820 h += this.getFrameWidth('tb');
7827 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7828 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7829 * if a width has not been set using CSS.
7832 getComputedWidth : function(){
7833 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7835 w = parseInt(this.getStyle('width'), 10) || 0;
7836 if(!this.isBorderBox()){
7837 w += this.getFrameWidth('lr');
7844 * Returns the size of the element.
7845 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7846 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7848 getSize : function(contentSize){
7849 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7853 * Returns the width and height of the viewport.
7854 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7856 getViewSize : function(){
7857 var d = this.dom, doc = document, aw = 0, ah = 0;
7858 if(d == doc || d == doc.body){
7859 return {width : D.getViewWidth(), height: D.getViewHeight()};
7862 width : d.clientWidth,
7863 height: d.clientHeight
7869 * Returns the value of the "value" attribute
7870 * @param {Boolean} asNumber true to parse the value as a number
7871 * @return {String/Number}
7873 getValue : function(asNumber){
7874 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7878 adjustWidth : function(width){
7879 if(typeof width == "number"){
7880 if(this.autoBoxAdjust && !this.isBorderBox()){
7881 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7891 adjustHeight : function(height){
7892 if(typeof height == "number"){
7893 if(this.autoBoxAdjust && !this.isBorderBox()){
7894 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7904 * Set the width of the element
7905 * @param {Number} width The new width
7906 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7907 * @return {Roo.Element} this
7909 setWidth : function(width, animate){
7910 width = this.adjustWidth(width);
7912 this.dom.style.width = this.addUnits(width);
7914 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7920 * Set the height of the element
7921 * @param {Number} height The new height
7922 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7923 * @return {Roo.Element} this
7925 setHeight : function(height, animate){
7926 height = this.adjustHeight(height);
7928 this.dom.style.height = this.addUnits(height);
7930 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7936 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7937 * @param {Number} width The new width
7938 * @param {Number} height The new height
7939 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7940 * @return {Roo.Element} this
7942 setSize : function(width, height, animate){
7943 if(typeof width == "object"){ // in case of object from getSize()
7944 height = width.height; width = width.width;
7946 width = this.adjustWidth(width); height = this.adjustHeight(height);
7948 this.dom.style.width = this.addUnits(width);
7949 this.dom.style.height = this.addUnits(height);
7951 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7957 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7958 * @param {Number} x X value for new position (coordinates are page-based)
7959 * @param {Number} y Y value for new position (coordinates are page-based)
7960 * @param {Number} width The new width
7961 * @param {Number} height The new height
7962 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7963 * @return {Roo.Element} this
7965 setBounds : function(x, y, width, height, animate){
7967 this.setSize(width, height);
7968 this.setLocation(x, y);
7970 width = this.adjustWidth(width); height = this.adjustHeight(height);
7971 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7972 this.preanim(arguments, 4), 'motion');
7978 * 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.
7979 * @param {Roo.lib.Region} region The region to fill
7980 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7981 * @return {Roo.Element} this
7983 setRegion : function(region, animate){
7984 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7989 * Appends an event handler
7991 * @param {String} eventName The type of event to append
7992 * @param {Function} fn The method the event invokes
7993 * @param {Object} scope (optional) The scope (this object) of the fn
7994 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7996 addListener : function(eventName, fn, scope, options){
7998 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8003 * Removes an event handler from this element
8004 * @param {String} eventName the type of event to remove
8005 * @param {Function} fn the method the event invokes
8006 * @return {Roo.Element} this
8008 removeListener : function(eventName, fn){
8009 Roo.EventManager.removeListener(this.dom, eventName, fn);
8014 * Removes all previous added listeners from this element
8015 * @return {Roo.Element} this
8017 removeAllListeners : function(){
8018 E.purgeElement(this.dom);
8022 relayEvent : function(eventName, observable){
8023 this.on(eventName, function(e){
8024 observable.fireEvent(eventName, e);
8029 * Set the opacity of the element
8030 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8031 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8032 * @return {Roo.Element} this
8034 setOpacity : function(opacity, animate){
8036 var s = this.dom.style;
8039 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8040 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8042 s.opacity = opacity;
8045 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8051 * Gets the left X coordinate
8052 * @param {Boolean} local True to get the local css position instead of page coordinate
8055 getLeft : function(local){
8059 return parseInt(this.getStyle("left"), 10) || 0;
8064 * Gets the right X coordinate of the element (element X position + element width)
8065 * @param {Boolean} local True to get the local css position instead of page coordinate
8068 getRight : function(local){
8070 return this.getX() + this.getWidth();
8072 return (this.getLeft(true) + this.getWidth()) || 0;
8077 * Gets the top Y coordinate
8078 * @param {Boolean} local True to get the local css position instead of page coordinate
8081 getTop : function(local) {
8085 return parseInt(this.getStyle("top"), 10) || 0;
8090 * Gets the bottom Y coordinate of the element (element Y position + element height)
8091 * @param {Boolean} local True to get the local css position instead of page coordinate
8094 getBottom : function(local){
8096 return this.getY() + this.getHeight();
8098 return (this.getTop(true) + this.getHeight()) || 0;
8103 * Initializes positioning on this element. If a desired position is not passed, it will make the
8104 * the element positioned relative IF it is not already positioned.
8105 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8106 * @param {Number} zIndex (optional) The zIndex to apply
8107 * @param {Number} x (optional) Set the page X position
8108 * @param {Number} y (optional) Set the page Y position
8110 position : function(pos, zIndex, x, y){
8112 if(this.getStyle('position') == 'static'){
8113 this.setStyle('position', 'relative');
8116 this.setStyle("position", pos);
8119 this.setStyle("z-index", zIndex);
8121 if(x !== undefined && y !== undefined){
8123 }else if(x !== undefined){
8125 }else if(y !== undefined){
8131 * Clear positioning back to the default when the document was loaded
8132 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8133 * @return {Roo.Element} this
8135 clearPositioning : function(value){
8143 "position" : "static"
8149 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8150 * snapshot before performing an update and then restoring the element.
8153 getPositioning : function(){
8154 var l = this.getStyle("left");
8155 var t = this.getStyle("top");
8157 "position" : this.getStyle("position"),
8159 "right" : l ? "" : this.getStyle("right"),
8161 "bottom" : t ? "" : this.getStyle("bottom"),
8162 "z-index" : this.getStyle("z-index")
8167 * Gets the width of the border(s) for the specified side(s)
8168 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8169 * passing lr would get the border (l)eft width + the border (r)ight width.
8170 * @return {Number} The width of the sides passed added together
8172 getBorderWidth : function(side){
8173 return this.addStyles(side, El.borders);
8177 * Gets the width of the padding(s) for the specified side(s)
8178 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8179 * passing lr would get the padding (l)eft + the padding (r)ight.
8180 * @return {Number} The padding of the sides passed added together
8182 getPadding : function(side){
8183 return this.addStyles(side, El.paddings);
8187 * Set positioning with an object returned by getPositioning().
8188 * @param {Object} posCfg
8189 * @return {Roo.Element} this
8191 setPositioning : function(pc){
8192 this.applyStyles(pc);
8193 if(pc.right == "auto"){
8194 this.dom.style.right = "";
8196 if(pc.bottom == "auto"){
8197 this.dom.style.bottom = "";
8203 fixDisplay : function(){
8204 if(this.getStyle("display") == "none"){
8205 this.setStyle("visibility", "hidden");
8206 this.setStyle("display", this.originalDisplay); // first try reverting to default
8207 if(this.getStyle("display") == "none"){ // if that fails, default to block
8208 this.setStyle("display", "block");
8214 * Quick set left and top adding default units
8215 * @param {String} left The left CSS property value
8216 * @param {String} top The top CSS property value
8217 * @return {Roo.Element} this
8219 setLeftTop : function(left, top){
8220 this.dom.style.left = this.addUnits(left);
8221 this.dom.style.top = this.addUnits(top);
8226 * Move this element relative to its current position.
8227 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8228 * @param {Number} distance How far to move the element in pixels
8229 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8230 * @return {Roo.Element} this
8232 move : function(direction, distance, animate){
8233 var xy = this.getXY();
8234 direction = direction.toLowerCase();
8238 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8242 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8247 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8252 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8259 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8260 * @return {Roo.Element} this
8263 if(!this.isClipped){
8264 this.isClipped = true;
8265 this.originalClip = {
8266 "o": this.getStyle("overflow"),
8267 "x": this.getStyle("overflow-x"),
8268 "y": this.getStyle("overflow-y")
8270 this.setStyle("overflow", "hidden");
8271 this.setStyle("overflow-x", "hidden");
8272 this.setStyle("overflow-y", "hidden");
8278 * Return clipping (overflow) to original clipping before clip() was called
8279 * @return {Roo.Element} this
8281 unclip : function(){
8283 this.isClipped = false;
8284 var o = this.originalClip;
8285 if(o.o){this.setStyle("overflow", o.o);}
8286 if(o.x){this.setStyle("overflow-x", o.x);}
8287 if(o.y){this.setStyle("overflow-y", o.y);}
8294 * Gets the x,y coordinates specified by the anchor position on the element.
8295 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8296 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8297 * {width: (target width), height: (target height)} (defaults to the element's current size)
8298 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8299 * @return {Array} [x, y] An array containing the element's x and y coordinates
8301 getAnchorXY : function(anchor, local, s){
8302 //Passing a different size is useful for pre-calculating anchors,
8303 //especially for anchored animations that change the el size.
8305 var w, h, vp = false;
8308 if(d == document.body || d == document){
8310 w = D.getViewWidth(); h = D.getViewHeight();
8312 w = this.getWidth(); h = this.getHeight();
8315 w = s.width; h = s.height;
8317 var x = 0, y = 0, r = Math.round;
8318 switch((anchor || "tl").toLowerCase()){
8360 var sc = this.getScroll();
8361 return [x + sc.left, y + sc.top];
8363 //Add the element's offset xy
8364 var o = this.getXY();
8365 return [x+o[0], y+o[1]];
8369 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8370 * supported position values.
8371 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8372 * @param {String} position The position to align to.
8373 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8374 * @return {Array} [x, y]
8376 getAlignToXY : function(el, p, o){
8380 throw "Element.alignTo with an element that doesn't exist";
8382 var c = false; //constrain to viewport
8383 var p1 = "", p2 = "";
8390 }else if(p.indexOf("-") == -1){
8393 p = p.toLowerCase();
8394 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8396 throw "Element.alignTo with an invalid alignment " + p;
8398 p1 = m[1]; p2 = m[2]; c = !!m[3];
8400 //Subtract the aligned el's internal xy from the target's offset xy
8401 //plus custom offset to get the aligned el's new offset xy
8402 var a1 = this.getAnchorXY(p1, true);
8403 var a2 = el.getAnchorXY(p2, false);
8404 var x = a2[0] - a1[0] + o[0];
8405 var y = a2[1] - a1[1] + o[1];
8407 //constrain the aligned el to viewport if necessary
8408 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8409 // 5px of margin for ie
8410 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8412 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8413 //perpendicular to the vp border, allow the aligned el to slide on that border,
8414 //otherwise swap the aligned el to the opposite border of the target.
8415 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8416 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8417 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8418 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8421 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8422 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8424 if((x+w) > dw + scrollX){
8425 x = swapX ? r.left-w : dw+scrollX-w;
8428 x = swapX ? r.right : scrollX;
8430 if((y+h) > dh + scrollY){
8431 y = swapY ? r.top-h : dh+scrollY-h;
8434 y = swapY ? r.bottom : scrollY;
8441 getConstrainToXY : function(){
8442 var os = {top:0, left:0, bottom:0, right: 0};
8444 return function(el, local, offsets, proposedXY){
8446 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8448 var vw, vh, vx = 0, vy = 0;
8449 if(el.dom == document.body || el.dom == document){
8450 vw = Roo.lib.Dom.getViewWidth();
8451 vh = Roo.lib.Dom.getViewHeight();
8453 vw = el.dom.clientWidth;
8454 vh = el.dom.clientHeight;
8456 var vxy = el.getXY();
8462 var s = el.getScroll();
8464 vx += offsets.left + s.left;
8465 vy += offsets.top + s.top;
8467 vw -= offsets.right;
8468 vh -= offsets.bottom;
8473 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8474 var x = xy[0], y = xy[1];
8475 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8477 // only move it if it needs it
8480 // first validate right/bottom
8489 // then make sure top/left isn't negative
8498 return moved ? [x, y] : false;
8503 adjustForConstraints : function(xy, parent, offsets){
8504 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8508 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8509 * document it aligns it to the viewport.
8510 * The position parameter is optional, and can be specified in any one of the following formats:
8512 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8513 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8514 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8515 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8516 * <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
8517 * element's anchor point, and the second value is used as the target's anchor point.</li>
8519 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8520 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8521 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8522 * that specified in order to enforce the viewport constraints.
8523 * Following are all of the supported anchor positions:
8526 ----- -----------------------------
8527 tl The top left corner (default)
8528 t The center of the top edge
8529 tr The top right corner
8530 l The center of the left edge
8531 c In the center of the element
8532 r The center of the right edge
8533 bl The bottom left corner
8534 b The center of the bottom edge
8535 br The bottom right corner
8539 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8540 el.alignTo("other-el");
8542 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8543 el.alignTo("other-el", "tr?");
8545 // align the bottom right corner of el with the center left edge of other-el
8546 el.alignTo("other-el", "br-l?");
8548 // align the center of el with the bottom left corner of other-el and
8549 // adjust the x position by -6 pixels (and the y position by 0)
8550 el.alignTo("other-el", "c-bl", [-6, 0]);
8552 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8553 * @param {String} position The position to align to.
8554 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8555 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8556 * @return {Roo.Element} this
8558 alignTo : function(element, position, offsets, animate){
8559 var xy = this.getAlignToXY(element, position, offsets);
8560 this.setXY(xy, this.preanim(arguments, 3));
8565 * Anchors an element to another element and realigns it when the window is resized.
8566 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8567 * @param {String} position The position to align to.
8568 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8569 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8570 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8571 * is a number, it is used as the buffer delay (defaults to 50ms).
8572 * @param {Function} callback The function to call after the animation finishes
8573 * @return {Roo.Element} this
8575 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8576 var action = function(){
8577 this.alignTo(el, alignment, offsets, animate);
8578 Roo.callback(callback, this);
8580 Roo.EventManager.onWindowResize(action, this);
8581 var tm = typeof monitorScroll;
8582 if(tm != 'undefined'){
8583 Roo.EventManager.on(window, 'scroll', action, this,
8584 {buffer: tm == 'number' ? monitorScroll : 50});
8586 action.call(this); // align immediately
8590 * Clears any opacity settings from this element. Required in some cases for IE.
8591 * @return {Roo.Element} this
8593 clearOpacity : function(){
8594 if (window.ActiveXObject) {
8595 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8596 this.dom.style.filter = "";
8599 this.dom.style.opacity = "";
8600 this.dom.style["-moz-opacity"] = "";
8601 this.dom.style["-khtml-opacity"] = "";
8607 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8608 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8609 * @return {Roo.Element} this
8611 hide : function(animate){
8612 this.setVisible(false, this.preanim(arguments, 0));
8617 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8618 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8619 * @return {Roo.Element} this
8621 show : function(animate){
8622 this.setVisible(true, this.preanim(arguments, 0));
8627 * @private Test if size has a unit, otherwise appends the default
8629 addUnits : function(size){
8630 return Roo.Element.addUnits(size, this.defaultUnit);
8634 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8635 * @return {Roo.Element} this
8637 beginMeasure : function(){
8639 if(el.offsetWidth || el.offsetHeight){
8640 return this; // offsets work already
8643 var p = this.dom, b = document.body; // start with this element
8644 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8645 var pe = Roo.get(p);
8646 if(pe.getStyle('display') == 'none'){
8647 changed.push({el: p, visibility: pe.getStyle("visibility")});
8648 p.style.visibility = "hidden";
8649 p.style.display = "block";
8653 this._measureChanged = changed;
8659 * Restores displays to before beginMeasure was called
8660 * @return {Roo.Element} this
8662 endMeasure : function(){
8663 var changed = this._measureChanged;
8665 for(var i = 0, len = changed.length; i < len; i++) {
8667 r.el.style.visibility = r.visibility;
8668 r.el.style.display = "none";
8670 this._measureChanged = null;
8676 * Update the innerHTML of this element, optionally searching for and processing scripts
8677 * @param {String} html The new HTML
8678 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8679 * @param {Function} callback For async script loading you can be noticed when the update completes
8680 * @return {Roo.Element} this
8682 update : function(html, loadScripts, callback){
8683 if(typeof html == "undefined"){
8686 if(loadScripts !== true){
8687 this.dom.innerHTML = html;
8688 if(typeof callback == "function"){
8696 html += '<span id="' + id + '"></span>';
8698 E.onAvailable(id, function(){
8699 var hd = document.getElementsByTagName("head")[0];
8700 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8701 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8702 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8705 while(match = re.exec(html)){
8706 var attrs = match[1];
8707 var srcMatch = attrs ? attrs.match(srcRe) : false;
8708 if(srcMatch && srcMatch[2]){
8709 var s = document.createElement("script");
8710 s.src = srcMatch[2];
8711 var typeMatch = attrs.match(typeRe);
8712 if(typeMatch && typeMatch[2]){
8713 s.type = typeMatch[2];
8716 }else if(match[2] && match[2].length > 0){
8717 if(window.execScript) {
8718 window.execScript(match[2]);
8726 window.eval(match[2]);
8730 var el = document.getElementById(id);
8731 if(el){el.parentNode.removeChild(el);}
8732 if(typeof callback == "function"){
8736 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8741 * Direct access to the UpdateManager update() method (takes the same parameters).
8742 * @param {String/Function} url The url for this request or a function to call to get the url
8743 * @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}
8744 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8745 * @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.
8746 * @return {Roo.Element} this
8749 var um = this.getUpdateManager();
8750 um.update.apply(um, arguments);
8755 * Gets this element's UpdateManager
8756 * @return {Roo.UpdateManager} The UpdateManager
8758 getUpdateManager : function(){
8759 if(!this.updateManager){
8760 this.updateManager = new Roo.UpdateManager(this);
8762 return this.updateManager;
8766 * Disables text selection for this element (normalized across browsers)
8767 * @return {Roo.Element} this
8769 unselectable : function(){
8770 this.dom.unselectable = "on";
8771 this.swallowEvent("selectstart", true);
8772 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8773 this.addClass("x-unselectable");
8778 * Calculates the x, y to center this element on the screen
8779 * @return {Array} The x, y values [x, y]
8781 getCenterXY : function(){
8782 return this.getAlignToXY(document, 'c-c');
8786 * Centers the Element in either the viewport, or another Element.
8787 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8789 center : function(centerIn){
8790 this.alignTo(centerIn || document, 'c-c');
8795 * Tests various css rules/browsers to determine if this element uses a border box
8798 isBorderBox : function(){
8799 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8803 * Return a box {x, y, width, height} that can be used to set another elements
8804 * size/location to match this element.
8805 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8806 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8807 * @return {Object} box An object in the format {x, y, width, height}
8809 getBox : function(contentBox, local){
8814 var left = parseInt(this.getStyle("left"), 10) || 0;
8815 var top = parseInt(this.getStyle("top"), 10) || 0;
8818 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8820 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8822 var l = this.getBorderWidth("l")+this.getPadding("l");
8823 var r = this.getBorderWidth("r")+this.getPadding("r");
8824 var t = this.getBorderWidth("t")+this.getPadding("t");
8825 var b = this.getBorderWidth("b")+this.getPadding("b");
8826 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)};
8828 bx.right = bx.x + bx.width;
8829 bx.bottom = bx.y + bx.height;
8834 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8835 for more information about the sides.
8836 * @param {String} sides
8839 getFrameWidth : function(sides, onlyContentBox){
8840 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8844 * 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.
8845 * @param {Object} box The box to fill {x, y, width, height}
8846 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8847 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8848 * @return {Roo.Element} this
8850 setBox : function(box, adjust, animate){
8851 var w = box.width, h = box.height;
8852 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8853 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8854 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8856 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8861 * Forces the browser to repaint this element
8862 * @return {Roo.Element} this
8864 repaint : function(){
8866 this.addClass("x-repaint");
8867 setTimeout(function(){
8868 Roo.get(dom).removeClass("x-repaint");
8874 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8875 * then it returns the calculated width of the sides (see getPadding)
8876 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8877 * @return {Object/Number}
8879 getMargins : function(side){
8882 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8883 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8884 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8885 right: parseInt(this.getStyle("margin-right"), 10) || 0
8888 return this.addStyles(side, El.margins);
8893 addStyles : function(sides, styles){
8895 for(var i = 0, len = sides.length; i < len; i++){
8896 v = this.getStyle(styles[sides.charAt(i)]);
8898 w = parseInt(v, 10);
8906 * Creates a proxy element of this element
8907 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8908 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8909 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8910 * @return {Roo.Element} The new proxy element
8912 createProxy : function(config, renderTo, matchBox){
8914 renderTo = Roo.getDom(renderTo);
8916 renderTo = document.body;
8918 config = typeof config == "object" ?
8919 config : {tag : "div", cls: config};
8920 var proxy = Roo.DomHelper.append(renderTo, config, true);
8922 proxy.setBox(this.getBox());
8928 * Puts a mask over this element to disable user interaction. Requires core.css.
8929 * This method can only be applied to elements which accept child nodes.
8930 * @param {String} msg (optional) A message to display in the mask
8931 * @param {String} msgCls (optional) A css class to apply to the msg element
8932 * @return {Element} The mask element
8934 mask : function(msg, msgCls)
8936 if(this.getStyle("position") == "static"){
8937 this.setStyle("position", "relative");
8940 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8942 this.addClass("x-masked");
8943 this._mask.setDisplayed(true);
8948 while (dom && dom.style) {
8949 if (!isNaN(parseInt(dom.style.zIndex))) {
8950 z = Math.max(z, parseInt(dom.style.zIndex));
8952 dom = dom.parentNode;
8954 // if we are masking the body - then it hides everything..
8955 if (this.dom == document.body) {
8957 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8958 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8961 if(typeof msg == 'string'){
8963 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8965 var mm = this._maskMsg;
8966 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8967 mm.dom.firstChild.innerHTML = msg;
8968 mm.setDisplayed(true);
8970 mm.setStyle('z-index', z + 102);
8972 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8973 this._mask.setHeight(this.getHeight());
8975 this._mask.setStyle('z-index', z + 100);
8981 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8982 * it is cached for reuse.
8984 unmask : function(removeEl){
8986 if(removeEl === true){
8987 this._mask.remove();
8990 this._maskMsg.remove();
8991 delete this._maskMsg;
8994 this._mask.setDisplayed(false);
8996 this._maskMsg.setDisplayed(false);
9000 this.removeClass("x-masked");
9004 * Returns true if this element is masked
9007 isMasked : function(){
9008 return this._mask && this._mask.isVisible();
9012 * Creates an iframe shim for this element to keep selects and other windowed objects from
9014 * @return {Roo.Element} The new shim element
9016 createShim : function(){
9017 var el = document.createElement('iframe');
9018 el.frameBorder = 'no';
9019 el.className = 'roo-shim';
9020 if(Roo.isIE && Roo.isSecure){
9021 el.src = Roo.SSL_SECURE_URL;
9023 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9024 shim.autoBoxAdjust = false;
9029 * Removes this element from the DOM and deletes it from the cache
9031 remove : function(){
9032 if(this.dom.parentNode){
9033 this.dom.parentNode.removeChild(this.dom);
9035 delete El.cache[this.dom.id];
9039 * Sets up event handlers to add and remove a css class when the mouse is over this element
9040 * @param {String} className
9041 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9042 * mouseout events for children elements
9043 * @return {Roo.Element} this
9045 addClassOnOver : function(className, preventFlicker){
9046 this.on("mouseover", function(){
9047 Roo.fly(this, '_internal').addClass(className);
9049 var removeFn = function(e){
9050 if(preventFlicker !== true || !e.within(this, true)){
9051 Roo.fly(this, '_internal').removeClass(className);
9054 this.on("mouseout", removeFn, this.dom);
9059 * Sets up event handlers to add and remove a css class when this element has the focus
9060 * @param {String} className
9061 * @return {Roo.Element} this
9063 addClassOnFocus : function(className){
9064 this.on("focus", function(){
9065 Roo.fly(this, '_internal').addClass(className);
9067 this.on("blur", function(){
9068 Roo.fly(this, '_internal').removeClass(className);
9073 * 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)
9074 * @param {String} className
9075 * @return {Roo.Element} this
9077 addClassOnClick : function(className){
9079 this.on("mousedown", function(){
9080 Roo.fly(dom, '_internal').addClass(className);
9081 var d = Roo.get(document);
9082 var fn = function(){
9083 Roo.fly(dom, '_internal').removeClass(className);
9084 d.removeListener("mouseup", fn);
9086 d.on("mouseup", fn);
9092 * Stops the specified event from bubbling and optionally prevents the default action
9093 * @param {String} eventName
9094 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9095 * @return {Roo.Element} this
9097 swallowEvent : function(eventName, preventDefault){
9098 var fn = function(e){
9099 e.stopPropagation();
9104 if(eventName instanceof Array){
9105 for(var i = 0, len = eventName.length; i < len; i++){
9106 this.on(eventName[i], fn);
9110 this.on(eventName, fn);
9117 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9120 * Sizes this element to its parent element's dimensions performing
9121 * neccessary box adjustments.
9122 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9123 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9124 * @return {Roo.Element} this
9126 fitToParent : function(monitorResize, targetParent) {
9127 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9128 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9129 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9132 var p = Roo.get(targetParent || this.dom.parentNode);
9133 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9134 if (monitorResize === true) {
9135 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9136 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9142 * Gets the next sibling, skipping text nodes
9143 * @return {HTMLElement} The next sibling or null
9145 getNextSibling : function(){
9146 var n = this.dom.nextSibling;
9147 while(n && n.nodeType != 1){
9154 * Gets the previous sibling, skipping text nodes
9155 * @return {HTMLElement} The previous sibling or null
9157 getPrevSibling : function(){
9158 var n = this.dom.previousSibling;
9159 while(n && n.nodeType != 1){
9160 n = n.previousSibling;
9167 * Appends the passed element(s) to this element
9168 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9169 * @return {Roo.Element} this
9171 appendChild: function(el){
9178 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9179 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9180 * automatically generated with the specified attributes.
9181 * @param {HTMLElement} insertBefore (optional) a child element of this element
9182 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9183 * @return {Roo.Element} The new child element
9185 createChild: function(config, insertBefore, returnDom){
9186 config = config || {tag:'div'};
9188 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9190 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9194 * Appends this element to the passed element
9195 * @param {String/HTMLElement/Element} el The new parent element
9196 * @return {Roo.Element} this
9198 appendTo: function(el){
9199 el = Roo.getDom(el);
9200 el.appendChild(this.dom);
9205 * Inserts this element before the passed element in the DOM
9206 * @param {String/HTMLElement/Element} el The element to insert before
9207 * @return {Roo.Element} this
9209 insertBefore: function(el){
9210 el = Roo.getDom(el);
9211 el.parentNode.insertBefore(this.dom, el);
9216 * Inserts this element after the passed element in the DOM
9217 * @param {String/HTMLElement/Element} el The element to insert after
9218 * @return {Roo.Element} this
9220 insertAfter: function(el){
9221 el = Roo.getDom(el);
9222 el.parentNode.insertBefore(this.dom, el.nextSibling);
9227 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9228 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9229 * @return {Roo.Element} The new child
9231 insertFirst: function(el, returnDom){
9233 if(typeof el == 'object' && !el.nodeType){ // dh config
9234 return this.createChild(el, this.dom.firstChild, returnDom);
9236 el = Roo.getDom(el);
9237 this.dom.insertBefore(el, this.dom.firstChild);
9238 return !returnDom ? Roo.get(el) : el;
9243 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9244 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9245 * @param {String} where (optional) 'before' or 'after' defaults to before
9246 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9247 * @return {Roo.Element} the inserted Element
9249 insertSibling: function(el, where, returnDom){
9250 where = where ? where.toLowerCase() : 'before';
9252 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9254 if(typeof el == 'object' && !el.nodeType){ // dh config
9255 if(where == 'after' && !this.dom.nextSibling){
9256 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9258 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9262 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9263 where == 'before' ? this.dom : this.dom.nextSibling);
9272 * Creates and wraps this element with another element
9273 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9274 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9275 * @return {HTMLElement/Element} The newly created wrapper element
9277 wrap: function(config, returnDom){
9279 config = {tag: "div"};
9281 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9282 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9287 * Replaces the passed element with this element
9288 * @param {String/HTMLElement/Element} el The element to replace
9289 * @return {Roo.Element} this
9291 replace: function(el){
9293 this.insertBefore(el);
9299 * Inserts an html fragment into this element
9300 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9301 * @param {String} html The HTML fragment
9302 * @param {Boolean} returnEl True to return an Roo.Element
9303 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9305 insertHtml : function(where, html, returnEl){
9306 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9307 return returnEl ? Roo.get(el) : el;
9311 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9312 * @param {Object} o The object with the attributes
9313 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9314 * @return {Roo.Element} this
9316 set : function(o, useSet){
9318 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9320 if(attr == "style" || typeof o[attr] == "function") continue;
9322 el.className = o["cls"];
9324 if(useSet) el.setAttribute(attr, o[attr]);
9325 else el[attr] = o[attr];
9329 Roo.DomHelper.applyStyles(el, o.style);
9335 * Convenience method for constructing a KeyMap
9336 * @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:
9337 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9338 * @param {Function} fn The function to call
9339 * @param {Object} scope (optional) The scope of the function
9340 * @return {Roo.KeyMap} The KeyMap created
9342 addKeyListener : function(key, fn, scope){
9344 if(typeof key != "object" || key instanceof Array){
9360 return new Roo.KeyMap(this, config);
9364 * Creates a KeyMap for this element
9365 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9366 * @return {Roo.KeyMap} The KeyMap created
9368 addKeyMap : function(config){
9369 return new Roo.KeyMap(this, config);
9373 * Returns true if this element is scrollable.
9376 isScrollable : function(){
9378 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9382 * 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().
9383 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9384 * @param {Number} value The new scroll value
9385 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9386 * @return {Element} this
9389 scrollTo : function(side, value, animate){
9390 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9392 this.dom[prop] = value;
9394 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9395 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9401 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9402 * within this element's scrollable range.
9403 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9404 * @param {Number} distance How far to scroll the element in pixels
9405 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9406 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9407 * was scrolled as far as it could go.
9409 scroll : function(direction, distance, animate){
9410 if(!this.isScrollable()){
9414 var l = el.scrollLeft, t = el.scrollTop;
9415 var w = el.scrollWidth, h = el.scrollHeight;
9416 var cw = el.clientWidth, ch = el.clientHeight;
9417 direction = direction.toLowerCase();
9418 var scrolled = false;
9419 var a = this.preanim(arguments, 2);
9424 var v = Math.min(l + distance, w-cw);
9425 this.scrollTo("left", v, a);
9432 var v = Math.max(l - distance, 0);
9433 this.scrollTo("left", v, a);
9441 var v = Math.max(t - distance, 0);
9442 this.scrollTo("top", v, a);
9450 var v = Math.min(t + distance, h-ch);
9451 this.scrollTo("top", v, a);
9460 * Translates the passed page coordinates into left/top css values for this element
9461 * @param {Number/Array} x The page x or an array containing [x, y]
9462 * @param {Number} y The page y
9463 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9465 translatePoints : function(x, y){
9466 if(typeof x == 'object' || x instanceof Array){
9469 var p = this.getStyle('position');
9470 var o = this.getXY();
9472 var l = parseInt(this.getStyle('left'), 10);
9473 var t = parseInt(this.getStyle('top'), 10);
9476 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9479 t = (p == "relative") ? 0 : this.dom.offsetTop;
9482 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9486 * Returns the current scroll position of the element.
9487 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9489 getScroll : function(){
9490 var d = this.dom, doc = document;
9491 if(d == doc || d == doc.body){
9492 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9493 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9494 return {left: l, top: t};
9496 return {left: d.scrollLeft, top: d.scrollTop};
9501 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9502 * are convert to standard 6 digit hex color.
9503 * @param {String} attr The css attribute
9504 * @param {String} defaultValue The default value to use when a valid color isn't found
9505 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9508 getColor : function(attr, defaultValue, prefix){
9509 var v = this.getStyle(attr);
9510 if(!v || v == "transparent" || v == "inherit") {
9511 return defaultValue;
9513 var color = typeof prefix == "undefined" ? "#" : prefix;
9514 if(v.substr(0, 4) == "rgb("){
9515 var rvs = v.slice(4, v.length -1).split(",");
9516 for(var i = 0; i < 3; i++){
9517 var h = parseInt(rvs[i]).toString(16);
9524 if(v.substr(0, 1) == "#"){
9526 for(var i = 1; i < 4; i++){
9527 var c = v.charAt(i);
9530 }else if(v.length == 7){
9531 color += v.substr(1);
9535 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9539 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9540 * gradient background, rounded corners and a 4-way shadow.
9541 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9542 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9543 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9544 * @return {Roo.Element} this
9546 boxWrap : function(cls){
9547 cls = cls || 'x-box';
9548 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9549 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9554 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9555 * @param {String} namespace The namespace in which to look for the attribute
9556 * @param {String} name The attribute name
9557 * @return {String} The attribute value
9559 getAttributeNS : Roo.isIE ? function(ns, name){
9561 var type = typeof d[ns+":"+name];
9562 if(type != 'undefined' && type != 'unknown'){
9563 return d[ns+":"+name];
9566 } : function(ns, name){
9568 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9573 * Sets or Returns the value the dom attribute value
9574 * @param {String} name The attribute name
9575 * @param {String} value (optional) The value to set the attribute to
9576 * @return {String} The attribute value
9578 attr : function(name){
9579 if (arguments.length > 1) {
9580 this.dom.setAttribute(name, arguments[1]);
9581 return arguments[1];
9583 if (!this.dom.hasAttribute(name)) {
9586 return this.dom.getAttribute(name);
9593 var ep = El.prototype;
9596 * Appends an event handler (Shorthand for addListener)
9597 * @param {String} eventName The type of event to append
9598 * @param {Function} fn The method the event invokes
9599 * @param {Object} scope (optional) The scope (this object) of the fn
9600 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9603 ep.on = ep.addListener;
9605 ep.mon = ep.addListener;
9608 * Removes an event handler from this element (shorthand for removeListener)
9609 * @param {String} eventName the type of event to remove
9610 * @param {Function} fn the method the event invokes
9611 * @return {Roo.Element} this
9614 ep.un = ep.removeListener;
9617 * true to automatically adjust width and height settings for box-model issues (default to true)
9619 ep.autoBoxAdjust = true;
9622 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9625 El.addUnits = function(v, defaultUnit){
9626 if(v === "" || v == "auto"){
9629 if(v === undefined){
9632 if(typeof v == "number" || !El.unitPattern.test(v)){
9633 return v + (defaultUnit || 'px');
9638 // special markup used throughout Roo when box wrapping elements
9639 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>';
9641 * Visibility mode constant - Use visibility to hide element
9647 * Visibility mode constant - Use display to hide element
9653 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9654 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9655 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9667 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9668 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9669 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9670 * @return {Element} The Element object
9673 El.get = function(el){
9675 if(!el){ return null; }
9676 if(typeof el == "string"){ // element id
9677 if(!(elm = document.getElementById(el))){
9680 if(ex = El.cache[el]){
9683 ex = El.cache[el] = new El(elm);
9686 }else if(el.tagName){ // dom element
9690 if(ex = El.cache[id]){
9693 ex = El.cache[id] = new El(el);
9696 }else if(el instanceof El){
9698 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9699 // catch case where it hasn't been appended
9700 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9703 }else if(el.isComposite){
9705 }else if(el instanceof Array){
9706 return El.select(el);
9707 }else if(el == document){
9708 // create a bogus element object representing the document object
9710 var f = function(){};
9711 f.prototype = El.prototype;
9713 docEl.dom = document;
9721 El.uncache = function(el){
9722 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9724 delete El.cache[a[i].id || a[i]];
9730 // Garbage collection - uncache elements/purge listeners on orphaned elements
9731 // so we don't hold a reference and cause the browser to retain them
9732 El.garbageCollect = function(){
9733 if(!Roo.enableGarbageCollector){
9734 clearInterval(El.collectorThread);
9737 for(var eid in El.cache){
9738 var el = El.cache[eid], d = el.dom;
9739 // -------------------------------------------------------
9740 // Determining what is garbage:
9741 // -------------------------------------------------------
9743 // dom node is null, definitely garbage
9744 // -------------------------------------------------------
9746 // no parentNode == direct orphan, definitely garbage
9747 // -------------------------------------------------------
9748 // !d.offsetParent && !document.getElementById(eid)
9749 // display none elements have no offsetParent so we will
9750 // also try to look it up by it's id. However, check
9751 // offsetParent first so we don't do unneeded lookups.
9752 // This enables collection of elements that are not orphans
9753 // directly, but somewhere up the line they have an orphan
9755 // -------------------------------------------------------
9756 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9757 delete El.cache[eid];
9758 if(d && Roo.enableListenerCollection){
9764 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9768 El.Flyweight = function(dom){
9771 El.Flyweight.prototype = El.prototype;
9773 El._flyweights = {};
9775 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9776 * the dom node can be overwritten by other code.
9777 * @param {String/HTMLElement} el The dom node or id
9778 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9779 * prevent conflicts (e.g. internally Roo uses "_internal")
9781 * @return {Element} The shared Element object
9783 El.fly = function(el, named){
9784 named = named || '_global';
9785 el = Roo.getDom(el);
9789 if(!El._flyweights[named]){
9790 El._flyweights[named] = new El.Flyweight();
9792 El._flyweights[named].dom = el;
9793 return El._flyweights[named];
9797 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9798 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9799 * Shorthand of {@link Roo.Element#get}
9800 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9801 * @return {Element} The Element object
9807 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9808 * the dom node can be overwritten by other code.
9809 * Shorthand of {@link Roo.Element#fly}
9810 * @param {String/HTMLElement} el The dom node or id
9811 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9812 * prevent conflicts (e.g. internally Roo uses "_internal")
9814 * @return {Element} The shared Element object
9820 // speedy lookup for elements never to box adjust
9821 var noBoxAdjust = Roo.isStrict ? {
9824 input:1, select:1, textarea:1
9826 if(Roo.isIE || Roo.isGecko){
9827 noBoxAdjust['button'] = 1;
9831 Roo.EventManager.on(window, 'unload', function(){
9833 delete El._flyweights;
9841 Roo.Element.selectorFunction = Roo.DomQuery.select;
9844 Roo.Element.select = function(selector, unique, root){
9846 if(typeof selector == "string"){
9847 els = Roo.Element.selectorFunction(selector, root);
9848 }else if(selector.length !== undefined){
9851 throw "Invalid selector";
9853 if(unique === true){
9854 return new Roo.CompositeElement(els);
9856 return new Roo.CompositeElementLite(els);
9860 * Selects elements based on the passed CSS selector to enable working on them as 1.
9861 * @param {String/Array} selector The CSS selector or an array of elements
9862 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9863 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9864 * @return {CompositeElementLite/CompositeElement}
9868 Roo.select = Roo.Element.select;
9885 * Ext JS Library 1.1.1
9886 * Copyright(c) 2006-2007, Ext JS, LLC.
9888 * Originally Released Under LGPL - original licence link has changed is not relivant.
9891 * <script type="text/javascript">
9896 //Notifies Element that fx methods are available
9897 Roo.enableFx = true;
9901 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9902 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9903 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9904 * Element effects to work.</p><br/>
9906 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9907 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9908 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9909 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9910 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9911 * expected results and should be done with care.</p><br/>
9913 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9914 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9917 ----- -----------------------------
9918 tl The top left corner
9919 t The center of the top edge
9920 tr The top right corner
9921 l The center of the left edge
9922 r The center of the right edge
9923 bl The bottom left corner
9924 b The center of the bottom edge
9925 br The bottom right corner
9927 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9928 * below are common options that can be passed to any Fx method.</b>
9929 * @cfg {Function} callback A function called when the effect is finished
9930 * @cfg {Object} scope The scope of the effect function
9931 * @cfg {String} easing A valid Easing value for the effect
9932 * @cfg {String} afterCls A css class to apply after the effect
9933 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9934 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9935 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9936 * effects that end with the element being visually hidden, ignored otherwise)
9937 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9938 * a function which returns such a specification that will be applied to the Element after the effect finishes
9939 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9940 * @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
9941 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9945 * Slides the element into view. An anchor point can be optionally passed to set the point of
9946 * origin for the slide effect. This function automatically handles wrapping the element with
9947 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9950 // default: slide the element in from the top
9953 // custom: slide the element in from the right with a 2-second duration
9954 el.slideIn('r', { duration: 2 });
9956 // common config options shown with default values
9962 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9963 * @param {Object} options (optional) Object literal with any of the Fx config options
9964 * @return {Roo.Element} The Element
9966 slideIn : function(anchor, o){
9967 var el = this.getFxEl();
9970 el.queueFx(o, function(){
9972 anchor = anchor || "t";
9974 // fix display to visibility
9977 // restore values after effect
9978 var r = this.getFxRestore();
9979 var b = this.getBox();
9980 // fixed size for slide
9984 var wrap = this.fxWrap(r.pos, o, "hidden");
9986 var st = this.dom.style;
9987 st.visibility = "visible";
9988 st.position = "absolute";
9990 // clear out temp styles after slide and unwrap
9991 var after = function(){
9992 el.fxUnwrap(wrap, r.pos, o);
9994 st.height = r.height;
9997 // time to calc the positions
9998 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10000 switch(anchor.toLowerCase()){
10002 wrap.setSize(b.width, 0);
10003 st.left = st.bottom = "0";
10007 wrap.setSize(0, b.height);
10008 st.right = st.top = "0";
10012 wrap.setSize(0, b.height);
10013 wrap.setX(b.right);
10014 st.left = st.top = "0";
10015 a = {width: bw, points: pt};
10018 wrap.setSize(b.width, 0);
10019 wrap.setY(b.bottom);
10020 st.left = st.top = "0";
10021 a = {height: bh, points: pt};
10024 wrap.setSize(0, 0);
10025 st.right = st.bottom = "0";
10026 a = {width: bw, height: bh};
10029 wrap.setSize(0, 0);
10030 wrap.setY(b.y+b.height);
10031 st.right = st.top = "0";
10032 a = {width: bw, height: bh, points: pt};
10035 wrap.setSize(0, 0);
10036 wrap.setXY([b.right, b.bottom]);
10037 st.left = st.top = "0";
10038 a = {width: bw, height: bh, points: pt};
10041 wrap.setSize(0, 0);
10042 wrap.setX(b.x+b.width);
10043 st.left = st.bottom = "0";
10044 a = {width: bw, height: bh, points: pt};
10047 this.dom.style.visibility = "visible";
10050 arguments.callee.anim = wrap.fxanim(a,
10060 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10061 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10062 * 'hidden') but block elements will still take up space in the document. The element must be removed
10063 * from the DOM using the 'remove' config option if desired. This function automatically handles
10064 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10067 // default: slide the element out to the top
10070 // custom: slide the element out to the right with a 2-second duration
10071 el.slideOut('r', { duration: 2 });
10073 // common config options shown with default values
10081 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10082 * @param {Object} options (optional) Object literal with any of the Fx config options
10083 * @return {Roo.Element} The Element
10085 slideOut : function(anchor, o){
10086 var el = this.getFxEl();
10089 el.queueFx(o, function(){
10091 anchor = anchor || "t";
10093 // restore values after effect
10094 var r = this.getFxRestore();
10096 var b = this.getBox();
10097 // fixed size for slide
10101 var wrap = this.fxWrap(r.pos, o, "visible");
10103 var st = this.dom.style;
10104 st.visibility = "visible";
10105 st.position = "absolute";
10109 var after = function(){
10111 el.setDisplayed(false);
10116 el.fxUnwrap(wrap, r.pos, o);
10118 st.width = r.width;
10119 st.height = r.height;
10124 var a, zero = {to: 0};
10125 switch(anchor.toLowerCase()){
10127 st.left = st.bottom = "0";
10128 a = {height: zero};
10131 st.right = st.top = "0";
10135 st.left = st.top = "0";
10136 a = {width: zero, points: {to:[b.right, b.y]}};
10139 st.left = st.top = "0";
10140 a = {height: zero, points: {to:[b.x, b.bottom]}};
10143 st.right = st.bottom = "0";
10144 a = {width: zero, height: zero};
10147 st.right = st.top = "0";
10148 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10151 st.left = st.top = "0";
10152 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10155 st.left = st.bottom = "0";
10156 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10160 arguments.callee.anim = wrap.fxanim(a,
10170 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10171 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10172 * The element must be removed from the DOM using the 'remove' config option if desired.
10178 // common config options shown with default values
10186 * @param {Object} options (optional) Object literal with any of the Fx config options
10187 * @return {Roo.Element} The Element
10189 puff : function(o){
10190 var el = this.getFxEl();
10193 el.queueFx(o, function(){
10194 this.clearOpacity();
10197 // restore values after effect
10198 var r = this.getFxRestore();
10199 var st = this.dom.style;
10201 var after = function(){
10203 el.setDisplayed(false);
10210 el.setPositioning(r.pos);
10211 st.width = r.width;
10212 st.height = r.height;
10217 var width = this.getWidth();
10218 var height = this.getHeight();
10220 arguments.callee.anim = this.fxanim({
10221 width : {to: this.adjustWidth(width * 2)},
10222 height : {to: this.adjustHeight(height * 2)},
10223 points : {by: [-(width * .5), -(height * .5)]},
10225 fontSize: {to:200, unit: "%"}
10236 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10237 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10238 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10244 // all config options shown with default values
10252 * @param {Object} options (optional) Object literal with any of the Fx config options
10253 * @return {Roo.Element} The Element
10255 switchOff : function(o){
10256 var el = this.getFxEl();
10259 el.queueFx(o, function(){
10260 this.clearOpacity();
10263 // restore values after effect
10264 var r = this.getFxRestore();
10265 var st = this.dom.style;
10267 var after = function(){
10269 el.setDisplayed(false);
10275 el.setPositioning(r.pos);
10276 st.width = r.width;
10277 st.height = r.height;
10282 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10283 this.clearOpacity();
10287 points:{by:[0, this.getHeight() * .5]}
10288 }, o, 'motion', 0.3, 'easeIn', after);
10289 }).defer(100, this);
10296 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10297 * changed using the "attr" config option) and then fading back to the original color. If no original
10298 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10301 // default: highlight background to yellow
10304 // custom: highlight foreground text to blue for 2 seconds
10305 el.highlight("0000ff", { attr: 'color', duration: 2 });
10307 // common config options shown with default values
10308 el.highlight("ffff9c", {
10309 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10310 endColor: (current color) or "ffffff",
10315 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10316 * @param {Object} options (optional) Object literal with any of the Fx config options
10317 * @return {Roo.Element} The Element
10319 highlight : function(color, o){
10320 var el = this.getFxEl();
10323 el.queueFx(o, function(){
10324 color = color || "ffff9c";
10325 attr = o.attr || "backgroundColor";
10327 this.clearOpacity();
10330 var origColor = this.getColor(attr);
10331 var restoreColor = this.dom.style[attr];
10332 endColor = (o.endColor || origColor) || "ffffff";
10334 var after = function(){
10335 el.dom.style[attr] = restoreColor;
10340 a[attr] = {from: color, to: endColor};
10341 arguments.callee.anim = this.fxanim(a,
10351 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10354 // default: a single light blue ripple
10357 // custom: 3 red ripples lasting 3 seconds total
10358 el.frame("ff0000", 3, { duration: 3 });
10360 // common config options shown with default values
10361 el.frame("C3DAF9", 1, {
10362 duration: 1 //duration of entire animation (not each individual ripple)
10363 // Note: Easing is not configurable and will be ignored if included
10366 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10367 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10368 * @param {Object} options (optional) Object literal with any of the Fx config options
10369 * @return {Roo.Element} The Element
10371 frame : function(color, count, o){
10372 var el = this.getFxEl();
10375 el.queueFx(o, function(){
10376 color = color || "#C3DAF9";
10377 if(color.length == 6){
10378 color = "#" + color;
10380 count = count || 1;
10381 duration = o.duration || 1;
10384 var b = this.getBox();
10385 var animFn = function(){
10386 var proxy = this.createProxy({
10389 visbility:"hidden",
10390 position:"absolute",
10391 "z-index":"35000", // yee haw
10392 border:"0px solid " + color
10395 var scale = Roo.isBorderBox ? 2 : 1;
10397 top:{from:b.y, to:b.y - 20},
10398 left:{from:b.x, to:b.x - 20},
10399 borderWidth:{from:0, to:10},
10400 opacity:{from:1, to:0},
10401 height:{from:b.height, to:(b.height + (20*scale))},
10402 width:{from:b.width, to:(b.width + (20*scale))}
10403 }, duration, function(){
10407 animFn.defer((duration/2)*1000, this);
10418 * Creates a pause before any subsequent queued effects begin. If there are
10419 * no effects queued after the pause it will have no effect.
10424 * @param {Number} seconds The length of time to pause (in seconds)
10425 * @return {Roo.Element} The Element
10427 pause : function(seconds){
10428 var el = this.getFxEl();
10431 el.queueFx(o, function(){
10432 setTimeout(function(){
10434 }, seconds * 1000);
10440 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10441 * using the "endOpacity" config option.
10444 // default: fade in from opacity 0 to 100%
10447 // custom: fade in from opacity 0 to 75% over 2 seconds
10448 el.fadeIn({ endOpacity: .75, duration: 2});
10450 // common config options shown with default values
10452 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10457 * @param {Object} options (optional) Object literal with any of the Fx config options
10458 * @return {Roo.Element} The Element
10460 fadeIn : function(o){
10461 var el = this.getFxEl();
10463 el.queueFx(o, function(){
10464 this.setOpacity(0);
10466 this.dom.style.visibility = 'visible';
10467 var to = o.endOpacity || 1;
10468 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10469 o, null, .5, "easeOut", function(){
10471 this.clearOpacity();
10480 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10481 * using the "endOpacity" config option.
10484 // default: fade out from the element's current opacity to 0
10487 // custom: fade out from the element's current opacity to 25% over 2 seconds
10488 el.fadeOut({ endOpacity: .25, duration: 2});
10490 // common config options shown with default values
10492 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10499 * @param {Object} options (optional) Object literal with any of the Fx config options
10500 * @return {Roo.Element} The Element
10502 fadeOut : function(o){
10503 var el = this.getFxEl();
10505 el.queueFx(o, function(){
10506 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10507 o, null, .5, "easeOut", function(){
10508 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10509 this.dom.style.display = "none";
10511 this.dom.style.visibility = "hidden";
10513 this.clearOpacity();
10521 * Animates the transition of an element's dimensions from a starting height/width
10522 * to an ending height/width.
10525 // change height and width to 100x100 pixels
10526 el.scale(100, 100);
10528 // common config options shown with default values. The height and width will default to
10529 // the element's existing values if passed as null.
10532 [element's height], {
10537 * @param {Number} width The new width (pass undefined to keep the original width)
10538 * @param {Number} height The new height (pass undefined to keep the original height)
10539 * @param {Object} options (optional) Object literal with any of the Fx config options
10540 * @return {Roo.Element} The Element
10542 scale : function(w, h, o){
10543 this.shift(Roo.apply({}, o, {
10551 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10552 * Any of these properties not specified in the config object will not be changed. This effect
10553 * requires that at least one new dimension, position or opacity setting must be passed in on
10554 * the config object in order for the function to have any effect.
10557 // slide the element horizontally to x position 200 while changing the height and opacity
10558 el.shift({ x: 200, height: 50, opacity: .8 });
10560 // common config options shown with default values.
10562 width: [element's width],
10563 height: [element's height],
10564 x: [element's x position],
10565 y: [element's y position],
10566 opacity: [element's opacity],
10571 * @param {Object} options Object literal with any of the Fx config options
10572 * @return {Roo.Element} The Element
10574 shift : function(o){
10575 var el = this.getFxEl();
10577 el.queueFx(o, function(){
10578 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10579 if(w !== undefined){
10580 a.width = {to: this.adjustWidth(w)};
10582 if(h !== undefined){
10583 a.height = {to: this.adjustHeight(h)};
10585 if(x !== undefined || y !== undefined){
10587 x !== undefined ? x : this.getX(),
10588 y !== undefined ? y : this.getY()
10591 if(op !== undefined){
10592 a.opacity = {to: op};
10594 if(o.xy !== undefined){
10595 a.points = {to: o.xy};
10597 arguments.callee.anim = this.fxanim(a,
10598 o, 'motion', .35, "easeOut", function(){
10606 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10607 * ending point of the effect.
10610 // default: slide the element downward while fading out
10613 // custom: slide the element out to the right with a 2-second duration
10614 el.ghost('r', { duration: 2 });
10616 // common config options shown with default values
10624 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10625 * @param {Object} options (optional) Object literal with any of the Fx config options
10626 * @return {Roo.Element} The Element
10628 ghost : function(anchor, o){
10629 var el = this.getFxEl();
10632 el.queueFx(o, function(){
10633 anchor = anchor || "b";
10635 // restore values after effect
10636 var r = this.getFxRestore();
10637 var w = this.getWidth(),
10638 h = this.getHeight();
10640 var st = this.dom.style;
10642 var after = function(){
10644 el.setDisplayed(false);
10650 el.setPositioning(r.pos);
10651 st.width = r.width;
10652 st.height = r.height;
10657 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10658 switch(anchor.toLowerCase()){
10685 arguments.callee.anim = this.fxanim(a,
10695 * Ensures that all effects queued after syncFx is called on the element are
10696 * run concurrently. This is the opposite of {@link #sequenceFx}.
10697 * @return {Roo.Element} The Element
10699 syncFx : function(){
10700 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10709 * Ensures that all effects queued after sequenceFx is called on the element are
10710 * run in sequence. This is the opposite of {@link #syncFx}.
10711 * @return {Roo.Element} The Element
10713 sequenceFx : function(){
10714 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10716 concurrent : false,
10723 nextFx : function(){
10724 var ef = this.fxQueue[0];
10731 * Returns true if the element has any effects actively running or queued, else returns false.
10732 * @return {Boolean} True if element has active effects, else false
10734 hasActiveFx : function(){
10735 return this.fxQueue && this.fxQueue[0];
10739 * Stops any running effects and clears the element's internal effects queue if it contains
10740 * any additional effects that haven't started yet.
10741 * @return {Roo.Element} The Element
10743 stopFx : function(){
10744 if(this.hasActiveFx()){
10745 var cur = this.fxQueue[0];
10746 if(cur && cur.anim && cur.anim.isAnimated()){
10747 this.fxQueue = [cur]; // clear out others
10748 cur.anim.stop(true);
10755 beforeFx : function(o){
10756 if(this.hasActiveFx() && !o.concurrent){
10767 * Returns true if the element is currently blocking so that no other effect can be queued
10768 * until this effect is finished, else returns false if blocking is not set. This is commonly
10769 * used to ensure that an effect initiated by a user action runs to completion prior to the
10770 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10771 * @return {Boolean} True if blocking, else false
10773 hasFxBlock : function(){
10774 var q = this.fxQueue;
10775 return q && q[0] && q[0].block;
10779 queueFx : function(o, fn){
10783 if(!this.hasFxBlock()){
10784 Roo.applyIf(o, this.fxDefaults);
10786 var run = this.beforeFx(o);
10787 fn.block = o.block;
10788 this.fxQueue.push(fn);
10800 fxWrap : function(pos, o, vis){
10802 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10805 wrapXY = this.getXY();
10807 var div = document.createElement("div");
10808 div.style.visibility = vis;
10809 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10810 wrap.setPositioning(pos);
10811 if(wrap.getStyle("position") == "static"){
10812 wrap.position("relative");
10814 this.clearPositioning('auto');
10816 wrap.dom.appendChild(this.dom);
10818 wrap.setXY(wrapXY);
10825 fxUnwrap : function(wrap, pos, o){
10826 this.clearPositioning();
10827 this.setPositioning(pos);
10829 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10835 getFxRestore : function(){
10836 var st = this.dom.style;
10837 return {pos: this.getPositioning(), width: st.width, height : st.height};
10841 afterFx : function(o){
10843 this.applyStyles(o.afterStyle);
10846 this.addClass(o.afterCls);
10848 if(o.remove === true){
10851 Roo.callback(o.callback, o.scope, [this]);
10853 this.fxQueue.shift();
10859 getFxEl : function(){ // support for composite element fx
10860 return Roo.get(this.dom);
10864 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10865 animType = animType || 'run';
10867 var anim = Roo.lib.Anim[animType](
10869 (opt.duration || defaultDur) || .35,
10870 (opt.easing || defaultEase) || 'easeOut',
10872 Roo.callback(cb, this);
10881 // backwords compat
10882 Roo.Fx.resize = Roo.Fx.scale;
10884 //When included, Roo.Fx is automatically applied to Element so that all basic
10885 //effects are available directly via the Element API
10886 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10888 * Ext JS Library 1.1.1
10889 * Copyright(c) 2006-2007, Ext JS, LLC.
10891 * Originally Released Under LGPL - original licence link has changed is not relivant.
10894 * <script type="text/javascript">
10899 * @class Roo.CompositeElement
10900 * Standard composite class. Creates a Roo.Element for every element in the collection.
10902 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10903 * actions will be performed on all the elements in this collection.</b>
10905 * All methods return <i>this</i> and can be chained.
10907 var els = Roo.select("#some-el div.some-class", true);
10908 // or select directly from an existing element
10909 var el = Roo.get('some-el');
10910 el.select('div.some-class', true);
10912 els.setWidth(100); // all elements become 100 width
10913 els.hide(true); // all elements fade out and hide
10915 els.setWidth(100).hide(true);
10918 Roo.CompositeElement = function(els){
10919 this.elements = [];
10920 this.addElements(els);
10922 Roo.CompositeElement.prototype = {
10924 addElements : function(els){
10925 if(!els) return this;
10926 if(typeof els == "string"){
10927 els = Roo.Element.selectorFunction(els);
10929 var yels = this.elements;
10930 var index = yels.length-1;
10931 for(var i = 0, len = els.length; i < len; i++) {
10932 yels[++index] = Roo.get(els[i]);
10938 * Clears this composite and adds the elements returned by the passed selector.
10939 * @param {String/Array} els A string CSS selector, an array of elements or an element
10940 * @return {CompositeElement} this
10942 fill : function(els){
10943 this.elements = [];
10949 * Filters this composite to only elements that match the passed selector.
10950 * @param {String} selector A string CSS selector
10951 * @return {CompositeElement} this
10953 filter : function(selector){
10955 this.each(function(el){
10956 if(el.is(selector)){
10957 els[els.length] = el.dom;
10964 invoke : function(fn, args){
10965 var els = this.elements;
10966 for(var i = 0, len = els.length; i < len; i++) {
10967 Roo.Element.prototype[fn].apply(els[i], args);
10972 * Adds elements to this composite.
10973 * @param {String/Array} els A string CSS selector, an array of elements or an element
10974 * @return {CompositeElement} this
10976 add : function(els){
10977 if(typeof els == "string"){
10978 this.addElements(Roo.Element.selectorFunction(els));
10979 }else if(els.length !== undefined){
10980 this.addElements(els);
10982 this.addElements([els]);
10987 * Calls the passed function passing (el, this, index) for each element in this composite.
10988 * @param {Function} fn The function to call
10989 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10990 * @return {CompositeElement} this
10992 each : function(fn, scope){
10993 var els = this.elements;
10994 for(var i = 0, len = els.length; i < len; i++){
10995 if(fn.call(scope || els[i], els[i], this, i) === false) {
11003 * Returns the Element object at the specified index
11004 * @param {Number} index
11005 * @return {Roo.Element}
11007 item : function(index){
11008 return this.elements[index] || null;
11012 * Returns the first Element
11013 * @return {Roo.Element}
11015 first : function(){
11016 return this.item(0);
11020 * Returns the last Element
11021 * @return {Roo.Element}
11024 return this.item(this.elements.length-1);
11028 * Returns the number of elements in this composite
11031 getCount : function(){
11032 return this.elements.length;
11036 * Returns true if this composite contains the passed element
11039 contains : function(el){
11040 return this.indexOf(el) !== -1;
11044 * Returns true if this composite contains the passed element
11047 indexOf : function(el){
11048 return this.elements.indexOf(Roo.get(el));
11053 * Removes the specified element(s).
11054 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11055 * or an array of any of those.
11056 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11057 * @return {CompositeElement} this
11059 removeElement : function(el, removeDom){
11060 if(el instanceof Array){
11061 for(var i = 0, len = el.length; i < len; i++){
11062 this.removeElement(el[i]);
11066 var index = typeof el == 'number' ? el : this.indexOf(el);
11069 var d = this.elements[index];
11073 d.parentNode.removeChild(d);
11076 this.elements.splice(index, 1);
11082 * Replaces the specified element with the passed element.
11083 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11085 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11086 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11087 * @return {CompositeElement} this
11089 replaceElement : function(el, replacement, domReplace){
11090 var index = typeof el == 'number' ? el : this.indexOf(el);
11093 this.elements[index].replaceWith(replacement);
11095 this.elements.splice(index, 1, Roo.get(replacement))
11102 * Removes all elements.
11104 clear : function(){
11105 this.elements = [];
11109 Roo.CompositeElement.createCall = function(proto, fnName){
11110 if(!proto[fnName]){
11111 proto[fnName] = function(){
11112 return this.invoke(fnName, arguments);
11116 for(var fnName in Roo.Element.prototype){
11117 if(typeof Roo.Element.prototype[fnName] == "function"){
11118 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11124 * Ext JS Library 1.1.1
11125 * Copyright(c) 2006-2007, Ext JS, LLC.
11127 * Originally Released Under LGPL - original licence link has changed is not relivant.
11130 * <script type="text/javascript">
11134 * @class Roo.CompositeElementLite
11135 * @extends Roo.CompositeElement
11136 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11138 var els = Roo.select("#some-el div.some-class");
11139 // or select directly from an existing element
11140 var el = Roo.get('some-el');
11141 el.select('div.some-class');
11143 els.setWidth(100); // all elements become 100 width
11144 els.hide(true); // all elements fade out and hide
11146 els.setWidth(100).hide(true);
11147 </code></pre><br><br>
11148 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11149 * actions will be performed on all the elements in this collection.</b>
11151 Roo.CompositeElementLite = function(els){
11152 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11153 this.el = new Roo.Element.Flyweight();
11155 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11156 addElements : function(els){
11158 if(els instanceof Array){
11159 this.elements = this.elements.concat(els);
11161 var yels = this.elements;
11162 var index = yels.length-1;
11163 for(var i = 0, len = els.length; i < len; i++) {
11164 yels[++index] = els[i];
11170 invoke : function(fn, args){
11171 var els = this.elements;
11173 for(var i = 0, len = els.length; i < len; i++) {
11175 Roo.Element.prototype[fn].apply(el, args);
11180 * Returns a flyweight Element of the dom element object at the specified index
11181 * @param {Number} index
11182 * @return {Roo.Element}
11184 item : function(index){
11185 if(!this.elements[index]){
11188 this.el.dom = this.elements[index];
11192 // fixes scope with flyweight
11193 addListener : function(eventName, handler, scope, opt){
11194 var els = this.elements;
11195 for(var i = 0, len = els.length; i < len; i++) {
11196 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11202 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11203 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11204 * a reference to the dom node, use el.dom.</b>
11205 * @param {Function} fn The function to call
11206 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11207 * @return {CompositeElement} this
11209 each : function(fn, scope){
11210 var els = this.elements;
11212 for(var i = 0, len = els.length; i < len; i++){
11214 if(fn.call(scope || el, el, this, i) === false){
11221 indexOf : function(el){
11222 return this.elements.indexOf(Roo.getDom(el));
11225 replaceElement : function(el, replacement, domReplace){
11226 var index = typeof el == 'number' ? el : this.indexOf(el);
11228 replacement = Roo.getDom(replacement);
11230 var d = this.elements[index];
11231 d.parentNode.insertBefore(replacement, d);
11232 d.parentNode.removeChild(d);
11234 this.elements.splice(index, 1, replacement);
11239 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11243 * Ext JS Library 1.1.1
11244 * Copyright(c) 2006-2007, Ext JS, LLC.
11246 * Originally Released Under LGPL - original licence link has changed is not relivant.
11249 * <script type="text/javascript">
11255 * @class Roo.data.Connection
11256 * @extends Roo.util.Observable
11257 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11258 * either to a configured URL, or to a URL specified at request time.<br><br>
11260 * Requests made by this class are asynchronous, and will return immediately. No data from
11261 * the server will be available to the statement immediately following the {@link #request} call.
11262 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11264 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11265 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11266 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11267 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11268 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11269 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11270 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11271 * standard DOM methods.
11273 * @param {Object} config a configuration object.
11275 Roo.data.Connection = function(config){
11276 Roo.apply(this, config);
11279 * @event beforerequest
11280 * Fires before a network request is made to retrieve a data object.
11281 * @param {Connection} conn This Connection object.
11282 * @param {Object} options The options config object passed to the {@link #request} method.
11284 "beforerequest" : true,
11286 * @event requestcomplete
11287 * Fires if the request was successfully completed.
11288 * @param {Connection} conn This Connection object.
11289 * @param {Object} response The XHR object containing the response data.
11290 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11291 * @param {Object} options The options config object passed to the {@link #request} method.
11293 "requestcomplete" : true,
11295 * @event requestexception
11296 * Fires if an error HTTP status was returned from the server.
11297 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11298 * @param {Connection} conn This Connection object.
11299 * @param {Object} response The XHR object containing the response data.
11300 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11301 * @param {Object} options The options config object passed to the {@link #request} method.
11303 "requestexception" : true
11305 Roo.data.Connection.superclass.constructor.call(this);
11308 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11310 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11313 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11314 * extra parameters to each request made by this object. (defaults to undefined)
11317 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11318 * to each request made by this object. (defaults to undefined)
11321 * @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)
11324 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11328 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11334 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11337 disableCaching: true,
11340 * Sends an HTTP request to a remote server.
11341 * @param {Object} options An object which may contain the following properties:<ul>
11342 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11343 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11344 * request, a url encoded string or a function to call to get either.</li>
11345 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11346 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11347 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11348 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11349 * <li>options {Object} The parameter to the request call.</li>
11350 * <li>success {Boolean} True if the request succeeded.</li>
11351 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11353 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11354 * The callback is passed the following parameters:<ul>
11355 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11356 * <li>options {Object} The parameter to the request call.</li>
11358 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11359 * The callback is passed the following parameters:<ul>
11360 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11361 * <li>options {Object} The parameter to the request call.</li>
11363 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11364 * for the callback function. Defaults to the browser window.</li>
11365 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11366 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11367 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11368 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11369 * params for the post data. Any params will be appended to the URL.</li>
11370 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11372 * @return {Number} transactionId
11374 request : function(o){
11375 if(this.fireEvent("beforerequest", this, o) !== false){
11378 if(typeof p == "function"){
11379 p = p.call(o.scope||window, o);
11381 if(typeof p == "object"){
11382 p = Roo.urlEncode(o.params);
11384 if(this.extraParams){
11385 var extras = Roo.urlEncode(this.extraParams);
11386 p = p ? (p + '&' + extras) : extras;
11389 var url = o.url || this.url;
11390 if(typeof url == 'function'){
11391 url = url.call(o.scope||window, o);
11395 var form = Roo.getDom(o.form);
11396 url = url || form.action;
11398 var enctype = form.getAttribute("enctype");
11399 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11400 return this.doFormUpload(o, p, url);
11402 var f = Roo.lib.Ajax.serializeForm(form);
11403 p = p ? (p + '&' + f) : f;
11406 var hs = o.headers;
11407 if(this.defaultHeaders){
11408 hs = Roo.apply(hs || {}, this.defaultHeaders);
11415 success: this.handleResponse,
11416 failure: this.handleFailure,
11418 argument: {options: o},
11419 timeout : o.timeout || this.timeout
11422 var method = o.method||this.method||(p ? "POST" : "GET");
11424 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11425 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11428 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11432 }else if(this.autoAbort !== false){
11436 if((method == 'GET' && p) || o.xmlData){
11437 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11440 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11441 return this.transId;
11443 Roo.callback(o.callback, o.scope, [o, null, null]);
11449 * Determine whether this object has a request outstanding.
11450 * @param {Number} transactionId (Optional) defaults to the last transaction
11451 * @return {Boolean} True if there is an outstanding request.
11453 isLoading : function(transId){
11455 return Roo.lib.Ajax.isCallInProgress(transId);
11457 return this.transId ? true : false;
11462 * Aborts any outstanding request.
11463 * @param {Number} transactionId (Optional) defaults to the last transaction
11465 abort : function(transId){
11466 if(transId || this.isLoading()){
11467 Roo.lib.Ajax.abort(transId || this.transId);
11472 handleResponse : function(response){
11473 this.transId = false;
11474 var options = response.argument.options;
11475 response.argument = options ? options.argument : null;
11476 this.fireEvent("requestcomplete", this, response, options);
11477 Roo.callback(options.success, options.scope, [response, options]);
11478 Roo.callback(options.callback, options.scope, [options, true, response]);
11482 handleFailure : function(response, e){
11483 this.transId = false;
11484 var options = response.argument.options;
11485 response.argument = options ? options.argument : null;
11486 this.fireEvent("requestexception", this, response, options, e);
11487 Roo.callback(options.failure, options.scope, [response, options]);
11488 Roo.callback(options.callback, options.scope, [options, false, response]);
11492 doFormUpload : function(o, ps, url){
11494 var frame = document.createElement('iframe');
11497 frame.className = 'x-hidden';
11499 frame.src = Roo.SSL_SECURE_URL;
11501 document.body.appendChild(frame);
11504 document.frames[id].name = id;
11507 var form = Roo.getDom(o.form);
11509 form.method = 'POST';
11510 form.enctype = form.encoding = 'multipart/form-data';
11516 if(ps){ // add dynamic params
11518 ps = Roo.urlDecode(ps, false);
11520 if(ps.hasOwnProperty(k)){
11521 hd = document.createElement('input');
11522 hd.type = 'hidden';
11525 form.appendChild(hd);
11532 var r = { // bogus response object
11537 r.argument = o ? o.argument : null;
11542 doc = frame.contentWindow.document;
11544 doc = (frame.contentDocument || window.frames[id].document);
11546 if(doc && doc.body){
11547 r.responseText = doc.body.innerHTML;
11549 if(doc && doc.XMLDocument){
11550 r.responseXML = doc.XMLDocument;
11552 r.responseXML = doc;
11559 Roo.EventManager.removeListener(frame, 'load', cb, this);
11561 this.fireEvent("requestcomplete", this, r, o);
11562 Roo.callback(o.success, o.scope, [r, o]);
11563 Roo.callback(o.callback, o.scope, [o, true, r]);
11565 setTimeout(function(){document.body.removeChild(frame);}, 100);
11568 Roo.EventManager.on(frame, 'load', cb, this);
11571 if(hiddens){ // remove dynamic params
11572 for(var i = 0, len = hiddens.length; i < len; i++){
11573 form.removeChild(hiddens[i]);
11580 * Ext JS Library 1.1.1
11581 * Copyright(c) 2006-2007, Ext JS, LLC.
11583 * Originally Released Under LGPL - original licence link has changed is not relivant.
11586 * <script type="text/javascript">
11590 * Global Ajax request class.
11593 * @extends Roo.data.Connection
11596 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11597 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11598 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11599 * @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)
11600 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11601 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11602 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11604 Roo.Ajax = new Roo.data.Connection({
11613 * Serialize the passed form into a url encoded string
11615 * @param {String/HTMLElement} form
11618 serializeForm : function(form){
11619 return Roo.lib.Ajax.serializeForm(form);
11623 * Ext JS Library 1.1.1
11624 * Copyright(c) 2006-2007, Ext JS, LLC.
11626 * Originally Released Under LGPL - original licence link has changed is not relivant.
11629 * <script type="text/javascript">
11634 * @class Roo.UpdateManager
11635 * @extends Roo.util.Observable
11636 * Provides AJAX-style update for Element object.<br><br>
11639 * // Get it from a Roo.Element object
11640 * var el = Roo.get("foo");
11641 * var mgr = el.getUpdateManager();
11642 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11644 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11646 * // or directly (returns the same UpdateManager instance)
11647 * var mgr = new Roo.UpdateManager("myElementId");
11648 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11649 * mgr.on("update", myFcnNeedsToKnow);
11651 // short handed call directly from the element object
11652 Roo.get("foo").load({
11656 text: "Loading Foo..."
11660 * Create new UpdateManager directly.
11661 * @param {String/HTMLElement/Roo.Element} el The element to update
11662 * @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).
11664 Roo.UpdateManager = function(el, forceNew){
11666 if(!forceNew && el.updateManager){
11667 return el.updateManager;
11670 * The Element object
11671 * @type Roo.Element
11675 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11678 this.defaultUrl = null;
11682 * @event beforeupdate
11683 * Fired before an update is made, return false from your handler and the update is cancelled.
11684 * @param {Roo.Element} el
11685 * @param {String/Object/Function} url
11686 * @param {String/Object} params
11688 "beforeupdate": true,
11691 * Fired after successful update is made.
11692 * @param {Roo.Element} el
11693 * @param {Object} oResponseObject The response Object
11698 * Fired on update failure.
11699 * @param {Roo.Element} el
11700 * @param {Object} oResponseObject The response Object
11704 var d = Roo.UpdateManager.defaults;
11706 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11709 this.sslBlankUrl = d.sslBlankUrl;
11711 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11714 this.disableCaching = d.disableCaching;
11716 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11719 this.indicatorText = d.indicatorText;
11721 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11724 this.showLoadIndicator = d.showLoadIndicator;
11726 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11729 this.timeout = d.timeout;
11732 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11735 this.loadScripts = d.loadScripts;
11738 * Transaction object of current executing transaction
11740 this.transaction = null;
11745 this.autoRefreshProcId = null;
11747 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11750 this.refreshDelegate = this.refresh.createDelegate(this);
11752 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11755 this.updateDelegate = this.update.createDelegate(this);
11757 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11760 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11764 this.successDelegate = this.processSuccess.createDelegate(this);
11768 this.failureDelegate = this.processFailure.createDelegate(this);
11770 if(!this.renderer){
11772 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11774 this.renderer = new Roo.UpdateManager.BasicRenderer();
11777 Roo.UpdateManager.superclass.constructor.call(this);
11780 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11782 * Get the Element this UpdateManager is bound to
11783 * @return {Roo.Element} The element
11785 getEl : function(){
11789 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11790 * @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:
11793 url: "your-url.php",<br/>
11794 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11795 callback: yourFunction,<br/>
11796 scope: yourObject, //(optional scope) <br/>
11797 discardUrl: false, <br/>
11798 nocache: false,<br/>
11799 text: "Loading...",<br/>
11801 scripts: false<br/>
11804 * The only required property is url. The optional properties nocache, text and scripts
11805 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11806 * @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}
11807 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11808 * @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.
11810 update : function(url, params, callback, discardUrl){
11811 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11812 var method = this.method,
11814 if(typeof url == "object"){ // must be config object
11817 params = params || cfg.params;
11818 callback = callback || cfg.callback;
11819 discardUrl = discardUrl || cfg.discardUrl;
11820 if(callback && cfg.scope){
11821 callback = callback.createDelegate(cfg.scope);
11823 if(typeof cfg.method != "undefined"){method = cfg.method;};
11824 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11825 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11826 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11827 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11829 this.showLoading();
11831 this.defaultUrl = url;
11833 if(typeof url == "function"){
11834 url = url.call(this);
11837 method = method || (params ? "POST" : "GET");
11838 if(method == "GET"){
11839 url = this.prepareUrl(url);
11842 var o = Roo.apply(cfg ||{}, {
11845 success: this.successDelegate,
11846 failure: this.failureDelegate,
11847 callback: undefined,
11848 timeout: (this.timeout*1000),
11849 argument: {"url": url, "form": null, "callback": callback, "params": params}
11851 Roo.log("updated manager called with timeout of " + o.timeout);
11852 this.transaction = Roo.Ajax.request(o);
11857 * 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.
11858 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11859 * @param {String/HTMLElement} form The form Id or form element
11860 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11861 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11862 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11864 formUpdate : function(form, url, reset, callback){
11865 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11866 if(typeof url == "function"){
11867 url = url.call(this);
11869 form = Roo.getDom(form);
11870 this.transaction = Roo.Ajax.request({
11873 success: this.successDelegate,
11874 failure: this.failureDelegate,
11875 timeout: (this.timeout*1000),
11876 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11878 this.showLoading.defer(1, this);
11883 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11884 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11886 refresh : function(callback){
11887 if(this.defaultUrl == null){
11890 this.update(this.defaultUrl, null, callback, true);
11894 * Set this element to auto refresh.
11895 * @param {Number} interval How often to update (in seconds).
11896 * @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)
11897 * @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}
11898 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11899 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11901 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11903 this.update(url || this.defaultUrl, params, callback, true);
11905 if(this.autoRefreshProcId){
11906 clearInterval(this.autoRefreshProcId);
11908 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11912 * Stop auto refresh on this element.
11914 stopAutoRefresh : function(){
11915 if(this.autoRefreshProcId){
11916 clearInterval(this.autoRefreshProcId);
11917 delete this.autoRefreshProcId;
11921 isAutoRefreshing : function(){
11922 return this.autoRefreshProcId ? true : false;
11925 * Called to update the element to "Loading" state. Override to perform custom action.
11927 showLoading : function(){
11928 if(this.showLoadIndicator){
11929 this.el.update(this.indicatorText);
11934 * Adds unique parameter to query string if disableCaching = true
11937 prepareUrl : function(url){
11938 if(this.disableCaching){
11939 var append = "_dc=" + (new Date().getTime());
11940 if(url.indexOf("?") !== -1){
11941 url += "&" + append;
11943 url += "?" + append;
11952 processSuccess : function(response){
11953 this.transaction = null;
11954 if(response.argument.form && response.argument.reset){
11955 try{ // put in try/catch since some older FF releases had problems with this
11956 response.argument.form.reset();
11959 if(this.loadScripts){
11960 this.renderer.render(this.el, response, this,
11961 this.updateComplete.createDelegate(this, [response]));
11963 this.renderer.render(this.el, response, this);
11964 this.updateComplete(response);
11968 updateComplete : function(response){
11969 this.fireEvent("update", this.el, response);
11970 if(typeof response.argument.callback == "function"){
11971 response.argument.callback(this.el, true, response);
11978 processFailure : function(response){
11979 this.transaction = null;
11980 this.fireEvent("failure", this.el, response);
11981 if(typeof response.argument.callback == "function"){
11982 response.argument.callback(this.el, false, response);
11987 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11988 * @param {Object} renderer The object implementing the render() method
11990 setRenderer : function(renderer){
11991 this.renderer = renderer;
11994 getRenderer : function(){
11995 return this.renderer;
11999 * Set the defaultUrl used for updates
12000 * @param {String/Function} defaultUrl The url or a function to call to get the url
12002 setDefaultUrl : function(defaultUrl){
12003 this.defaultUrl = defaultUrl;
12007 * Aborts the executing transaction
12009 abort : function(){
12010 if(this.transaction){
12011 Roo.Ajax.abort(this.transaction);
12016 * Returns true if an update is in progress
12017 * @return {Boolean}
12019 isUpdating : function(){
12020 if(this.transaction){
12021 return Roo.Ajax.isLoading(this.transaction);
12028 * @class Roo.UpdateManager.defaults
12029 * @static (not really - but it helps the doc tool)
12030 * The defaults collection enables customizing the default properties of UpdateManager
12032 Roo.UpdateManager.defaults = {
12034 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12040 * True to process scripts by default (Defaults to false).
12043 loadScripts : false,
12046 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12049 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12051 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12054 disableCaching : false,
12056 * Whether to show indicatorText when loading (Defaults to true).
12059 showLoadIndicator : true,
12061 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12064 indicatorText : '<div class="loading-indicator">Loading...</div>'
12068 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12070 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12071 * @param {String/HTMLElement/Roo.Element} el The element to update
12072 * @param {String} url The url
12073 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12074 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12077 * @member Roo.UpdateManager
12079 Roo.UpdateManager.updateElement = function(el, url, params, options){
12080 var um = Roo.get(el, true).getUpdateManager();
12081 Roo.apply(um, options);
12082 um.update(url, params, options ? options.callback : null);
12084 // alias for backwards compat
12085 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12087 * @class Roo.UpdateManager.BasicRenderer
12088 * Default Content renderer. Updates the elements innerHTML with the responseText.
12090 Roo.UpdateManager.BasicRenderer = function(){};
12092 Roo.UpdateManager.BasicRenderer.prototype = {
12094 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12095 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12096 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12097 * @param {Roo.Element} el The element being rendered
12098 * @param {Object} response The YUI Connect response object
12099 * @param {UpdateManager} updateManager The calling update manager
12100 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12102 render : function(el, response, updateManager, callback){
12103 el.update(response.responseText, updateManager.loadScripts, callback);
12109 * (c)) Alan Knowles
12115 * @class Roo.DomTemplate
12116 * @extends Roo.Template
12117 * An effort at a dom based template engine..
12119 * Similar to XTemplate, except it uses dom parsing to create the template..
12121 * Supported features:
12126 {a_variable} - output encoded.
12127 {a_variable.format:("Y-m-d")} - call a method on the variable
12128 {a_variable:raw} - unencoded output
12129 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12130 {a_variable:this.method_on_template(...)} - call a method on the template object.
12135 <div roo-for="a_variable or condition.."></div>
12136 <div roo-if="a_variable or condition"></div>
12137 <div roo-exec="some javascript"></div>
12138 <div roo-name="named_template"></div>
12143 Roo.DomTemplate = function()
12145 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12152 Roo.extend(Roo.DomTemplate, Roo.Template, {
12154 * id counter for sub templates.
12158 * flag to indicate if dom parser is inside a pre,
12159 * it will strip whitespace if not.
12164 * The various sub templates
12172 * basic tag replacing syntax
12175 * // you can fake an object call by doing this
12179 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12180 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12182 iterChild : function (node, method) {
12184 var oldPre = this.inPre;
12185 if (node.tagName == 'PRE') {
12188 for( var i = 0; i < node.childNodes.length; i++) {
12189 method.call(this, node.childNodes[i]);
12191 this.inPre = oldPre;
12197 * compile the template
12199 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12202 compile: function()
12206 // covert the html into DOM...
12210 doc = document.implementation.createHTMLDocument("");
12211 doc.documentElement.innerHTML = this.html ;
12212 div = doc.documentElement;
12214 // old IE... - nasty -- it causes all sorts of issues.. with
12215 // images getting pulled from server..
12216 div = document.createElement('div');
12217 div.innerHTML = this.html;
12219 //doc.documentElement.innerHTML = htmlBody
12225 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12227 var tpls = this.tpls;
12229 // create a top level template from the snippet..
12231 //Roo.log(div.innerHTML);
12238 body : div.innerHTML,
12251 Roo.each(tpls, function(tp){
12252 this.compileTpl(tp);
12253 this.tpls[tp.id] = tp;
12256 this.master = tpls[0];
12262 compileNode : function(node, istop) {
12267 // skip anything not a tag..
12268 if (node.nodeType != 1) {
12269 if (node.nodeType == 3 && !this.inPre) {
12270 // reduce white space..
12271 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12294 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12295 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12296 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12297 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12303 // just itterate children..
12304 this.iterChild(node,this.compileNode);
12307 tpl.uid = this.id++;
12308 tpl.value = node.getAttribute('roo-' + tpl.attr);
12309 node.removeAttribute('roo-'+ tpl.attr);
12310 if (tpl.attr != 'name') {
12311 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12312 node.parentNode.replaceChild(placeholder, node);
12315 var placeholder = document.createElement('span');
12316 placeholder.className = 'roo-tpl-' + tpl.value;
12317 node.parentNode.replaceChild(placeholder, node);
12320 // parent now sees '{domtplXXXX}
12321 this.iterChild(node,this.compileNode);
12323 // we should now have node body...
12324 var div = document.createElement('div');
12325 div.appendChild(node);
12327 // this has the unfortunate side effect of converting tagged attributes
12328 // eg. href="{...}" into %7C...%7D
12329 // this has been fixed by searching for those combo's although it's a bit hacky..
12332 tpl.body = div.innerHTML;
12339 switch (tpl.value) {
12340 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12341 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12342 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12347 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12351 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12355 tpl.id = tpl.value; // replace non characters???
12361 this.tpls.push(tpl);
12371 * Compile a segment of the template into a 'sub-template'
12377 compileTpl : function(tpl)
12379 var fm = Roo.util.Format;
12380 var useF = this.disableFormats !== true;
12382 var sep = Roo.isGecko ? "+\n" : ",\n";
12384 var undef = function(str) {
12385 Roo.debug && Roo.log("Property not found :" + str);
12389 //Roo.log(tpl.body);
12393 var fn = function(m, lbrace, name, format, args)
12396 //Roo.log(arguments);
12397 args = args ? args.replace(/\\'/g,"'") : args;
12398 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12399 if (typeof(format) == 'undefined') {
12400 format = 'htmlEncode';
12402 if (format == 'raw' ) {
12406 if(name.substr(0, 6) == 'domtpl'){
12407 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12410 // build an array of options to determine if value is undefined..
12412 // basically get 'xxxx.yyyy' then do
12413 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12414 // (function () { Roo.log("Property not found"); return ''; })() :
12419 Roo.each(name.split('.'), function(st) {
12420 lookfor += (lookfor.length ? '.': '') + st;
12421 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12424 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12427 if(format && useF){
12429 args = args ? ',' + args : "";
12431 if(format.substr(0, 5) != "this."){
12432 format = "fm." + format + '(';
12434 format = 'this.call("'+ format.substr(5) + '", ';
12438 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12441 if (args && args.length) {
12442 // called with xxyx.yuu:(test,test)
12444 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12446 // raw.. - :raw modifier..
12447 return "'"+ sep + udef_st + name + ")"+sep+"'";
12451 // branched to use + in gecko and [].join() in others
12453 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12454 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12457 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12458 body.push(tpl.body.replace(/(\r\n|\n)/g,
12459 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12460 body.push("'].join('');};};");
12461 body = body.join('');
12464 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12466 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12473 * same as applyTemplate, except it's done to one of the subTemplates
12474 * when using named templates, you can do:
12476 * var str = pl.applySubTemplate('your-name', values);
12479 * @param {Number} id of the template
12480 * @param {Object} values to apply to template
12481 * @param {Object} parent (normaly the instance of this object)
12483 applySubTemplate : function(id, values, parent)
12487 var t = this.tpls[id];
12491 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12492 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12496 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12503 if(t.execCall && t.execCall.call(this, values, parent)){
12507 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12513 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12514 parent = t.target ? values : parent;
12515 if(t.forCall && vs instanceof Array){
12517 for(var i = 0, len = vs.length; i < len; i++){
12519 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12521 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12523 //Roo.log(t.compiled);
12527 return buf.join('');
12530 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12535 return t.compiled.call(this, vs, parent);
12537 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12539 //Roo.log(t.compiled);
12547 applyTemplate : function(values){
12548 return this.master.compiled.call(this, values, {});
12549 //var s = this.subs;
12552 apply : function(){
12553 return this.applyTemplate.apply(this, arguments);
12558 Roo.DomTemplate.from = function(el){
12559 el = Roo.getDom(el);
12560 return new Roo.Domtemplate(el.value || el.innerHTML);
12563 * Ext JS Library 1.1.1
12564 * Copyright(c) 2006-2007, Ext JS, LLC.
12566 * Originally Released Under LGPL - original licence link has changed is not relivant.
12569 * <script type="text/javascript">
12573 * @class Roo.util.DelayedTask
12574 * Provides a convenient method of performing setTimeout where a new
12575 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12576 * You can use this class to buffer
12577 * the keypress events for a certain number of milliseconds, and perform only if they stop
12578 * for that amount of time.
12579 * @constructor The parameters to this constructor serve as defaults and are not required.
12580 * @param {Function} fn (optional) The default function to timeout
12581 * @param {Object} scope (optional) The default scope of that timeout
12582 * @param {Array} args (optional) The default Array of arguments
12584 Roo.util.DelayedTask = function(fn, scope, args){
12585 var id = null, d, t;
12587 var call = function(){
12588 var now = new Date().getTime();
12592 fn.apply(scope, args || []);
12596 * Cancels any pending timeout and queues a new one
12597 * @param {Number} delay The milliseconds to delay
12598 * @param {Function} newFn (optional) Overrides function passed to constructor
12599 * @param {Object} newScope (optional) Overrides scope passed to constructor
12600 * @param {Array} newArgs (optional) Overrides args passed to constructor
12602 this.delay = function(delay, newFn, newScope, newArgs){
12603 if(id && delay != d){
12607 t = new Date().getTime();
12609 scope = newScope || scope;
12610 args = newArgs || args;
12612 id = setInterval(call, d);
12617 * Cancel the last queued timeout
12619 this.cancel = function(){
12627 * Ext JS Library 1.1.1
12628 * Copyright(c) 2006-2007, Ext JS, LLC.
12630 * Originally Released Under LGPL - original licence link has changed is not relivant.
12633 * <script type="text/javascript">
12637 Roo.util.TaskRunner = function(interval){
12638 interval = interval || 10;
12639 var tasks = [], removeQueue = [];
12641 var running = false;
12643 var stopThread = function(){
12649 var startThread = function(){
12652 id = setInterval(runTasks, interval);
12656 var removeTask = function(task){
12657 removeQueue.push(task);
12663 var runTasks = function(){
12664 if(removeQueue.length > 0){
12665 for(var i = 0, len = removeQueue.length; i < len; i++){
12666 tasks.remove(removeQueue[i]);
12669 if(tasks.length < 1){
12674 var now = new Date().getTime();
12675 for(var i = 0, len = tasks.length; i < len; ++i){
12677 var itime = now - t.taskRunTime;
12678 if(t.interval <= itime){
12679 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12680 t.taskRunTime = now;
12681 if(rt === false || t.taskRunCount === t.repeat){
12686 if(t.duration && t.duration <= (now - t.taskStartTime)){
12693 * Queues a new task.
12694 * @param {Object} task
12696 this.start = function(task){
12698 task.taskStartTime = new Date().getTime();
12699 task.taskRunTime = 0;
12700 task.taskRunCount = 0;
12705 this.stop = function(task){
12710 this.stopAll = function(){
12712 for(var i = 0, len = tasks.length; i < len; i++){
12713 if(tasks[i].onStop){
12722 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12724 * Ext JS Library 1.1.1
12725 * Copyright(c) 2006-2007, Ext JS, LLC.
12727 * Originally Released Under LGPL - original licence link has changed is not relivant.
12730 * <script type="text/javascript">
12735 * @class Roo.util.MixedCollection
12736 * @extends Roo.util.Observable
12737 * A Collection class that maintains both numeric indexes and keys and exposes events.
12739 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12740 * collection (defaults to false)
12741 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12742 * and return the key value for that item. This is used when available to look up the key on items that
12743 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12744 * equivalent to providing an implementation for the {@link #getKey} method.
12746 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12754 * Fires when the collection is cleared.
12759 * Fires when an item is added to the collection.
12760 * @param {Number} index The index at which the item was added.
12761 * @param {Object} o The item added.
12762 * @param {String} key The key associated with the added item.
12767 * Fires when an item is replaced in the collection.
12768 * @param {String} key he key associated with the new added.
12769 * @param {Object} old The item being replaced.
12770 * @param {Object} new The new item.
12775 * Fires when an item is removed from the collection.
12776 * @param {Object} o The item being removed.
12777 * @param {String} key (optional) The key associated with the removed item.
12782 this.allowFunctions = allowFunctions === true;
12784 this.getKey = keyFn;
12786 Roo.util.MixedCollection.superclass.constructor.call(this);
12789 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12790 allowFunctions : false,
12793 * Adds an item to the collection.
12794 * @param {String} key The key to associate with the item
12795 * @param {Object} o The item to add.
12796 * @return {Object} The item added.
12798 add : function(key, o){
12799 if(arguments.length == 1){
12801 key = this.getKey(o);
12803 if(typeof key == "undefined" || key === null){
12805 this.items.push(o);
12806 this.keys.push(null);
12808 var old = this.map[key];
12810 return this.replace(key, o);
12813 this.items.push(o);
12815 this.keys.push(key);
12817 this.fireEvent("add", this.length-1, o, key);
12822 * MixedCollection has a generic way to fetch keys if you implement getKey.
12825 var mc = new Roo.util.MixedCollection();
12826 mc.add(someEl.dom.id, someEl);
12827 mc.add(otherEl.dom.id, otherEl);
12831 var mc = new Roo.util.MixedCollection();
12832 mc.getKey = function(el){
12838 // or via the constructor
12839 var mc = new Roo.util.MixedCollection(false, function(el){
12845 * @param o {Object} The item for which to find the key.
12846 * @return {Object} The key for the passed item.
12848 getKey : function(o){
12853 * Replaces an item in the collection.
12854 * @param {String} key The key associated with the item to replace, or the item to replace.
12855 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12856 * @return {Object} The new item.
12858 replace : function(key, o){
12859 if(arguments.length == 1){
12861 key = this.getKey(o);
12863 var old = this.item(key);
12864 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12865 return this.add(key, o);
12867 var index = this.indexOfKey(key);
12868 this.items[index] = o;
12870 this.fireEvent("replace", key, old, o);
12875 * Adds all elements of an Array or an Object to the collection.
12876 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12877 * an Array of values, each of which are added to the collection.
12879 addAll : function(objs){
12880 if(arguments.length > 1 || objs instanceof Array){
12881 var args = arguments.length > 1 ? arguments : objs;
12882 for(var i = 0, len = args.length; i < len; i++){
12886 for(var key in objs){
12887 if(this.allowFunctions || typeof objs[key] != "function"){
12888 this.add(key, objs[key]);
12895 * Executes the specified function once for every item in the collection, passing each
12896 * item as the first and only parameter. returning false from the function will stop the iteration.
12897 * @param {Function} fn The function to execute for each item.
12898 * @param {Object} scope (optional) The scope in which to execute the function.
12900 each : function(fn, scope){
12901 var items = [].concat(this.items); // each safe for removal
12902 for(var i = 0, len = items.length; i < len; i++){
12903 if(fn.call(scope || items[i], items[i], i, len) === false){
12910 * Executes the specified function once for every key in the collection, passing each
12911 * key, and its associated item as the first two parameters.
12912 * @param {Function} fn The function to execute for each item.
12913 * @param {Object} scope (optional) The scope in which to execute the function.
12915 eachKey : function(fn, scope){
12916 for(var i = 0, len = this.keys.length; i < len; i++){
12917 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12922 * Returns the first item in the collection which elicits a true return value from the
12923 * passed selection function.
12924 * @param {Function} fn The selection function to execute for each item.
12925 * @param {Object} scope (optional) The scope in which to execute the function.
12926 * @return {Object} The first item in the collection which returned true from the selection function.
12928 find : function(fn, scope){
12929 for(var i = 0, len = this.items.length; i < len; i++){
12930 if(fn.call(scope || window, this.items[i], this.keys[i])){
12931 return this.items[i];
12938 * Inserts an item at the specified index in the collection.
12939 * @param {Number} index The index to insert the item at.
12940 * @param {String} key The key to associate with the new item, or the item itself.
12941 * @param {Object} o (optional) If the second parameter was a key, the new item.
12942 * @return {Object} The item inserted.
12944 insert : function(index, key, o){
12945 if(arguments.length == 2){
12947 key = this.getKey(o);
12949 if(index >= this.length){
12950 return this.add(key, o);
12953 this.items.splice(index, 0, o);
12954 if(typeof key != "undefined" && key != null){
12957 this.keys.splice(index, 0, key);
12958 this.fireEvent("add", index, o, key);
12963 * Removed an item from the collection.
12964 * @param {Object} o The item to remove.
12965 * @return {Object} The item removed.
12967 remove : function(o){
12968 return this.removeAt(this.indexOf(o));
12972 * Remove an item from a specified index in the collection.
12973 * @param {Number} index The index within the collection of the item to remove.
12975 removeAt : function(index){
12976 if(index < this.length && index >= 0){
12978 var o = this.items[index];
12979 this.items.splice(index, 1);
12980 var key = this.keys[index];
12981 if(typeof key != "undefined"){
12982 delete this.map[key];
12984 this.keys.splice(index, 1);
12985 this.fireEvent("remove", o, key);
12990 * Removed an item associated with the passed key fom the collection.
12991 * @param {String} key The key of the item to remove.
12993 removeKey : function(key){
12994 return this.removeAt(this.indexOfKey(key));
12998 * Returns the number of items in the collection.
12999 * @return {Number} the number of items in the collection.
13001 getCount : function(){
13002 return this.length;
13006 * Returns index within the collection of the passed Object.
13007 * @param {Object} o The item to find the index of.
13008 * @return {Number} index of the item.
13010 indexOf : function(o){
13011 if(!this.items.indexOf){
13012 for(var i = 0, len = this.items.length; i < len; i++){
13013 if(this.items[i] == o) return i;
13017 return this.items.indexOf(o);
13022 * Returns index within the collection of the passed key.
13023 * @param {String} key The key to find the index of.
13024 * @return {Number} index of the key.
13026 indexOfKey : function(key){
13027 if(!this.keys.indexOf){
13028 for(var i = 0, len = this.keys.length; i < len; i++){
13029 if(this.keys[i] == key) return i;
13033 return this.keys.indexOf(key);
13038 * Returns the item associated with the passed key OR index. Key has priority over index.
13039 * @param {String/Number} key The key or index of the item.
13040 * @return {Object} The item associated with the passed key.
13042 item : function(key){
13043 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13044 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13048 * Returns the item at the specified index.
13049 * @param {Number} index The index of the item.
13052 itemAt : function(index){
13053 return this.items[index];
13057 * Returns the item associated with the passed key.
13058 * @param {String/Number} key The key of the item.
13059 * @return {Object} The item associated with the passed key.
13061 key : function(key){
13062 return this.map[key];
13066 * Returns true if the collection contains the passed Object as an item.
13067 * @param {Object} o The Object to look for in the collection.
13068 * @return {Boolean} True if the collection contains the Object as an item.
13070 contains : function(o){
13071 return this.indexOf(o) != -1;
13075 * Returns true if the collection contains the passed Object as a key.
13076 * @param {String} key The key to look for in the collection.
13077 * @return {Boolean} True if the collection contains the Object as a key.
13079 containsKey : function(key){
13080 return typeof this.map[key] != "undefined";
13084 * Removes all items from the collection.
13086 clear : function(){
13091 this.fireEvent("clear");
13095 * Returns the first item in the collection.
13096 * @return {Object} the first item in the collection..
13098 first : function(){
13099 return this.items[0];
13103 * Returns the last item in the collection.
13104 * @return {Object} the last item in the collection..
13107 return this.items[this.length-1];
13110 _sort : function(property, dir, fn){
13111 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13112 fn = fn || function(a, b){
13115 var c = [], k = this.keys, items = this.items;
13116 for(var i = 0, len = items.length; i < len; i++){
13117 c[c.length] = {key: k[i], value: items[i], index: i};
13119 c.sort(function(a, b){
13120 var v = fn(a[property], b[property]) * dsc;
13122 v = (a.index < b.index ? -1 : 1);
13126 for(var i = 0, len = c.length; i < len; i++){
13127 items[i] = c[i].value;
13130 this.fireEvent("sort", this);
13134 * Sorts this collection with the passed comparison function
13135 * @param {String} direction (optional) "ASC" or "DESC"
13136 * @param {Function} fn (optional) comparison function
13138 sort : function(dir, fn){
13139 this._sort("value", dir, fn);
13143 * Sorts this collection by keys
13144 * @param {String} direction (optional) "ASC" or "DESC"
13145 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13147 keySort : function(dir, fn){
13148 this._sort("key", dir, fn || function(a, b){
13149 return String(a).toUpperCase()-String(b).toUpperCase();
13154 * Returns a range of items in this collection
13155 * @param {Number} startIndex (optional) defaults to 0
13156 * @param {Number} endIndex (optional) default to the last item
13157 * @return {Array} An array of items
13159 getRange : function(start, end){
13160 var items = this.items;
13161 if(items.length < 1){
13164 start = start || 0;
13165 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13168 for(var i = start; i <= end; i++) {
13169 r[r.length] = items[i];
13172 for(var i = start; i >= end; i--) {
13173 r[r.length] = items[i];
13180 * Filter the <i>objects</i> in this collection by a specific property.
13181 * Returns a new collection that has been filtered.
13182 * @param {String} property A property on your objects
13183 * @param {String/RegExp} value Either string that the property values
13184 * should start with or a RegExp to test against the property
13185 * @return {MixedCollection} The new filtered collection
13187 filter : function(property, value){
13188 if(!value.exec){ // not a regex
13189 value = String(value);
13190 if(value.length == 0){
13191 return this.clone();
13193 value = new RegExp("^" + Roo.escapeRe(value), "i");
13195 return this.filterBy(function(o){
13196 return o && value.test(o[property]);
13201 * Filter by a function. * Returns a new collection that has been filtered.
13202 * The passed function will be called with each
13203 * object in the collection. If the function returns true, the value is included
13204 * otherwise it is filtered.
13205 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13206 * @param {Object} scope (optional) The scope of the function (defaults to this)
13207 * @return {MixedCollection} The new filtered collection
13209 filterBy : function(fn, scope){
13210 var r = new Roo.util.MixedCollection();
13211 r.getKey = this.getKey;
13212 var k = this.keys, it = this.items;
13213 for(var i = 0, len = it.length; i < len; i++){
13214 if(fn.call(scope||this, it[i], k[i])){
13215 r.add(k[i], it[i]);
13222 * Creates a duplicate of this collection
13223 * @return {MixedCollection}
13225 clone : function(){
13226 var r = new Roo.util.MixedCollection();
13227 var k = this.keys, it = this.items;
13228 for(var i = 0, len = it.length; i < len; i++){
13229 r.add(k[i], it[i]);
13231 r.getKey = this.getKey;
13236 * Returns the item associated with the passed key or index.
13238 * @param {String/Number} key The key or index of the item.
13239 * @return {Object} The item associated with the passed key.
13241 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13243 * Ext JS Library 1.1.1
13244 * Copyright(c) 2006-2007, Ext JS, LLC.
13246 * Originally Released Under LGPL - original licence link has changed is not relivant.
13249 * <script type="text/javascript">
13252 * @class Roo.util.JSON
13253 * Modified version of Douglas Crockford"s json.js that doesn"t
13254 * mess with the Object prototype
13255 * http://www.json.org/js.html
13258 Roo.util.JSON = new (function(){
13259 var useHasOwn = {}.hasOwnProperty ? true : false;
13261 // crashes Safari in some instances
13262 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13264 var pad = function(n) {
13265 return n < 10 ? "0" + n : n;
13278 var encodeString = function(s){
13279 if (/["\\\x00-\x1f]/.test(s)) {
13280 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13285 c = b.charCodeAt();
13287 Math.floor(c / 16).toString(16) +
13288 (c % 16).toString(16);
13291 return '"' + s + '"';
13294 var encodeArray = function(o){
13295 var a = ["["], b, i, l = o.length, v;
13296 for (i = 0; i < l; i += 1) {
13298 switch (typeof v) {
13307 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13315 var encodeDate = function(o){
13316 return '"' + o.getFullYear() + "-" +
13317 pad(o.getMonth() + 1) + "-" +
13318 pad(o.getDate()) + "T" +
13319 pad(o.getHours()) + ":" +
13320 pad(o.getMinutes()) + ":" +
13321 pad(o.getSeconds()) + '"';
13325 * Encodes an Object, Array or other value
13326 * @param {Mixed} o The variable to encode
13327 * @return {String} The JSON string
13329 this.encode = function(o)
13331 // should this be extended to fully wrap stringify..
13333 if(typeof o == "undefined" || o === null){
13335 }else if(o instanceof Array){
13336 return encodeArray(o);
13337 }else if(o instanceof Date){
13338 return encodeDate(o);
13339 }else if(typeof o == "string"){
13340 return encodeString(o);
13341 }else if(typeof o == "number"){
13342 return isFinite(o) ? String(o) : "null";
13343 }else if(typeof o == "boolean"){
13346 var a = ["{"], b, i, v;
13348 if(!useHasOwn || o.hasOwnProperty(i)) {
13350 switch (typeof v) {
13359 a.push(this.encode(i), ":",
13360 v === null ? "null" : this.encode(v));
13371 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13372 * @param {String} json The JSON string
13373 * @return {Object} The resulting object
13375 this.decode = function(json){
13377 return /** eval:var:json */ eval("(" + json + ')');
13381 * Shorthand for {@link Roo.util.JSON#encode}
13382 * @member Roo encode
13384 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13386 * Shorthand for {@link Roo.util.JSON#decode}
13387 * @member Roo decode
13389 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13392 * Ext JS Library 1.1.1
13393 * Copyright(c) 2006-2007, Ext JS, LLC.
13395 * Originally Released Under LGPL - original licence link has changed is not relivant.
13398 * <script type="text/javascript">
13402 * @class Roo.util.Format
13403 * Reusable data formatting functions
13406 Roo.util.Format = function(){
13407 var trimRe = /^\s+|\s+$/g;
13410 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13411 * @param {String} value The string to truncate
13412 * @param {Number} length The maximum length to allow before truncating
13413 * @return {String} The converted text
13415 ellipsis : function(value, len){
13416 if(value && value.length > len){
13417 return value.substr(0, len-3)+"...";
13423 * Checks a reference and converts it to empty string if it is undefined
13424 * @param {Mixed} value Reference to check
13425 * @return {Mixed} Empty string if converted, otherwise the original value
13427 undef : function(value){
13428 return typeof value != "undefined" ? value : "";
13432 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13433 * @param {String} value The string to encode
13434 * @return {String} The encoded text
13436 htmlEncode : function(value){
13437 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13441 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13442 * @param {String} value The string to decode
13443 * @return {String} The decoded text
13445 htmlDecode : function(value){
13446 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13450 * Trims any whitespace from either side of a string
13451 * @param {String} value The text to trim
13452 * @return {String} The trimmed text
13454 trim : function(value){
13455 return String(value).replace(trimRe, "");
13459 * Returns a substring from within an original string
13460 * @param {String} value The original text
13461 * @param {Number} start The start index of the substring
13462 * @param {Number} length The length of the substring
13463 * @return {String} The substring
13465 substr : function(value, start, length){
13466 return String(value).substr(start, length);
13470 * Converts a string to all lower case letters
13471 * @param {String} value The text to convert
13472 * @return {String} The converted text
13474 lowercase : function(value){
13475 return String(value).toLowerCase();
13479 * Converts a string to all upper case letters
13480 * @param {String} value The text to convert
13481 * @return {String} The converted text
13483 uppercase : function(value){
13484 return String(value).toUpperCase();
13488 * Converts the first character only of a string to upper case
13489 * @param {String} value The text to convert
13490 * @return {String} The converted text
13492 capitalize : function(value){
13493 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13497 call : function(value, fn){
13498 if(arguments.length > 2){
13499 var args = Array.prototype.slice.call(arguments, 2);
13500 args.unshift(value);
13502 return /** eval:var:value */ eval(fn).apply(window, args);
13504 /** eval:var:value */
13505 return /** eval:var:value */ eval(fn).call(window, value);
13511 * safer version of Math.toFixed..??/
13512 * @param {Number/String} value The numeric value to format
13513 * @param {Number/String} value Decimal places
13514 * @return {String} The formatted currency string
13516 toFixed : function(v, n)
13518 // why not use to fixed - precision is buggered???
13520 return Math.round(v-0);
13522 var fact = Math.pow(10,n+1);
13523 v = (Math.round((v-0)*fact))/fact;
13524 var z = (''+fact).substring(2);
13525 if (v == Math.floor(v)) {
13526 return Math.floor(v) + '.' + z;
13529 // now just padd decimals..
13530 var ps = String(v).split('.');
13531 var fd = (ps[1] + z);
13532 var r = fd.substring(0,n);
13533 var rm = fd.substring(n);
13535 return ps[0] + '.' + r;
13537 r*=1; // turn it into a number;
13539 if (String(r).length != n) {
13542 r = String(r).substring(1); // chop the end off.
13545 return ps[0] + '.' + r;
13550 * Format a number as US currency
13551 * @param {Number/String} value The numeric value to format
13552 * @return {String} The formatted currency string
13554 usMoney : function(v){
13555 return '$' + Roo.util.Format.number(v);
13560 * eventually this should probably emulate php's number_format
13561 * @param {Number/String} value The numeric value to format
13562 * @param {Number} decimals number of decimal places
13563 * @return {String} The formatted currency string
13565 number : function(v,decimals)
13567 // multiply and round.
13568 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13569 var mul = Math.pow(10, decimals);
13570 var zero = String(mul).substring(1);
13571 v = (Math.round((v-0)*mul))/mul;
13573 // if it's '0' number.. then
13575 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13577 var ps = v.split('.');
13581 var r = /(\d+)(\d{3})/;
13583 while (r.test(whole)) {
13584 whole = whole.replace(r, '$1' + ',' + '$2');
13590 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13591 // does not have decimals
13592 (decimals ? ('.' + zero) : '');
13595 return whole + sub ;
13599 * Parse a value into a formatted date using the specified format pattern.
13600 * @param {Mixed} value The value to format
13601 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13602 * @return {String} The formatted date string
13604 date : function(v, format){
13608 if(!(v instanceof Date)){
13609 v = new Date(Date.parse(v));
13611 return v.dateFormat(format || Roo.util.Format.defaults.date);
13615 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13616 * @param {String} format Any valid date format string
13617 * @return {Function} The date formatting function
13619 dateRenderer : function(format){
13620 return function(v){
13621 return Roo.util.Format.date(v, format);
13626 stripTagsRE : /<\/?[^>]+>/gi,
13629 * Strips all HTML tags
13630 * @param {Mixed} value The text from which to strip tags
13631 * @return {String} The stripped text
13633 stripTags : function(v){
13634 return !v ? v : String(v).replace(this.stripTagsRE, "");
13638 Roo.util.Format.defaults = {
13642 * Ext JS Library 1.1.1
13643 * Copyright(c) 2006-2007, Ext JS, LLC.
13645 * Originally Released Under LGPL - original licence link has changed is not relivant.
13648 * <script type="text/javascript">
13655 * @class Roo.MasterTemplate
13656 * @extends Roo.Template
13657 * Provides a template that can have child templates. The syntax is:
13659 var t = new Roo.MasterTemplate(
13660 '<select name="{name}">',
13661 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13664 t.add('options', {value: 'foo', text: 'bar'});
13665 // or you can add multiple child elements in one shot
13666 t.addAll('options', [
13667 {value: 'foo', text: 'bar'},
13668 {value: 'foo2', text: 'bar2'},
13669 {value: 'foo3', text: 'bar3'}
13671 // then append, applying the master template values
13672 t.append('my-form', {name: 'my-select'});
13674 * A name attribute for the child template is not required if you have only one child
13675 * template or you want to refer to them by index.
13677 Roo.MasterTemplate = function(){
13678 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13679 this.originalHtml = this.html;
13681 var m, re = this.subTemplateRe;
13684 while(m = re.exec(this.html)){
13685 var name = m[1], content = m[2];
13690 tpl : new Roo.Template(content)
13693 st[name] = st[subIndex];
13695 st[subIndex].tpl.compile();
13696 st[subIndex].tpl.call = this.call.createDelegate(this);
13699 this.subCount = subIndex;
13702 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13704 * The regular expression used to match sub templates
13708 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13711 * Applies the passed values to a child template.
13712 * @param {String/Number} name (optional) The name or index of the child template
13713 * @param {Array/Object} values The values to be applied to the template
13714 * @return {MasterTemplate} this
13716 add : function(name, values){
13717 if(arguments.length == 1){
13718 values = arguments[0];
13721 var s = this.subs[name];
13722 s.buffer[s.buffer.length] = s.tpl.apply(values);
13727 * Applies all the passed values to a child template.
13728 * @param {String/Number} name (optional) The name or index of the child template
13729 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13730 * @param {Boolean} reset (optional) True to reset the template first
13731 * @return {MasterTemplate} this
13733 fill : function(name, values, reset){
13735 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13743 for(var i = 0, len = values.length; i < len; i++){
13744 this.add(name, values[i]);
13750 * Resets the template for reuse
13751 * @return {MasterTemplate} this
13753 reset : function(){
13755 for(var i = 0; i < this.subCount; i++){
13761 applyTemplate : function(values){
13763 var replaceIndex = -1;
13764 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13765 return s[++replaceIndex].buffer.join("");
13767 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13770 apply : function(){
13771 return this.applyTemplate.apply(this, arguments);
13774 compile : function(){return this;}
13778 * Alias for fill().
13781 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13783 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13784 * var tpl = Roo.MasterTemplate.from('element-id');
13785 * @param {String/HTMLElement} el
13786 * @param {Object} config
13789 Roo.MasterTemplate.from = function(el, config){
13790 el = Roo.getDom(el);
13791 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13794 * Ext JS Library 1.1.1
13795 * Copyright(c) 2006-2007, Ext JS, LLC.
13797 * Originally Released Under LGPL - original licence link has changed is not relivant.
13800 * <script type="text/javascript">
13805 * @class Roo.util.CSS
13806 * Utility class for manipulating CSS rules
13809 Roo.util.CSS = function(){
13811 var doc = document;
13813 var camelRe = /(-[a-z])/gi;
13814 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13818 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13819 * tag and appended to the HEAD of the document.
13820 * @param {String|Object} cssText The text containing the css rules
13821 * @param {String} id An id to add to the stylesheet for later removal
13822 * @return {StyleSheet}
13824 createStyleSheet : function(cssText, id){
13826 var head = doc.getElementsByTagName("head")[0];
13827 var nrules = doc.createElement("style");
13828 nrules.setAttribute("type", "text/css");
13830 nrules.setAttribute("id", id);
13832 if (typeof(cssText) != 'string') {
13833 // support object maps..
13834 // not sure if this a good idea..
13835 // perhaps it should be merged with the general css handling
13836 // and handle js style props.
13837 var cssTextNew = [];
13838 for(var n in cssText) {
13840 for(var k in cssText[n]) {
13841 citems.push( k + ' : ' +cssText[n][k] + ';' );
13843 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13846 cssText = cssTextNew.join("\n");
13852 head.appendChild(nrules);
13853 ss = nrules.styleSheet;
13854 ss.cssText = cssText;
13857 nrules.appendChild(doc.createTextNode(cssText));
13859 nrules.cssText = cssText;
13861 head.appendChild(nrules);
13862 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13864 this.cacheStyleSheet(ss);
13869 * Removes a style or link tag by id
13870 * @param {String} id The id of the tag
13872 removeStyleSheet : function(id){
13873 var existing = doc.getElementById(id);
13875 existing.parentNode.removeChild(existing);
13880 * Dynamically swaps an existing stylesheet reference for a new one
13881 * @param {String} id The id of an existing link tag to remove
13882 * @param {String} url The href of the new stylesheet to include
13884 swapStyleSheet : function(id, url){
13885 this.removeStyleSheet(id);
13886 var ss = doc.createElement("link");
13887 ss.setAttribute("rel", "stylesheet");
13888 ss.setAttribute("type", "text/css");
13889 ss.setAttribute("id", id);
13890 ss.setAttribute("href", url);
13891 doc.getElementsByTagName("head")[0].appendChild(ss);
13895 * Refresh the rule cache if you have dynamically added stylesheets
13896 * @return {Object} An object (hash) of rules indexed by selector
13898 refreshCache : function(){
13899 return this.getRules(true);
13903 cacheStyleSheet : function(stylesheet){
13907 try{// try catch for cross domain access issue
13908 var ssRules = stylesheet.cssRules || stylesheet.rules;
13909 for(var j = ssRules.length-1; j >= 0; --j){
13910 rules[ssRules[j].selectorText] = ssRules[j];
13916 * Gets all css rules for the document
13917 * @param {Boolean} refreshCache true to refresh the internal cache
13918 * @return {Object} An object (hash) of rules indexed by selector
13920 getRules : function(refreshCache){
13921 if(rules == null || refreshCache){
13923 var ds = doc.styleSheets;
13924 for(var i =0, len = ds.length; i < len; i++){
13926 this.cacheStyleSheet(ds[i]);
13934 * Gets an an individual CSS rule by selector(s)
13935 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13936 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13937 * @return {CSSRule} The CSS rule or null if one is not found
13939 getRule : function(selector, refreshCache){
13940 var rs = this.getRules(refreshCache);
13941 if(!(selector instanceof Array)){
13942 return rs[selector];
13944 for(var i = 0; i < selector.length; i++){
13945 if(rs[selector[i]]){
13946 return rs[selector[i]];
13954 * Updates a rule property
13955 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13956 * @param {String} property The css property
13957 * @param {String} value The new value for the property
13958 * @return {Boolean} true If a rule was found and updated
13960 updateRule : function(selector, property, value){
13961 if(!(selector instanceof Array)){
13962 var rule = this.getRule(selector);
13964 rule.style[property.replace(camelRe, camelFn)] = value;
13968 for(var i = 0; i < selector.length; i++){
13969 if(this.updateRule(selector[i], property, value)){
13979 * Ext JS Library 1.1.1
13980 * Copyright(c) 2006-2007, Ext JS, LLC.
13982 * Originally Released Under LGPL - original licence link has changed is not relivant.
13985 * <script type="text/javascript">
13991 * @class Roo.util.ClickRepeater
13992 * @extends Roo.util.Observable
13994 * A wrapper class which can be applied to any element. Fires a "click" event while the
13995 * mouse is pressed. The interval between firings may be specified in the config but
13996 * defaults to 10 milliseconds.
13998 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14000 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14001 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14002 * Similar to an autorepeat key delay.
14003 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14004 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14005 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14006 * "interval" and "delay" are ignored. "immediate" is honored.
14007 * @cfg {Boolean} preventDefault True to prevent the default click event
14008 * @cfg {Boolean} stopDefault True to stop the default click event
14011 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14012 * 2007-02-02 jvs Renamed to ClickRepeater
14013 * 2007-02-03 jvs Modifications for FF Mac and Safari
14016 * @param {String/HTMLElement/Element} el The element to listen on
14017 * @param {Object} config
14019 Roo.util.ClickRepeater = function(el, config)
14021 this.el = Roo.get(el);
14022 this.el.unselectable();
14024 Roo.apply(this, config);
14029 * Fires when the mouse button is depressed.
14030 * @param {Roo.util.ClickRepeater} this
14032 "mousedown" : true,
14035 * Fires on a specified interval during the time the element is pressed.
14036 * @param {Roo.util.ClickRepeater} this
14041 * Fires when the mouse key is released.
14042 * @param {Roo.util.ClickRepeater} this
14047 this.el.on("mousedown", this.handleMouseDown, this);
14048 if(this.preventDefault || this.stopDefault){
14049 this.el.on("click", function(e){
14050 if(this.preventDefault){
14051 e.preventDefault();
14053 if(this.stopDefault){
14059 // allow inline handler
14061 this.on("click", this.handler, this.scope || this);
14064 Roo.util.ClickRepeater.superclass.constructor.call(this);
14067 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14070 preventDefault : true,
14071 stopDefault : false,
14075 handleMouseDown : function(){
14076 clearTimeout(this.timer);
14078 if(this.pressClass){
14079 this.el.addClass(this.pressClass);
14081 this.mousedownTime = new Date();
14083 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14084 this.el.on("mouseout", this.handleMouseOut, this);
14086 this.fireEvent("mousedown", this);
14087 this.fireEvent("click", this);
14089 this.timer = this.click.defer(this.delay || this.interval, this);
14093 click : function(){
14094 this.fireEvent("click", this);
14095 this.timer = this.click.defer(this.getInterval(), this);
14099 getInterval: function(){
14100 if(!this.accelerate){
14101 return this.interval;
14103 var pressTime = this.mousedownTime.getElapsed();
14104 if(pressTime < 500){
14106 }else if(pressTime < 1700){
14108 }else if(pressTime < 2600){
14110 }else if(pressTime < 3500){
14112 }else if(pressTime < 4400){
14114 }else if(pressTime < 5300){
14116 }else if(pressTime < 6200){
14124 handleMouseOut : function(){
14125 clearTimeout(this.timer);
14126 if(this.pressClass){
14127 this.el.removeClass(this.pressClass);
14129 this.el.on("mouseover", this.handleMouseReturn, this);
14133 handleMouseReturn : function(){
14134 this.el.un("mouseover", this.handleMouseReturn);
14135 if(this.pressClass){
14136 this.el.addClass(this.pressClass);
14142 handleMouseUp : function(){
14143 clearTimeout(this.timer);
14144 this.el.un("mouseover", this.handleMouseReturn);
14145 this.el.un("mouseout", this.handleMouseOut);
14146 Roo.get(document).un("mouseup", this.handleMouseUp);
14147 this.el.removeClass(this.pressClass);
14148 this.fireEvent("mouseup", this);
14152 * Ext JS Library 1.1.1
14153 * Copyright(c) 2006-2007, Ext JS, LLC.
14155 * Originally Released Under LGPL - original licence link has changed is not relivant.
14158 * <script type="text/javascript">
14163 * @class Roo.KeyNav
14164 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14165 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14166 * way to implement custom navigation schemes for any UI component.</p>
14167 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14168 * pageUp, pageDown, del, home, end. Usage:</p>
14170 var nav = new Roo.KeyNav("my-element", {
14171 "left" : function(e){
14172 this.moveLeft(e.ctrlKey);
14174 "right" : function(e){
14175 this.moveRight(e.ctrlKey);
14177 "enter" : function(e){
14184 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14185 * @param {Object} config The config
14187 Roo.KeyNav = function(el, config){
14188 this.el = Roo.get(el);
14189 Roo.apply(this, config);
14190 if(!this.disabled){
14191 this.disabled = true;
14196 Roo.KeyNav.prototype = {
14198 * @cfg {Boolean} disabled
14199 * True to disable this KeyNav instance (defaults to false)
14203 * @cfg {String} defaultEventAction
14204 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14205 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14206 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14208 defaultEventAction: "stopEvent",
14210 * @cfg {Boolean} forceKeyDown
14211 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14212 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14213 * handle keydown instead of keypress.
14215 forceKeyDown : false,
14218 prepareEvent : function(e){
14219 var k = e.getKey();
14220 var h = this.keyToHandler[k];
14221 //if(h && this[h]){
14222 // e.stopPropagation();
14224 if(Roo.isSafari && h && k >= 37 && k <= 40){
14230 relay : function(e){
14231 var k = e.getKey();
14232 var h = this.keyToHandler[k];
14234 if(this.doRelay(e, this[h], h) !== true){
14235 e[this.defaultEventAction]();
14241 doRelay : function(e, h, hname){
14242 return h.call(this.scope || this, e);
14245 // possible handlers
14259 // quick lookup hash
14276 * Enable this KeyNav
14278 enable: function(){
14280 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14281 // the EventObject will normalize Safari automatically
14282 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14283 this.el.on("keydown", this.relay, this);
14285 this.el.on("keydown", this.prepareEvent, this);
14286 this.el.on("keypress", this.relay, this);
14288 this.disabled = false;
14293 * Disable this KeyNav
14295 disable: function(){
14296 if(!this.disabled){
14297 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14298 this.el.un("keydown", this.relay);
14300 this.el.un("keydown", this.prepareEvent);
14301 this.el.un("keypress", this.relay);
14303 this.disabled = true;
14308 * Ext JS Library 1.1.1
14309 * Copyright(c) 2006-2007, Ext JS, LLC.
14311 * Originally Released Under LGPL - original licence link has changed is not relivant.
14314 * <script type="text/javascript">
14319 * @class Roo.KeyMap
14320 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14321 * The constructor accepts the same config object as defined by {@link #addBinding}.
14322 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14323 * combination it will call the function with this signature (if the match is a multi-key
14324 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14325 * A KeyMap can also handle a string representation of keys.<br />
14328 // map one key by key code
14329 var map = new Roo.KeyMap("my-element", {
14330 key: 13, // or Roo.EventObject.ENTER
14335 // map multiple keys to one action by string
14336 var map = new Roo.KeyMap("my-element", {
14342 // map multiple keys to multiple actions by strings and array of codes
14343 var map = new Roo.KeyMap("my-element", [
14346 fn: function(){ alert("Return was pressed"); }
14349 fn: function(){ alert('a, b or c was pressed'); }
14354 fn: function(){ alert('Control + shift + tab was pressed.'); }
14358 * <b>Note: A KeyMap starts enabled</b>
14360 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14361 * @param {Object} config The config (see {@link #addBinding})
14362 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14364 Roo.KeyMap = function(el, config, eventName){
14365 this.el = Roo.get(el);
14366 this.eventName = eventName || "keydown";
14367 this.bindings = [];
14369 this.addBinding(config);
14374 Roo.KeyMap.prototype = {
14376 * True to stop the event from bubbling and prevent the default browser action if the
14377 * key was handled by the KeyMap (defaults to false)
14383 * Add a new binding to this KeyMap. The following config object properties are supported:
14385 Property Type Description
14386 ---------- --------------- ----------------------------------------------------------------------
14387 key String/Array A single keycode or an array of keycodes to handle
14388 shift Boolean True to handle key only when shift is pressed (defaults to false)
14389 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14390 alt Boolean True to handle key only when alt is pressed (defaults to false)
14391 fn Function The function to call when KeyMap finds the expected key combination
14392 scope Object The scope of the callback function
14398 var map = new Roo.KeyMap(document, {
14399 key: Roo.EventObject.ENTER,
14404 //Add a new binding to the existing KeyMap later
14412 * @param {Object/Array} config A single KeyMap config or an array of configs
14414 addBinding : function(config){
14415 if(config instanceof Array){
14416 for(var i = 0, len = config.length; i < len; i++){
14417 this.addBinding(config[i]);
14421 var keyCode = config.key,
14422 shift = config.shift,
14423 ctrl = config.ctrl,
14426 scope = config.scope;
14427 if(typeof keyCode == "string"){
14429 var keyString = keyCode.toUpperCase();
14430 for(var j = 0, len = keyString.length; j < len; j++){
14431 ks.push(keyString.charCodeAt(j));
14435 var keyArray = keyCode instanceof Array;
14436 var handler = function(e){
14437 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14438 var k = e.getKey();
14440 for(var i = 0, len = keyCode.length; i < len; i++){
14441 if(keyCode[i] == k){
14442 if(this.stopEvent){
14445 fn.call(scope || window, k, e);
14451 if(this.stopEvent){
14454 fn.call(scope || window, k, e);
14459 this.bindings.push(handler);
14463 * Shorthand for adding a single key listener
14464 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14465 * following options:
14466 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14467 * @param {Function} fn The function to call
14468 * @param {Object} scope (optional) The scope of the function
14470 on : function(key, fn, scope){
14471 var keyCode, shift, ctrl, alt;
14472 if(typeof key == "object" && !(key instanceof Array)){
14491 handleKeyDown : function(e){
14492 if(this.enabled){ //just in case
14493 var b = this.bindings;
14494 for(var i = 0, len = b.length; i < len; i++){
14495 b[i].call(this, e);
14501 * Returns true if this KeyMap is enabled
14502 * @return {Boolean}
14504 isEnabled : function(){
14505 return this.enabled;
14509 * Enables this KeyMap
14511 enable: function(){
14513 this.el.on(this.eventName, this.handleKeyDown, this);
14514 this.enabled = true;
14519 * Disable this KeyMap
14521 disable: function(){
14523 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14524 this.enabled = false;
14529 * Ext JS Library 1.1.1
14530 * Copyright(c) 2006-2007, Ext JS, LLC.
14532 * Originally Released Under LGPL - original licence link has changed is not relivant.
14535 * <script type="text/javascript">
14540 * @class Roo.util.TextMetrics
14541 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14542 * wide, in pixels, a given block of text will be.
14545 Roo.util.TextMetrics = function(){
14549 * Measures the size of the specified text
14550 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14551 * that can affect the size of the rendered text
14552 * @param {String} text The text to measure
14553 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14554 * in order to accurately measure the text height
14555 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14557 measure : function(el, text, fixedWidth){
14559 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14562 shared.setFixedWidth(fixedWidth || 'auto');
14563 return shared.getSize(text);
14567 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14568 * the overhead of multiple calls to initialize the style properties on each measurement.
14569 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14570 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14571 * in order to accurately measure the text height
14572 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14574 createInstance : function(el, fixedWidth){
14575 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14582 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14583 var ml = new Roo.Element(document.createElement('div'));
14584 document.body.appendChild(ml.dom);
14585 ml.position('absolute');
14586 ml.setLeftTop(-1000, -1000);
14590 ml.setWidth(fixedWidth);
14595 * Returns the size of the specified text based on the internal element's style and width properties
14596 * @memberOf Roo.util.TextMetrics.Instance#
14597 * @param {String} text The text to measure
14598 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14600 getSize : function(text){
14602 var s = ml.getSize();
14608 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14609 * that can affect the size of the rendered text
14610 * @memberOf Roo.util.TextMetrics.Instance#
14611 * @param {String/HTMLElement} el The element, dom node or id
14613 bind : function(el){
14615 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14620 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14621 * to set a fixed width in order to accurately measure the text height.
14622 * @memberOf Roo.util.TextMetrics.Instance#
14623 * @param {Number} width The width to set on the element
14625 setFixedWidth : function(width){
14626 ml.setWidth(width);
14630 * Returns the measured width of the specified text
14631 * @memberOf Roo.util.TextMetrics.Instance#
14632 * @param {String} text The text to measure
14633 * @return {Number} width The width in pixels
14635 getWidth : function(text){
14636 ml.dom.style.width = 'auto';
14637 return this.getSize(text).width;
14641 * Returns the measured height of the specified text. For multiline text, be sure to call
14642 * {@link #setFixedWidth} if necessary.
14643 * @memberOf Roo.util.TextMetrics.Instance#
14644 * @param {String} text The text to measure
14645 * @return {Number} height The height in pixels
14647 getHeight : function(text){
14648 return this.getSize(text).height;
14652 instance.bind(bindTo);
14657 // backwards compat
14658 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14660 * Ext JS Library 1.1.1
14661 * Copyright(c) 2006-2007, Ext JS, LLC.
14663 * Originally Released Under LGPL - original licence link has changed is not relivant.
14666 * <script type="text/javascript">
14670 * @class Roo.state.Provider
14671 * Abstract base class for state provider implementations. This class provides methods
14672 * for encoding and decoding <b>typed</b> variables including dates and defines the
14673 * Provider interface.
14675 Roo.state.Provider = function(){
14677 * @event statechange
14678 * Fires when a state change occurs.
14679 * @param {Provider} this This state provider
14680 * @param {String} key The state key which was changed
14681 * @param {String} value The encoded value for the state
14684 "statechange": true
14687 Roo.state.Provider.superclass.constructor.call(this);
14689 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14691 * Returns the current value for a key
14692 * @param {String} name The key name
14693 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14694 * @return {Mixed} The state data
14696 get : function(name, defaultValue){
14697 return typeof this.state[name] == "undefined" ?
14698 defaultValue : this.state[name];
14702 * Clears a value from the state
14703 * @param {String} name The key name
14705 clear : function(name){
14706 delete this.state[name];
14707 this.fireEvent("statechange", this, name, null);
14711 * Sets the value for a key
14712 * @param {String} name The key name
14713 * @param {Mixed} value The value to set
14715 set : function(name, value){
14716 this.state[name] = value;
14717 this.fireEvent("statechange", this, name, value);
14721 * Decodes a string previously encoded with {@link #encodeValue}.
14722 * @param {String} value The value to decode
14723 * @return {Mixed} The decoded value
14725 decodeValue : function(cookie){
14726 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14727 var matches = re.exec(unescape(cookie));
14728 if(!matches || !matches[1]) return; // non state cookie
14729 var type = matches[1];
14730 var v = matches[2];
14733 return parseFloat(v);
14735 return new Date(Date.parse(v));
14740 var values = v.split("^");
14741 for(var i = 0, len = values.length; i < len; i++){
14742 all.push(this.decodeValue(values[i]));
14747 var values = v.split("^");
14748 for(var i = 0, len = values.length; i < len; i++){
14749 var kv = values[i].split("=");
14750 all[kv[0]] = this.decodeValue(kv[1]);
14759 * Encodes a value including type information. Decode with {@link #decodeValue}.
14760 * @param {Mixed} value The value to encode
14761 * @return {String} The encoded value
14763 encodeValue : function(v){
14765 if(typeof v == "number"){
14767 }else if(typeof v == "boolean"){
14768 enc = "b:" + (v ? "1" : "0");
14769 }else if(v instanceof Date){
14770 enc = "d:" + v.toGMTString();
14771 }else if(v instanceof Array){
14773 for(var i = 0, len = v.length; i < len; i++){
14774 flat += this.encodeValue(v[i]);
14775 if(i != len-1) flat += "^";
14778 }else if(typeof v == "object"){
14781 if(typeof v[key] != "function"){
14782 flat += key + "=" + this.encodeValue(v[key]) + "^";
14785 enc = "o:" + flat.substring(0, flat.length-1);
14789 return escape(enc);
14795 * Ext JS Library 1.1.1
14796 * Copyright(c) 2006-2007, Ext JS, LLC.
14798 * Originally Released Under LGPL - original licence link has changed is not relivant.
14801 * <script type="text/javascript">
14804 * @class Roo.state.Manager
14805 * This is the global state manager. By default all components that are "state aware" check this class
14806 * for state information if you don't pass them a custom state provider. In order for this class
14807 * to be useful, it must be initialized with a provider when your application initializes.
14809 // in your initialization function
14811 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14813 // supposed you have a {@link Roo.BorderLayout}
14814 var layout = new Roo.BorderLayout(...);
14815 layout.restoreState();
14816 // or a {Roo.BasicDialog}
14817 var dialog = new Roo.BasicDialog(...);
14818 dialog.restoreState();
14822 Roo.state.Manager = function(){
14823 var provider = new Roo.state.Provider();
14827 * Configures the default state provider for your application
14828 * @param {Provider} stateProvider The state provider to set
14830 setProvider : function(stateProvider){
14831 provider = stateProvider;
14835 * Returns the current value for a key
14836 * @param {String} name The key name
14837 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14838 * @return {Mixed} The state data
14840 get : function(key, defaultValue){
14841 return provider.get(key, defaultValue);
14845 * Sets the value for a key
14846 * @param {String} name The key name
14847 * @param {Mixed} value The state data
14849 set : function(key, value){
14850 provider.set(key, value);
14854 * Clears a value from the state
14855 * @param {String} name The key name
14857 clear : function(key){
14858 provider.clear(key);
14862 * Gets the currently configured state provider
14863 * @return {Provider} The state provider
14865 getProvider : function(){
14872 * Ext JS Library 1.1.1
14873 * Copyright(c) 2006-2007, Ext JS, LLC.
14875 * Originally Released Under LGPL - original licence link has changed is not relivant.
14878 * <script type="text/javascript">
14881 * @class Roo.state.CookieProvider
14882 * @extends Roo.state.Provider
14883 * The default Provider implementation which saves state via cookies.
14886 var cp = new Roo.state.CookieProvider({
14888 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14889 domain: "roojs.com"
14891 Roo.state.Manager.setProvider(cp);
14893 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14894 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14895 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14896 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14897 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14898 * domain the page is running on including the 'www' like 'www.roojs.com')
14899 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14901 * Create a new CookieProvider
14902 * @param {Object} config The configuration object
14904 Roo.state.CookieProvider = function(config){
14905 Roo.state.CookieProvider.superclass.constructor.call(this);
14907 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14908 this.domain = null;
14909 this.secure = false;
14910 Roo.apply(this, config);
14911 this.state = this.readCookies();
14914 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14916 set : function(name, value){
14917 if(typeof value == "undefined" || value === null){
14921 this.setCookie(name, value);
14922 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14926 clear : function(name){
14927 this.clearCookie(name);
14928 Roo.state.CookieProvider.superclass.clear.call(this, name);
14932 readCookies : function(){
14934 var c = document.cookie + ";";
14935 var re = /\s?(.*?)=(.*?);/g;
14937 while((matches = re.exec(c)) != null){
14938 var name = matches[1];
14939 var value = matches[2];
14940 if(name && name.substring(0,3) == "ys-"){
14941 cookies[name.substr(3)] = this.decodeValue(value);
14948 setCookie : function(name, value){
14949 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14950 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14951 ((this.path == null) ? "" : ("; path=" + this.path)) +
14952 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14953 ((this.secure == true) ? "; secure" : "");
14957 clearCookie : function(name){
14958 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14959 ((this.path == null) ? "" : ("; path=" + this.path)) +
14960 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14961 ((this.secure == true) ? "; secure" : "");
14965 * Ext JS Library 1.1.1
14966 * Copyright(c) 2006-2007, Ext JS, LLC.
14968 * Originally Released Under LGPL - original licence link has changed is not relivant.
14971 * <script type="text/javascript">
14976 * @class Roo.ComponentMgr
14977 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14980 Roo.ComponentMgr = function(){
14981 var all = new Roo.util.MixedCollection();
14985 * Registers a component.
14986 * @param {Roo.Component} c The component
14988 register : function(c){
14993 * Unregisters a component.
14994 * @param {Roo.Component} c The component
14996 unregister : function(c){
15001 * Returns a component by id
15002 * @param {String} id The component id
15004 get : function(id){
15005 return all.get(id);
15009 * Registers a function that will be called when a specified component is added to ComponentMgr
15010 * @param {String} id The component id
15011 * @param {Funtction} fn The callback function
15012 * @param {Object} scope The scope of the callback
15014 onAvailable : function(id, fn, scope){
15015 all.on("add", function(index, o){
15017 fn.call(scope || o, o);
15018 all.un("add", fn, scope);
15025 * Ext JS Library 1.1.1
15026 * Copyright(c) 2006-2007, Ext JS, LLC.
15028 * Originally Released Under LGPL - original licence link has changed is not relivant.
15031 * <script type="text/javascript">
15035 * @class Roo.Component
15036 * @extends Roo.util.Observable
15037 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15038 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15039 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15040 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15041 * All visual components (widgets) that require rendering into a layout should subclass Component.
15043 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15044 * 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
15045 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15047 Roo.Component = function(config){
15048 config = config || {};
15049 if(config.tagName || config.dom || typeof config == "string"){ // element object
15050 config = {el: config, id: config.id || config};
15052 this.initialConfig = config;
15054 Roo.apply(this, config);
15058 * Fires after the component is disabled.
15059 * @param {Roo.Component} this
15064 * Fires after the component is enabled.
15065 * @param {Roo.Component} this
15069 * @event beforeshow
15070 * Fires before the component is shown. Return false to stop the show.
15071 * @param {Roo.Component} this
15076 * Fires after the component is shown.
15077 * @param {Roo.Component} this
15081 * @event beforehide
15082 * Fires before the component is hidden. Return false to stop the hide.
15083 * @param {Roo.Component} this
15088 * Fires after the component is hidden.
15089 * @param {Roo.Component} this
15093 * @event beforerender
15094 * Fires before the component is rendered. Return false to stop the render.
15095 * @param {Roo.Component} this
15097 beforerender : true,
15100 * Fires after the component is rendered.
15101 * @param {Roo.Component} this
15105 * @event beforedestroy
15106 * Fires before the component is destroyed. Return false to stop the destroy.
15107 * @param {Roo.Component} this
15109 beforedestroy : true,
15112 * Fires after the component is destroyed.
15113 * @param {Roo.Component} this
15118 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15120 Roo.ComponentMgr.register(this);
15121 Roo.Component.superclass.constructor.call(this);
15122 this.initComponent();
15123 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15124 this.render(this.renderTo);
15125 delete this.renderTo;
15130 Roo.Component.AUTO_ID = 1000;
15132 Roo.extend(Roo.Component, Roo.util.Observable, {
15134 * @scope Roo.Component.prototype
15136 * true if this component is hidden. Read-only.
15141 * true if this component is disabled. Read-only.
15146 * true if this component has been rendered. Read-only.
15150 /** @cfg {String} disableClass
15151 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15153 disabledClass : "x-item-disabled",
15154 /** @cfg {Boolean} allowDomMove
15155 * Whether the component can move the Dom node when rendering (defaults to true).
15157 allowDomMove : true,
15158 /** @cfg {String} hideMode
15159 * How this component should hidden. Supported values are
15160 * "visibility" (css visibility), "offsets" (negative offset position) and
15161 * "display" (css display) - defaults to "display".
15163 hideMode: 'display',
15166 ctype : "Roo.Component",
15169 * @cfg {String} actionMode
15170 * which property holds the element that used for hide() / show() / disable() / enable()
15176 getActionEl : function(){
15177 return this[this.actionMode];
15180 initComponent : Roo.emptyFn,
15182 * If this is a lazy rendering component, render it to its container element.
15183 * @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.
15185 render : function(container, position){
15186 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15187 if(!container && this.el){
15188 this.el = Roo.get(this.el);
15189 container = this.el.dom.parentNode;
15190 this.allowDomMove = false;
15192 this.container = Roo.get(container);
15193 this.rendered = true;
15194 if(position !== undefined){
15195 if(typeof position == 'number'){
15196 position = this.container.dom.childNodes[position];
15198 position = Roo.getDom(position);
15201 this.onRender(this.container, position || null);
15203 this.el.addClass(this.cls);
15207 this.el.applyStyles(this.style);
15210 this.fireEvent("render", this);
15211 this.afterRender(this.container);
15223 // default function is not really useful
15224 onRender : function(ct, position){
15226 this.el = Roo.get(this.el);
15227 if(this.allowDomMove !== false){
15228 ct.dom.insertBefore(this.el.dom, position);
15234 getAutoCreate : function(){
15235 var cfg = typeof this.autoCreate == "object" ?
15236 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15237 if(this.id && !cfg.id){
15244 afterRender : Roo.emptyFn,
15247 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15248 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15250 destroy : function(){
15251 if(this.fireEvent("beforedestroy", this) !== false){
15252 this.purgeListeners();
15253 this.beforeDestroy();
15255 this.el.removeAllListeners();
15257 if(this.actionMode == "container"){
15258 this.container.remove();
15262 Roo.ComponentMgr.unregister(this);
15263 this.fireEvent("destroy", this);
15268 beforeDestroy : function(){
15273 onDestroy : function(){
15278 * Returns the underlying {@link Roo.Element}.
15279 * @return {Roo.Element} The element
15281 getEl : function(){
15286 * Returns the id of this component.
15289 getId : function(){
15294 * Try to focus this component.
15295 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15296 * @return {Roo.Component} this
15298 focus : function(selectText){
15301 if(selectText === true){
15302 this.el.dom.select();
15317 * Disable this component.
15318 * @return {Roo.Component} this
15320 disable : function(){
15324 this.disabled = true;
15325 this.fireEvent("disable", this);
15330 onDisable : function(){
15331 this.getActionEl().addClass(this.disabledClass);
15332 this.el.dom.disabled = true;
15336 * Enable this component.
15337 * @return {Roo.Component} this
15339 enable : function(){
15343 this.disabled = false;
15344 this.fireEvent("enable", this);
15349 onEnable : function(){
15350 this.getActionEl().removeClass(this.disabledClass);
15351 this.el.dom.disabled = false;
15355 * Convenience function for setting disabled/enabled by boolean.
15356 * @param {Boolean} disabled
15358 setDisabled : function(disabled){
15359 this[disabled ? "disable" : "enable"]();
15363 * Show this component.
15364 * @return {Roo.Component} this
15367 if(this.fireEvent("beforeshow", this) !== false){
15368 this.hidden = false;
15372 this.fireEvent("show", this);
15378 onShow : function(){
15379 var ae = this.getActionEl();
15380 if(this.hideMode == 'visibility'){
15381 ae.dom.style.visibility = "visible";
15382 }else if(this.hideMode == 'offsets'){
15383 ae.removeClass('x-hidden');
15385 ae.dom.style.display = "";
15390 * Hide this component.
15391 * @return {Roo.Component} this
15394 if(this.fireEvent("beforehide", this) !== false){
15395 this.hidden = true;
15399 this.fireEvent("hide", this);
15405 onHide : function(){
15406 var ae = this.getActionEl();
15407 if(this.hideMode == 'visibility'){
15408 ae.dom.style.visibility = "hidden";
15409 }else if(this.hideMode == 'offsets'){
15410 ae.addClass('x-hidden');
15412 ae.dom.style.display = "none";
15417 * Convenience function to hide or show this component by boolean.
15418 * @param {Boolean} visible True to show, false to hide
15419 * @return {Roo.Component} this
15421 setVisible: function(visible){
15431 * Returns true if this component is visible.
15433 isVisible : function(){
15434 return this.getActionEl().isVisible();
15437 cloneConfig : function(overrides){
15438 overrides = overrides || {};
15439 var id = overrides.id || Roo.id();
15440 var cfg = Roo.applyIf(overrides, this.initialConfig);
15441 cfg.id = id; // prevent dup id
15442 return new this.constructor(cfg);
15446 * Ext JS Library 1.1.1
15447 * Copyright(c) 2006-2007, Ext JS, LLC.
15449 * Originally Released Under LGPL - original licence link has changed is not relivant.
15452 * <script type="text/javascript">
15456 * @class Roo.BoxComponent
15457 * @extends Roo.Component
15458 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15459 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15460 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15461 * layout containers.
15463 * @param {Roo.Element/String/Object} config The configuration options.
15465 Roo.BoxComponent = function(config){
15466 Roo.Component.call(this, config);
15470 * Fires after the component is resized.
15471 * @param {Roo.Component} this
15472 * @param {Number} adjWidth The box-adjusted width that was set
15473 * @param {Number} adjHeight The box-adjusted height that was set
15474 * @param {Number} rawWidth The width that was originally specified
15475 * @param {Number} rawHeight The height that was originally specified
15480 * Fires after the component is moved.
15481 * @param {Roo.Component} this
15482 * @param {Number} x The new x position
15483 * @param {Number} y The new y position
15489 Roo.extend(Roo.BoxComponent, Roo.Component, {
15490 // private, set in afterRender to signify that the component has been rendered
15492 // private, used to defer height settings to subclasses
15493 deferHeight: false,
15494 /** @cfg {Number} width
15495 * width (optional) size of component
15497 /** @cfg {Number} height
15498 * height (optional) size of component
15502 * Sets the width and height of the component. This method fires the resize event. This method can accept
15503 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15504 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15505 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15506 * @return {Roo.BoxComponent} this
15508 setSize : function(w, h){
15509 // support for standard size objects
15510 if(typeof w == 'object'){
15515 if(!this.boxReady){
15521 // prevent recalcs when not needed
15522 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15525 this.lastSize = {width: w, height: h};
15527 var adj = this.adjustSize(w, h);
15528 var aw = adj.width, ah = adj.height;
15529 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15530 var rz = this.getResizeEl();
15531 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15532 rz.setSize(aw, ah);
15533 }else if(!this.deferHeight && ah !== undefined){
15535 }else if(aw !== undefined){
15538 this.onResize(aw, ah, w, h);
15539 this.fireEvent('resize', this, aw, ah, w, h);
15545 * Gets the current size of the component's underlying element.
15546 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15548 getSize : function(){
15549 return this.el.getSize();
15553 * Gets the current XY position of the component's underlying element.
15554 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15555 * @return {Array} The XY position of the element (e.g., [100, 200])
15557 getPosition : function(local){
15558 if(local === true){
15559 return [this.el.getLeft(true), this.el.getTop(true)];
15561 return this.xy || this.el.getXY();
15565 * Gets the current box measurements of the component's underlying element.
15566 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15567 * @returns {Object} box An object in the format {x, y, width, height}
15569 getBox : function(local){
15570 var s = this.el.getSize();
15572 s.x = this.el.getLeft(true);
15573 s.y = this.el.getTop(true);
15575 var xy = this.xy || this.el.getXY();
15583 * Sets the current box measurements of the component's underlying element.
15584 * @param {Object} box An object in the format {x, y, width, height}
15585 * @returns {Roo.BoxComponent} this
15587 updateBox : function(box){
15588 this.setSize(box.width, box.height);
15589 this.setPagePosition(box.x, box.y);
15594 getResizeEl : function(){
15595 return this.resizeEl || this.el;
15599 getPositionEl : function(){
15600 return this.positionEl || this.el;
15604 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15605 * This method fires the move event.
15606 * @param {Number} left The new left
15607 * @param {Number} top The new top
15608 * @returns {Roo.BoxComponent} this
15610 setPosition : function(x, y){
15613 if(!this.boxReady){
15616 var adj = this.adjustPosition(x, y);
15617 var ax = adj.x, ay = adj.y;
15619 var el = this.getPositionEl();
15620 if(ax !== undefined || ay !== undefined){
15621 if(ax !== undefined && ay !== undefined){
15622 el.setLeftTop(ax, ay);
15623 }else if(ax !== undefined){
15625 }else if(ay !== undefined){
15628 this.onPosition(ax, ay);
15629 this.fireEvent('move', this, ax, ay);
15635 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15636 * This method fires the move event.
15637 * @param {Number} x The new x position
15638 * @param {Number} y The new y position
15639 * @returns {Roo.BoxComponent} this
15641 setPagePosition : function(x, y){
15644 if(!this.boxReady){
15647 if(x === undefined || y === undefined){ // cannot translate undefined points
15650 var p = this.el.translatePoints(x, y);
15651 this.setPosition(p.left, p.top);
15656 onRender : function(ct, position){
15657 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15659 this.resizeEl = Roo.get(this.resizeEl);
15661 if(this.positionEl){
15662 this.positionEl = Roo.get(this.positionEl);
15667 afterRender : function(){
15668 Roo.BoxComponent.superclass.afterRender.call(this);
15669 this.boxReady = true;
15670 this.setSize(this.width, this.height);
15671 if(this.x || this.y){
15672 this.setPosition(this.x, this.y);
15674 if(this.pageX || this.pageY){
15675 this.setPagePosition(this.pageX, this.pageY);
15680 * Force the component's size to recalculate based on the underlying element's current height and width.
15681 * @returns {Roo.BoxComponent} this
15683 syncSize : function(){
15684 delete this.lastSize;
15685 this.setSize(this.el.getWidth(), this.el.getHeight());
15690 * Called after the component is resized, this method is empty by default but can be implemented by any
15691 * subclass that needs to perform custom logic after a resize occurs.
15692 * @param {Number} adjWidth The box-adjusted width that was set
15693 * @param {Number} adjHeight The box-adjusted height that was set
15694 * @param {Number} rawWidth The width that was originally specified
15695 * @param {Number} rawHeight The height that was originally specified
15697 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15702 * Called after the component is moved, this method is empty by default but can be implemented by any
15703 * subclass that needs to perform custom logic after a move occurs.
15704 * @param {Number} x The new x position
15705 * @param {Number} y The new y position
15707 onPosition : function(x, y){
15712 adjustSize : function(w, h){
15713 if(this.autoWidth){
15716 if(this.autoHeight){
15719 return {width : w, height: h};
15723 adjustPosition : function(x, y){
15724 return {x : x, y: y};
15727 * Original code for Roojs - LGPL
15728 * <script type="text/javascript">
15732 * @class Roo.XComponent
15733 * A delayed Element creator...
15734 * Or a way to group chunks of interface together.
15736 * Mypart.xyx = new Roo.XComponent({
15738 parent : 'Mypart.xyz', // empty == document.element.!!
15742 disabled : function() {}
15744 tree : function() { // return an tree of xtype declared components
15748 xtype : 'NestedLayoutPanel',
15755 * It can be used to build a big heiracy, with parent etc.
15756 * or you can just use this to render a single compoent to a dom element
15757 * MYPART.render(Roo.Element | String(id) | dom_element )
15759 * @extends Roo.util.Observable
15761 * @param cfg {Object} configuration of component
15764 Roo.XComponent = function(cfg) {
15765 Roo.apply(this, cfg);
15769 * Fires when this the componnt is built
15770 * @param {Roo.XComponent} c the component
15775 this.region = this.region || 'center'; // default..
15776 Roo.XComponent.register(this);
15777 this.modules = false;
15778 this.el = false; // where the layout goes..
15782 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15785 * The created element (with Roo.factory())
15786 * @type {Roo.Layout}
15792 * for BC - use el in new code
15793 * @type {Roo.Layout}
15799 * for BC - use el in new code
15800 * @type {Roo.Layout}
15805 * @cfg {Function|boolean} disabled
15806 * If this module is disabled by some rule, return true from the funtion
15811 * @cfg {String} parent
15812 * Name of parent element which it get xtype added to..
15817 * @cfg {String} order
15818 * Used to set the order in which elements are created (usefull for multiple tabs)
15823 * @cfg {String} name
15824 * String to display while loading.
15828 * @cfg {String} region
15829 * Region to render component to (defaults to center)
15834 * @cfg {Array} items
15835 * A single item array - the first element is the root of the tree..
15836 * It's done this way to stay compatible with the Xtype system...
15842 * The method that retuns the tree of parts that make up this compoennt
15849 * render element to dom or tree
15850 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15853 render : function(el)
15857 var hp = this.parent ? 1 : 0;
15859 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15860 // if parent is a '#.....' string, then let's use that..
15861 var ename = this.parent.substr(1)
15862 this.parent = (this.parent == '#bootstrap') ? { el : true} : false; // flags it as a top module...
15863 el = Roo.get(ename);
15864 if (!el && !this.parent) {
15865 Roo.log("Warning - element can not be found :#" + ename );
15871 if (!this.parent) {
15873 el = el ? Roo.get(el) : false;
15875 // it's a top level one..
15877 el : new Roo.BorderLayout(el || document.body, {
15883 tabPosition: 'top',
15884 //resizeTabs: true,
15885 alwaysShowTabs: el && hp? false : true,
15886 hideTabs: el || !hp ? true : false,
15893 if (!this.parent.el) {
15894 // probably an old style ctor, which has been disabled.
15898 // The 'tree' method is '_tree now'
15900 var tree = this._tree ? this._tree() : this.tree();
15901 tree.region = tree.region || this.region;
15903 if (this.parent.el === true) {
15904 // bootstrap... - body..
15905 this.parent.el = Roo.factory(tree);
15908 this.el = this.parent.el.addxtype(tree);
15909 this.fireEvent('built', this);
15911 this.panel = this.el;
15912 this.layout = this.panel.layout;
15913 this.parentLayout = this.parent.layout || false;
15919 Roo.apply(Roo.XComponent, {
15921 * @property hideProgress
15922 * true to disable the building progress bar.. usefull on single page renders.
15925 hideProgress : false,
15927 * @property buildCompleted
15928 * True when the builder has completed building the interface.
15931 buildCompleted : false,
15934 * @property topModule
15935 * the upper most module - uses document.element as it's constructor.
15942 * @property modules
15943 * array of modules to be created by registration system.
15944 * @type {Array} of Roo.XComponent
15949 * @property elmodules
15950 * array of modules to be created by which use #ID
15951 * @type {Array} of Roo.XComponent
15957 * @property build_from_html
15958 * Build elements from html - used by bootstrap HTML stuff
15959 * - this is cleared after build is completed
15960 * @type {boolean} true (default false)
15963 build_from_html : false,
15966 * Register components to be built later.
15968 * This solves the following issues
15969 * - Building is not done on page load, but after an authentication process has occured.
15970 * - Interface elements are registered on page load
15971 * - Parent Interface elements may not be loaded before child, so this handles that..
15978 module : 'Pman.Tab.projectMgr',
15980 parent : 'Pman.layout',
15981 disabled : false, // or use a function..
15984 * * @param {Object} details about module
15986 register : function(obj) {
15988 Roo.XComponent.event.fireEvent('register', obj);
15989 switch(typeof(obj.disabled) ) {
15995 if ( obj.disabled() ) {
16001 if (obj.disabled) {
16007 this.modules.push(obj);
16011 * convert a string to an object..
16012 * eg. 'AAA.BBB' -> finds AAA.BBB
16016 toObject : function(str)
16018 if (!str || typeof(str) == 'object') {
16021 if (str.substring(0,1) == '#') {
16025 var ar = str.split('.');
16030 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16032 throw "Module not found : " + str;
16036 throw "Module not found : " + str;
16038 Roo.each(ar, function(e) {
16039 if (typeof(o[e]) == 'undefined') {
16040 throw "Module not found : " + str;
16051 * move modules into their correct place in the tree..
16054 preBuild : function ()
16057 Roo.each(this.modules , function (obj)
16059 Roo.XComponent.event.fireEvent('beforebuild', obj);
16061 var opar = obj.parent;
16063 obj.parent = this.toObject(opar);
16065 Roo.log("parent:toObject failed: " + e.toString());
16070 Roo.debug && Roo.log("GOT top level module");
16071 Roo.debug && Roo.log(obj);
16072 obj.modules = new Roo.util.MixedCollection(false,
16073 function(o) { return o.order + '' }
16075 this.topModule = obj;
16078 // parent is a string (usually a dom element name..)
16079 if (typeof(obj.parent) == 'string') {
16080 this.elmodules.push(obj);
16083 if (obj.parent.constructor != Roo.XComponent) {
16084 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16086 if (!obj.parent.modules) {
16087 obj.parent.modules = new Roo.util.MixedCollection(false,
16088 function(o) { return o.order + '' }
16091 if (obj.parent.disabled) {
16092 obj.disabled = true;
16094 obj.parent.modules.add(obj);
16099 * make a list of modules to build.
16100 * @return {Array} list of modules.
16103 buildOrder : function()
16106 var cmp = function(a,b) {
16107 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16109 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16110 throw "No top level modules to build";
16113 // make a flat list in order of modules to build.
16114 var mods = this.topModule ? [ this.topModule ] : [];
16117 // elmodules (is a list of DOM based modules )
16118 Roo.each(this.elmodules, function(e) {
16120 if (!this.topModule &&
16121 typeof(e.parent) == 'string' &&
16122 e.parent.substring(0,1) == '#' &&
16123 Roo.get(e.parent.substr(1))
16126 _this.topModule = e;
16132 // add modules to their parents..
16133 var addMod = function(m) {
16134 Roo.debug && Roo.log("build Order: add: " + m.name);
16137 if (m.modules && !m.disabled) {
16138 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16139 m.modules.keySort('ASC', cmp );
16140 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16142 m.modules.each(addMod);
16144 Roo.debug && Roo.log("build Order: no child modules");
16146 // not sure if this is used any more..
16148 m.finalize.name = m.name + " (clean up) ";
16149 mods.push(m.finalize);
16153 if (this.topModule && this.topModule.modules) {
16154 this.topModule.modules.keySort('ASC', cmp );
16155 this.topModule.modules.each(addMod);
16161 * Build the registered modules.
16162 * @param {Object} parent element.
16163 * @param {Function} optional method to call after module has been added.
16167 build : function(opts)
16170 if (typeof(opts) != 'undefined') {
16171 Roo.apply(this,opts);
16175 var mods = this.buildOrder();
16177 //this.allmods = mods;
16178 //Roo.debug && Roo.log(mods);
16180 if (!mods.length) { // should not happen
16181 throw "NO modules!!!";
16185 var msg = "Building Interface...";
16186 // flash it up as modal - so we store the mask!?
16187 if (!this.hideProgress && Roo.MessageBox) {
16188 Roo.MessageBox.show({ title: 'loading' });
16189 Roo.MessageBox.show({
16190 title: "Please wait...",
16199 var total = mods.length;
16202 var progressRun = function() {
16203 if (!mods.length) {
16204 Roo.debug && Roo.log('hide?');
16205 if (!this.hideProgress && Roo.MessageBox) {
16206 Roo.MessageBox.hide();
16208 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16210 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16216 var m = mods.shift();
16219 Roo.debug && Roo.log(m);
16220 // not sure if this is supported any more.. - modules that are are just function
16221 if (typeof(m) == 'function') {
16223 return progressRun.defer(10, _this);
16227 msg = "Building Interface " + (total - mods.length) +
16229 (m.name ? (' - ' + m.name) : '');
16230 Roo.debug && Roo.log(msg);
16231 if (!this.hideProgress && Roo.MessageBox) {
16232 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16236 // is the module disabled?
16237 var disabled = (typeof(m.disabled) == 'function') ?
16238 m.disabled.call(m.module.disabled) : m.disabled;
16242 return progressRun(); // we do not update the display!
16250 // it's 10 on top level, and 1 on others??? why...
16251 return progressRun.defer(10, _this);
16254 progressRun.defer(1, _this);
16268 * wrapper for event.on - aliased later..
16269 * Typically use to register a event handler for register:
16271 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16280 Roo.XComponent.event = new Roo.util.Observable({
16284 * Fires when an Component is registered,
16285 * set the disable property on the Component to stop registration.
16286 * @param {Roo.XComponent} c the component being registerd.
16291 * @event beforebuild
16292 * Fires before each Component is built
16293 * can be used to apply permissions.
16294 * @param {Roo.XComponent} c the component being registerd.
16297 'beforebuild' : true,
16299 * @event buildcomplete
16300 * Fires on the top level element when all elements have been built
16301 * @param {Roo.XComponent} the top level component.
16303 'buildcomplete' : true
16308 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16311 * Ext JS Library 1.1.1
16312 * Copyright(c) 2006-2007, Ext JS, LLC.
16314 * Originally Released Under LGPL - original licence link has changed is not relivant.
16317 * <script type="text/javascript">
16323 * These classes are derivatives of the similarly named classes in the YUI Library.
16324 * The original license:
16325 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16326 * Code licensed under the BSD License:
16327 * http://developer.yahoo.net/yui/license.txt
16332 var Event=Roo.EventManager;
16333 var Dom=Roo.lib.Dom;
16336 * @class Roo.dd.DragDrop
16337 * @extends Roo.util.Observable
16338 * Defines the interface and base operation of items that that can be
16339 * dragged or can be drop targets. It was designed to be extended, overriding
16340 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16341 * Up to three html elements can be associated with a DragDrop instance:
16343 * <li>linked element: the element that is passed into the constructor.
16344 * This is the element which defines the boundaries for interaction with
16345 * other DragDrop objects.</li>
16346 * <li>handle element(s): The drag operation only occurs if the element that
16347 * was clicked matches a handle element. By default this is the linked
16348 * element, but there are times that you will want only a portion of the
16349 * linked element to initiate the drag operation, and the setHandleElId()
16350 * method provides a way to define this.</li>
16351 * <li>drag element: this represents the element that would be moved along
16352 * with the cursor during a drag operation. By default, this is the linked
16353 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16354 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16357 * This class should not be instantiated until the onload event to ensure that
16358 * the associated elements are available.
16359 * The following would define a DragDrop obj that would interact with any
16360 * other DragDrop obj in the "group1" group:
16362 * dd = new Roo.dd.DragDrop("div1", "group1");
16364 * Since none of the event handlers have been implemented, nothing would
16365 * actually happen if you were to run the code above. Normally you would
16366 * override this class or one of the default implementations, but you can
16367 * also override the methods you want on an instance of the class...
16369 * dd.onDragDrop = function(e, id) {
16370 * alert("dd was dropped on " + id);
16374 * @param {String} id of the element that is linked to this instance
16375 * @param {String} sGroup the group of related DragDrop objects
16376 * @param {object} config an object containing configurable attributes
16377 * Valid properties for DragDrop:
16378 * padding, isTarget, maintainOffset, primaryButtonOnly
16380 Roo.dd.DragDrop = function(id, sGroup, config) {
16382 this.init(id, sGroup, config);
16387 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16390 * The id of the element associated with this object. This is what we
16391 * refer to as the "linked element" because the size and position of
16392 * this element is used to determine when the drag and drop objects have
16400 * Configuration attributes passed into the constructor
16407 * The id of the element that will be dragged. By default this is same
16408 * as the linked element , but could be changed to another element. Ex:
16410 * @property dragElId
16417 * the id of the element that initiates the drag operation. By default
16418 * this is the linked element, but could be changed to be a child of this
16419 * element. This lets us do things like only starting the drag when the
16420 * header element within the linked html element is clicked.
16421 * @property handleElId
16428 * An associative array of HTML tags that will be ignored if clicked.
16429 * @property invalidHandleTypes
16430 * @type {string: string}
16432 invalidHandleTypes: null,
16435 * An associative array of ids for elements that will be ignored if clicked
16436 * @property invalidHandleIds
16437 * @type {string: string}
16439 invalidHandleIds: null,
16442 * An indexted array of css class names for elements that will be ignored
16444 * @property invalidHandleClasses
16447 invalidHandleClasses: null,
16450 * The linked element's absolute X position at the time the drag was
16452 * @property startPageX
16459 * The linked element's absolute X position at the time the drag was
16461 * @property startPageY
16468 * The group defines a logical collection of DragDrop objects that are
16469 * related. Instances only get events when interacting with other
16470 * DragDrop object in the same group. This lets us define multiple
16471 * groups using a single DragDrop subclass if we want.
16473 * @type {string: string}
16478 * Individual drag/drop instances can be locked. This will prevent
16479 * onmousedown start drag.
16487 * Lock this instance
16490 lock: function() { this.locked = true; },
16493 * Unlock this instace
16496 unlock: function() { this.locked = false; },
16499 * By default, all insances can be a drop target. This can be disabled by
16500 * setting isTarget to false.
16507 * The padding configured for this drag and drop object for calculating
16508 * the drop zone intersection with this object.
16515 * Cached reference to the linked element
16516 * @property _domRef
16522 * Internal typeof flag
16523 * @property __ygDragDrop
16526 __ygDragDrop: true,
16529 * Set to true when horizontal contraints are applied
16530 * @property constrainX
16537 * Set to true when vertical contraints are applied
16538 * @property constrainY
16545 * The left constraint
16553 * The right constraint
16561 * The up constraint
16570 * The down constraint
16578 * Maintain offsets when we resetconstraints. Set to true when you want
16579 * the position of the element relative to its parent to stay the same
16580 * when the page changes
16582 * @property maintainOffset
16585 maintainOffset: false,
16588 * Array of pixel locations the element will snap to if we specified a
16589 * horizontal graduation/interval. This array is generated automatically
16590 * when you define a tick interval.
16597 * Array of pixel locations the element will snap to if we specified a
16598 * vertical graduation/interval. This array is generated automatically
16599 * when you define a tick interval.
16606 * By default the drag and drop instance will only respond to the primary
16607 * button click (left button for a right-handed mouse). Set to true to
16608 * allow drag and drop to start with any mouse click that is propogated
16610 * @property primaryButtonOnly
16613 primaryButtonOnly: true,
16616 * The availabe property is false until the linked dom element is accessible.
16617 * @property available
16623 * By default, drags can only be initiated if the mousedown occurs in the
16624 * region the linked element is. This is done in part to work around a
16625 * bug in some browsers that mis-report the mousedown if the previous
16626 * mouseup happened outside of the window. This property is set to true
16627 * if outer handles are defined.
16629 * @property hasOuterHandles
16633 hasOuterHandles: false,
16636 * Code that executes immediately before the startDrag event
16637 * @method b4StartDrag
16640 b4StartDrag: function(x, y) { },
16643 * Abstract method called after a drag/drop object is clicked
16644 * and the drag or mousedown time thresholds have beeen met.
16645 * @method startDrag
16646 * @param {int} X click location
16647 * @param {int} Y click location
16649 startDrag: function(x, y) { /* override this */ },
16652 * Code that executes immediately before the onDrag event
16656 b4Drag: function(e) { },
16659 * Abstract method called during the onMouseMove event while dragging an
16662 * @param {Event} e the mousemove event
16664 onDrag: function(e) { /* override this */ },
16667 * Abstract method called when this element fist begins hovering over
16668 * another DragDrop obj
16669 * @method onDragEnter
16670 * @param {Event} e the mousemove event
16671 * @param {String|DragDrop[]} id In POINT mode, the element
16672 * id this is hovering over. In INTERSECT mode, an array of one or more
16673 * dragdrop items being hovered over.
16675 onDragEnter: function(e, id) { /* override this */ },
16678 * Code that executes immediately before the onDragOver event
16679 * @method b4DragOver
16682 b4DragOver: function(e) { },
16685 * Abstract method called when this element is hovering over another
16687 * @method onDragOver
16688 * @param {Event} e the mousemove event
16689 * @param {String|DragDrop[]} id In POINT mode, the element
16690 * id this is hovering over. In INTERSECT mode, an array of dd items
16691 * being hovered over.
16693 onDragOver: function(e, id) { /* override this */ },
16696 * Code that executes immediately before the onDragOut event
16697 * @method b4DragOut
16700 b4DragOut: function(e) { },
16703 * Abstract method called when we are no longer hovering over an element
16704 * @method onDragOut
16705 * @param {Event} e the mousemove event
16706 * @param {String|DragDrop[]} id In POINT mode, the element
16707 * id this was hovering over. In INTERSECT mode, an array of dd items
16708 * that the mouse is no longer over.
16710 onDragOut: function(e, id) { /* override this */ },
16713 * Code that executes immediately before the onDragDrop event
16714 * @method b4DragDrop
16717 b4DragDrop: function(e) { },
16720 * Abstract method called when this item is dropped on another DragDrop
16722 * @method onDragDrop
16723 * @param {Event} e the mouseup event
16724 * @param {String|DragDrop[]} id In POINT mode, the element
16725 * id this was dropped on. In INTERSECT mode, an array of dd items this
16728 onDragDrop: function(e, id) { /* override this */ },
16731 * Abstract method called when this item is dropped on an area with no
16733 * @method onInvalidDrop
16734 * @param {Event} e the mouseup event
16736 onInvalidDrop: function(e) { /* override this */ },
16739 * Code that executes immediately before the endDrag event
16740 * @method b4EndDrag
16743 b4EndDrag: function(e) { },
16746 * Fired when we are done dragging the object
16748 * @param {Event} e the mouseup event
16750 endDrag: function(e) { /* override this */ },
16753 * Code executed immediately before the onMouseDown event
16754 * @method b4MouseDown
16755 * @param {Event} e the mousedown event
16758 b4MouseDown: function(e) { },
16761 * Event handler that fires when a drag/drop obj gets a mousedown
16762 * @method onMouseDown
16763 * @param {Event} e the mousedown event
16765 onMouseDown: function(e) { /* override this */ },
16768 * Event handler that fires when a drag/drop obj gets a mouseup
16769 * @method onMouseUp
16770 * @param {Event} e the mouseup event
16772 onMouseUp: function(e) { /* override this */ },
16775 * Override the onAvailable method to do what is needed after the initial
16776 * position was determined.
16777 * @method onAvailable
16779 onAvailable: function () {
16783 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16786 defaultPadding : {left:0, right:0, top:0, bottom:0},
16789 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16793 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16794 { dragElId: "existingProxyDiv" });
16795 dd.startDrag = function(){
16796 this.constrainTo("parent-id");
16799 * Or you can initalize it using the {@link Roo.Element} object:
16801 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16802 startDrag : function(){
16803 this.constrainTo("parent-id");
16807 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16808 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16809 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16810 * an object containing the sides to pad. For example: {right:10, bottom:10}
16811 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16813 constrainTo : function(constrainTo, pad, inContent){
16814 if(typeof pad == "number"){
16815 pad = {left: pad, right:pad, top:pad, bottom:pad};
16817 pad = pad || this.defaultPadding;
16818 var b = Roo.get(this.getEl()).getBox();
16819 var ce = Roo.get(constrainTo);
16820 var s = ce.getScroll();
16821 var c, cd = ce.dom;
16822 if(cd == document.body){
16823 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16826 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16830 var topSpace = b.y - c.y;
16831 var leftSpace = b.x - c.x;
16833 this.resetConstraints();
16834 this.setXConstraint(leftSpace - (pad.left||0), // left
16835 c.width - leftSpace - b.width - (pad.right||0) //right
16837 this.setYConstraint(topSpace - (pad.top||0), //top
16838 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16843 * Returns a reference to the linked element
16845 * @return {HTMLElement} the html element
16847 getEl: function() {
16848 if (!this._domRef) {
16849 this._domRef = Roo.getDom(this.id);
16852 return this._domRef;
16856 * Returns a reference to the actual element to drag. By default this is
16857 * the same as the html element, but it can be assigned to another
16858 * element. An example of this can be found in Roo.dd.DDProxy
16859 * @method getDragEl
16860 * @return {HTMLElement} the html element
16862 getDragEl: function() {
16863 return Roo.getDom(this.dragElId);
16867 * Sets up the DragDrop object. Must be called in the constructor of any
16868 * Roo.dd.DragDrop subclass
16870 * @param id the id of the linked element
16871 * @param {String} sGroup the group of related items
16872 * @param {object} config configuration attributes
16874 init: function(id, sGroup, config) {
16875 this.initTarget(id, sGroup, config);
16876 if (!Roo.isTouch) {
16877 Event.on(this.id, "mousedown", this.handleMouseDown, this);
16879 Event.on(this.id, "touchstart", this.handleMouseDown, this);
16880 // Event.on(this.id, "selectstart", Event.preventDefault);
16884 * Initializes Targeting functionality only... the object does not
16885 * get a mousedown handler.
16886 * @method initTarget
16887 * @param id the id of the linked element
16888 * @param {String} sGroup the group of related items
16889 * @param {object} config configuration attributes
16891 initTarget: function(id, sGroup, config) {
16893 // configuration attributes
16894 this.config = config || {};
16896 // create a local reference to the drag and drop manager
16897 this.DDM = Roo.dd.DDM;
16898 // initialize the groups array
16901 // assume that we have an element reference instead of an id if the
16902 // parameter is not a string
16903 if (typeof id !== "string") {
16910 // add to an interaction group
16911 this.addToGroup((sGroup) ? sGroup : "default");
16913 // We don't want to register this as the handle with the manager
16914 // so we just set the id rather than calling the setter.
16915 this.handleElId = id;
16917 // the linked element is the element that gets dragged by default
16918 this.setDragElId(id);
16920 // by default, clicked anchors will not start drag operations.
16921 this.invalidHandleTypes = { A: "A" };
16922 this.invalidHandleIds = {};
16923 this.invalidHandleClasses = [];
16925 this.applyConfig();
16927 this.handleOnAvailable();
16931 * Applies the configuration parameters that were passed into the constructor.
16932 * This is supposed to happen at each level through the inheritance chain. So
16933 * a DDProxy implentation will execute apply config on DDProxy, DD, and
16934 * DragDrop in order to get all of the parameters that are available in
16936 * @method applyConfig
16938 applyConfig: function() {
16940 // configurable properties:
16941 // padding, isTarget, maintainOffset, primaryButtonOnly
16942 this.padding = this.config.padding || [0, 0, 0, 0];
16943 this.isTarget = (this.config.isTarget !== false);
16944 this.maintainOffset = (this.config.maintainOffset);
16945 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
16950 * Executed when the linked element is available
16951 * @method handleOnAvailable
16954 handleOnAvailable: function() {
16955 this.available = true;
16956 this.resetConstraints();
16957 this.onAvailable();
16961 * Configures the padding for the target zone in px. Effectively expands
16962 * (or reduces) the virtual object size for targeting calculations.
16963 * Supports css-style shorthand; if only one parameter is passed, all sides
16964 * will have that padding, and if only two are passed, the top and bottom
16965 * will have the first param, the left and right the second.
16966 * @method setPadding
16967 * @param {int} iTop Top pad
16968 * @param {int} iRight Right pad
16969 * @param {int} iBot Bot pad
16970 * @param {int} iLeft Left pad
16972 setPadding: function(iTop, iRight, iBot, iLeft) {
16973 // this.padding = [iLeft, iRight, iTop, iBot];
16974 if (!iRight && 0 !== iRight) {
16975 this.padding = [iTop, iTop, iTop, iTop];
16976 } else if (!iBot && 0 !== iBot) {
16977 this.padding = [iTop, iRight, iTop, iRight];
16979 this.padding = [iTop, iRight, iBot, iLeft];
16984 * Stores the initial placement of the linked element.
16985 * @method setInitialPosition
16986 * @param {int} diffX the X offset, default 0
16987 * @param {int} diffY the Y offset, default 0
16989 setInitPosition: function(diffX, diffY) {
16990 var el = this.getEl();
16992 if (!this.DDM.verifyEl(el)) {
16996 var dx = diffX || 0;
16997 var dy = diffY || 0;
16999 var p = Dom.getXY( el );
17001 this.initPageX = p[0] - dx;
17002 this.initPageY = p[1] - dy;
17004 this.lastPageX = p[0];
17005 this.lastPageY = p[1];
17008 this.setStartPosition(p);
17012 * Sets the start position of the element. This is set when the obj
17013 * is initialized, the reset when a drag is started.
17014 * @method setStartPosition
17015 * @param pos current position (from previous lookup)
17018 setStartPosition: function(pos) {
17019 var p = pos || Dom.getXY( this.getEl() );
17020 this.deltaSetXY = null;
17022 this.startPageX = p[0];
17023 this.startPageY = p[1];
17027 * Add this instance to a group of related drag/drop objects. All
17028 * instances belong to at least one group, and can belong to as many
17029 * groups as needed.
17030 * @method addToGroup
17031 * @param sGroup {string} the name of the group
17033 addToGroup: function(sGroup) {
17034 this.groups[sGroup] = true;
17035 this.DDM.regDragDrop(this, sGroup);
17039 * Remove's this instance from the supplied interaction group
17040 * @method removeFromGroup
17041 * @param {string} sGroup The group to drop
17043 removeFromGroup: function(sGroup) {
17044 if (this.groups[sGroup]) {
17045 delete this.groups[sGroup];
17048 this.DDM.removeDDFromGroup(this, sGroup);
17052 * Allows you to specify that an element other than the linked element
17053 * will be moved with the cursor during a drag
17054 * @method setDragElId
17055 * @param id {string} the id of the element that will be used to initiate the drag
17057 setDragElId: function(id) {
17058 this.dragElId = id;
17062 * Allows you to specify a child of the linked element that should be
17063 * used to initiate the drag operation. An example of this would be if
17064 * you have a content div with text and links. Clicking anywhere in the
17065 * content area would normally start the drag operation. Use this method
17066 * to specify that an element inside of the content div is the element
17067 * that starts the drag operation.
17068 * @method setHandleElId
17069 * @param id {string} the id of the element that will be used to
17070 * initiate the drag.
17072 setHandleElId: function(id) {
17073 if (typeof id !== "string") {
17076 this.handleElId = id;
17077 this.DDM.regHandle(this.id, id);
17081 * Allows you to set an element outside of the linked element as a drag
17083 * @method setOuterHandleElId
17084 * @param id the id of the element that will be used to initiate the drag
17086 setOuterHandleElId: function(id) {
17087 if (typeof id !== "string") {
17090 Event.on(id, "mousedown",
17091 this.handleMouseDown, this);
17092 this.setHandleElId(id);
17094 this.hasOuterHandles = true;
17098 * Remove all drag and drop hooks for this element
17101 unreg: function() {
17102 Event.un(this.id, "mousedown",
17103 this.handleMouseDown);
17104 Event.un(this.id, "touchstart",
17105 this.handleMouseDown);
17106 this._domRef = null;
17107 this.DDM._remove(this);
17110 destroy : function(){
17115 * Returns true if this instance is locked, or the drag drop mgr is locked
17116 * (meaning that all drag/drop is disabled on the page.)
17118 * @return {boolean} true if this obj or all drag/drop is locked, else
17121 isLocked: function() {
17122 return (this.DDM.isLocked() || this.locked);
17126 * Fired when this object is clicked
17127 * @method handleMouseDown
17129 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17132 handleMouseDown: function(e, oDD){
17134 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17135 //Roo.log('not touch/ button !=0');
17138 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17139 return; // double touch..
17143 if (this.isLocked()) {
17144 //Roo.log('locked');
17148 this.DDM.refreshCache(this.groups);
17149 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17150 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17151 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17152 //Roo.log('no outer handes or not over target');
17155 // Roo.log('check validator');
17156 if (this.clickValidator(e)) {
17157 // Roo.log('validate success');
17158 // set the initial element position
17159 this.setStartPosition();
17162 this.b4MouseDown(e);
17163 this.onMouseDown(e);
17165 this.DDM.handleMouseDown(e, this);
17167 this.DDM.stopEvent(e);
17175 clickValidator: function(e) {
17176 var target = e.getTarget();
17177 return ( this.isValidHandleChild(target) &&
17178 (this.id == this.handleElId ||
17179 this.DDM.handleWasClicked(target, this.id)) );
17183 * Allows you to specify a tag name that should not start a drag operation
17184 * when clicked. This is designed to facilitate embedding links within a
17185 * drag handle that do something other than start the drag.
17186 * @method addInvalidHandleType
17187 * @param {string} tagName the type of element to exclude
17189 addInvalidHandleType: function(tagName) {
17190 var type = tagName.toUpperCase();
17191 this.invalidHandleTypes[type] = type;
17195 * Lets you to specify an element id for a child of a drag handle
17196 * that should not initiate a drag
17197 * @method addInvalidHandleId
17198 * @param {string} id the element id of the element you wish to ignore
17200 addInvalidHandleId: function(id) {
17201 if (typeof id !== "string") {
17204 this.invalidHandleIds[id] = id;
17208 * Lets you specify a css class of elements that will not initiate a drag
17209 * @method addInvalidHandleClass
17210 * @param {string} cssClass the class of the elements you wish to ignore
17212 addInvalidHandleClass: function(cssClass) {
17213 this.invalidHandleClasses.push(cssClass);
17217 * Unsets an excluded tag name set by addInvalidHandleType
17218 * @method removeInvalidHandleType
17219 * @param {string} tagName the type of element to unexclude
17221 removeInvalidHandleType: function(tagName) {
17222 var type = tagName.toUpperCase();
17223 // this.invalidHandleTypes[type] = null;
17224 delete this.invalidHandleTypes[type];
17228 * Unsets an invalid handle id
17229 * @method removeInvalidHandleId
17230 * @param {string} id the id of the element to re-enable
17232 removeInvalidHandleId: function(id) {
17233 if (typeof id !== "string") {
17236 delete this.invalidHandleIds[id];
17240 * Unsets an invalid css class
17241 * @method removeInvalidHandleClass
17242 * @param {string} cssClass the class of the element(s) you wish to
17245 removeInvalidHandleClass: function(cssClass) {
17246 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17247 if (this.invalidHandleClasses[i] == cssClass) {
17248 delete this.invalidHandleClasses[i];
17254 * Checks the tag exclusion list to see if this click should be ignored
17255 * @method isValidHandleChild
17256 * @param {HTMLElement} node the HTMLElement to evaluate
17257 * @return {boolean} true if this is a valid tag type, false if not
17259 isValidHandleChild: function(node) {
17262 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17265 nodeName = node.nodeName.toUpperCase();
17267 nodeName = node.nodeName;
17269 valid = valid && !this.invalidHandleTypes[nodeName];
17270 valid = valid && !this.invalidHandleIds[node.id];
17272 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17273 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17282 * Create the array of horizontal tick marks if an interval was specified
17283 * in setXConstraint().
17284 * @method setXTicks
17287 setXTicks: function(iStartX, iTickSize) {
17289 this.xTickSize = iTickSize;
17293 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17295 this.xTicks[this.xTicks.length] = i;
17300 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17302 this.xTicks[this.xTicks.length] = i;
17307 this.xTicks.sort(this.DDM.numericSort) ;
17311 * Create the array of vertical tick marks if an interval was specified in
17312 * setYConstraint().
17313 * @method setYTicks
17316 setYTicks: function(iStartY, iTickSize) {
17318 this.yTickSize = iTickSize;
17322 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17324 this.yTicks[this.yTicks.length] = i;
17329 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17331 this.yTicks[this.yTicks.length] = i;
17336 this.yTicks.sort(this.DDM.numericSort) ;
17340 * By default, the element can be dragged any place on the screen. Use
17341 * this method to limit the horizontal travel of the element. Pass in
17342 * 0,0 for the parameters if you want to lock the drag to the y axis.
17343 * @method setXConstraint
17344 * @param {int} iLeft the number of pixels the element can move to the left
17345 * @param {int} iRight the number of pixels the element can move to the
17347 * @param {int} iTickSize optional parameter for specifying that the
17349 * should move iTickSize pixels at a time.
17351 setXConstraint: function(iLeft, iRight, iTickSize) {
17352 this.leftConstraint = iLeft;
17353 this.rightConstraint = iRight;
17355 this.minX = this.initPageX - iLeft;
17356 this.maxX = this.initPageX + iRight;
17357 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17359 this.constrainX = true;
17363 * Clears any constraints applied to this instance. Also clears ticks
17364 * since they can't exist independent of a constraint at this time.
17365 * @method clearConstraints
17367 clearConstraints: function() {
17368 this.constrainX = false;
17369 this.constrainY = false;
17374 * Clears any tick interval defined for this instance
17375 * @method clearTicks
17377 clearTicks: function() {
17378 this.xTicks = null;
17379 this.yTicks = null;
17380 this.xTickSize = 0;
17381 this.yTickSize = 0;
17385 * By default, the element can be dragged any place on the screen. Set
17386 * this to limit the vertical travel of the element. Pass in 0,0 for the
17387 * parameters if you want to lock the drag to the x axis.
17388 * @method setYConstraint
17389 * @param {int} iUp the number of pixels the element can move up
17390 * @param {int} iDown the number of pixels the element can move down
17391 * @param {int} iTickSize optional parameter for specifying that the
17392 * element should move iTickSize pixels at a time.
17394 setYConstraint: function(iUp, iDown, iTickSize) {
17395 this.topConstraint = iUp;
17396 this.bottomConstraint = iDown;
17398 this.minY = this.initPageY - iUp;
17399 this.maxY = this.initPageY + iDown;
17400 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17402 this.constrainY = true;
17407 * resetConstraints must be called if you manually reposition a dd element.
17408 * @method resetConstraints
17409 * @param {boolean} maintainOffset
17411 resetConstraints: function() {
17414 // Maintain offsets if necessary
17415 if (this.initPageX || this.initPageX === 0) {
17416 // figure out how much this thing has moved
17417 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17418 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17420 this.setInitPosition(dx, dy);
17422 // This is the first time we have detected the element's position
17424 this.setInitPosition();
17427 if (this.constrainX) {
17428 this.setXConstraint( this.leftConstraint,
17429 this.rightConstraint,
17433 if (this.constrainY) {
17434 this.setYConstraint( this.topConstraint,
17435 this.bottomConstraint,
17441 * Normally the drag element is moved pixel by pixel, but we can specify
17442 * that it move a number of pixels at a time. This method resolves the
17443 * location when we have it set up like this.
17445 * @param {int} val where we want to place the object
17446 * @param {int[]} tickArray sorted array of valid points
17447 * @return {int} the closest tick
17450 getTick: function(val, tickArray) {
17453 // If tick interval is not defined, it is effectively 1 pixel,
17454 // so we return the value passed to us.
17456 } else if (tickArray[0] >= val) {
17457 // The value is lower than the first tick, so we return the first
17459 return tickArray[0];
17461 for (var i=0, len=tickArray.length; i<len; ++i) {
17463 if (tickArray[next] && tickArray[next] >= val) {
17464 var diff1 = val - tickArray[i];
17465 var diff2 = tickArray[next] - val;
17466 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17470 // The value is larger than the last tick, so we return the last
17472 return tickArray[tickArray.length - 1];
17479 * @return {string} string representation of the dd obj
17481 toString: function() {
17482 return ("DragDrop " + this.id);
17490 * Ext JS Library 1.1.1
17491 * Copyright(c) 2006-2007, Ext JS, LLC.
17493 * Originally Released Under LGPL - original licence link has changed is not relivant.
17496 * <script type="text/javascript">
17501 * The drag and drop utility provides a framework for building drag and drop
17502 * applications. In addition to enabling drag and drop for specific elements,
17503 * the drag and drop elements are tracked by the manager class, and the
17504 * interactions between the various elements are tracked during the drag and
17505 * the implementing code is notified about these important moments.
17508 // Only load the library once. Rewriting the manager class would orphan
17509 // existing drag and drop instances.
17510 if (!Roo.dd.DragDropMgr) {
17513 * @class Roo.dd.DragDropMgr
17514 * DragDropMgr is a singleton that tracks the element interaction for
17515 * all DragDrop items in the window. Generally, you will not call
17516 * this class directly, but it does have helper methods that could
17517 * be useful in your DragDrop implementations.
17520 Roo.dd.DragDropMgr = function() {
17522 var Event = Roo.EventManager;
17527 * Two dimensional Array of registered DragDrop objects. The first
17528 * dimension is the DragDrop item group, the second the DragDrop
17531 * @type {string: string}
17538 * Array of element ids defined as drag handles. Used to determine
17539 * if the element that generated the mousedown event is actually the
17540 * handle and not the html element itself.
17541 * @property handleIds
17542 * @type {string: string}
17549 * the DragDrop object that is currently being dragged
17550 * @property dragCurrent
17558 * the DragDrop object(s) that are being hovered over
17559 * @property dragOvers
17567 * the X distance between the cursor and the object being dragged
17576 * the Y distance between the cursor and the object being dragged
17585 * Flag to determine if we should prevent the default behavior of the
17586 * events we define. By default this is true, but this can be set to
17587 * false if you need the default behavior (not recommended)
17588 * @property preventDefault
17592 preventDefault: true,
17595 * Flag to determine if we should stop the propagation of the events
17596 * we generate. This is true by default but you may want to set it to
17597 * false if the html element contains other features that require the
17599 * @property stopPropagation
17603 stopPropagation: true,
17606 * Internal flag that is set to true when drag and drop has been
17608 * @property initialized
17615 * All drag and drop can be disabled.
17623 * Called the first time an element is registered.
17629 this.initialized = true;
17633 * In point mode, drag and drop interaction is defined by the
17634 * location of the cursor during the drag/drop
17642 * In intersect mode, drag and drop interactio nis defined by the
17643 * overlap of two or more drag and drop objects.
17644 * @property INTERSECT
17651 * The current drag and drop mode. Default: POINT
17659 * Runs method on all drag and drop objects
17660 * @method _execOnAll
17664 _execOnAll: function(sMethod, args) {
17665 for (var i in this.ids) {
17666 for (var j in this.ids[i]) {
17667 var oDD = this.ids[i][j];
17668 if (! this.isTypeOfDD(oDD)) {
17671 oDD[sMethod].apply(oDD, args);
17677 * Drag and drop initialization. Sets up the global event handlers
17682 _onLoad: function() {
17686 if (!Roo.isTouch) {
17687 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17688 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17690 Event.on(document, "touchend", this.handleMouseUp, this, true);
17691 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17693 Event.on(window, "unload", this._onUnload, this, true);
17694 Event.on(window, "resize", this._onResize, this, true);
17695 // Event.on(window, "mouseout", this._test);
17700 * Reset constraints on all drag and drop objs
17701 * @method _onResize
17705 _onResize: function(e) {
17706 this._execOnAll("resetConstraints", []);
17710 * Lock all drag and drop functionality
17714 lock: function() { this.locked = true; },
17717 * Unlock all drag and drop functionality
17721 unlock: function() { this.locked = false; },
17724 * Is drag and drop locked?
17726 * @return {boolean} True if drag and drop is locked, false otherwise.
17729 isLocked: function() { return this.locked; },
17732 * Location cache that is set for all drag drop objects when a drag is
17733 * initiated, cleared when the drag is finished.
17734 * @property locationCache
17741 * Set useCache to false if you want to force object the lookup of each
17742 * drag and drop linked element constantly during a drag.
17743 * @property useCache
17750 * The number of pixels that the mouse needs to move after the
17751 * mousedown before the drag is initiated. Default=3;
17752 * @property clickPixelThresh
17756 clickPixelThresh: 3,
17759 * The number of milliseconds after the mousedown event to initiate the
17760 * drag if we don't get a mouseup event. Default=1000
17761 * @property clickTimeThresh
17765 clickTimeThresh: 350,
17768 * Flag that indicates that either the drag pixel threshold or the
17769 * mousdown time threshold has been met
17770 * @property dragThreshMet
17775 dragThreshMet: false,
17778 * Timeout used for the click time threshold
17779 * @property clickTimeout
17784 clickTimeout: null,
17787 * The X position of the mousedown event stored for later use when a
17788 * drag threshold is met.
17797 * The Y position of the mousedown event stored for later use when a
17798 * drag threshold is met.
17807 * Each DragDrop instance must be registered with the DragDropMgr.
17808 * This is executed in DragDrop.init()
17809 * @method regDragDrop
17810 * @param {DragDrop} oDD the DragDrop object to register
17811 * @param {String} sGroup the name of the group this element belongs to
17814 regDragDrop: function(oDD, sGroup) {
17815 if (!this.initialized) { this.init(); }
17817 if (!this.ids[sGroup]) {
17818 this.ids[sGroup] = {};
17820 this.ids[sGroup][oDD.id] = oDD;
17824 * Removes the supplied dd instance from the supplied group. Executed
17825 * by DragDrop.removeFromGroup, so don't call this function directly.
17826 * @method removeDDFromGroup
17830 removeDDFromGroup: function(oDD, sGroup) {
17831 if (!this.ids[sGroup]) {
17832 this.ids[sGroup] = {};
17835 var obj = this.ids[sGroup];
17836 if (obj && obj[oDD.id]) {
17837 delete obj[oDD.id];
17842 * Unregisters a drag and drop item. This is executed in
17843 * DragDrop.unreg, use that method instead of calling this directly.
17848 _remove: function(oDD) {
17849 for (var g in oDD.groups) {
17850 if (g && this.ids[g][oDD.id]) {
17851 delete this.ids[g][oDD.id];
17854 delete this.handleIds[oDD.id];
17858 * Each DragDrop handle element must be registered. This is done
17859 * automatically when executing DragDrop.setHandleElId()
17860 * @method regHandle
17861 * @param {String} sDDId the DragDrop id this element is a handle for
17862 * @param {String} sHandleId the id of the element that is the drag
17866 regHandle: function(sDDId, sHandleId) {
17867 if (!this.handleIds[sDDId]) {
17868 this.handleIds[sDDId] = {};
17870 this.handleIds[sDDId][sHandleId] = sHandleId;
17874 * Utility function to determine if a given element has been
17875 * registered as a drag drop item.
17876 * @method isDragDrop
17877 * @param {String} id the element id to check
17878 * @return {boolean} true if this element is a DragDrop item,
17882 isDragDrop: function(id) {
17883 return ( this.getDDById(id) ) ? true : false;
17887 * Returns the drag and drop instances that are in all groups the
17888 * passed in instance belongs to.
17889 * @method getRelated
17890 * @param {DragDrop} p_oDD the obj to get related data for
17891 * @param {boolean} bTargetsOnly if true, only return targetable objs
17892 * @return {DragDrop[]} the related instances
17895 getRelated: function(p_oDD, bTargetsOnly) {
17897 for (var i in p_oDD.groups) {
17898 for (j in this.ids[i]) {
17899 var dd = this.ids[i][j];
17900 if (! this.isTypeOfDD(dd)) {
17903 if (!bTargetsOnly || dd.isTarget) {
17904 oDDs[oDDs.length] = dd;
17913 * Returns true if the specified dd target is a legal target for
17914 * the specifice drag obj
17915 * @method isLegalTarget
17916 * @param {DragDrop} the drag obj
17917 * @param {DragDrop} the target
17918 * @return {boolean} true if the target is a legal target for the
17922 isLegalTarget: function (oDD, oTargetDD) {
17923 var targets = this.getRelated(oDD, true);
17924 for (var i=0, len=targets.length;i<len;++i) {
17925 if (targets[i].id == oTargetDD.id) {
17934 * My goal is to be able to transparently determine if an object is
17935 * typeof DragDrop, and the exact subclass of DragDrop. typeof
17936 * returns "object", oDD.constructor.toString() always returns
17937 * "DragDrop" and not the name of the subclass. So for now it just
17938 * evaluates a well-known variable in DragDrop.
17939 * @method isTypeOfDD
17940 * @param {Object} the object to evaluate
17941 * @return {boolean} true if typeof oDD = DragDrop
17944 isTypeOfDD: function (oDD) {
17945 return (oDD && oDD.__ygDragDrop);
17949 * Utility function to determine if a given element has been
17950 * registered as a drag drop handle for the given Drag Drop object.
17952 * @param {String} id the element id to check
17953 * @return {boolean} true if this element is a DragDrop handle, false
17957 isHandle: function(sDDId, sHandleId) {
17958 return ( this.handleIds[sDDId] &&
17959 this.handleIds[sDDId][sHandleId] );
17963 * Returns the DragDrop instance for a given id
17964 * @method getDDById
17965 * @param {String} id the id of the DragDrop object
17966 * @return {DragDrop} the drag drop object, null if it is not found
17969 getDDById: function(id) {
17970 for (var i in this.ids) {
17971 if (this.ids[i][id]) {
17972 return this.ids[i][id];
17979 * Fired after a registered DragDrop object gets the mousedown event.
17980 * Sets up the events required to track the object being dragged
17981 * @method handleMouseDown
17982 * @param {Event} e the event
17983 * @param oDD the DragDrop object being dragged
17987 handleMouseDown: function(e, oDD) {
17989 Roo.QuickTips.disable();
17991 this.currentTarget = e.getTarget();
17993 this.dragCurrent = oDD;
17995 var el = oDD.getEl();
17997 // track start position
17998 this.startX = e.getPageX();
17999 this.startY = e.getPageY();
18001 this.deltaX = this.startX - el.offsetLeft;
18002 this.deltaY = this.startY - el.offsetTop;
18004 this.dragThreshMet = false;
18006 this.clickTimeout = setTimeout(
18008 var DDM = Roo.dd.DDM;
18009 DDM.startDrag(DDM.startX, DDM.startY);
18011 this.clickTimeThresh );
18015 * Fired when either the drag pixel threshol or the mousedown hold
18016 * time threshold has been met.
18017 * @method startDrag
18018 * @param x {int} the X position of the original mousedown
18019 * @param y {int} the Y position of the original mousedown
18022 startDrag: function(x, y) {
18023 clearTimeout(this.clickTimeout);
18024 if (this.dragCurrent) {
18025 this.dragCurrent.b4StartDrag(x, y);
18026 this.dragCurrent.startDrag(x, y);
18028 this.dragThreshMet = true;
18032 * Internal function to handle the mouseup event. Will be invoked
18033 * from the context of the document.
18034 * @method handleMouseUp
18035 * @param {Event} e the event
18039 handleMouseUp: function(e) {
18042 Roo.QuickTips.enable();
18044 if (! this.dragCurrent) {
18048 clearTimeout(this.clickTimeout);
18050 if (this.dragThreshMet) {
18051 this.fireEvents(e, true);
18061 * Utility to stop event propagation and event default, if these
18062 * features are turned on.
18063 * @method stopEvent
18064 * @param {Event} e the event as returned by this.getEvent()
18067 stopEvent: function(e){
18068 if(this.stopPropagation) {
18069 e.stopPropagation();
18072 if (this.preventDefault) {
18073 e.preventDefault();
18078 * Internal function to clean up event handlers after the drag
18079 * operation is complete
18081 * @param {Event} e the event
18085 stopDrag: function(e) {
18086 // Fire the drag end event for the item that was dragged
18087 if (this.dragCurrent) {
18088 if (this.dragThreshMet) {
18089 this.dragCurrent.b4EndDrag(e);
18090 this.dragCurrent.endDrag(e);
18093 this.dragCurrent.onMouseUp(e);
18096 this.dragCurrent = null;
18097 this.dragOvers = {};
18101 * Internal function to handle the mousemove event. Will be invoked
18102 * from the context of the html element.
18104 * @TODO figure out what we can do about mouse events lost when the
18105 * user drags objects beyond the window boundary. Currently we can
18106 * detect this in internet explorer by verifying that the mouse is
18107 * down during the mousemove event. Firefox doesn't give us the
18108 * button state on the mousemove event.
18109 * @method handleMouseMove
18110 * @param {Event} e the event
18114 handleMouseMove: function(e) {
18115 if (! this.dragCurrent) {
18119 // var button = e.which || e.button;
18121 // check for IE mouseup outside of page boundary
18122 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18124 return this.handleMouseUp(e);
18127 if (!this.dragThreshMet) {
18128 var diffX = Math.abs(this.startX - e.getPageX());
18129 var diffY = Math.abs(this.startY - e.getPageY());
18130 if (diffX > this.clickPixelThresh ||
18131 diffY > this.clickPixelThresh) {
18132 this.startDrag(this.startX, this.startY);
18136 if (this.dragThreshMet) {
18137 this.dragCurrent.b4Drag(e);
18138 this.dragCurrent.onDrag(e);
18139 if(!this.dragCurrent.moveOnly){
18140 this.fireEvents(e, false);
18150 * Iterates over all of the DragDrop elements to find ones we are
18151 * hovering over or dropping on
18152 * @method fireEvents
18153 * @param {Event} e the event
18154 * @param {boolean} isDrop is this a drop op or a mouseover op?
18158 fireEvents: function(e, isDrop) {
18159 var dc = this.dragCurrent;
18161 // If the user did the mouse up outside of the window, we could
18162 // get here even though we have ended the drag.
18163 if (!dc || dc.isLocked()) {
18167 var pt = e.getPoint();
18169 // cache the previous dragOver array
18175 var enterEvts = [];
18177 // Check to see if the object(s) we were hovering over is no longer
18178 // being hovered over so we can fire the onDragOut event
18179 for (var i in this.dragOvers) {
18181 var ddo = this.dragOvers[i];
18183 if (! this.isTypeOfDD(ddo)) {
18187 if (! this.isOverTarget(pt, ddo, this.mode)) {
18188 outEvts.push( ddo );
18191 oldOvers[i] = true;
18192 delete this.dragOvers[i];
18195 for (var sGroup in dc.groups) {
18197 if ("string" != typeof sGroup) {
18201 for (i in this.ids[sGroup]) {
18202 var oDD = this.ids[sGroup][i];
18203 if (! this.isTypeOfDD(oDD)) {
18207 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18208 if (this.isOverTarget(pt, oDD, this.mode)) {
18209 // look for drop interactions
18211 dropEvts.push( oDD );
18212 // look for drag enter and drag over interactions
18215 // initial drag over: dragEnter fires
18216 if (!oldOvers[oDD.id]) {
18217 enterEvts.push( oDD );
18218 // subsequent drag overs: dragOver fires
18220 overEvts.push( oDD );
18223 this.dragOvers[oDD.id] = oDD;
18231 if (outEvts.length) {
18232 dc.b4DragOut(e, outEvts);
18233 dc.onDragOut(e, outEvts);
18236 if (enterEvts.length) {
18237 dc.onDragEnter(e, enterEvts);
18240 if (overEvts.length) {
18241 dc.b4DragOver(e, overEvts);
18242 dc.onDragOver(e, overEvts);
18245 if (dropEvts.length) {
18246 dc.b4DragDrop(e, dropEvts);
18247 dc.onDragDrop(e, dropEvts);
18251 // fire dragout events
18253 for (i=0, len=outEvts.length; i<len; ++i) {
18254 dc.b4DragOut(e, outEvts[i].id);
18255 dc.onDragOut(e, outEvts[i].id);
18258 // fire enter events
18259 for (i=0,len=enterEvts.length; i<len; ++i) {
18260 // dc.b4DragEnter(e, oDD.id);
18261 dc.onDragEnter(e, enterEvts[i].id);
18264 // fire over events
18265 for (i=0,len=overEvts.length; i<len; ++i) {
18266 dc.b4DragOver(e, overEvts[i].id);
18267 dc.onDragOver(e, overEvts[i].id);
18270 // fire drop events
18271 for (i=0, len=dropEvts.length; i<len; ++i) {
18272 dc.b4DragDrop(e, dropEvts[i].id);
18273 dc.onDragDrop(e, dropEvts[i].id);
18278 // notify about a drop that did not find a target
18279 if (isDrop && !dropEvts.length) {
18280 dc.onInvalidDrop(e);
18286 * Helper function for getting the best match from the list of drag
18287 * and drop objects returned by the drag and drop events when we are
18288 * in INTERSECT mode. It returns either the first object that the
18289 * cursor is over, or the object that has the greatest overlap with
18290 * the dragged element.
18291 * @method getBestMatch
18292 * @param {DragDrop[]} dds The array of drag and drop objects
18294 * @return {DragDrop} The best single match
18297 getBestMatch: function(dds) {
18299 // Return null if the input is not what we expect
18300 //if (!dds || !dds.length || dds.length == 0) {
18302 // If there is only one item, it wins
18303 //} else if (dds.length == 1) {
18305 var len = dds.length;
18310 // Loop through the targeted items
18311 for (var i=0; i<len; ++i) {
18313 // If the cursor is over the object, it wins. If the
18314 // cursor is over multiple matches, the first one we come
18316 if (dd.cursorIsOver) {
18319 // Otherwise the object with the most overlap wins
18322 winner.overlap.getArea() < dd.overlap.getArea()) {
18333 * Refreshes the cache of the top-left and bottom-right points of the
18334 * drag and drop objects in the specified group(s). This is in the
18335 * format that is stored in the drag and drop instance, so typical
18338 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18342 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18344 * @TODO this really should be an indexed array. Alternatively this
18345 * method could accept both.
18346 * @method refreshCache
18347 * @param {Object} groups an associative array of groups to refresh
18350 refreshCache: function(groups) {
18351 for (var sGroup in groups) {
18352 if ("string" != typeof sGroup) {
18355 for (var i in this.ids[sGroup]) {
18356 var oDD = this.ids[sGroup][i];
18358 if (this.isTypeOfDD(oDD)) {
18359 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18360 var loc = this.getLocation(oDD);
18362 this.locationCache[oDD.id] = loc;
18364 delete this.locationCache[oDD.id];
18365 // this will unregister the drag and drop object if
18366 // the element is not in a usable state
18375 * This checks to make sure an element exists and is in the DOM. The
18376 * main purpose is to handle cases where innerHTML is used to remove
18377 * drag and drop objects from the DOM. IE provides an 'unspecified
18378 * error' when trying to access the offsetParent of such an element
18380 * @param {HTMLElement} el the element to check
18381 * @return {boolean} true if the element looks usable
18384 verifyEl: function(el) {
18389 parent = el.offsetParent;
18392 parent = el.offsetParent;
18403 * Returns a Region object containing the drag and drop element's position
18404 * and size, including the padding configured for it
18405 * @method getLocation
18406 * @param {DragDrop} oDD the drag and drop object to get the
18408 * @return {Roo.lib.Region} a Region object representing the total area
18409 * the element occupies, including any padding
18410 * the instance is configured for.
18413 getLocation: function(oDD) {
18414 if (! this.isTypeOfDD(oDD)) {
18418 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18421 pos= Roo.lib.Dom.getXY(el);
18429 x2 = x1 + el.offsetWidth;
18431 y2 = y1 + el.offsetHeight;
18433 t = y1 - oDD.padding[0];
18434 r = x2 + oDD.padding[1];
18435 b = y2 + oDD.padding[2];
18436 l = x1 - oDD.padding[3];
18438 return new Roo.lib.Region( t, r, b, l );
18442 * Checks the cursor location to see if it over the target
18443 * @method isOverTarget
18444 * @param {Roo.lib.Point} pt The point to evaluate
18445 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18446 * @return {boolean} true if the mouse is over the target
18450 isOverTarget: function(pt, oTarget, intersect) {
18451 // use cache if available
18452 var loc = this.locationCache[oTarget.id];
18453 if (!loc || !this.useCache) {
18454 loc = this.getLocation(oTarget);
18455 this.locationCache[oTarget.id] = loc;
18463 oTarget.cursorIsOver = loc.contains( pt );
18465 // DragDrop is using this as a sanity check for the initial mousedown
18466 // in this case we are done. In POINT mode, if the drag obj has no
18467 // contraints, we are also done. Otherwise we need to evaluate the
18468 // location of the target as related to the actual location of the
18469 // dragged element.
18470 var dc = this.dragCurrent;
18471 if (!dc || !dc.getTargetCoord ||
18472 (!intersect && !dc.constrainX && !dc.constrainY)) {
18473 return oTarget.cursorIsOver;
18476 oTarget.overlap = null;
18478 // Get the current location of the drag element, this is the
18479 // location of the mouse event less the delta that represents
18480 // where the original mousedown happened on the element. We
18481 // need to consider constraints and ticks as well.
18482 var pos = dc.getTargetCoord(pt.x, pt.y);
18484 var el = dc.getDragEl();
18485 var curRegion = new Roo.lib.Region( pos.y,
18486 pos.x + el.offsetWidth,
18487 pos.y + el.offsetHeight,
18490 var overlap = curRegion.intersect(loc);
18493 oTarget.overlap = overlap;
18494 return (intersect) ? true : oTarget.cursorIsOver;
18501 * unload event handler
18502 * @method _onUnload
18506 _onUnload: function(e, me) {
18507 Roo.dd.DragDropMgr.unregAll();
18511 * Cleans up the drag and drop events and objects.
18516 unregAll: function() {
18518 if (this.dragCurrent) {
18520 this.dragCurrent = null;
18523 this._execOnAll("unreg", []);
18525 for (i in this.elementCache) {
18526 delete this.elementCache[i];
18529 this.elementCache = {};
18534 * A cache of DOM elements
18535 * @property elementCache
18542 * Get the wrapper for the DOM element specified
18543 * @method getElWrapper
18544 * @param {String} id the id of the element to get
18545 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18547 * @deprecated This wrapper isn't that useful
18550 getElWrapper: function(id) {
18551 var oWrapper = this.elementCache[id];
18552 if (!oWrapper || !oWrapper.el) {
18553 oWrapper = this.elementCache[id] =
18554 new this.ElementWrapper(Roo.getDom(id));
18560 * Returns the actual DOM element
18561 * @method getElement
18562 * @param {String} id the id of the elment to get
18563 * @return {Object} The element
18564 * @deprecated use Roo.getDom instead
18567 getElement: function(id) {
18568 return Roo.getDom(id);
18572 * Returns the style property for the DOM element (i.e.,
18573 * document.getElById(id).style)
18575 * @param {String} id the id of the elment to get
18576 * @return {Object} The style property of the element
18577 * @deprecated use Roo.getDom instead
18580 getCss: function(id) {
18581 var el = Roo.getDom(id);
18582 return (el) ? el.style : null;
18586 * Inner class for cached elements
18587 * @class DragDropMgr.ElementWrapper
18592 ElementWrapper: function(el) {
18597 this.el = el || null;
18602 this.id = this.el && el.id;
18604 * A reference to the style property
18607 this.css = this.el && el.style;
18611 * Returns the X position of an html element
18613 * @param el the element for which to get the position
18614 * @return {int} the X coordinate
18616 * @deprecated use Roo.lib.Dom.getX instead
18619 getPosX: function(el) {
18620 return Roo.lib.Dom.getX(el);
18624 * Returns the Y position of an html element
18626 * @param el the element for which to get the position
18627 * @return {int} the Y coordinate
18628 * @deprecated use Roo.lib.Dom.getY instead
18631 getPosY: function(el) {
18632 return Roo.lib.Dom.getY(el);
18636 * Swap two nodes. In IE, we use the native method, for others we
18637 * emulate the IE behavior
18639 * @param n1 the first node to swap
18640 * @param n2 the other node to swap
18643 swapNode: function(n1, n2) {
18647 var p = n2.parentNode;
18648 var s = n2.nextSibling;
18651 p.insertBefore(n1, n2);
18652 } else if (n2 == n1.nextSibling) {
18653 p.insertBefore(n2, n1);
18655 n1.parentNode.replaceChild(n2, n1);
18656 p.insertBefore(n1, s);
18662 * Returns the current scroll position
18663 * @method getScroll
18667 getScroll: function () {
18668 var t, l, dde=document.documentElement, db=document.body;
18669 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18671 l = dde.scrollLeft;
18678 return { top: t, left: l };
18682 * Returns the specified element style property
18684 * @param {HTMLElement} el the element
18685 * @param {string} styleProp the style property
18686 * @return {string} The value of the style property
18687 * @deprecated use Roo.lib.Dom.getStyle
18690 getStyle: function(el, styleProp) {
18691 return Roo.fly(el).getStyle(styleProp);
18695 * Gets the scrollTop
18696 * @method getScrollTop
18697 * @return {int} the document's scrollTop
18700 getScrollTop: function () { return this.getScroll().top; },
18703 * Gets the scrollLeft
18704 * @method getScrollLeft
18705 * @return {int} the document's scrollTop
18708 getScrollLeft: function () { return this.getScroll().left; },
18711 * Sets the x/y position of an element to the location of the
18714 * @param {HTMLElement} moveEl The element to move
18715 * @param {HTMLElement} targetEl The position reference element
18718 moveToEl: function (moveEl, targetEl) {
18719 var aCoord = Roo.lib.Dom.getXY(targetEl);
18720 Roo.lib.Dom.setXY(moveEl, aCoord);
18724 * Numeric array sort function
18725 * @method numericSort
18728 numericSort: function(a, b) { return (a - b); },
18732 * @property _timeoutCount
18739 * Trying to make the load order less important. Without this we get
18740 * an error if this file is loaded before the Event Utility.
18741 * @method _addListeners
18745 _addListeners: function() {
18746 var DDM = Roo.dd.DDM;
18747 if ( Roo.lib.Event && document ) {
18750 if (DDM._timeoutCount > 2000) {
18752 setTimeout(DDM._addListeners, 10);
18753 if (document && document.body) {
18754 DDM._timeoutCount += 1;
18761 * Recursively searches the immediate parent and all child nodes for
18762 * the handle element in order to determine wheter or not it was
18764 * @method handleWasClicked
18765 * @param node the html element to inspect
18768 handleWasClicked: function(node, id) {
18769 if (this.isHandle(id, node.id)) {
18772 // check to see if this is a text node child of the one we want
18773 var p = node.parentNode;
18776 if (this.isHandle(id, p.id)) {
18791 // shorter alias, save a few bytes
18792 Roo.dd.DDM = Roo.dd.DragDropMgr;
18793 Roo.dd.DDM._addListeners();
18797 * Ext JS Library 1.1.1
18798 * Copyright(c) 2006-2007, Ext JS, LLC.
18800 * Originally Released Under LGPL - original licence link has changed is not relivant.
18803 * <script type="text/javascript">
18808 * A DragDrop implementation where the linked element follows the
18809 * mouse cursor during a drag.
18810 * @extends Roo.dd.DragDrop
18812 * @param {String} id the id of the linked element
18813 * @param {String} sGroup the group of related DragDrop items
18814 * @param {object} config an object containing configurable attributes
18815 * Valid properties for DD:
18818 Roo.dd.DD = function(id, sGroup, config) {
18820 this.init(id, sGroup, config);
18824 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18827 * When set to true, the utility automatically tries to scroll the browser
18828 * window wehn a drag and drop element is dragged near the viewport boundary.
18829 * Defaults to true.
18836 * Sets the pointer offset to the distance between the linked element's top
18837 * left corner and the location the element was clicked
18838 * @method autoOffset
18839 * @param {int} iPageX the X coordinate of the click
18840 * @param {int} iPageY the Y coordinate of the click
18842 autoOffset: function(iPageX, iPageY) {
18843 var x = iPageX - this.startPageX;
18844 var y = iPageY - this.startPageY;
18845 this.setDelta(x, y);
18849 * Sets the pointer offset. You can call this directly to force the
18850 * offset to be in a particular location (e.g., pass in 0,0 to set it
18851 * to the center of the object)
18853 * @param {int} iDeltaX the distance from the left
18854 * @param {int} iDeltaY the distance from the top
18856 setDelta: function(iDeltaX, iDeltaY) {
18857 this.deltaX = iDeltaX;
18858 this.deltaY = iDeltaY;
18862 * Sets the drag element to the location of the mousedown or click event,
18863 * maintaining the cursor location relative to the location on the element
18864 * that was clicked. Override this if you want to place the element in a
18865 * location other than where the cursor is.
18866 * @method setDragElPos
18867 * @param {int} iPageX the X coordinate of the mousedown or drag event
18868 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18870 setDragElPos: function(iPageX, iPageY) {
18871 // the first time we do this, we are going to check to make sure
18872 // the element has css positioning
18874 var el = this.getDragEl();
18875 this.alignElWithMouse(el, iPageX, iPageY);
18879 * Sets the element to the location of the mousedown or click event,
18880 * maintaining the cursor location relative to the location on the element
18881 * that was clicked. Override this if you want to place the element in a
18882 * location other than where the cursor is.
18883 * @method alignElWithMouse
18884 * @param {HTMLElement} el the element to move
18885 * @param {int} iPageX the X coordinate of the mousedown or drag event
18886 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18888 alignElWithMouse: function(el, iPageX, iPageY) {
18889 var oCoord = this.getTargetCoord(iPageX, iPageY);
18890 var fly = el.dom ? el : Roo.fly(el);
18891 if (!this.deltaSetXY) {
18892 var aCoord = [oCoord.x, oCoord.y];
18894 var newLeft = fly.getLeft(true);
18895 var newTop = fly.getTop(true);
18896 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
18898 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
18901 this.cachePosition(oCoord.x, oCoord.y);
18902 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
18907 * Saves the most recent position so that we can reset the constraints and
18908 * tick marks on-demand. We need to know this so that we can calculate the
18909 * number of pixels the element is offset from its original position.
18910 * @method cachePosition
18911 * @param iPageX the current x position (optional, this just makes it so we
18912 * don't have to look it up again)
18913 * @param iPageY the current y position (optional, this just makes it so we
18914 * don't have to look it up again)
18916 cachePosition: function(iPageX, iPageY) {
18918 this.lastPageX = iPageX;
18919 this.lastPageY = iPageY;
18921 var aCoord = Roo.lib.Dom.getXY(this.getEl());
18922 this.lastPageX = aCoord[0];
18923 this.lastPageY = aCoord[1];
18928 * Auto-scroll the window if the dragged object has been moved beyond the
18929 * visible window boundary.
18930 * @method autoScroll
18931 * @param {int} x the drag element's x position
18932 * @param {int} y the drag element's y position
18933 * @param {int} h the height of the drag element
18934 * @param {int} w the width of the drag element
18937 autoScroll: function(x, y, h, w) {
18940 // The client height
18941 var clientH = Roo.lib.Dom.getViewWidth();
18943 // The client width
18944 var clientW = Roo.lib.Dom.getViewHeight();
18946 // The amt scrolled down
18947 var st = this.DDM.getScrollTop();
18949 // The amt scrolled right
18950 var sl = this.DDM.getScrollLeft();
18952 // Location of the bottom of the element
18955 // Location of the right of the element
18958 // The distance from the cursor to the bottom of the visible area,
18959 // adjusted so that we don't scroll if the cursor is beyond the
18960 // element drag constraints
18961 var toBot = (clientH + st - y - this.deltaY);
18963 // The distance from the cursor to the right of the visible area
18964 var toRight = (clientW + sl - x - this.deltaX);
18967 // How close to the edge the cursor must be before we scroll
18968 // var thresh = (document.all) ? 100 : 40;
18971 // How many pixels to scroll per autoscroll op. This helps to reduce
18972 // clunky scrolling. IE is more sensitive about this ... it needs this
18973 // value to be higher.
18974 var scrAmt = (document.all) ? 80 : 30;
18976 // Scroll down if we are near the bottom of the visible page and the
18977 // obj extends below the crease
18978 if ( bot > clientH && toBot < thresh ) {
18979 window.scrollTo(sl, st + scrAmt);
18982 // Scroll up if the window is scrolled down and the top of the object
18983 // goes above the top border
18984 if ( y < st && st > 0 && y - st < thresh ) {
18985 window.scrollTo(sl, st - scrAmt);
18988 // Scroll right if the obj is beyond the right border and the cursor is
18989 // near the border.
18990 if ( right > clientW && toRight < thresh ) {
18991 window.scrollTo(sl + scrAmt, st);
18994 // Scroll left if the window has been scrolled to the right and the obj
18995 // extends past the left border
18996 if ( x < sl && sl > 0 && x - sl < thresh ) {
18997 window.scrollTo(sl - scrAmt, st);
19003 * Finds the location the element should be placed if we want to move
19004 * it to where the mouse location less the click offset would place us.
19005 * @method getTargetCoord
19006 * @param {int} iPageX the X coordinate of the click
19007 * @param {int} iPageY the Y coordinate of the click
19008 * @return an object that contains the coordinates (Object.x and Object.y)
19011 getTargetCoord: function(iPageX, iPageY) {
19014 var x = iPageX - this.deltaX;
19015 var y = iPageY - this.deltaY;
19017 if (this.constrainX) {
19018 if (x < this.minX) { x = this.minX; }
19019 if (x > this.maxX) { x = this.maxX; }
19022 if (this.constrainY) {
19023 if (y < this.minY) { y = this.minY; }
19024 if (y > this.maxY) { y = this.maxY; }
19027 x = this.getTick(x, this.xTicks);
19028 y = this.getTick(y, this.yTicks);
19035 * Sets up config options specific to this class. Overrides
19036 * Roo.dd.DragDrop, but all versions of this method through the
19037 * inheritance chain are called
19039 applyConfig: function() {
19040 Roo.dd.DD.superclass.applyConfig.call(this);
19041 this.scroll = (this.config.scroll !== false);
19045 * Event that fires prior to the onMouseDown event. Overrides
19048 b4MouseDown: function(e) {
19049 // this.resetConstraints();
19050 this.autoOffset(e.getPageX(),
19055 * Event that fires prior to the onDrag event. Overrides
19058 b4Drag: function(e) {
19059 this.setDragElPos(e.getPageX(),
19063 toString: function() {
19064 return ("DD " + this.id);
19067 //////////////////////////////////////////////////////////////////////////
19068 // Debugging ygDragDrop events that can be overridden
19069 //////////////////////////////////////////////////////////////////////////
19071 startDrag: function(x, y) {
19074 onDrag: function(e) {
19077 onDragEnter: function(e, id) {
19080 onDragOver: function(e, id) {
19083 onDragOut: function(e, id) {
19086 onDragDrop: function(e, id) {
19089 endDrag: function(e) {
19096 * Ext JS Library 1.1.1
19097 * Copyright(c) 2006-2007, Ext JS, LLC.
19099 * Originally Released Under LGPL - original licence link has changed is not relivant.
19102 * <script type="text/javascript">
19106 * @class Roo.dd.DDProxy
19107 * A DragDrop implementation that inserts an empty, bordered div into
19108 * the document that follows the cursor during drag operations. At the time of
19109 * the click, the frame div is resized to the dimensions of the linked html
19110 * element, and moved to the exact location of the linked element.
19112 * References to the "frame" element refer to the single proxy element that
19113 * was created to be dragged in place of all DDProxy elements on the
19116 * @extends Roo.dd.DD
19118 * @param {String} id the id of the linked html element
19119 * @param {String} sGroup the group of related DragDrop objects
19120 * @param {object} config an object containing configurable attributes
19121 * Valid properties for DDProxy in addition to those in DragDrop:
19122 * resizeFrame, centerFrame, dragElId
19124 Roo.dd.DDProxy = function(id, sGroup, config) {
19126 this.init(id, sGroup, config);
19132 * The default drag frame div id
19133 * @property Roo.dd.DDProxy.dragElId
19137 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19139 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19142 * By default we resize the drag frame to be the same size as the element
19143 * we want to drag (this is to get the frame effect). We can turn it off
19144 * if we want a different behavior.
19145 * @property resizeFrame
19151 * By default the frame is positioned exactly where the drag element is, so
19152 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19153 * you do not have constraints on the obj is to have the drag frame centered
19154 * around the cursor. Set centerFrame to true for this effect.
19155 * @property centerFrame
19158 centerFrame: false,
19161 * Creates the proxy element if it does not yet exist
19162 * @method createFrame
19164 createFrame: function() {
19166 var body = document.body;
19168 if (!body || !body.firstChild) {
19169 setTimeout( function() { self.createFrame(); }, 50 );
19173 var div = this.getDragEl();
19176 div = document.createElement("div");
19177 div.id = this.dragElId;
19180 s.position = "absolute";
19181 s.visibility = "hidden";
19183 s.border = "2px solid #aaa";
19186 // appendChild can blow up IE if invoked prior to the window load event
19187 // while rendering a table. It is possible there are other scenarios
19188 // that would cause this to happen as well.
19189 body.insertBefore(div, body.firstChild);
19194 * Initialization for the drag frame element. Must be called in the
19195 * constructor of all subclasses
19196 * @method initFrame
19198 initFrame: function() {
19199 this.createFrame();
19202 applyConfig: function() {
19203 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19205 this.resizeFrame = (this.config.resizeFrame !== false);
19206 this.centerFrame = (this.config.centerFrame);
19207 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19211 * Resizes the drag frame to the dimensions of the clicked object, positions
19212 * it over the object, and finally displays it
19213 * @method showFrame
19214 * @param {int} iPageX X click position
19215 * @param {int} iPageY Y click position
19218 showFrame: function(iPageX, iPageY) {
19219 var el = this.getEl();
19220 var dragEl = this.getDragEl();
19221 var s = dragEl.style;
19223 this._resizeProxy();
19225 if (this.centerFrame) {
19226 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19227 Math.round(parseInt(s.height, 10)/2) );
19230 this.setDragElPos(iPageX, iPageY);
19232 Roo.fly(dragEl).show();
19236 * The proxy is automatically resized to the dimensions of the linked
19237 * element when a drag is initiated, unless resizeFrame is set to false
19238 * @method _resizeProxy
19241 _resizeProxy: function() {
19242 if (this.resizeFrame) {
19243 var el = this.getEl();
19244 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19248 // overrides Roo.dd.DragDrop
19249 b4MouseDown: function(e) {
19250 var x = e.getPageX();
19251 var y = e.getPageY();
19252 this.autoOffset(x, y);
19253 this.setDragElPos(x, y);
19256 // overrides Roo.dd.DragDrop
19257 b4StartDrag: function(x, y) {
19258 // show the drag frame
19259 this.showFrame(x, y);
19262 // overrides Roo.dd.DragDrop
19263 b4EndDrag: function(e) {
19264 Roo.fly(this.getDragEl()).hide();
19267 // overrides Roo.dd.DragDrop
19268 // By default we try to move the element to the last location of the frame.
19269 // This is so that the default behavior mirrors that of Roo.dd.DD.
19270 endDrag: function(e) {
19272 var lel = this.getEl();
19273 var del = this.getDragEl();
19275 // Show the drag frame briefly so we can get its position
19276 del.style.visibility = "";
19279 // Hide the linked element before the move to get around a Safari
19281 lel.style.visibility = "hidden";
19282 Roo.dd.DDM.moveToEl(lel, del);
19283 del.style.visibility = "hidden";
19284 lel.style.visibility = "";
19289 beforeMove : function(){
19293 afterDrag : function(){
19297 toString: function() {
19298 return ("DDProxy " + this.id);
19304 * Ext JS Library 1.1.1
19305 * Copyright(c) 2006-2007, Ext JS, LLC.
19307 * Originally Released Under LGPL - original licence link has changed is not relivant.
19310 * <script type="text/javascript">
19314 * @class Roo.dd.DDTarget
19315 * A DragDrop implementation that does not move, but can be a drop
19316 * target. You would get the same result by simply omitting implementation
19317 * for the event callbacks, but this way we reduce the processing cost of the
19318 * event listener and the callbacks.
19319 * @extends Roo.dd.DragDrop
19321 * @param {String} id the id of the element that is a drop target
19322 * @param {String} sGroup the group of related DragDrop objects
19323 * @param {object} config an object containing configurable attributes
19324 * Valid properties for DDTarget in addition to those in
19328 Roo.dd.DDTarget = function(id, sGroup, config) {
19330 this.initTarget(id, sGroup, config);
19332 if (config.listeners || config.events) {
19333 Roo.dd.DragDrop.superclass.constructor.call(this, {
19334 listeners : config.listeners || {},
19335 events : config.events || {}
19340 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19341 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19342 toString: function() {
19343 return ("DDTarget " + this.id);
19348 * Ext JS Library 1.1.1
19349 * Copyright(c) 2006-2007, Ext JS, LLC.
19351 * Originally Released Under LGPL - original licence link has changed is not relivant.
19354 * <script type="text/javascript">
19359 * @class Roo.dd.ScrollManager
19360 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19361 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19364 Roo.dd.ScrollManager = function(){
19365 var ddm = Roo.dd.DragDropMgr;
19372 var onStop = function(e){
19377 var triggerRefresh = function(){
19378 if(ddm.dragCurrent){
19379 ddm.refreshCache(ddm.dragCurrent.groups);
19383 var doScroll = function(){
19384 if(ddm.dragCurrent){
19385 var dds = Roo.dd.ScrollManager;
19387 if(proc.el.scroll(proc.dir, dds.increment)){
19391 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19396 var clearProc = function(){
19398 clearInterval(proc.id);
19405 var startProc = function(el, dir){
19406 Roo.log('scroll startproc');
19410 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19413 var onFire = function(e, isDrop){
19415 if(isDrop || !ddm.dragCurrent){ return; }
19416 var dds = Roo.dd.ScrollManager;
19417 if(!dragEl || dragEl != ddm.dragCurrent){
19418 dragEl = ddm.dragCurrent;
19419 // refresh regions on drag start
19420 dds.refreshCache();
19423 var xy = Roo.lib.Event.getXY(e);
19424 var pt = new Roo.lib.Point(xy[0], xy[1]);
19425 for(var id in els){
19426 var el = els[id], r = el._region;
19427 if(r && r.contains(pt) && el.isScrollable()){
19428 if(r.bottom - pt.y <= dds.thresh){
19430 startProc(el, "down");
19433 }else if(r.right - pt.x <= dds.thresh){
19435 startProc(el, "left");
19438 }else if(pt.y - r.top <= dds.thresh){
19440 startProc(el, "up");
19443 }else if(pt.x - r.left <= dds.thresh){
19445 startProc(el, "right");
19454 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19455 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19459 * Registers new overflow element(s) to auto scroll
19460 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19462 register : function(el){
19463 if(el instanceof Array){
19464 for(var i = 0, len = el.length; i < len; i++) {
19465 this.register(el[i]);
19471 Roo.dd.ScrollManager.els = els;
19475 * Unregisters overflow element(s) so they are no longer scrolled
19476 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19478 unregister : function(el){
19479 if(el instanceof Array){
19480 for(var i = 0, len = el.length; i < len; i++) {
19481 this.unregister(el[i]);
19490 * The number of pixels from the edge of a container the pointer needs to be to
19491 * trigger scrolling (defaults to 25)
19497 * The number of pixels to scroll in each scroll increment (defaults to 50)
19503 * The frequency of scrolls in milliseconds (defaults to 500)
19509 * True to animate the scroll (defaults to true)
19515 * The animation duration in seconds -
19516 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19522 * Manually trigger a cache refresh.
19524 refreshCache : function(){
19525 for(var id in els){
19526 if(typeof els[id] == 'object'){ // for people extending the object prototype
19527 els[id]._region = els[id].getRegion();
19534 * Ext JS Library 1.1.1
19535 * Copyright(c) 2006-2007, Ext JS, LLC.
19537 * Originally Released Under LGPL - original licence link has changed is not relivant.
19540 * <script type="text/javascript">
19545 * @class Roo.dd.Registry
19546 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19547 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19550 Roo.dd.Registry = function(){
19553 var autoIdSeed = 0;
19555 var getId = function(el, autogen){
19556 if(typeof el == "string"){
19560 if(!id && autogen !== false){
19561 id = "roodd-" + (++autoIdSeed);
19569 * Register a drag drop element
19570 * @param {String|HTMLElement} element The id or DOM node to register
19571 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19572 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19573 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19574 * populated in the data object (if applicable):
19576 Value Description<br />
19577 --------- ------------------------------------------<br />
19578 handles Array of DOM nodes that trigger dragging<br />
19579 for the element being registered<br />
19580 isHandle True if the element passed in triggers<br />
19581 dragging itself, else false
19584 register : function(el, data){
19586 if(typeof el == "string"){
19587 el = document.getElementById(el);
19590 elements[getId(el)] = data;
19591 if(data.isHandle !== false){
19592 handles[data.ddel.id] = data;
19595 var hs = data.handles;
19596 for(var i = 0, len = hs.length; i < len; i++){
19597 handles[getId(hs[i])] = data;
19603 * Unregister a drag drop element
19604 * @param {String|HTMLElement} element The id or DOM node to unregister
19606 unregister : function(el){
19607 var id = getId(el, false);
19608 var data = elements[id];
19610 delete elements[id];
19612 var hs = data.handles;
19613 for(var i = 0, len = hs.length; i < len; i++){
19614 delete handles[getId(hs[i], false)];
19621 * Returns the handle registered for a DOM Node by id
19622 * @param {String|HTMLElement} id The DOM node or id to look up
19623 * @return {Object} handle The custom handle data
19625 getHandle : function(id){
19626 if(typeof id != "string"){ // must be element?
19629 return handles[id];
19633 * Returns the handle that is registered for the DOM node that is the target of the event
19634 * @param {Event} e The event
19635 * @return {Object} handle The custom handle data
19637 getHandleFromEvent : function(e){
19638 var t = Roo.lib.Event.getTarget(e);
19639 return t ? handles[t.id] : null;
19643 * Returns a custom data object that is registered for a DOM node by id
19644 * @param {String|HTMLElement} id The DOM node or id to look up
19645 * @return {Object} data The custom data
19647 getTarget : function(id){
19648 if(typeof id != "string"){ // must be element?
19651 return elements[id];
19655 * Returns a custom data object that is registered for the DOM node that is the target of the event
19656 * @param {Event} e The event
19657 * @return {Object} data The custom data
19659 getTargetFromEvent : function(e){
19660 var t = Roo.lib.Event.getTarget(e);
19661 return t ? elements[t.id] || handles[t.id] : null;
19666 * Ext JS Library 1.1.1
19667 * Copyright(c) 2006-2007, Ext JS, LLC.
19669 * Originally Released Under LGPL - original licence link has changed is not relivant.
19672 * <script type="text/javascript">
19677 * @class Roo.dd.StatusProxy
19678 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19679 * default drag proxy used by all Roo.dd components.
19681 * @param {Object} config
19683 Roo.dd.StatusProxy = function(config){
19684 Roo.apply(this, config);
19685 this.id = this.id || Roo.id();
19686 this.el = new Roo.Layer({
19688 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19689 {tag: "div", cls: "x-dd-drop-icon"},
19690 {tag: "div", cls: "x-dd-drag-ghost"}
19693 shadow: !config || config.shadow !== false
19695 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19696 this.dropStatus = this.dropNotAllowed;
19699 Roo.dd.StatusProxy.prototype = {
19701 * @cfg {String} dropAllowed
19702 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19704 dropAllowed : "x-dd-drop-ok",
19706 * @cfg {String} dropNotAllowed
19707 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19709 dropNotAllowed : "x-dd-drop-nodrop",
19712 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19713 * over the current target element.
19714 * @param {String} cssClass The css class for the new drop status indicator image
19716 setStatus : function(cssClass){
19717 cssClass = cssClass || this.dropNotAllowed;
19718 if(this.dropStatus != cssClass){
19719 this.el.replaceClass(this.dropStatus, cssClass);
19720 this.dropStatus = cssClass;
19725 * Resets the status indicator to the default dropNotAllowed value
19726 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19728 reset : function(clearGhost){
19729 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19730 this.dropStatus = this.dropNotAllowed;
19732 this.ghost.update("");
19737 * Updates the contents of the ghost element
19738 * @param {String} html The html that will replace the current innerHTML of the ghost element
19740 update : function(html){
19741 if(typeof html == "string"){
19742 this.ghost.update(html);
19744 this.ghost.update("");
19745 html.style.margin = "0";
19746 this.ghost.dom.appendChild(html);
19748 // ensure float = none set?? cant remember why though.
19749 var el = this.ghost.dom.firstChild;
19751 Roo.fly(el).setStyle('float', 'none');
19756 * Returns the underlying proxy {@link Roo.Layer}
19757 * @return {Roo.Layer} el
19759 getEl : function(){
19764 * Returns the ghost element
19765 * @return {Roo.Element} el
19767 getGhost : function(){
19773 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19775 hide : function(clear){
19783 * Stops the repair animation if it's currently running
19786 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19792 * Displays this proxy
19799 * Force the Layer to sync its shadow and shim positions to the element
19806 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19807 * invalid drop operation by the item being dragged.
19808 * @param {Array} xy The XY position of the element ([x, y])
19809 * @param {Function} callback The function to call after the repair is complete
19810 * @param {Object} scope The scope in which to execute the callback
19812 repair : function(xy, callback, scope){
19813 this.callback = callback;
19814 this.scope = scope;
19815 if(xy && this.animRepair !== false){
19816 this.el.addClass("x-dd-drag-repair");
19817 this.el.hideUnders(true);
19818 this.anim = this.el.shift({
19819 duration: this.repairDuration || .5,
19823 callback: this.afterRepair,
19827 this.afterRepair();
19832 afterRepair : function(){
19834 if(typeof this.callback == "function"){
19835 this.callback.call(this.scope || this);
19837 this.callback = null;
19842 * Ext JS Library 1.1.1
19843 * Copyright(c) 2006-2007, Ext JS, LLC.
19845 * Originally Released Under LGPL - original licence link has changed is not relivant.
19848 * <script type="text/javascript">
19852 * @class Roo.dd.DragSource
19853 * @extends Roo.dd.DDProxy
19854 * A simple class that provides the basic implementation needed to make any element draggable.
19856 * @param {String/HTMLElement/Element} el The container element
19857 * @param {Object} config
19859 Roo.dd.DragSource = function(el, config){
19860 this.el = Roo.get(el);
19861 this.dragData = {};
19863 Roo.apply(this, config);
19866 this.proxy = new Roo.dd.StatusProxy();
19869 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
19870 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
19872 this.dragging = false;
19875 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
19877 * @cfg {String} dropAllowed
19878 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
19880 dropAllowed : "x-dd-drop-ok",
19882 * @cfg {String} dropNotAllowed
19883 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
19885 dropNotAllowed : "x-dd-drop-nodrop",
19888 * Returns the data object associated with this drag source
19889 * @return {Object} data An object containing arbitrary data
19891 getDragData : function(e){
19892 return this.dragData;
19896 onDragEnter : function(e, id){
19897 var target = Roo.dd.DragDropMgr.getDDById(id);
19898 this.cachedTarget = target;
19899 if(this.beforeDragEnter(target, e, id) !== false){
19900 if(target.isNotifyTarget){
19901 var status = target.notifyEnter(this, e, this.dragData);
19902 this.proxy.setStatus(status);
19904 this.proxy.setStatus(this.dropAllowed);
19907 if(this.afterDragEnter){
19909 * An empty function by default, but provided so that you can perform a custom action
19910 * when the dragged item enters the drop target by providing an implementation.
19911 * @param {Roo.dd.DragDrop} target The drop target
19912 * @param {Event} e The event object
19913 * @param {String} id The id of the dragged element
19914 * @method afterDragEnter
19916 this.afterDragEnter(target, e, id);
19922 * An empty function by default, but provided so that you can perform a custom action
19923 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
19924 * @param {Roo.dd.DragDrop} target The drop target
19925 * @param {Event} e The event object
19926 * @param {String} id The id of the dragged element
19927 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19929 beforeDragEnter : function(target, e, id){
19934 alignElWithMouse: function() {
19935 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
19940 onDragOver : function(e, id){
19941 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19942 if(this.beforeDragOver(target, e, id) !== false){
19943 if(target.isNotifyTarget){
19944 var status = target.notifyOver(this, e, this.dragData);
19945 this.proxy.setStatus(status);
19948 if(this.afterDragOver){
19950 * An empty function by default, but provided so that you can perform a custom action
19951 * while the dragged item is over the drop target by providing an implementation.
19952 * @param {Roo.dd.DragDrop} target The drop target
19953 * @param {Event} e The event object
19954 * @param {String} id The id of the dragged element
19955 * @method afterDragOver
19957 this.afterDragOver(target, e, id);
19963 * An empty function by default, but provided so that you can perform a custom action
19964 * while the dragged item is over the drop target and optionally cancel the onDragOver.
19965 * @param {Roo.dd.DragDrop} target The drop target
19966 * @param {Event} e The event object
19967 * @param {String} id The id of the dragged element
19968 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19970 beforeDragOver : function(target, e, id){
19975 onDragOut : function(e, id){
19976 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19977 if(this.beforeDragOut(target, e, id) !== false){
19978 if(target.isNotifyTarget){
19979 target.notifyOut(this, e, this.dragData);
19981 this.proxy.reset();
19982 if(this.afterDragOut){
19984 * An empty function by default, but provided so that you can perform a custom action
19985 * after the dragged item is dragged out of the target without dropping.
19986 * @param {Roo.dd.DragDrop} target The drop target
19987 * @param {Event} e The event object
19988 * @param {String} id The id of the dragged element
19989 * @method afterDragOut
19991 this.afterDragOut(target, e, id);
19994 this.cachedTarget = null;
19998 * An empty function by default, but provided so that you can perform a custom action before the dragged
19999 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20000 * @param {Roo.dd.DragDrop} target The drop target
20001 * @param {Event} e The event object
20002 * @param {String} id The id of the dragged element
20003 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20005 beforeDragOut : function(target, e, id){
20010 onDragDrop : function(e, id){
20011 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20012 if(this.beforeDragDrop(target, e, id) !== false){
20013 if(target.isNotifyTarget){
20014 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20015 this.onValidDrop(target, e, id);
20017 this.onInvalidDrop(target, e, id);
20020 this.onValidDrop(target, e, id);
20023 if(this.afterDragDrop){
20025 * An empty function by default, but provided so that you can perform a custom action
20026 * after a valid drag drop has occurred by providing an implementation.
20027 * @param {Roo.dd.DragDrop} target The drop target
20028 * @param {Event} e The event object
20029 * @param {String} id The id of the dropped element
20030 * @method afterDragDrop
20032 this.afterDragDrop(target, e, id);
20035 delete this.cachedTarget;
20039 * An empty function by default, but provided so that you can perform a custom action before the dragged
20040 * item is dropped onto the target and optionally cancel the onDragDrop.
20041 * @param {Roo.dd.DragDrop} target The drop target
20042 * @param {Event} e The event object
20043 * @param {String} id The id of the dragged element
20044 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20046 beforeDragDrop : function(target, e, id){
20051 onValidDrop : function(target, e, id){
20053 if(this.afterValidDrop){
20055 * An empty function by default, but provided so that you can perform a custom action
20056 * after a valid drop has occurred by providing an implementation.
20057 * @param {Object} target The target DD
20058 * @param {Event} e The event object
20059 * @param {String} id The id of the dropped element
20060 * @method afterInvalidDrop
20062 this.afterValidDrop(target, e, id);
20067 getRepairXY : function(e, data){
20068 return this.el.getXY();
20072 onInvalidDrop : function(target, e, id){
20073 this.beforeInvalidDrop(target, e, id);
20074 if(this.cachedTarget){
20075 if(this.cachedTarget.isNotifyTarget){
20076 this.cachedTarget.notifyOut(this, e, this.dragData);
20078 this.cacheTarget = null;
20080 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20082 if(this.afterInvalidDrop){
20084 * An empty function by default, but provided so that you can perform a custom action
20085 * after an invalid drop has occurred by providing an implementation.
20086 * @param {Event} e The event object
20087 * @param {String} id The id of the dropped element
20088 * @method afterInvalidDrop
20090 this.afterInvalidDrop(e, id);
20095 afterRepair : function(){
20097 this.el.highlight(this.hlColor || "c3daf9");
20099 this.dragging = false;
20103 * An empty function by default, but provided so that you can perform a custom action after an invalid
20104 * drop has occurred.
20105 * @param {Roo.dd.DragDrop} target The drop target
20106 * @param {Event} e The event object
20107 * @param {String} id The id of the dragged element
20108 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20110 beforeInvalidDrop : function(target, e, id){
20115 handleMouseDown : function(e){
20116 if(this.dragging) {
20119 var data = this.getDragData(e);
20120 if(data && this.onBeforeDrag(data, e) !== false){
20121 this.dragData = data;
20123 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20128 * An empty function by default, but provided so that you can perform a custom action before the initial
20129 * drag event begins and optionally cancel it.
20130 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20131 * @param {Event} e The event object
20132 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20134 onBeforeDrag : function(data, e){
20139 * An empty function by default, but provided so that you can perform a custom action once the initial
20140 * drag event has begun. The drag cannot be canceled from this function.
20141 * @param {Number} x The x position of the click on the dragged object
20142 * @param {Number} y The y position of the click on the dragged object
20144 onStartDrag : Roo.emptyFn,
20146 // private - YUI override
20147 startDrag : function(x, y){
20148 this.proxy.reset();
20149 this.dragging = true;
20150 this.proxy.update("");
20151 this.onInitDrag(x, y);
20156 onInitDrag : function(x, y){
20157 var clone = this.el.dom.cloneNode(true);
20158 clone.id = Roo.id(); // prevent duplicate ids
20159 this.proxy.update(clone);
20160 this.onStartDrag(x, y);
20165 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20166 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20168 getProxy : function(){
20173 * Hides the drag source's {@link Roo.dd.StatusProxy}
20175 hideProxy : function(){
20177 this.proxy.reset(true);
20178 this.dragging = false;
20182 triggerCacheRefresh : function(){
20183 Roo.dd.DDM.refreshCache(this.groups);
20186 // private - override to prevent hiding
20187 b4EndDrag: function(e) {
20190 // private - override to prevent moving
20191 endDrag : function(e){
20192 this.onEndDrag(this.dragData, e);
20196 onEndDrag : function(data, e){
20199 // private - pin to cursor
20200 autoOffset : function(x, y) {
20201 this.setDelta(-12, -20);
20205 * Ext JS Library 1.1.1
20206 * Copyright(c) 2006-2007, Ext JS, LLC.
20208 * Originally Released Under LGPL - original licence link has changed is not relivant.
20211 * <script type="text/javascript">
20216 * @class Roo.dd.DropTarget
20217 * @extends Roo.dd.DDTarget
20218 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20219 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20221 * @param {String/HTMLElement/Element} el The container element
20222 * @param {Object} config
20224 Roo.dd.DropTarget = function(el, config){
20225 this.el = Roo.get(el);
20227 var listeners = false; ;
20228 if (config && config.listeners) {
20229 listeners= config.listeners;
20230 delete config.listeners;
20232 Roo.apply(this, config);
20234 if(this.containerScroll){
20235 Roo.dd.ScrollManager.register(this.el);
20239 * @scope Roo.dd.DropTarget
20244 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20245 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20246 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20248 * IMPORTANT : it should set this.overClass and this.dropAllowed
20250 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20251 * @param {Event} e The event
20252 * @param {Object} data An object containing arbitrary data supplied by the drag source
20258 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20259 * This method will be called on every mouse movement while the drag source is over the drop target.
20260 * This default implementation simply returns the dropAllowed config value.
20262 * IMPORTANT : it should set this.dropAllowed
20264 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20265 * @param {Event} e The event
20266 * @param {Object} data An object containing arbitrary data supplied by the drag source
20272 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20273 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20274 * overClass (if any) from the drop element.
20276 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20277 * @param {Event} e The event
20278 * @param {Object} data An object containing arbitrary data supplied by the drag source
20284 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20285 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20286 * implementation that does something to process the drop event and returns true so that the drag source's
20287 * repair action does not run.
20289 * IMPORTANT : it should set this.success
20291 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20292 * @param {Event} e The event
20293 * @param {Object} data An object containing arbitrary data supplied by the drag source
20299 Roo.dd.DropTarget.superclass.constructor.call( this,
20301 this.ddGroup || this.group,
20304 listeners : listeners || {}
20312 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20314 * @cfg {String} overClass
20315 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20318 * @cfg {String} ddGroup
20319 * The drag drop group to handle drop events for
20323 * @cfg {String} dropAllowed
20324 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20326 dropAllowed : "x-dd-drop-ok",
20328 * @cfg {String} dropNotAllowed
20329 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20331 dropNotAllowed : "x-dd-drop-nodrop",
20333 * @cfg {boolean} success
20334 * set this after drop listener..
20338 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20339 * if the drop point is valid for over/enter..
20346 isNotifyTarget : true,
20351 notifyEnter : function(dd, e, data)
20354 this.fireEvent('enter', dd, e, data);
20355 if(this.overClass){
20356 this.el.addClass(this.overClass);
20358 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20359 this.valid ? this.dropAllowed : this.dropNotAllowed
20366 notifyOver : function(dd, e, data)
20369 this.fireEvent('over', dd, e, data);
20370 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20371 this.valid ? this.dropAllowed : this.dropNotAllowed
20378 notifyOut : function(dd, e, data)
20380 this.fireEvent('out', dd, e, data);
20381 if(this.overClass){
20382 this.el.removeClass(this.overClass);
20389 notifyDrop : function(dd, e, data)
20391 this.success = false;
20392 this.fireEvent('drop', dd, e, data);
20393 return this.success;
20397 * Ext JS Library 1.1.1
20398 * Copyright(c) 2006-2007, Ext JS, LLC.
20400 * Originally Released Under LGPL - original licence link has changed is not relivant.
20403 * <script type="text/javascript">
20408 * @class Roo.dd.DragZone
20409 * @extends Roo.dd.DragSource
20410 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20411 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20413 * @param {String/HTMLElement/Element} el The container element
20414 * @param {Object} config
20416 Roo.dd.DragZone = function(el, config){
20417 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20418 if(this.containerScroll){
20419 Roo.dd.ScrollManager.register(this.el);
20423 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20425 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20426 * for auto scrolling during drag operations.
20429 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20430 * method after a failed drop (defaults to "c3daf9" - light blue)
20434 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20435 * for a valid target to drag based on the mouse down. Override this method
20436 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20437 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20438 * @param {EventObject} e The mouse down event
20439 * @return {Object} The dragData
20441 getDragData : function(e){
20442 return Roo.dd.Registry.getHandleFromEvent(e);
20446 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20447 * this.dragData.ddel
20448 * @param {Number} x The x position of the click on the dragged object
20449 * @param {Number} y The y position of the click on the dragged object
20450 * @return {Boolean} true to continue the drag, false to cancel
20452 onInitDrag : function(x, y){
20453 this.proxy.update(this.dragData.ddel.cloneNode(true));
20454 this.onStartDrag(x, y);
20459 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20461 afterRepair : function(){
20463 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20465 this.dragging = false;
20469 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20470 * the XY of this.dragData.ddel
20471 * @param {EventObject} e The mouse up event
20472 * @return {Array} The xy location (e.g. [100, 200])
20474 getRepairXY : function(e){
20475 return Roo.Element.fly(this.dragData.ddel).getXY();
20479 * Ext JS Library 1.1.1
20480 * Copyright(c) 2006-2007, Ext JS, LLC.
20482 * Originally Released Under LGPL - original licence link has changed is not relivant.
20485 * <script type="text/javascript">
20488 * @class Roo.dd.DropZone
20489 * @extends Roo.dd.DropTarget
20490 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20491 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20493 * @param {String/HTMLElement/Element} el The container element
20494 * @param {Object} config
20496 Roo.dd.DropZone = function(el, config){
20497 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20500 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20502 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20503 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20504 * provide your own custom lookup.
20505 * @param {Event} e The event
20506 * @return {Object} data The custom data
20508 getTargetFromEvent : function(e){
20509 return Roo.dd.Registry.getTargetFromEvent(e);
20513 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20514 * that it has registered. This method has no default implementation and should be overridden to provide
20515 * node-specific processing if necessary.
20516 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20517 * {@link #getTargetFromEvent} for this node)
20518 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20519 * @param {Event} e The event
20520 * @param {Object} data An object containing arbitrary data supplied by the drag source
20522 onNodeEnter : function(n, dd, e, data){
20527 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20528 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20529 * overridden to provide the proper feedback.
20530 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20531 * {@link #getTargetFromEvent} for this node)
20532 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20533 * @param {Event} e The event
20534 * @param {Object} data An object containing arbitrary data supplied by the drag source
20535 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20536 * underlying {@link Roo.dd.StatusProxy} can be updated
20538 onNodeOver : function(n, dd, e, data){
20539 return this.dropAllowed;
20543 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20544 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20545 * node-specific processing if necessary.
20546 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20547 * {@link #getTargetFromEvent} for this node)
20548 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20549 * @param {Event} e The event
20550 * @param {Object} data An object containing arbitrary data supplied by the drag source
20552 onNodeOut : function(n, dd, e, data){
20557 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20558 * the drop node. The default implementation returns false, so it should be overridden to provide the
20559 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20560 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20561 * {@link #getTargetFromEvent} for this node)
20562 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20563 * @param {Event} e The event
20564 * @param {Object} data An object containing arbitrary data supplied by the drag source
20565 * @return {Boolean} True if the drop was valid, else false
20567 onNodeDrop : function(n, dd, e, data){
20572 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20573 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20574 * it should be overridden to provide the proper feedback if necessary.
20575 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20576 * @param {Event} e The event
20577 * @param {Object} data An object containing arbitrary data supplied by the drag source
20578 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20579 * underlying {@link Roo.dd.StatusProxy} can be updated
20581 onContainerOver : function(dd, e, data){
20582 return this.dropNotAllowed;
20586 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20587 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20588 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20589 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20590 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20591 * @param {Event} e The event
20592 * @param {Object} data An object containing arbitrary data supplied by the drag source
20593 * @return {Boolean} True if the drop was valid, else false
20595 onContainerDrop : function(dd, e, data){
20600 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20601 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20602 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20603 * you should override this method and provide a custom implementation.
20604 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20605 * @param {Event} e The event
20606 * @param {Object} data An object containing arbitrary data supplied by the drag source
20607 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20608 * underlying {@link Roo.dd.StatusProxy} can be updated
20610 notifyEnter : function(dd, e, data){
20611 return this.dropNotAllowed;
20615 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20616 * This method will be called on every mouse movement while the drag source is over the drop zone.
20617 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20618 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20619 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20620 * registered node, it will call {@link #onContainerOver}.
20621 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20622 * @param {Event} e The event
20623 * @param {Object} data An object containing arbitrary data supplied by the drag source
20624 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20625 * underlying {@link Roo.dd.StatusProxy} can be updated
20627 notifyOver : function(dd, e, data){
20628 var n = this.getTargetFromEvent(e);
20629 if(!n){ // not over valid drop target
20630 if(this.lastOverNode){
20631 this.onNodeOut(this.lastOverNode, dd, e, data);
20632 this.lastOverNode = null;
20634 return this.onContainerOver(dd, e, data);
20636 if(this.lastOverNode != n){
20637 if(this.lastOverNode){
20638 this.onNodeOut(this.lastOverNode, dd, e, data);
20640 this.onNodeEnter(n, dd, e, data);
20641 this.lastOverNode = n;
20643 return this.onNodeOver(n, dd, e, data);
20647 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20648 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20649 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20650 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20651 * @param {Event} e The event
20652 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20654 notifyOut : function(dd, e, data){
20655 if(this.lastOverNode){
20656 this.onNodeOut(this.lastOverNode, dd, e, data);
20657 this.lastOverNode = null;
20662 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20663 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20664 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20665 * otherwise it will call {@link #onContainerDrop}.
20666 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20667 * @param {Event} e The event
20668 * @param {Object} data An object containing arbitrary data supplied by the drag source
20669 * @return {Boolean} True if the drop was valid, else false
20671 notifyDrop : function(dd, e, data){
20672 if(this.lastOverNode){
20673 this.onNodeOut(this.lastOverNode, dd, e, data);
20674 this.lastOverNode = null;
20676 var n = this.getTargetFromEvent(e);
20678 this.onNodeDrop(n, dd, e, data) :
20679 this.onContainerDrop(dd, e, data);
20683 triggerCacheRefresh : function(){
20684 Roo.dd.DDM.refreshCache(this.groups);
20688 * Ext JS Library 1.1.1
20689 * Copyright(c) 2006-2007, Ext JS, LLC.
20691 * Originally Released Under LGPL - original licence link has changed is not relivant.
20694 * <script type="text/javascript">
20699 * @class Roo.data.SortTypes
20701 * Defines the default sorting (casting?) comparison functions used when sorting data.
20703 Roo.data.SortTypes = {
20705 * Default sort that does nothing
20706 * @param {Mixed} s The value being converted
20707 * @return {Mixed} The comparison value
20709 none : function(s){
20714 * The regular expression used to strip tags
20718 stripTagsRE : /<\/?[^>]+>/gi,
20721 * Strips all HTML tags to sort on text only
20722 * @param {Mixed} s The value being converted
20723 * @return {String} The comparison value
20725 asText : function(s){
20726 return String(s).replace(this.stripTagsRE, "");
20730 * Strips all HTML tags to sort on text only - Case insensitive
20731 * @param {Mixed} s The value being converted
20732 * @return {String} The comparison value
20734 asUCText : function(s){
20735 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20739 * Case insensitive string
20740 * @param {Mixed} s The value being converted
20741 * @return {String} The comparison value
20743 asUCString : function(s) {
20744 return String(s).toUpperCase();
20749 * @param {Mixed} s The value being converted
20750 * @return {Number} The comparison value
20752 asDate : function(s) {
20756 if(s instanceof Date){
20757 return s.getTime();
20759 return Date.parse(String(s));
20764 * @param {Mixed} s The value being converted
20765 * @return {Float} The comparison value
20767 asFloat : function(s) {
20768 var val = parseFloat(String(s).replace(/,/g, ""));
20769 if(isNaN(val)) val = 0;
20775 * @param {Mixed} s The value being converted
20776 * @return {Number} The comparison value
20778 asInt : function(s) {
20779 var val = parseInt(String(s).replace(/,/g, ""));
20780 if(isNaN(val)) val = 0;
20785 * Ext JS Library 1.1.1
20786 * Copyright(c) 2006-2007, Ext JS, LLC.
20788 * Originally Released Under LGPL - original licence link has changed is not relivant.
20791 * <script type="text/javascript">
20795 * @class Roo.data.Record
20796 * Instances of this class encapsulate both record <em>definition</em> information, and record
20797 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20798 * to access Records cached in an {@link Roo.data.Store} object.<br>
20800 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20801 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20804 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20806 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20807 * {@link #create}. The parameters are the same.
20808 * @param {Array} data An associative Array of data values keyed by the field name.
20809 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20810 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20811 * not specified an integer id is generated.
20813 Roo.data.Record = function(data, id){
20814 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20819 * Generate a constructor for a specific record layout.
20820 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20821 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20822 * Each field definition object may contain the following properties: <ul>
20823 * <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,
20824 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20825 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20826 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20827 * is being used, then this is a string containing the javascript expression to reference the data relative to
20828 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20829 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20830 * this may be omitted.</p></li>
20831 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20832 * <ul><li>auto (Default, implies no conversion)</li>
20837 * <li>date</li></ul></p></li>
20838 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20839 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20840 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20841 * by the Reader into an object that will be stored in the Record. It is passed the
20842 * following parameters:<ul>
20843 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20845 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20847 * <br>usage:<br><pre><code>
20848 var TopicRecord = Roo.data.Record.create(
20849 {name: 'title', mapping: 'topic_title'},
20850 {name: 'author', mapping: 'username'},
20851 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20852 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20853 {name: 'lastPoster', mapping: 'user2'},
20854 {name: 'excerpt', mapping: 'post_text'}
20857 var myNewRecord = new TopicRecord({
20858 title: 'Do my job please',
20861 lastPost: new Date(),
20862 lastPoster: 'Animal',
20863 excerpt: 'No way dude!'
20865 myStore.add(myNewRecord);
20870 Roo.data.Record.create = function(o){
20871 var f = function(){
20872 f.superclass.constructor.apply(this, arguments);
20874 Roo.extend(f, Roo.data.Record);
20875 var p = f.prototype;
20876 p.fields = new Roo.util.MixedCollection(false, function(field){
20879 for(var i = 0, len = o.length; i < len; i++){
20880 p.fields.add(new Roo.data.Field(o[i]));
20882 f.getField = function(name){
20883 return p.fields.get(name);
20888 Roo.data.Record.AUTO_ID = 1000;
20889 Roo.data.Record.EDIT = 'edit';
20890 Roo.data.Record.REJECT = 'reject';
20891 Roo.data.Record.COMMIT = 'commit';
20893 Roo.data.Record.prototype = {
20895 * Readonly flag - true if this record has been modified.
20904 join : function(store){
20905 this.store = store;
20909 * Set the named field to the specified value.
20910 * @param {String} name The name of the field to set.
20911 * @param {Object} value The value to set the field to.
20913 set : function(name, value){
20914 if(this.data[name] == value){
20918 if(!this.modified){
20919 this.modified = {};
20921 if(typeof this.modified[name] == 'undefined'){
20922 this.modified[name] = this.data[name];
20924 this.data[name] = value;
20925 if(!this.editing && this.store){
20926 this.store.afterEdit(this);
20931 * Get the value of the named field.
20932 * @param {String} name The name of the field to get the value of.
20933 * @return {Object} The value of the field.
20935 get : function(name){
20936 return this.data[name];
20940 beginEdit : function(){
20941 this.editing = true;
20942 this.modified = {};
20946 cancelEdit : function(){
20947 this.editing = false;
20948 delete this.modified;
20952 endEdit : function(){
20953 this.editing = false;
20954 if(this.dirty && this.store){
20955 this.store.afterEdit(this);
20960 * Usually called by the {@link Roo.data.Store} which owns the Record.
20961 * Rejects all changes made to the Record since either creation, or the last commit operation.
20962 * Modified fields are reverted to their original values.
20964 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20965 * of reject operations.
20967 reject : function(){
20968 var m = this.modified;
20970 if(typeof m[n] != "function"){
20971 this.data[n] = m[n];
20974 this.dirty = false;
20975 delete this.modified;
20976 this.editing = false;
20978 this.store.afterReject(this);
20983 * Usually called by the {@link Roo.data.Store} which owns the Record.
20984 * Commits all changes made to the Record since either creation, or the last commit operation.
20986 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20987 * of commit operations.
20989 commit : function(){
20990 this.dirty = false;
20991 delete this.modified;
20992 this.editing = false;
20994 this.store.afterCommit(this);
20999 hasError : function(){
21000 return this.error != null;
21004 clearError : function(){
21009 * Creates a copy of this record.
21010 * @param {String} id (optional) A new record id if you don't want to use this record's id
21013 copy : function(newId) {
21014 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21018 * Ext JS Library 1.1.1
21019 * Copyright(c) 2006-2007, Ext JS, LLC.
21021 * Originally Released Under LGPL - original licence link has changed is not relivant.
21024 * <script type="text/javascript">
21030 * @class Roo.data.Store
21031 * @extends Roo.util.Observable
21032 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21033 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21035 * 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
21036 * has no knowledge of the format of the data returned by the Proxy.<br>
21038 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21039 * instances from the data object. These records are cached and made available through accessor functions.
21041 * Creates a new Store.
21042 * @param {Object} config A config object containing the objects needed for the Store to access data,
21043 * and read the data into Records.
21045 Roo.data.Store = function(config){
21046 this.data = new Roo.util.MixedCollection(false);
21047 this.data.getKey = function(o){
21050 this.baseParams = {};
21052 this.paramNames = {
21057 "multisort" : "_multisort"
21060 if(config && config.data){
21061 this.inlineData = config.data;
21062 delete config.data;
21065 Roo.apply(this, config);
21067 if(this.reader){ // reader passed
21068 this.reader = Roo.factory(this.reader, Roo.data);
21069 this.reader.xmodule = this.xmodule || false;
21070 if(!this.recordType){
21071 this.recordType = this.reader.recordType;
21073 if(this.reader.onMetaChange){
21074 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21078 if(this.recordType){
21079 this.fields = this.recordType.prototype.fields;
21081 this.modified = [];
21085 * @event datachanged
21086 * Fires when the data cache has changed, and a widget which is using this Store
21087 * as a Record cache should refresh its view.
21088 * @param {Store} this
21090 datachanged : true,
21092 * @event metachange
21093 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21094 * @param {Store} this
21095 * @param {Object} meta The JSON metadata
21100 * Fires when Records have been added to the Store
21101 * @param {Store} this
21102 * @param {Roo.data.Record[]} records The array of Records added
21103 * @param {Number} index The index at which the record(s) were added
21108 * Fires when a Record has been removed from the Store
21109 * @param {Store} this
21110 * @param {Roo.data.Record} record The Record that was removed
21111 * @param {Number} index The index at which the record was removed
21116 * Fires when a Record has been updated
21117 * @param {Store} this
21118 * @param {Roo.data.Record} record The Record that was updated
21119 * @param {String} operation The update operation being performed. Value may be one of:
21121 Roo.data.Record.EDIT
21122 Roo.data.Record.REJECT
21123 Roo.data.Record.COMMIT
21129 * Fires when the data cache has been cleared.
21130 * @param {Store} this
21134 * @event beforeload
21135 * Fires before a request is made for a new data object. If the beforeload handler returns false
21136 * the load action will be canceled.
21137 * @param {Store} this
21138 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21142 * @event beforeloadadd
21143 * Fires after a new set of Records has been loaded.
21144 * @param {Store} this
21145 * @param {Roo.data.Record[]} records The Records that were loaded
21146 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21148 beforeloadadd : true,
21151 * Fires after a new set of Records has been loaded, before they are added to the store.
21152 * @param {Store} this
21153 * @param {Roo.data.Record[]} records The Records that were loaded
21154 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21155 * @params {Object} return from reader
21159 * @event loadexception
21160 * Fires if an exception occurs in the Proxy during loading.
21161 * Called with the signature of the Proxy's "loadexception" event.
21162 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21165 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21166 * @param {Object} load options
21167 * @param {Object} jsonData from your request (normally this contains the Exception)
21169 loadexception : true
21173 this.proxy = Roo.factory(this.proxy, Roo.data);
21174 this.proxy.xmodule = this.xmodule || false;
21175 this.relayEvents(this.proxy, ["loadexception"]);
21177 this.sortToggle = {};
21178 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21180 Roo.data.Store.superclass.constructor.call(this);
21182 if(this.inlineData){
21183 this.loadData(this.inlineData);
21184 delete this.inlineData;
21188 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21190 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21191 * without a remote query - used by combo/forms at present.
21195 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21198 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21201 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21202 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21205 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21206 * on any HTTP request
21209 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21212 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21216 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21217 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21219 remoteSort : false,
21222 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21223 * loaded or when a record is removed. (defaults to false).
21225 pruneModifiedRecords : false,
21228 lastOptions : null,
21231 * Add Records to the Store and fires the add event.
21232 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21234 add : function(records){
21235 records = [].concat(records);
21236 for(var i = 0, len = records.length; i < len; i++){
21237 records[i].join(this);
21239 var index = this.data.length;
21240 this.data.addAll(records);
21241 this.fireEvent("add", this, records, index);
21245 * Remove a Record from the Store and fires the remove event.
21246 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21248 remove : function(record){
21249 var index = this.data.indexOf(record);
21250 this.data.removeAt(index);
21251 if(this.pruneModifiedRecords){
21252 this.modified.remove(record);
21254 this.fireEvent("remove", this, record, index);
21258 * Remove all Records from the Store and fires the clear event.
21260 removeAll : function(){
21262 if(this.pruneModifiedRecords){
21263 this.modified = [];
21265 this.fireEvent("clear", this);
21269 * Inserts Records to the Store at the given index and fires the add event.
21270 * @param {Number} index The start index at which to insert the passed Records.
21271 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21273 insert : function(index, records){
21274 records = [].concat(records);
21275 for(var i = 0, len = records.length; i < len; i++){
21276 this.data.insert(index, records[i]);
21277 records[i].join(this);
21279 this.fireEvent("add", this, records, index);
21283 * Get the index within the cache of the passed Record.
21284 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21285 * @return {Number} The index of the passed Record. Returns -1 if not found.
21287 indexOf : function(record){
21288 return this.data.indexOf(record);
21292 * Get the index within the cache of the Record with the passed id.
21293 * @param {String} id The id of the Record to find.
21294 * @return {Number} The index of the Record. Returns -1 if not found.
21296 indexOfId : function(id){
21297 return this.data.indexOfKey(id);
21301 * Get the Record with the specified id.
21302 * @param {String} id The id of the Record to find.
21303 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21305 getById : function(id){
21306 return this.data.key(id);
21310 * Get the Record at the specified index.
21311 * @param {Number} index The index of the Record to find.
21312 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21314 getAt : function(index){
21315 return this.data.itemAt(index);
21319 * Returns a range of Records between specified indices.
21320 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21321 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21322 * @return {Roo.data.Record[]} An array of Records
21324 getRange : function(start, end){
21325 return this.data.getRange(start, end);
21329 storeOptions : function(o){
21330 o = Roo.apply({}, o);
21333 this.lastOptions = o;
21337 * Loads the Record cache from the configured Proxy using the configured Reader.
21339 * If using remote paging, then the first load call must specify the <em>start</em>
21340 * and <em>limit</em> properties in the options.params property to establish the initial
21341 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21343 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21344 * and this call will return before the new data has been loaded. Perform any post-processing
21345 * in a callback function, or in a "load" event handler.</strong>
21347 * @param {Object} options An object containing properties which control loading options:<ul>
21348 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21349 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21350 * passed the following arguments:<ul>
21351 * <li>r : Roo.data.Record[]</li>
21352 * <li>options: Options object from the load call</li>
21353 * <li>success: Boolean success indicator</li></ul></li>
21354 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21355 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21358 load : function(options){
21359 options = options || {};
21360 if(this.fireEvent("beforeload", this, options) !== false){
21361 this.storeOptions(options);
21362 var p = Roo.apply(options.params || {}, this.baseParams);
21363 // if meta was not loaded from remote source.. try requesting it.
21364 if (!this.reader.metaFromRemote) {
21365 p._requestMeta = 1;
21367 if(this.sortInfo && this.remoteSort){
21368 var pn = this.paramNames;
21369 p[pn["sort"]] = this.sortInfo.field;
21370 p[pn["dir"]] = this.sortInfo.direction;
21372 if (this.multiSort) {
21373 var pn = this.paramNames;
21374 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21377 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21382 * Reloads the Record cache from the configured Proxy using the configured Reader and
21383 * the options from the last load operation performed.
21384 * @param {Object} options (optional) An object containing properties which may override the options
21385 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21386 * the most recently used options are reused).
21388 reload : function(options){
21389 this.load(Roo.applyIf(options||{}, this.lastOptions));
21393 // Called as a callback by the Reader during a load operation.
21394 loadRecords : function(o, options, success){
21395 if(!o || success === false){
21396 if(success !== false){
21397 this.fireEvent("load", this, [], options, o);
21399 if(options.callback){
21400 options.callback.call(options.scope || this, [], options, false);
21404 // if data returned failure - throw an exception.
21405 if (o.success === false) {
21406 // show a message if no listener is registered.
21407 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21408 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21410 // loadmask wil be hooked into this..
21411 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21414 var r = o.records, t = o.totalRecords || r.length;
21416 this.fireEvent("beforeloadadd", this, r, options, o);
21418 if(!options || options.add !== true){
21419 if(this.pruneModifiedRecords){
21420 this.modified = [];
21422 for(var i = 0, len = r.length; i < len; i++){
21426 this.data = this.snapshot;
21427 delete this.snapshot;
21430 this.data.addAll(r);
21431 this.totalLength = t;
21433 this.fireEvent("datachanged", this);
21435 this.totalLength = Math.max(t, this.data.length+r.length);
21438 this.fireEvent("load", this, r, options, o);
21439 if(options.callback){
21440 options.callback.call(options.scope || this, r, options, true);
21446 * Loads data from a passed data block. A Reader which understands the format of the data
21447 * must have been configured in the constructor.
21448 * @param {Object} data The data block from which to read the Records. The format of the data expected
21449 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21450 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21452 loadData : function(o, append){
21453 var r = this.reader.readRecords(o);
21454 this.loadRecords(r, {add: append}, true);
21458 * Gets the number of cached records.
21460 * <em>If using paging, this may not be the total size of the dataset. If the data object
21461 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21462 * the data set size</em>
21464 getCount : function(){
21465 return this.data.length || 0;
21469 * Gets the total number of records in the dataset as returned by the server.
21471 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21472 * the dataset size</em>
21474 getTotalCount : function(){
21475 return this.totalLength || 0;
21479 * Returns the sort state of the Store as an object with two properties:
21481 field {String} The name of the field by which the Records are sorted
21482 direction {String} The sort order, "ASC" or "DESC"
21485 getSortState : function(){
21486 return this.sortInfo;
21490 applySort : function(){
21491 if(this.sortInfo && !this.remoteSort){
21492 var s = this.sortInfo, f = s.field;
21493 var st = this.fields.get(f).sortType;
21494 var fn = function(r1, r2){
21495 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21496 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21498 this.data.sort(s.direction, fn);
21499 if(this.snapshot && this.snapshot != this.data){
21500 this.snapshot.sort(s.direction, fn);
21506 * Sets the default sort column and order to be used by the next load operation.
21507 * @param {String} fieldName The name of the field to sort by.
21508 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21510 setDefaultSort : function(field, dir){
21511 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21515 * Sort the Records.
21516 * If remote sorting is used, the sort is performed on the server, and the cache is
21517 * reloaded. If local sorting is used, the cache is sorted internally.
21518 * @param {String} fieldName The name of the field to sort by.
21519 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21521 sort : function(fieldName, dir){
21522 var f = this.fields.get(fieldName);
21524 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21526 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21527 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21532 this.sortToggle[f.name] = dir;
21533 this.sortInfo = {field: f.name, direction: dir};
21534 if(!this.remoteSort){
21536 this.fireEvent("datachanged", this);
21538 this.load(this.lastOptions);
21543 * Calls the specified function for each of the Records in the cache.
21544 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21545 * Returning <em>false</em> aborts and exits the iteration.
21546 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21548 each : function(fn, scope){
21549 this.data.each(fn, scope);
21553 * Gets all records modified since the last commit. Modified records are persisted across load operations
21554 * (e.g., during paging).
21555 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21557 getModifiedRecords : function(){
21558 return this.modified;
21562 createFilterFn : function(property, value, anyMatch){
21563 if(!value.exec){ // not a regex
21564 value = String(value);
21565 if(value.length == 0){
21568 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21570 return function(r){
21571 return value.test(r.data[property]);
21576 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21577 * @param {String} property A field on your records
21578 * @param {Number} start The record index to start at (defaults to 0)
21579 * @param {Number} end The last record index to include (defaults to length - 1)
21580 * @return {Number} The sum
21582 sum : function(property, start, end){
21583 var rs = this.data.items, v = 0;
21584 start = start || 0;
21585 end = (end || end === 0) ? end : rs.length-1;
21587 for(var i = start; i <= end; i++){
21588 v += (rs[i].data[property] || 0);
21594 * Filter the records by a specified property.
21595 * @param {String} field A field on your records
21596 * @param {String/RegExp} value Either a string that the field
21597 * should start with or a RegExp to test against the field
21598 * @param {Boolean} anyMatch True to match any part not just the beginning
21600 filter : function(property, value, anyMatch){
21601 var fn = this.createFilterFn(property, value, anyMatch);
21602 return fn ? this.filterBy(fn) : this.clearFilter();
21606 * Filter by a function. The specified function will be called with each
21607 * record in this data source. If the function returns true the record is included,
21608 * otherwise it is filtered.
21609 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21610 * @param {Object} scope (optional) The scope of the function (defaults to this)
21612 filterBy : function(fn, scope){
21613 this.snapshot = this.snapshot || this.data;
21614 this.data = this.queryBy(fn, scope||this);
21615 this.fireEvent("datachanged", this);
21619 * Query the records by a specified property.
21620 * @param {String} field A field on your records
21621 * @param {String/RegExp} value Either a string that the field
21622 * should start with or a RegExp to test against the field
21623 * @param {Boolean} anyMatch True to match any part not just the beginning
21624 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21626 query : function(property, value, anyMatch){
21627 var fn = this.createFilterFn(property, value, anyMatch);
21628 return fn ? this.queryBy(fn) : this.data.clone();
21632 * Query by a function. The specified function will be called with each
21633 * record in this data source. If the function returns true the record is included
21635 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21636 * @param {Object} scope (optional) The scope of the function (defaults to this)
21637 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21639 queryBy : function(fn, scope){
21640 var data = this.snapshot || this.data;
21641 return data.filterBy(fn, scope||this);
21645 * Collects unique values for a particular dataIndex from this store.
21646 * @param {String} dataIndex The property to collect
21647 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21648 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21649 * @return {Array} An array of the unique values
21651 collect : function(dataIndex, allowNull, bypassFilter){
21652 var d = (bypassFilter === true && this.snapshot) ?
21653 this.snapshot.items : this.data.items;
21654 var v, sv, r = [], l = {};
21655 for(var i = 0, len = d.length; i < len; i++){
21656 v = d[i].data[dataIndex];
21658 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21667 * Revert to a view of the Record cache with no filtering applied.
21668 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21670 clearFilter : function(suppressEvent){
21671 if(this.snapshot && this.snapshot != this.data){
21672 this.data = this.snapshot;
21673 delete this.snapshot;
21674 if(suppressEvent !== true){
21675 this.fireEvent("datachanged", this);
21681 afterEdit : function(record){
21682 if(this.modified.indexOf(record) == -1){
21683 this.modified.push(record);
21685 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21689 afterReject : function(record){
21690 this.modified.remove(record);
21691 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21695 afterCommit : function(record){
21696 this.modified.remove(record);
21697 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21701 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21702 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21704 commitChanges : function(){
21705 var m = this.modified.slice(0);
21706 this.modified = [];
21707 for(var i = 0, len = m.length; i < len; i++){
21713 * Cancel outstanding changes on all changed records.
21715 rejectChanges : function(){
21716 var m = this.modified.slice(0);
21717 this.modified = [];
21718 for(var i = 0, len = m.length; i < len; i++){
21723 onMetaChange : function(meta, rtype, o){
21724 this.recordType = rtype;
21725 this.fields = rtype.prototype.fields;
21726 delete this.snapshot;
21727 this.sortInfo = meta.sortInfo || this.sortInfo;
21728 this.modified = [];
21729 this.fireEvent('metachange', this, this.reader.meta);
21733 * Ext JS Library 1.1.1
21734 * Copyright(c) 2006-2007, Ext JS, LLC.
21736 * Originally Released Under LGPL - original licence link has changed is not relivant.
21739 * <script type="text/javascript">
21743 * @class Roo.data.SimpleStore
21744 * @extends Roo.data.Store
21745 * Small helper class to make creating Stores from Array data easier.
21746 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21747 * @cfg {Array} fields An array of field definition objects, or field name strings.
21748 * @cfg {Array} data The multi-dimensional array of data
21750 * @param {Object} config
21752 Roo.data.SimpleStore = function(config){
21753 Roo.data.SimpleStore.superclass.constructor.call(this, {
21755 reader: new Roo.data.ArrayReader({
21758 Roo.data.Record.create(config.fields)
21760 proxy : new Roo.data.MemoryProxy(config.data)
21764 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21766 * Ext JS Library 1.1.1
21767 * Copyright(c) 2006-2007, Ext JS, LLC.
21769 * Originally Released Under LGPL - original licence link has changed is not relivant.
21772 * <script type="text/javascript">
21777 * @extends Roo.data.Store
21778 * @class Roo.data.JsonStore
21779 * Small helper class to make creating Stores for JSON data easier. <br/>
21781 var store = new Roo.data.JsonStore({
21782 url: 'get-images.php',
21784 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21787 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21788 * JsonReader and HttpProxy (unless inline data is provided).</b>
21789 * @cfg {Array} fields An array of field definition objects, or field name strings.
21791 * @param {Object} config
21793 Roo.data.JsonStore = function(c){
21794 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21795 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21796 reader: new Roo.data.JsonReader(c, c.fields)
21799 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21801 * Ext JS Library 1.1.1
21802 * Copyright(c) 2006-2007, Ext JS, LLC.
21804 * Originally Released Under LGPL - original licence link has changed is not relivant.
21807 * <script type="text/javascript">
21811 Roo.data.Field = function(config){
21812 if(typeof config == "string"){
21813 config = {name: config};
21815 Roo.apply(this, config);
21818 this.type = "auto";
21821 var st = Roo.data.SortTypes;
21822 // named sortTypes are supported, here we look them up
21823 if(typeof this.sortType == "string"){
21824 this.sortType = st[this.sortType];
21827 // set default sortType for strings and dates
21828 if(!this.sortType){
21831 this.sortType = st.asUCString;
21834 this.sortType = st.asDate;
21837 this.sortType = st.none;
21842 var stripRe = /[\$,%]/g;
21844 // prebuilt conversion function for this field, instead of
21845 // switching every time we're reading a value
21847 var cv, dateFormat = this.dateFormat;
21852 cv = function(v){ return v; };
21855 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
21859 return v !== undefined && v !== null && v !== '' ?
21860 parseInt(String(v).replace(stripRe, ""), 10) : '';
21865 return v !== undefined && v !== null && v !== '' ?
21866 parseFloat(String(v).replace(stripRe, ""), 10) : '';
21871 cv = function(v){ return v === true || v === "true" || v == 1; };
21878 if(v instanceof Date){
21882 if(dateFormat == "timestamp"){
21883 return new Date(v*1000);
21885 return Date.parseDate(v, dateFormat);
21887 var parsed = Date.parse(v);
21888 return parsed ? new Date(parsed) : null;
21897 Roo.data.Field.prototype = {
21905 * Ext JS Library 1.1.1
21906 * Copyright(c) 2006-2007, Ext JS, LLC.
21908 * Originally Released Under LGPL - original licence link has changed is not relivant.
21911 * <script type="text/javascript">
21914 // Base class for reading structured data from a data source. This class is intended to be
21915 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
21918 * @class Roo.data.DataReader
21919 * Base class for reading structured data from a data source. This class is intended to be
21920 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
21923 Roo.data.DataReader = function(meta, recordType){
21927 this.recordType = recordType instanceof Array ?
21928 Roo.data.Record.create(recordType) : recordType;
21931 Roo.data.DataReader.prototype = {
21933 * Create an empty record
21934 * @param {Object} data (optional) - overlay some values
21935 * @return {Roo.data.Record} record created.
21937 newRow : function(d) {
21939 this.recordType.prototype.fields.each(function(c) {
21941 case 'int' : da[c.name] = 0; break;
21942 case 'date' : da[c.name] = new Date(); break;
21943 case 'float' : da[c.name] = 0.0; break;
21944 case 'boolean' : da[c.name] = false; break;
21945 default : da[c.name] = ""; break;
21949 return new this.recordType(Roo.apply(da, d));
21954 * Ext JS Library 1.1.1
21955 * Copyright(c) 2006-2007, Ext JS, LLC.
21957 * Originally Released Under LGPL - original licence link has changed is not relivant.
21960 * <script type="text/javascript">
21964 * @class Roo.data.DataProxy
21965 * @extends Roo.data.Observable
21966 * This class is an abstract base class for implementations which provide retrieval of
21967 * unformatted data objects.<br>
21969 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
21970 * (of the appropriate type which knows how to parse the data object) to provide a block of
21971 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
21973 * Custom implementations must implement the load method as described in
21974 * {@link Roo.data.HttpProxy#load}.
21976 Roo.data.DataProxy = function(){
21979 * @event beforeload
21980 * Fires before a network request is made to retrieve a data object.
21981 * @param {Object} This DataProxy object.
21982 * @param {Object} params The params parameter to the load function.
21987 * Fires before the load method's callback is called.
21988 * @param {Object} This DataProxy object.
21989 * @param {Object} o The data object.
21990 * @param {Object} arg The callback argument object passed to the load function.
21994 * @event loadexception
21995 * Fires if an Exception occurs during data retrieval.
21996 * @param {Object} This DataProxy object.
21997 * @param {Object} o The data object.
21998 * @param {Object} arg The callback argument object passed to the load function.
21999 * @param {Object} e The Exception.
22001 loadexception : true
22003 Roo.data.DataProxy.superclass.constructor.call(this);
22006 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22009 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22013 * Ext JS Library 1.1.1
22014 * Copyright(c) 2006-2007, Ext JS, LLC.
22016 * Originally Released Under LGPL - original licence link has changed is not relivant.
22019 * <script type="text/javascript">
22022 * @class Roo.data.MemoryProxy
22023 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22024 * to the Reader when its load method is called.
22026 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22028 Roo.data.MemoryProxy = function(data){
22032 Roo.data.MemoryProxy.superclass.constructor.call(this);
22036 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22038 * Load data from the requested source (in this case an in-memory
22039 * data object passed to the constructor), read the data object into
22040 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22041 * process that block using the passed callback.
22042 * @param {Object} params This parameter is not used by the MemoryProxy class.
22043 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22044 * object into a block of Roo.data.Records.
22045 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22046 * The function must be passed <ul>
22047 * <li>The Record block object</li>
22048 * <li>The "arg" argument from the load function</li>
22049 * <li>A boolean success indicator</li>
22051 * @param {Object} scope The scope in which to call the callback
22052 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22054 load : function(params, reader, callback, scope, arg){
22055 params = params || {};
22058 result = reader.readRecords(this.data);
22060 this.fireEvent("loadexception", this, arg, null, e);
22061 callback.call(scope, null, arg, false);
22064 callback.call(scope, result, arg, true);
22068 update : function(params, records){
22073 * Ext JS Library 1.1.1
22074 * Copyright(c) 2006-2007, Ext JS, LLC.
22076 * Originally Released Under LGPL - original licence link has changed is not relivant.
22079 * <script type="text/javascript">
22082 * @class Roo.data.HttpProxy
22083 * @extends Roo.data.DataProxy
22084 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22085 * configured to reference a certain URL.<br><br>
22087 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22088 * from which the running page was served.<br><br>
22090 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22092 * Be aware that to enable the browser to parse an XML document, the server must set
22093 * the Content-Type header in the HTTP response to "text/xml".
22095 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22096 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22097 * will be used to make the request.
22099 Roo.data.HttpProxy = function(conn){
22100 Roo.data.HttpProxy.superclass.constructor.call(this);
22101 // is conn a conn config or a real conn?
22103 this.useAjax = !conn || !conn.events;
22107 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22108 // thse are take from connection...
22111 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22114 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22115 * extra parameters to each request made by this object. (defaults to undefined)
22118 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22119 * to each request made by this object. (defaults to undefined)
22122 * @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)
22125 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22128 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22134 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22138 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22139 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22140 * a finer-grained basis than the DataProxy events.
22142 getConnection : function(){
22143 return this.useAjax ? Roo.Ajax : this.conn;
22147 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22148 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22149 * process that block using the passed callback.
22150 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22151 * for the request to the remote server.
22152 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22153 * object into a block of Roo.data.Records.
22154 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22155 * The function must be passed <ul>
22156 * <li>The Record block object</li>
22157 * <li>The "arg" argument from the load function</li>
22158 * <li>A boolean success indicator</li>
22160 * @param {Object} scope The scope in which to call the callback
22161 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22163 load : function(params, reader, callback, scope, arg){
22164 if(this.fireEvent("beforeload", this, params) !== false){
22166 params : params || {},
22168 callback : callback,
22173 callback : this.loadResponse,
22177 Roo.applyIf(o, this.conn);
22178 if(this.activeRequest){
22179 Roo.Ajax.abort(this.activeRequest);
22181 this.activeRequest = Roo.Ajax.request(o);
22183 this.conn.request(o);
22186 callback.call(scope||this, null, arg, false);
22191 loadResponse : function(o, success, response){
22192 delete this.activeRequest;
22194 this.fireEvent("loadexception", this, o, response);
22195 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22200 result = o.reader.read(response);
22202 this.fireEvent("loadexception", this, o, response, e);
22203 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22207 this.fireEvent("load", this, o, o.request.arg);
22208 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22212 update : function(dataSet){
22217 updateResponse : function(dataSet){
22222 * Ext JS Library 1.1.1
22223 * Copyright(c) 2006-2007, Ext JS, LLC.
22225 * Originally Released Under LGPL - original licence link has changed is not relivant.
22228 * <script type="text/javascript">
22232 * @class Roo.data.ScriptTagProxy
22233 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22234 * other than the originating domain of the running page.<br><br>
22236 * <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
22237 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22239 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22240 * source code that is used as the source inside a <script> tag.<br><br>
22242 * In order for the browser to process the returned data, the server must wrap the data object
22243 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22244 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22245 * depending on whether the callback name was passed:
22248 boolean scriptTag = false;
22249 String cb = request.getParameter("callback");
22252 response.setContentType("text/javascript");
22254 response.setContentType("application/x-json");
22256 Writer out = response.getWriter();
22258 out.write(cb + "(");
22260 out.print(dataBlock.toJsonString());
22267 * @param {Object} config A configuration object.
22269 Roo.data.ScriptTagProxy = function(config){
22270 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22271 Roo.apply(this, config);
22272 this.head = document.getElementsByTagName("head")[0];
22275 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22277 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22279 * @cfg {String} url The URL from which to request the data object.
22282 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22286 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22287 * the server the name of the callback function set up by the load call to process the returned data object.
22288 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22289 * javascript output which calls this named function passing the data object as its only parameter.
22291 callbackParam : "callback",
22293 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22294 * name to the request.
22299 * Load data from the configured URL, read the data object into
22300 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22301 * process that block using the passed callback.
22302 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22303 * for the request to the remote server.
22304 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22305 * object into a block of Roo.data.Records.
22306 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22307 * The function must be passed <ul>
22308 * <li>The Record block object</li>
22309 * <li>The "arg" argument from the load function</li>
22310 * <li>A boolean success indicator</li>
22312 * @param {Object} scope The scope in which to call the callback
22313 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22315 load : function(params, reader, callback, scope, arg){
22316 if(this.fireEvent("beforeload", this, params) !== false){
22318 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22320 var url = this.url;
22321 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22323 url += "&_dc=" + (new Date().getTime());
22325 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22328 cb : "stcCallback"+transId,
22329 scriptId : "stcScript"+transId,
22333 callback : callback,
22339 window[trans.cb] = function(o){
22340 conn.handleResponse(o, trans);
22343 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22345 if(this.autoAbort !== false){
22349 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22351 var script = document.createElement("script");
22352 script.setAttribute("src", url);
22353 script.setAttribute("type", "text/javascript");
22354 script.setAttribute("id", trans.scriptId);
22355 this.head.appendChild(script);
22357 this.trans = trans;
22359 callback.call(scope||this, null, arg, false);
22364 isLoading : function(){
22365 return this.trans ? true : false;
22369 * Abort the current server request.
22371 abort : function(){
22372 if(this.isLoading()){
22373 this.destroyTrans(this.trans);
22378 destroyTrans : function(trans, isLoaded){
22379 this.head.removeChild(document.getElementById(trans.scriptId));
22380 clearTimeout(trans.timeoutId);
22382 window[trans.cb] = undefined;
22384 delete window[trans.cb];
22387 // if hasn't been loaded, wait for load to remove it to prevent script error
22388 window[trans.cb] = function(){
22389 window[trans.cb] = undefined;
22391 delete window[trans.cb];
22398 handleResponse : function(o, trans){
22399 this.trans = false;
22400 this.destroyTrans(trans, true);
22403 result = trans.reader.readRecords(o);
22405 this.fireEvent("loadexception", this, o, trans.arg, e);
22406 trans.callback.call(trans.scope||window, null, trans.arg, false);
22409 this.fireEvent("load", this, o, trans.arg);
22410 trans.callback.call(trans.scope||window, result, trans.arg, true);
22414 handleFailure : function(trans){
22415 this.trans = false;
22416 this.destroyTrans(trans, false);
22417 this.fireEvent("loadexception", this, null, trans.arg);
22418 trans.callback.call(trans.scope||window, null, trans.arg, false);
22422 * Ext JS Library 1.1.1
22423 * Copyright(c) 2006-2007, Ext JS, LLC.
22425 * Originally Released Under LGPL - original licence link has changed is not relivant.
22428 * <script type="text/javascript">
22432 * @class Roo.data.JsonReader
22433 * @extends Roo.data.DataReader
22434 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22435 * based on mappings in a provided Roo.data.Record constructor.
22437 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22438 * in the reply previously.
22443 var RecordDef = Roo.data.Record.create([
22444 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22445 {name: 'occupation'} // This field will use "occupation" as the mapping.
22447 var myReader = new Roo.data.JsonReader({
22448 totalProperty: "results", // The property which contains the total dataset size (optional)
22449 root: "rows", // The property which contains an Array of row objects
22450 id: "id" // The property within each row object that provides an ID for the record (optional)
22454 * This would consume a JSON file like this:
22456 { 'results': 2, 'rows': [
22457 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22458 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22461 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22462 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22463 * paged from the remote server.
22464 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22465 * @cfg {String} root name of the property which contains the Array of row objects.
22466 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22468 * Create a new JsonReader
22469 * @param {Object} meta Metadata configuration options
22470 * @param {Object} recordType Either an Array of field definition objects,
22471 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22473 Roo.data.JsonReader = function(meta, recordType){
22476 // set some defaults:
22477 Roo.applyIf(meta, {
22478 totalProperty: 'total',
22479 successProperty : 'success',
22484 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22486 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22489 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22490 * Used by Store query builder to append _requestMeta to params.
22493 metaFromRemote : false,
22495 * This method is only used by a DataProxy which has retrieved data from a remote server.
22496 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22497 * @return {Object} data A data block which is used by an Roo.data.Store object as
22498 * a cache of Roo.data.Records.
22500 read : function(response){
22501 var json = response.responseText;
22503 var o = /* eval:var:o */ eval("("+json+")");
22505 throw {message: "JsonReader.read: Json object not found"};
22511 this.metaFromRemote = true;
22512 this.meta = o.metaData;
22513 this.recordType = Roo.data.Record.create(o.metaData.fields);
22514 this.onMetaChange(this.meta, this.recordType, o);
22516 return this.readRecords(o);
22519 // private function a store will implement
22520 onMetaChange : function(meta, recordType, o){
22527 simpleAccess: function(obj, subsc) {
22534 getJsonAccessor: function(){
22536 return function(expr) {
22538 return(re.test(expr))
22539 ? new Function("obj", "return obj." + expr)
22544 return Roo.emptyFn;
22549 * Create a data block containing Roo.data.Records from an XML document.
22550 * @param {Object} o An object which contains an Array of row objects in the property specified
22551 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22552 * which contains the total size of the dataset.
22553 * @return {Object} data A data block which is used by an Roo.data.Store object as
22554 * a cache of Roo.data.Records.
22556 readRecords : function(o){
22558 * After any data loads, the raw JSON data is available for further custom processing.
22562 var s = this.meta, Record = this.recordType,
22563 f = Record.prototype.fields, fi = f.items, fl = f.length;
22565 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22567 if(s.totalProperty) {
22568 this.getTotal = this.getJsonAccessor(s.totalProperty);
22570 if(s.successProperty) {
22571 this.getSuccess = this.getJsonAccessor(s.successProperty);
22573 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22575 var g = this.getJsonAccessor(s.id);
22576 this.getId = function(rec) {
22578 return (r === undefined || r === "") ? null : r;
22581 this.getId = function(){return null;};
22584 for(var jj = 0; jj < fl; jj++){
22586 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22587 this.ef[jj] = this.getJsonAccessor(map);
22591 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22592 if(s.totalProperty){
22593 var vt = parseInt(this.getTotal(o), 10);
22598 if(s.successProperty){
22599 var vs = this.getSuccess(o);
22600 if(vs === false || vs === 'false'){
22605 for(var i = 0; i < c; i++){
22608 var id = this.getId(n);
22609 for(var j = 0; j < fl; j++){
22611 var v = this.ef[j](n);
22613 Roo.log('missing convert for ' + f.name);
22617 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22619 var record = new Record(values, id);
22621 records[i] = record;
22627 totalRecords : totalRecords
22632 * Ext JS Library 1.1.1
22633 * Copyright(c) 2006-2007, Ext JS, LLC.
22635 * Originally Released Under LGPL - original licence link has changed is not relivant.
22638 * <script type="text/javascript">
22642 * @class Roo.data.XmlReader
22643 * @extends Roo.data.DataReader
22644 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22645 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22647 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22648 * header in the HTTP response must be set to "text/xml".</em>
22652 var RecordDef = Roo.data.Record.create([
22653 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22654 {name: 'occupation'} // This field will use "occupation" as the mapping.
22656 var myReader = new Roo.data.XmlReader({
22657 totalRecords: "results", // The element which contains the total dataset size (optional)
22658 record: "row", // The repeated element which contains row information
22659 id: "id" // The element within the row that provides an ID for the record (optional)
22663 * This would consume an XML file like this:
22667 <results>2</results>
22670 <name>Bill</name>
22671 <occupation>Gardener</occupation>
22675 <name>Ben</name>
22676 <occupation>Horticulturalist</occupation>
22680 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22681 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22682 * paged from the remote server.
22683 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22684 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22685 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22686 * a record identifier value.
22688 * Create a new XmlReader
22689 * @param {Object} meta Metadata configuration options
22690 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22691 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22692 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22694 Roo.data.XmlReader = function(meta, recordType){
22696 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22698 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22700 * This method is only used by a DataProxy which has retrieved data from a remote server.
22701 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22702 * to contain a method called 'responseXML' that returns an XML document object.
22703 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22704 * a cache of Roo.data.Records.
22706 read : function(response){
22707 var doc = response.responseXML;
22709 throw {message: "XmlReader.read: XML Document not available"};
22711 return this.readRecords(doc);
22715 * Create a data block containing Roo.data.Records from an XML document.
22716 * @param {Object} doc A parsed XML document.
22717 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22718 * a cache of Roo.data.Records.
22720 readRecords : function(doc){
22722 * After any data loads/reads, the raw XML Document is available for further custom processing.
22723 * @type XMLDocument
22725 this.xmlData = doc;
22726 var root = doc.documentElement || doc;
22727 var q = Roo.DomQuery;
22728 var recordType = this.recordType, fields = recordType.prototype.fields;
22729 var sid = this.meta.id;
22730 var totalRecords = 0, success = true;
22731 if(this.meta.totalRecords){
22732 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22735 if(this.meta.success){
22736 var sv = q.selectValue(this.meta.success, root, true);
22737 success = sv !== false && sv !== 'false';
22740 var ns = q.select(this.meta.record, root);
22741 for(var i = 0, len = ns.length; i < len; i++) {
22744 var id = sid ? q.selectValue(sid, n) : undefined;
22745 for(var j = 0, jlen = fields.length; j < jlen; j++){
22746 var f = fields.items[j];
22747 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22749 values[f.name] = v;
22751 var record = new recordType(values, id);
22753 records[records.length] = record;
22759 totalRecords : totalRecords || records.length
22764 * Ext JS Library 1.1.1
22765 * Copyright(c) 2006-2007, Ext JS, LLC.
22767 * Originally Released Under LGPL - original licence link has changed is not relivant.
22770 * <script type="text/javascript">
22774 * @class Roo.data.ArrayReader
22775 * @extends Roo.data.DataReader
22776 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22777 * Each element of that Array represents a row of data fields. The
22778 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22779 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22783 var RecordDef = Roo.data.Record.create([
22784 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22785 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22787 var myReader = new Roo.data.ArrayReader({
22788 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22792 * This would consume an Array like this:
22794 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22796 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22798 * Create a new JsonReader
22799 * @param {Object} meta Metadata configuration options.
22800 * @param {Object} recordType Either an Array of field definition objects
22801 * as specified to {@link Roo.data.Record#create},
22802 * or an {@link Roo.data.Record} object
22803 * created using {@link Roo.data.Record#create}.
22805 Roo.data.ArrayReader = function(meta, recordType){
22806 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22809 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22811 * Create a data block containing Roo.data.Records from an XML document.
22812 * @param {Object} o An Array of row objects which represents the dataset.
22813 * @return {Object} data A data block which is used by an Roo.data.Store object as
22814 * a cache of Roo.data.Records.
22816 readRecords : function(o){
22817 var sid = this.meta ? this.meta.id : null;
22818 var recordType = this.recordType, fields = recordType.prototype.fields;
22821 for(var i = 0; i < root.length; i++){
22824 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22825 for(var j = 0, jlen = fields.length; j < jlen; j++){
22826 var f = fields.items[j];
22827 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22828 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22830 values[f.name] = v;
22832 var record = new recordType(values, id);
22834 records[records.length] = record;
22838 totalRecords : records.length
22843 * Ext JS Library 1.1.1
22844 * Copyright(c) 2006-2007, Ext JS, LLC.
22846 * Originally Released Under LGPL - original licence link has changed is not relivant.
22849 * <script type="text/javascript">
22854 * @class Roo.data.Tree
22855 * @extends Roo.util.Observable
22856 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
22857 * in the tree have most standard DOM functionality.
22859 * @param {Node} root (optional) The root node
22861 Roo.data.Tree = function(root){
22862 this.nodeHash = {};
22864 * The root node for this tree
22869 this.setRootNode(root);
22874 * Fires when a new child node is appended to a node in this tree.
22875 * @param {Tree} tree The owner tree
22876 * @param {Node} parent The parent node
22877 * @param {Node} node The newly appended node
22878 * @param {Number} index The index of the newly appended node
22883 * Fires when a child node is removed from a node in this tree.
22884 * @param {Tree} tree The owner tree
22885 * @param {Node} parent The parent node
22886 * @param {Node} node The child node removed
22891 * Fires when a node is moved to a new location in the tree
22892 * @param {Tree} tree The owner tree
22893 * @param {Node} node The node moved
22894 * @param {Node} oldParent The old parent of this node
22895 * @param {Node} newParent The new parent of this node
22896 * @param {Number} index The index it was moved to
22901 * Fires when a new child node is inserted in a node in this tree.
22902 * @param {Tree} tree The owner tree
22903 * @param {Node} parent The parent node
22904 * @param {Node} node The child node inserted
22905 * @param {Node} refNode The child node the node was inserted before
22909 * @event beforeappend
22910 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
22911 * @param {Tree} tree The owner tree
22912 * @param {Node} parent The parent node
22913 * @param {Node} node The child node to be appended
22915 "beforeappend" : true,
22917 * @event beforeremove
22918 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
22919 * @param {Tree} tree The owner tree
22920 * @param {Node} parent The parent node
22921 * @param {Node} node The child node to be removed
22923 "beforeremove" : true,
22925 * @event beforemove
22926 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
22927 * @param {Tree} tree The owner tree
22928 * @param {Node} node The node being moved
22929 * @param {Node} oldParent The parent of the node
22930 * @param {Node} newParent The new parent the node is moving to
22931 * @param {Number} index The index it is being moved to
22933 "beforemove" : true,
22935 * @event beforeinsert
22936 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
22937 * @param {Tree} tree The owner tree
22938 * @param {Node} parent The parent node
22939 * @param {Node} node The child node to be inserted
22940 * @param {Node} refNode The child node the node is being inserted before
22942 "beforeinsert" : true
22945 Roo.data.Tree.superclass.constructor.call(this);
22948 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
22949 pathSeparator: "/",
22951 proxyNodeEvent : function(){
22952 return this.fireEvent.apply(this, arguments);
22956 * Returns the root node for this tree.
22959 getRootNode : function(){
22964 * Sets the root node for this tree.
22965 * @param {Node} node
22968 setRootNode : function(node){
22970 node.ownerTree = this;
22971 node.isRoot = true;
22972 this.registerNode(node);
22977 * Gets a node in this tree by its id.
22978 * @param {String} id
22981 getNodeById : function(id){
22982 return this.nodeHash[id];
22985 registerNode : function(node){
22986 this.nodeHash[node.id] = node;
22989 unregisterNode : function(node){
22990 delete this.nodeHash[node.id];
22993 toString : function(){
22994 return "[Tree"+(this.id?" "+this.id:"")+"]";
22999 * @class Roo.data.Node
23000 * @extends Roo.util.Observable
23001 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23002 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23004 * @param {Object} attributes The attributes/config for the node
23006 Roo.data.Node = function(attributes){
23008 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23011 this.attributes = attributes || {};
23012 this.leaf = this.attributes.leaf;
23014 * The node id. @type String
23016 this.id = this.attributes.id;
23018 this.id = Roo.id(null, "ynode-");
23019 this.attributes.id = this.id;
23024 * All child nodes of this node. @type Array
23026 this.childNodes = [];
23027 if(!this.childNodes.indexOf){ // indexOf is a must
23028 this.childNodes.indexOf = function(o){
23029 for(var i = 0, len = this.length; i < len; i++){
23038 * The parent node for this node. @type Node
23040 this.parentNode = null;
23042 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23044 this.firstChild = null;
23046 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23048 this.lastChild = null;
23050 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23052 this.previousSibling = null;
23054 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23056 this.nextSibling = null;
23061 * Fires when a new child node is appended
23062 * @param {Tree} tree The owner tree
23063 * @param {Node} this This node
23064 * @param {Node} node The newly appended node
23065 * @param {Number} index The index of the newly appended node
23070 * Fires when a child node is removed
23071 * @param {Tree} tree The owner tree
23072 * @param {Node} this This node
23073 * @param {Node} node The removed node
23078 * Fires when this node is moved to a new location in the tree
23079 * @param {Tree} tree The owner tree
23080 * @param {Node} this This node
23081 * @param {Node} oldParent The old parent of this node
23082 * @param {Node} newParent The new parent of this node
23083 * @param {Number} index The index it was moved to
23088 * Fires when a new child node is inserted.
23089 * @param {Tree} tree The owner tree
23090 * @param {Node} this This node
23091 * @param {Node} node The child node inserted
23092 * @param {Node} refNode The child node the node was inserted before
23096 * @event beforeappend
23097 * Fires before a new child is appended, return false to cancel the append.
23098 * @param {Tree} tree The owner tree
23099 * @param {Node} this This node
23100 * @param {Node} node The child node to be appended
23102 "beforeappend" : true,
23104 * @event beforeremove
23105 * Fires before a child is removed, return false to cancel the remove.
23106 * @param {Tree} tree The owner tree
23107 * @param {Node} this This node
23108 * @param {Node} node The child node to be removed
23110 "beforeremove" : true,
23112 * @event beforemove
23113 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23114 * @param {Tree} tree The owner tree
23115 * @param {Node} this This node
23116 * @param {Node} oldParent The parent of this node
23117 * @param {Node} newParent The new parent this node is moving to
23118 * @param {Number} index The index it is being moved to
23120 "beforemove" : true,
23122 * @event beforeinsert
23123 * Fires before a new child is inserted, return false to cancel the insert.
23124 * @param {Tree} tree The owner tree
23125 * @param {Node} this This node
23126 * @param {Node} node The child node to be inserted
23127 * @param {Node} refNode The child node the node is being inserted before
23129 "beforeinsert" : true
23131 this.listeners = this.attributes.listeners;
23132 Roo.data.Node.superclass.constructor.call(this);
23135 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23136 fireEvent : function(evtName){
23137 // first do standard event for this node
23138 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23141 // then bubble it up to the tree if the event wasn't cancelled
23142 var ot = this.getOwnerTree();
23144 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23152 * Returns true if this node is a leaf
23153 * @return {Boolean}
23155 isLeaf : function(){
23156 return this.leaf === true;
23160 setFirstChild : function(node){
23161 this.firstChild = node;
23165 setLastChild : function(node){
23166 this.lastChild = node;
23171 * Returns true if this node is the last child of its parent
23172 * @return {Boolean}
23174 isLast : function(){
23175 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23179 * Returns true if this node is the first child of its parent
23180 * @return {Boolean}
23182 isFirst : function(){
23183 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23186 hasChildNodes : function(){
23187 return !this.isLeaf() && this.childNodes.length > 0;
23191 * Insert node(s) as the last child node of this node.
23192 * @param {Node/Array} node The node or Array of nodes to append
23193 * @return {Node} The appended node if single append, or null if an array was passed
23195 appendChild : function(node){
23197 if(node instanceof Array){
23199 }else if(arguments.length > 1){
23202 // if passed an array or multiple args do them one by one
23204 for(var i = 0, len = multi.length; i < len; i++) {
23205 this.appendChild(multi[i]);
23208 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23211 var index = this.childNodes.length;
23212 var oldParent = node.parentNode;
23213 // it's a move, make sure we move it cleanly
23215 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23218 oldParent.removeChild(node);
23220 index = this.childNodes.length;
23222 this.setFirstChild(node);
23224 this.childNodes.push(node);
23225 node.parentNode = this;
23226 var ps = this.childNodes[index-1];
23228 node.previousSibling = ps;
23229 ps.nextSibling = node;
23231 node.previousSibling = null;
23233 node.nextSibling = null;
23234 this.setLastChild(node);
23235 node.setOwnerTree(this.getOwnerTree());
23236 this.fireEvent("append", this.ownerTree, this, node, index);
23238 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23245 * Removes a child node from this node.
23246 * @param {Node} node The node to remove
23247 * @return {Node} The removed node
23249 removeChild : function(node){
23250 var index = this.childNodes.indexOf(node);
23254 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23258 // remove it from childNodes collection
23259 this.childNodes.splice(index, 1);
23262 if(node.previousSibling){
23263 node.previousSibling.nextSibling = node.nextSibling;
23265 if(node.nextSibling){
23266 node.nextSibling.previousSibling = node.previousSibling;
23269 // update child refs
23270 if(this.firstChild == node){
23271 this.setFirstChild(node.nextSibling);
23273 if(this.lastChild == node){
23274 this.setLastChild(node.previousSibling);
23277 node.setOwnerTree(null);
23278 // clear any references from the node
23279 node.parentNode = null;
23280 node.previousSibling = null;
23281 node.nextSibling = null;
23282 this.fireEvent("remove", this.ownerTree, this, node);
23287 * Inserts the first node before the second node in this nodes childNodes collection.
23288 * @param {Node} node The node to insert
23289 * @param {Node} refNode The node to insert before (if null the node is appended)
23290 * @return {Node} The inserted node
23292 insertBefore : function(node, refNode){
23293 if(!refNode){ // like standard Dom, refNode can be null for append
23294 return this.appendChild(node);
23297 if(node == refNode){
23301 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23304 var index = this.childNodes.indexOf(refNode);
23305 var oldParent = node.parentNode;
23306 var refIndex = index;
23308 // when moving internally, indexes will change after remove
23309 if(oldParent == this && this.childNodes.indexOf(node) < index){
23313 // it's a move, make sure we move it cleanly
23315 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23318 oldParent.removeChild(node);
23321 this.setFirstChild(node);
23323 this.childNodes.splice(refIndex, 0, node);
23324 node.parentNode = this;
23325 var ps = this.childNodes[refIndex-1];
23327 node.previousSibling = ps;
23328 ps.nextSibling = node;
23330 node.previousSibling = null;
23332 node.nextSibling = refNode;
23333 refNode.previousSibling = node;
23334 node.setOwnerTree(this.getOwnerTree());
23335 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23337 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23343 * Returns the child node at the specified index.
23344 * @param {Number} index
23347 item : function(index){
23348 return this.childNodes[index];
23352 * Replaces one child node in this node with another.
23353 * @param {Node} newChild The replacement node
23354 * @param {Node} oldChild The node to replace
23355 * @return {Node} The replaced node
23357 replaceChild : function(newChild, oldChild){
23358 this.insertBefore(newChild, oldChild);
23359 this.removeChild(oldChild);
23364 * Returns the index of a child node
23365 * @param {Node} node
23366 * @return {Number} The index of the node or -1 if it was not found
23368 indexOf : function(child){
23369 return this.childNodes.indexOf(child);
23373 * Returns the tree this node is in.
23376 getOwnerTree : function(){
23377 // if it doesn't have one, look for one
23378 if(!this.ownerTree){
23382 this.ownerTree = p.ownerTree;
23388 return this.ownerTree;
23392 * Returns depth of this node (the root node has a depth of 0)
23395 getDepth : function(){
23398 while(p.parentNode){
23406 setOwnerTree : function(tree){
23407 // if it's move, we need to update everyone
23408 if(tree != this.ownerTree){
23409 if(this.ownerTree){
23410 this.ownerTree.unregisterNode(this);
23412 this.ownerTree = tree;
23413 var cs = this.childNodes;
23414 for(var i = 0, len = cs.length; i < len; i++) {
23415 cs[i].setOwnerTree(tree);
23418 tree.registerNode(this);
23424 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23425 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23426 * @return {String} The path
23428 getPath : function(attr){
23429 attr = attr || "id";
23430 var p = this.parentNode;
23431 var b = [this.attributes[attr]];
23433 b.unshift(p.attributes[attr]);
23436 var sep = this.getOwnerTree().pathSeparator;
23437 return sep + b.join(sep);
23441 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23442 * function call will be the scope provided or the current node. The arguments to the function
23443 * will be the args provided or the current node. If the function returns false at any point,
23444 * the bubble is stopped.
23445 * @param {Function} fn The function to call
23446 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23447 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23449 bubble : function(fn, scope, args){
23452 if(fn.call(scope || p, args || p) === false){
23460 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23461 * function call will be the scope provided or the current node. The arguments to the function
23462 * will be the args provided or the current node. If the function returns false at any point,
23463 * the cascade is stopped on that branch.
23464 * @param {Function} fn The function to call
23465 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23466 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23468 cascade : function(fn, scope, args){
23469 if(fn.call(scope || this, args || this) !== false){
23470 var cs = this.childNodes;
23471 for(var i = 0, len = cs.length; i < len; i++) {
23472 cs[i].cascade(fn, scope, args);
23478 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23479 * function call will be the scope provided or the current node. The arguments to the function
23480 * will be the args provided or the current node. If the function returns false at any point,
23481 * the iteration stops.
23482 * @param {Function} fn The function to call
23483 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23484 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23486 eachChild : function(fn, scope, args){
23487 var cs = this.childNodes;
23488 for(var i = 0, len = cs.length; i < len; i++) {
23489 if(fn.call(scope || this, args || cs[i]) === false){
23496 * Finds the first child that has the attribute with the specified value.
23497 * @param {String} attribute The attribute name
23498 * @param {Mixed} value The value to search for
23499 * @return {Node} The found child or null if none was found
23501 findChild : function(attribute, value){
23502 var cs = this.childNodes;
23503 for(var i = 0, len = cs.length; i < len; i++) {
23504 if(cs[i].attributes[attribute] == value){
23512 * Finds the first child by a custom function. The child matches if the function passed
23514 * @param {Function} fn
23515 * @param {Object} scope (optional)
23516 * @return {Node} The found child or null if none was found
23518 findChildBy : function(fn, scope){
23519 var cs = this.childNodes;
23520 for(var i = 0, len = cs.length; i < len; i++) {
23521 if(fn.call(scope||cs[i], cs[i]) === true){
23529 * Sorts this nodes children using the supplied sort function
23530 * @param {Function} fn
23531 * @param {Object} scope (optional)
23533 sort : function(fn, scope){
23534 var cs = this.childNodes;
23535 var len = cs.length;
23537 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23539 for(var i = 0; i < len; i++){
23541 n.previousSibling = cs[i-1];
23542 n.nextSibling = cs[i+1];
23544 this.setFirstChild(n);
23547 this.setLastChild(n);
23554 * Returns true if this node is an ancestor (at any point) of the passed node.
23555 * @param {Node} node
23556 * @return {Boolean}
23558 contains : function(node){
23559 return node.isAncestor(this);
23563 * Returns true if the passed node is an ancestor (at any point) of this node.
23564 * @param {Node} node
23565 * @return {Boolean}
23567 isAncestor : function(node){
23568 var p = this.parentNode;
23578 toString : function(){
23579 return "[Node"+(this.id?" "+this.id:"")+"]";
23583 * Ext JS Library 1.1.1
23584 * Copyright(c) 2006-2007, Ext JS, LLC.
23586 * Originally Released Under LGPL - original licence link has changed is not relivant.
23589 * <script type="text/javascript">
23594 * @extends Roo.Element
23595 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23596 * automatic maintaining of shadow/shim positions.
23597 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23598 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23599 * you can pass a string with a CSS class name. False turns off the shadow.
23600 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23601 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23602 * @cfg {String} cls CSS class to add to the element
23603 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23604 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23606 * @param {Object} config An object with config options.
23607 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23610 Roo.Layer = function(config, existingEl){
23611 config = config || {};
23612 var dh = Roo.DomHelper;
23613 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23615 this.dom = Roo.getDom(existingEl);
23618 var o = config.dh || {tag: "div", cls: "x-layer"};
23619 this.dom = dh.append(pel, o);
23622 this.addClass(config.cls);
23624 this.constrain = config.constrain !== false;
23625 this.visibilityMode = Roo.Element.VISIBILITY;
23627 this.id = this.dom.id = config.id;
23629 this.id = Roo.id(this.dom);
23631 this.zindex = config.zindex || this.getZIndex();
23632 this.position("absolute", this.zindex);
23634 this.shadowOffset = config.shadowOffset || 4;
23635 this.shadow = new Roo.Shadow({
23636 offset : this.shadowOffset,
23637 mode : config.shadow
23640 this.shadowOffset = 0;
23642 this.useShim = config.shim !== false && Roo.useShims;
23643 this.useDisplay = config.useDisplay;
23647 var supr = Roo.Element.prototype;
23649 // shims are shared among layer to keep from having 100 iframes
23652 Roo.extend(Roo.Layer, Roo.Element, {
23654 getZIndex : function(){
23655 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23658 getShim : function(){
23665 var shim = shims.shift();
23667 shim = this.createShim();
23668 shim.enableDisplayMode('block');
23669 shim.dom.style.display = 'none';
23670 shim.dom.style.visibility = 'visible';
23672 var pn = this.dom.parentNode;
23673 if(shim.dom.parentNode != pn){
23674 pn.insertBefore(shim.dom, this.dom);
23676 shim.setStyle('z-index', this.getZIndex()-2);
23681 hideShim : function(){
23683 this.shim.setDisplayed(false);
23684 shims.push(this.shim);
23689 disableShadow : function(){
23691 this.shadowDisabled = true;
23692 this.shadow.hide();
23693 this.lastShadowOffset = this.shadowOffset;
23694 this.shadowOffset = 0;
23698 enableShadow : function(show){
23700 this.shadowDisabled = false;
23701 this.shadowOffset = this.lastShadowOffset;
23702 delete this.lastShadowOffset;
23710 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23711 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23712 sync : function(doShow){
23713 var sw = this.shadow;
23714 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23715 var sh = this.getShim();
23717 var w = this.getWidth(),
23718 h = this.getHeight();
23720 var l = this.getLeft(true),
23721 t = this.getTop(true);
23723 if(sw && !this.shadowDisabled){
23724 if(doShow && !sw.isVisible()){
23727 sw.realign(l, t, w, h);
23733 // fit the shim behind the shadow, so it is shimmed too
23734 var a = sw.adjusts, s = sh.dom.style;
23735 s.left = (Math.min(l, l+a.l))+"px";
23736 s.top = (Math.min(t, t+a.t))+"px";
23737 s.width = (w+a.w)+"px";
23738 s.height = (h+a.h)+"px";
23745 sh.setLeftTop(l, t);
23752 destroy : function(){
23755 this.shadow.hide();
23757 this.removeAllListeners();
23758 var pn = this.dom.parentNode;
23760 pn.removeChild(this.dom);
23762 Roo.Element.uncache(this.id);
23765 remove : function(){
23770 beginUpdate : function(){
23771 this.updating = true;
23775 endUpdate : function(){
23776 this.updating = false;
23781 hideUnders : function(negOffset){
23783 this.shadow.hide();
23789 constrainXY : function(){
23790 if(this.constrain){
23791 var vw = Roo.lib.Dom.getViewWidth(),
23792 vh = Roo.lib.Dom.getViewHeight();
23793 var s = Roo.get(document).getScroll();
23795 var xy = this.getXY();
23796 var x = xy[0], y = xy[1];
23797 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23798 // only move it if it needs it
23800 // first validate right/bottom
23801 if((x + w) > vw+s.left){
23802 x = vw - w - this.shadowOffset;
23805 if((y + h) > vh+s.top){
23806 y = vh - h - this.shadowOffset;
23809 // then make sure top/left isn't negative
23820 var ay = this.avoidY;
23821 if(y <= ay && (y+h) >= ay){
23827 supr.setXY.call(this, xy);
23833 isVisible : function(){
23834 return this.visible;
23838 showAction : function(){
23839 this.visible = true; // track visibility to prevent getStyle calls
23840 if(this.useDisplay === true){
23841 this.setDisplayed("");
23842 }else if(this.lastXY){
23843 supr.setXY.call(this, this.lastXY);
23844 }else if(this.lastLT){
23845 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23850 hideAction : function(){
23851 this.visible = false;
23852 if(this.useDisplay === true){
23853 this.setDisplayed(false);
23855 this.setLeftTop(-10000,-10000);
23859 // overridden Element method
23860 setVisible : function(v, a, d, c, e){
23865 var cb = function(){
23870 }.createDelegate(this);
23871 supr.setVisible.call(this, true, true, d, cb, e);
23874 this.hideUnders(true);
23883 }.createDelegate(this);
23885 supr.setVisible.call(this, v, a, d, cb, e);
23894 storeXY : function(xy){
23895 delete this.lastLT;
23899 storeLeftTop : function(left, top){
23900 delete this.lastXY;
23901 this.lastLT = [left, top];
23905 beforeFx : function(){
23906 this.beforeAction();
23907 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23911 afterFx : function(){
23912 Roo.Layer.superclass.afterFx.apply(this, arguments);
23913 this.sync(this.isVisible());
23917 beforeAction : function(){
23918 if(!this.updating && this.shadow){
23919 this.shadow.hide();
23923 // overridden Element method
23924 setLeft : function(left){
23925 this.storeLeftTop(left, this.getTop(true));
23926 supr.setLeft.apply(this, arguments);
23930 setTop : function(top){
23931 this.storeLeftTop(this.getLeft(true), top);
23932 supr.setTop.apply(this, arguments);
23936 setLeftTop : function(left, top){
23937 this.storeLeftTop(left, top);
23938 supr.setLeftTop.apply(this, arguments);
23942 setXY : function(xy, a, d, c, e){
23944 this.beforeAction();
23946 var cb = this.createCB(c);
23947 supr.setXY.call(this, xy, a, d, cb, e);
23954 createCB : function(c){
23965 // overridden Element method
23966 setX : function(x, a, d, c, e){
23967 this.setXY([x, this.getY()], a, d, c, e);
23970 // overridden Element method
23971 setY : function(y, a, d, c, e){
23972 this.setXY([this.getX(), y], a, d, c, e);
23975 // overridden Element method
23976 setSize : function(w, h, a, d, c, e){
23977 this.beforeAction();
23978 var cb = this.createCB(c);
23979 supr.setSize.call(this, w, h, a, d, cb, e);
23985 // overridden Element method
23986 setWidth : function(w, a, d, c, e){
23987 this.beforeAction();
23988 var cb = this.createCB(c);
23989 supr.setWidth.call(this, w, a, d, cb, e);
23995 // overridden Element method
23996 setHeight : function(h, a, d, c, e){
23997 this.beforeAction();
23998 var cb = this.createCB(c);
23999 supr.setHeight.call(this, h, a, d, cb, e);
24005 // overridden Element method
24006 setBounds : function(x, y, w, h, a, d, c, e){
24007 this.beforeAction();
24008 var cb = this.createCB(c);
24010 this.storeXY([x, y]);
24011 supr.setXY.call(this, [x, y]);
24012 supr.setSize.call(this, w, h, a, d, cb, e);
24015 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24021 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24022 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24023 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24024 * @param {Number} zindex The new z-index to set
24025 * @return {this} The Layer
24027 setZIndex : function(zindex){
24028 this.zindex = zindex;
24029 this.setStyle("z-index", zindex + 2);
24031 this.shadow.setZIndex(zindex + 1);
24034 this.shim.setStyle("z-index", zindex);
24040 * Ext JS Library 1.1.1
24041 * Copyright(c) 2006-2007, Ext JS, LLC.
24043 * Originally Released Under LGPL - original licence link has changed is not relivant.
24046 * <script type="text/javascript">
24051 * @class Roo.Shadow
24052 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24053 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24054 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24056 * Create a new Shadow
24057 * @param {Object} config The config object
24059 Roo.Shadow = function(config){
24060 Roo.apply(this, config);
24061 if(typeof this.mode != "string"){
24062 this.mode = this.defaultMode;
24064 var o = this.offset, a = {h: 0};
24065 var rad = Math.floor(this.offset/2);
24066 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24072 a.l -= this.offset + rad;
24073 a.t -= this.offset + rad;
24084 a.l -= (this.offset - rad);
24085 a.t -= this.offset + rad;
24087 a.w -= (this.offset - rad)*2;
24098 a.l -= (this.offset - rad);
24099 a.t -= (this.offset - rad);
24101 a.w -= (this.offset + rad + 1);
24102 a.h -= (this.offset + rad);
24111 Roo.Shadow.prototype = {
24113 * @cfg {String} mode
24114 * The shadow display mode. Supports the following options:<br />
24115 * sides: Shadow displays on both sides and bottom only<br />
24116 * frame: Shadow displays equally on all four sides<br />
24117 * drop: Traditional bottom-right drop shadow (default)
24120 * @cfg {String} offset
24121 * The number of pixels to offset the shadow from the element (defaults to 4)
24126 defaultMode: "drop",
24129 * Displays the shadow under the target element
24130 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24132 show : function(target){
24133 target = Roo.get(target);
24135 this.el = Roo.Shadow.Pool.pull();
24136 if(this.el.dom.nextSibling != target.dom){
24137 this.el.insertBefore(target);
24140 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24142 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24145 target.getLeft(true),
24146 target.getTop(true),
24150 this.el.dom.style.display = "block";
24154 * Returns true if the shadow is visible, else false
24156 isVisible : function(){
24157 return this.el ? true : false;
24161 * Direct alignment when values are already available. Show must be called at least once before
24162 * calling this method to ensure it is initialized.
24163 * @param {Number} left The target element left position
24164 * @param {Number} top The target element top position
24165 * @param {Number} width The target element width
24166 * @param {Number} height The target element height
24168 realign : function(l, t, w, h){
24172 var a = this.adjusts, d = this.el.dom, s = d.style;
24174 s.left = (l+a.l)+"px";
24175 s.top = (t+a.t)+"px";
24176 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24178 if(s.width != sws || s.height != shs){
24182 var cn = d.childNodes;
24183 var sww = Math.max(0, (sw-12))+"px";
24184 cn[0].childNodes[1].style.width = sww;
24185 cn[1].childNodes[1].style.width = sww;
24186 cn[2].childNodes[1].style.width = sww;
24187 cn[1].style.height = Math.max(0, (sh-12))+"px";
24193 * Hides this shadow
24197 this.el.dom.style.display = "none";
24198 Roo.Shadow.Pool.push(this.el);
24204 * Adjust the z-index of this shadow
24205 * @param {Number} zindex The new z-index
24207 setZIndex : function(z){
24210 this.el.setStyle("z-index", z);
24215 // Private utility class that manages the internal Shadow cache
24216 Roo.Shadow.Pool = function(){
24218 var markup = Roo.isIE ?
24219 '<div class="x-ie-shadow"></div>' :
24220 '<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>';
24223 var sh = p.shift();
24225 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24226 sh.autoBoxAdjust = false;
24231 push : function(sh){
24237 * Ext JS Library 1.1.1
24238 * Copyright(c) 2006-2007, Ext JS, LLC.
24240 * Originally Released Under LGPL - original licence link has changed is not relivant.
24243 * <script type="text/javascript">
24248 * @class Roo.SplitBar
24249 * @extends Roo.util.Observable
24250 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24254 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24255 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24256 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24257 split.minSize = 100;
24258 split.maxSize = 600;
24259 split.animate = true;
24260 split.on('moved', splitterMoved);
24263 * Create a new SplitBar
24264 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24265 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24266 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24267 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24268 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24269 position of the SplitBar).
24271 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24274 this.el = Roo.get(dragElement, true);
24275 this.el.dom.unselectable = "on";
24277 this.resizingEl = Roo.get(resizingElement, true);
24281 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24282 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24285 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24288 * The minimum size of the resizing element. (Defaults to 0)
24294 * The maximum size of the resizing element. (Defaults to 2000)
24297 this.maxSize = 2000;
24300 * Whether to animate the transition to the new size
24303 this.animate = false;
24306 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24309 this.useShim = false;
24314 if(!existingProxy){
24316 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24318 this.proxy = Roo.get(existingProxy).dom;
24321 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24324 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24327 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24330 this.dragSpecs = {};
24333 * @private The adapter to use to positon and resize elements
24335 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24336 this.adapter.init(this);
24338 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24340 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24341 this.el.addClass("x-splitbar-h");
24344 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24345 this.el.addClass("x-splitbar-v");
24351 * Fires when the splitter is moved (alias for {@link #event-moved})
24352 * @param {Roo.SplitBar} this
24353 * @param {Number} newSize the new width or height
24358 * Fires when the splitter is moved
24359 * @param {Roo.SplitBar} this
24360 * @param {Number} newSize the new width or height
24364 * @event beforeresize
24365 * Fires before the splitter is dragged
24366 * @param {Roo.SplitBar} this
24368 "beforeresize" : true,
24370 "beforeapply" : true
24373 Roo.util.Observable.call(this);
24376 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24377 onStartProxyDrag : function(x, y){
24378 this.fireEvent("beforeresize", this);
24380 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24382 o.enableDisplayMode("block");
24383 // all splitbars share the same overlay
24384 Roo.SplitBar.prototype.overlay = o;
24386 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24387 this.overlay.show();
24388 Roo.get(this.proxy).setDisplayed("block");
24389 var size = this.adapter.getElementSize(this);
24390 this.activeMinSize = this.getMinimumSize();;
24391 this.activeMaxSize = this.getMaximumSize();;
24392 var c1 = size - this.activeMinSize;
24393 var c2 = Math.max(this.activeMaxSize - size, 0);
24394 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24395 this.dd.resetConstraints();
24396 this.dd.setXConstraint(
24397 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24398 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24400 this.dd.setYConstraint(0, 0);
24402 this.dd.resetConstraints();
24403 this.dd.setXConstraint(0, 0);
24404 this.dd.setYConstraint(
24405 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24406 this.placement == Roo.SplitBar.TOP ? c2 : c1
24409 this.dragSpecs.startSize = size;
24410 this.dragSpecs.startPoint = [x, y];
24411 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24415 * @private Called after the drag operation by the DDProxy
24417 onEndProxyDrag : function(e){
24418 Roo.get(this.proxy).setDisplayed(false);
24419 var endPoint = Roo.lib.Event.getXY(e);
24421 this.overlay.hide();
24424 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24425 newSize = this.dragSpecs.startSize +
24426 (this.placement == Roo.SplitBar.LEFT ?
24427 endPoint[0] - this.dragSpecs.startPoint[0] :
24428 this.dragSpecs.startPoint[0] - endPoint[0]
24431 newSize = this.dragSpecs.startSize +
24432 (this.placement == Roo.SplitBar.TOP ?
24433 endPoint[1] - this.dragSpecs.startPoint[1] :
24434 this.dragSpecs.startPoint[1] - endPoint[1]
24437 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24438 if(newSize != this.dragSpecs.startSize){
24439 if(this.fireEvent('beforeapply', this, newSize) !== false){
24440 this.adapter.setElementSize(this, newSize);
24441 this.fireEvent("moved", this, newSize);
24442 this.fireEvent("resize", this, newSize);
24448 * Get the adapter this SplitBar uses
24449 * @return The adapter object
24451 getAdapter : function(){
24452 return this.adapter;
24456 * Set the adapter this SplitBar uses
24457 * @param {Object} adapter A SplitBar adapter object
24459 setAdapter : function(adapter){
24460 this.adapter = adapter;
24461 this.adapter.init(this);
24465 * Gets the minimum size for the resizing element
24466 * @return {Number} The minimum size
24468 getMinimumSize : function(){
24469 return this.minSize;
24473 * Sets the minimum size for the resizing element
24474 * @param {Number} minSize The minimum size
24476 setMinimumSize : function(minSize){
24477 this.minSize = minSize;
24481 * Gets the maximum size for the resizing element
24482 * @return {Number} The maximum size
24484 getMaximumSize : function(){
24485 return this.maxSize;
24489 * Sets the maximum size for the resizing element
24490 * @param {Number} maxSize The maximum size
24492 setMaximumSize : function(maxSize){
24493 this.maxSize = maxSize;
24497 * Sets the initialize size for the resizing element
24498 * @param {Number} size The initial size
24500 setCurrentSize : function(size){
24501 var oldAnimate = this.animate;
24502 this.animate = false;
24503 this.adapter.setElementSize(this, size);
24504 this.animate = oldAnimate;
24508 * Destroy this splitbar.
24509 * @param {Boolean} removeEl True to remove the element
24511 destroy : function(removeEl){
24513 this.shim.remove();
24516 this.proxy.parentNode.removeChild(this.proxy);
24524 * @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.
24526 Roo.SplitBar.createProxy = function(dir){
24527 var proxy = new Roo.Element(document.createElement("div"));
24528 proxy.unselectable();
24529 var cls = 'x-splitbar-proxy';
24530 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24531 document.body.appendChild(proxy.dom);
24536 * @class Roo.SplitBar.BasicLayoutAdapter
24537 * Default Adapter. It assumes the splitter and resizing element are not positioned
24538 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24540 Roo.SplitBar.BasicLayoutAdapter = function(){
24543 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24544 // do nothing for now
24545 init : function(s){
24549 * Called before drag operations to get the current size of the resizing element.
24550 * @param {Roo.SplitBar} s The SplitBar using this adapter
24552 getElementSize : function(s){
24553 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24554 return s.resizingEl.getWidth();
24556 return s.resizingEl.getHeight();
24561 * Called after drag operations to set the size of the resizing element.
24562 * @param {Roo.SplitBar} s The SplitBar using this adapter
24563 * @param {Number} newSize The new size to set
24564 * @param {Function} onComplete A function to be invoked when resizing is complete
24566 setElementSize : function(s, newSize, onComplete){
24567 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24569 s.resizingEl.setWidth(newSize);
24571 onComplete(s, newSize);
24574 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24579 s.resizingEl.setHeight(newSize);
24581 onComplete(s, newSize);
24584 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24591 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24592 * @extends Roo.SplitBar.BasicLayoutAdapter
24593 * Adapter that moves the splitter element to align with the resized sizing element.
24594 * Used with an absolute positioned SplitBar.
24595 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24596 * document.body, make sure you assign an id to the body element.
24598 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24599 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24600 this.container = Roo.get(container);
24603 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24604 init : function(s){
24605 this.basic.init(s);
24608 getElementSize : function(s){
24609 return this.basic.getElementSize(s);
24612 setElementSize : function(s, newSize, onComplete){
24613 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24616 moveSplitter : function(s){
24617 var yes = Roo.SplitBar;
24618 switch(s.placement){
24620 s.el.setX(s.resizingEl.getRight());
24623 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24626 s.el.setY(s.resizingEl.getBottom());
24629 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24636 * Orientation constant - Create a vertical SplitBar
24640 Roo.SplitBar.VERTICAL = 1;
24643 * Orientation constant - Create a horizontal SplitBar
24647 Roo.SplitBar.HORIZONTAL = 2;
24650 * Placement constant - The resizing element is to the left of the splitter element
24654 Roo.SplitBar.LEFT = 1;
24657 * Placement constant - The resizing element is to the right of the splitter element
24661 Roo.SplitBar.RIGHT = 2;
24664 * Placement constant - The resizing element is positioned above the splitter element
24668 Roo.SplitBar.TOP = 3;
24671 * Placement constant - The resizing element is positioned under splitter element
24675 Roo.SplitBar.BOTTOM = 4;
24678 * Ext JS Library 1.1.1
24679 * Copyright(c) 2006-2007, Ext JS, LLC.
24681 * Originally Released Under LGPL - original licence link has changed is not relivant.
24684 * <script type="text/javascript">
24689 * @extends Roo.util.Observable
24690 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24691 * This class also supports single and multi selection modes. <br>
24692 * Create a data model bound view:
24694 var store = new Roo.data.Store(...);
24696 var view = new Roo.View({
24698 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24700 singleSelect: true,
24701 selectedClass: "ydataview-selected",
24705 // listen for node click?
24706 view.on("click", function(vw, index, node, e){
24707 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24711 dataModel.load("foobar.xml");
24713 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24715 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24716 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24718 * Note: old style constructor is still suported (container, template, config)
24721 * Create a new View
24722 * @param {Object} config The config object
24725 Roo.View = function(config, depreciated_tpl, depreciated_config){
24727 if (typeof(depreciated_tpl) == 'undefined') {
24728 // new way.. - universal constructor.
24729 Roo.apply(this, config);
24730 this.el = Roo.get(this.el);
24733 this.el = Roo.get(config);
24734 this.tpl = depreciated_tpl;
24735 Roo.apply(this, depreciated_config);
24737 this.wrapEl = this.el.wrap().wrap();
24738 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24741 if(typeof(this.tpl) == "string"){
24742 this.tpl = new Roo.Template(this.tpl);
24744 // support xtype ctors..
24745 this.tpl = new Roo.factory(this.tpl, Roo);
24749 this.tpl.compile();
24757 * @event beforeclick
24758 * Fires before a click is processed. Returns false to cancel the default action.
24759 * @param {Roo.View} this
24760 * @param {Number} index The index of the target node
24761 * @param {HTMLElement} node The target node
24762 * @param {Roo.EventObject} e The raw event object
24764 "beforeclick" : true,
24767 * Fires when a template node is clicked.
24768 * @param {Roo.View} this
24769 * @param {Number} index The index of the target node
24770 * @param {HTMLElement} node The target node
24771 * @param {Roo.EventObject} e The raw event object
24776 * Fires when a template node is double clicked.
24777 * @param {Roo.View} this
24778 * @param {Number} index The index of the target node
24779 * @param {HTMLElement} node The target node
24780 * @param {Roo.EventObject} e The raw event object
24784 * @event contextmenu
24785 * Fires when a template node is right clicked.
24786 * @param {Roo.View} this
24787 * @param {Number} index The index of the target node
24788 * @param {HTMLElement} node The target node
24789 * @param {Roo.EventObject} e The raw event object
24791 "contextmenu" : true,
24793 * @event selectionchange
24794 * Fires when the selected nodes change.
24795 * @param {Roo.View} this
24796 * @param {Array} selections Array of the selected nodes
24798 "selectionchange" : true,
24801 * @event beforeselect
24802 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24803 * @param {Roo.View} this
24804 * @param {HTMLElement} node The node to be selected
24805 * @param {Array} selections Array of currently selected nodes
24807 "beforeselect" : true,
24809 * @event preparedata
24810 * Fires on every row to render, to allow you to change the data.
24811 * @param {Roo.View} this
24812 * @param {Object} data to be rendered (change this)
24814 "preparedata" : true
24822 "click": this.onClick,
24823 "dblclick": this.onDblClick,
24824 "contextmenu": this.onContextMenu,
24828 this.selections = [];
24830 this.cmp = new Roo.CompositeElementLite([]);
24832 this.store = Roo.factory(this.store, Roo.data);
24833 this.setStore(this.store, true);
24836 if ( this.footer && this.footer.xtype) {
24838 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24840 this.footer.dataSource = this.store
24841 this.footer.container = fctr;
24842 this.footer = Roo.factory(this.footer, Roo);
24843 fctr.insertFirst(this.el);
24845 // this is a bit insane - as the paging toolbar seems to detach the el..
24846 // dom.parentNode.parentNode.parentNode
24847 // they get detached?
24851 Roo.View.superclass.constructor.call(this);
24856 Roo.extend(Roo.View, Roo.util.Observable, {
24859 * @cfg {Roo.data.Store} store Data store to load data from.
24864 * @cfg {String|Roo.Element} el The container element.
24869 * @cfg {String|Roo.Template} tpl The template used by this View
24873 * @cfg {String} dataName the named area of the template to use as the data area
24874 * Works with domtemplates roo-name="name"
24878 * @cfg {String} selectedClass The css class to add to selected nodes
24880 selectedClass : "x-view-selected",
24882 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24887 * @cfg {String} text to display on mask (default Loading)
24891 * @cfg {Boolean} multiSelect Allow multiple selection
24893 multiSelect : false,
24895 * @cfg {Boolean} singleSelect Allow single selection
24897 singleSelect: false,
24900 * @cfg {Boolean} toggleSelect - selecting
24902 toggleSelect : false,
24905 * Returns the element this view is bound to.
24906 * @return {Roo.Element}
24908 getEl : function(){
24909 return this.wrapEl;
24915 * Refreshes the view. - called by datachanged on the store. - do not call directly.
24917 refresh : function(){
24920 // if we are using something like 'domtemplate', then
24921 // the what gets used is:
24922 // t.applySubtemplate(NAME, data, wrapping data..)
24923 // the outer template then get' applied with
24924 // the store 'extra data'
24925 // and the body get's added to the
24926 // roo-name="data" node?
24927 // <span class='roo-tpl-{name}'></span> ?????
24931 this.clearSelections();
24932 this.el.update("");
24934 var records = this.store.getRange();
24935 if(records.length < 1) {
24937 // is this valid?? = should it render a template??
24939 this.el.update(this.emptyText);
24943 if (this.dataName) {
24944 this.el.update(t.apply(this.store.meta)); //????
24945 el = this.el.child('.roo-tpl-' + this.dataName);
24948 for(var i = 0, len = records.length; i < len; i++){
24949 var data = this.prepareData(records[i].data, i, records[i]);
24950 this.fireEvent("preparedata", this, data, i, records[i]);
24951 html[html.length] = Roo.util.Format.trim(
24953 t.applySubtemplate(this.dataName, data, this.store.meta) :
24960 el.update(html.join(""));
24961 this.nodes = el.dom.childNodes;
24962 this.updateIndexes(0);
24966 * Function to override to reformat the data that is sent to
24967 * the template for each node.
24968 * DEPRICATED - use the preparedata event handler.
24969 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
24970 * a JSON object for an UpdateManager bound view).
24972 prepareData : function(data, index, record)
24974 this.fireEvent("preparedata", this, data, index, record);
24978 onUpdate : function(ds, record){
24979 this.clearSelections();
24980 var index = this.store.indexOf(record);
24981 var n = this.nodes[index];
24982 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
24983 n.parentNode.removeChild(n);
24984 this.updateIndexes(index, index);
24990 onAdd : function(ds, records, index)
24992 this.clearSelections();
24993 if(this.nodes.length == 0){
24997 var n = this.nodes[index];
24998 for(var i = 0, len = records.length; i < len; i++){
24999 var d = this.prepareData(records[i].data, i, records[i]);
25001 this.tpl.insertBefore(n, d);
25004 this.tpl.append(this.el, d);
25007 this.updateIndexes(index);
25010 onRemove : function(ds, record, index){
25011 this.clearSelections();
25012 var el = this.dataName ?
25013 this.el.child('.roo-tpl-' + this.dataName) :
25015 el.dom.removeChild(this.nodes[index]);
25016 this.updateIndexes(index);
25020 * Refresh an individual node.
25021 * @param {Number} index
25023 refreshNode : function(index){
25024 this.onUpdate(this.store, this.store.getAt(index));
25027 updateIndexes : function(startIndex, endIndex){
25028 var ns = this.nodes;
25029 startIndex = startIndex || 0;
25030 endIndex = endIndex || ns.length - 1;
25031 for(var i = startIndex; i <= endIndex; i++){
25032 ns[i].nodeIndex = i;
25037 * Changes the data store this view uses and refresh the view.
25038 * @param {Store} store
25040 setStore : function(store, initial){
25041 if(!initial && this.store){
25042 this.store.un("datachanged", this.refresh);
25043 this.store.un("add", this.onAdd);
25044 this.store.un("remove", this.onRemove);
25045 this.store.un("update", this.onUpdate);
25046 this.store.un("clear", this.refresh);
25047 this.store.un("beforeload", this.onBeforeLoad);
25048 this.store.un("load", this.onLoad);
25049 this.store.un("loadexception", this.onLoad);
25053 store.on("datachanged", this.refresh, this);
25054 store.on("add", this.onAdd, this);
25055 store.on("remove", this.onRemove, this);
25056 store.on("update", this.onUpdate, this);
25057 store.on("clear", this.refresh, this);
25058 store.on("beforeload", this.onBeforeLoad, this);
25059 store.on("load", this.onLoad, this);
25060 store.on("loadexception", this.onLoad, this);
25068 * onbeforeLoad - masks the loading area.
25071 onBeforeLoad : function()
25073 this.el.update("");
25074 this.el.mask(this.mask ? this.mask : "Loading" );
25076 onLoad : function ()
25083 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25084 * @param {HTMLElement} node
25085 * @return {HTMLElement} The template node
25087 findItemFromChild : function(node){
25088 var el = this.dataName ?
25089 this.el.child('.roo-tpl-' + this.dataName,true) :
25092 if(!node || node.parentNode == el){
25095 var p = node.parentNode;
25096 while(p && p != el){
25097 if(p.parentNode == el){
25106 onClick : function(e){
25107 var item = this.findItemFromChild(e.getTarget());
25109 var index = this.indexOf(item);
25110 if(this.onItemClick(item, index, e) !== false){
25111 this.fireEvent("click", this, index, item, e);
25114 this.clearSelections();
25119 onContextMenu : function(e){
25120 var item = this.findItemFromChild(e.getTarget());
25122 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25127 onDblClick : function(e){
25128 var item = this.findItemFromChild(e.getTarget());
25130 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25134 onItemClick : function(item, index, e)
25136 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25139 if (this.toggleSelect) {
25140 var m = this.isSelected(item) ? 'unselect' : 'select';
25143 _t[m](item, true, false);
25146 if(this.multiSelect || this.singleSelect){
25147 if(this.multiSelect && e.shiftKey && this.lastSelection){
25148 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25150 this.select(item, this.multiSelect && e.ctrlKey);
25151 this.lastSelection = item;
25153 e.preventDefault();
25159 * Get the number of selected nodes.
25162 getSelectionCount : function(){
25163 return this.selections.length;
25167 * Get the currently selected nodes.
25168 * @return {Array} An array of HTMLElements
25170 getSelectedNodes : function(){
25171 return this.selections;
25175 * Get the indexes of the selected nodes.
25178 getSelectedIndexes : function(){
25179 var indexes = [], s = this.selections;
25180 for(var i = 0, len = s.length; i < len; i++){
25181 indexes.push(s[i].nodeIndex);
25187 * Clear all selections
25188 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25190 clearSelections : function(suppressEvent){
25191 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25192 this.cmp.elements = this.selections;
25193 this.cmp.removeClass(this.selectedClass);
25194 this.selections = [];
25195 if(!suppressEvent){
25196 this.fireEvent("selectionchange", this, this.selections);
25202 * Returns true if the passed node is selected
25203 * @param {HTMLElement/Number} node The node or node index
25204 * @return {Boolean}
25206 isSelected : function(node){
25207 var s = this.selections;
25211 node = this.getNode(node);
25212 return s.indexOf(node) !== -1;
25217 * @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
25218 * @param {Boolean} keepExisting (optional) true to keep existing selections
25219 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25221 select : function(nodeInfo, keepExisting, suppressEvent){
25222 if(nodeInfo instanceof Array){
25224 this.clearSelections(true);
25226 for(var i = 0, len = nodeInfo.length; i < len; i++){
25227 this.select(nodeInfo[i], true, true);
25231 var node = this.getNode(nodeInfo);
25232 if(!node || this.isSelected(node)){
25233 return; // already selected.
25236 this.clearSelections(true);
25238 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25239 Roo.fly(node).addClass(this.selectedClass);
25240 this.selections.push(node);
25241 if(!suppressEvent){
25242 this.fireEvent("selectionchange", this, this.selections);
25250 * @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
25251 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25252 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25254 unselect : function(nodeInfo, keepExisting, suppressEvent)
25256 if(nodeInfo instanceof Array){
25257 Roo.each(this.selections, function(s) {
25258 this.unselect(s, nodeInfo);
25262 var node = this.getNode(nodeInfo);
25263 if(!node || !this.isSelected(node)){
25264 Roo.log("not selected");
25265 return; // not selected.
25269 Roo.each(this.selections, function(s) {
25271 Roo.fly(node).removeClass(this.selectedClass);
25278 this.selections= ns;
25279 this.fireEvent("selectionchange", this, this.selections);
25283 * Gets a template node.
25284 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25285 * @return {HTMLElement} The node or null if it wasn't found
25287 getNode : function(nodeInfo){
25288 if(typeof nodeInfo == "string"){
25289 return document.getElementById(nodeInfo);
25290 }else if(typeof nodeInfo == "number"){
25291 return this.nodes[nodeInfo];
25297 * Gets a range template nodes.
25298 * @param {Number} startIndex
25299 * @param {Number} endIndex
25300 * @return {Array} An array of nodes
25302 getNodes : function(start, end){
25303 var ns = this.nodes;
25304 start = start || 0;
25305 end = typeof end == "undefined" ? ns.length - 1 : end;
25308 for(var i = start; i <= end; i++){
25312 for(var i = start; i >= end; i--){
25320 * Finds the index of the passed node
25321 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25322 * @return {Number} The index of the node or -1
25324 indexOf : function(node){
25325 node = this.getNode(node);
25326 if(typeof node.nodeIndex == "number"){
25327 return node.nodeIndex;
25329 var ns = this.nodes;
25330 for(var i = 0, len = ns.length; i < len; i++){
25340 * Ext JS Library 1.1.1
25341 * Copyright(c) 2006-2007, Ext JS, LLC.
25343 * Originally Released Under LGPL - original licence link has changed is not relivant.
25346 * <script type="text/javascript">
25350 * @class Roo.JsonView
25351 * @extends Roo.View
25352 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25354 var view = new Roo.JsonView({
25355 container: "my-element",
25356 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25361 // listen for node click?
25362 view.on("click", function(vw, index, node, e){
25363 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25366 // direct load of JSON data
25367 view.load("foobar.php");
25369 // Example from my blog list
25370 var tpl = new Roo.Template(
25371 '<div class="entry">' +
25372 '<a class="entry-title" href="{link}">{title}</a>' +
25373 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25374 "</div><hr />"
25377 var moreView = new Roo.JsonView({
25378 container : "entry-list",
25382 moreView.on("beforerender", this.sortEntries, this);
25384 url: "/blog/get-posts.php",
25385 params: "allposts=true",
25386 text: "Loading Blog Entries..."
25390 * Note: old code is supported with arguments : (container, template, config)
25394 * Create a new JsonView
25396 * @param {Object} config The config object
25399 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25402 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25404 var um = this.el.getUpdateManager();
25405 um.setRenderer(this);
25406 um.on("update", this.onLoad, this);
25407 um.on("failure", this.onLoadException, this);
25410 * @event beforerender
25411 * Fires before rendering of the downloaded JSON data.
25412 * @param {Roo.JsonView} this
25413 * @param {Object} data The JSON data loaded
25417 * Fires when data is loaded.
25418 * @param {Roo.JsonView} this
25419 * @param {Object} data The JSON data loaded
25420 * @param {Object} response The raw Connect response object
25423 * @event loadexception
25424 * Fires when loading fails.
25425 * @param {Roo.JsonView} this
25426 * @param {Object} response The raw Connect response object
25429 'beforerender' : true,
25431 'loadexception' : true
25434 Roo.extend(Roo.JsonView, Roo.View, {
25436 * @type {String} The root property in the loaded JSON object that contains the data
25441 * Refreshes the view.
25443 refresh : function(){
25444 this.clearSelections();
25445 this.el.update("");
25447 var o = this.jsonData;
25448 if(o && o.length > 0){
25449 for(var i = 0, len = o.length; i < len; i++){
25450 var data = this.prepareData(o[i], i, o);
25451 html[html.length] = this.tpl.apply(data);
25454 html.push(this.emptyText);
25456 this.el.update(html.join(""));
25457 this.nodes = this.el.dom.childNodes;
25458 this.updateIndexes(0);
25462 * 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.
25463 * @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:
25466 url: "your-url.php",
25467 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25468 callback: yourFunction,
25469 scope: yourObject, //(optional scope)
25472 text: "Loading...",
25477 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25478 * 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.
25479 * @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}
25480 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25481 * @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.
25484 var um = this.el.getUpdateManager();
25485 um.update.apply(um, arguments);
25488 render : function(el, response){
25489 this.clearSelections();
25490 this.el.update("");
25493 o = Roo.util.JSON.decode(response.responseText);
25496 o = o[this.jsonRoot];
25501 * The current JSON data or null
25504 this.beforeRender();
25509 * Get the number of records in the current JSON dataset
25512 getCount : function(){
25513 return this.jsonData ? this.jsonData.length : 0;
25517 * Returns the JSON object for the specified node(s)
25518 * @param {HTMLElement/Array} node The node or an array of nodes
25519 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25520 * you get the JSON object for the node
25522 getNodeData : function(node){
25523 if(node instanceof Array){
25525 for(var i = 0, len = node.length; i < len; i++){
25526 data.push(this.getNodeData(node[i]));
25530 return this.jsonData[this.indexOf(node)] || null;
25533 beforeRender : function(){
25534 this.snapshot = this.jsonData;
25536 this.sort.apply(this, this.sortInfo);
25538 this.fireEvent("beforerender", this, this.jsonData);
25541 onLoad : function(el, o){
25542 this.fireEvent("load", this, this.jsonData, o);
25545 onLoadException : function(el, o){
25546 this.fireEvent("loadexception", this, o);
25550 * Filter the data by a specific property.
25551 * @param {String} property A property on your JSON objects
25552 * @param {String/RegExp} value Either string that the property values
25553 * should start with, or a RegExp to test against the property
25555 filter : function(property, value){
25558 var ss = this.snapshot;
25559 if(typeof value == "string"){
25560 var vlen = value.length;
25562 this.clearFilter();
25565 value = value.toLowerCase();
25566 for(var i = 0, len = ss.length; i < len; i++){
25568 if(o[property].substr(0, vlen).toLowerCase() == value){
25572 } else if(value.exec){ // regex?
25573 for(var i = 0, len = ss.length; i < len; i++){
25575 if(value.test(o[property])){
25582 this.jsonData = data;
25588 * Filter by a function. The passed function will be called with each
25589 * object in the current dataset. If the function returns true the value is kept,
25590 * otherwise it is filtered.
25591 * @param {Function} fn
25592 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25594 filterBy : function(fn, scope){
25597 var ss = this.snapshot;
25598 for(var i = 0, len = ss.length; i < len; i++){
25600 if(fn.call(scope || this, o)){
25604 this.jsonData = data;
25610 * Clears the current filter.
25612 clearFilter : function(){
25613 if(this.snapshot && this.jsonData != this.snapshot){
25614 this.jsonData = this.snapshot;
25621 * Sorts the data for this view and refreshes it.
25622 * @param {String} property A property on your JSON objects to sort on
25623 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25624 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25626 sort : function(property, dir, sortType){
25627 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25630 var dsc = dir && dir.toLowerCase() == "desc";
25631 var f = function(o1, o2){
25632 var v1 = sortType ? sortType(o1[p]) : o1[p];
25633 var v2 = sortType ? sortType(o2[p]) : o2[p];
25636 return dsc ? +1 : -1;
25637 } else if(v1 > v2){
25638 return dsc ? -1 : +1;
25643 this.jsonData.sort(f);
25645 if(this.jsonData != this.snapshot){
25646 this.snapshot.sort(f);
25652 * Ext JS Library 1.1.1
25653 * Copyright(c) 2006-2007, Ext JS, LLC.
25655 * Originally Released Under LGPL - original licence link has changed is not relivant.
25658 * <script type="text/javascript">
25663 * @class Roo.ColorPalette
25664 * @extends Roo.Component
25665 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25666 * Here's an example of typical usage:
25668 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25669 cp.render('my-div');
25671 cp.on('select', function(palette, selColor){
25672 // do something with selColor
25676 * Create a new ColorPalette
25677 * @param {Object} config The config object
25679 Roo.ColorPalette = function(config){
25680 Roo.ColorPalette.superclass.constructor.call(this, config);
25684 * Fires when a color is selected
25685 * @param {ColorPalette} this
25686 * @param {String} color The 6-digit color hex code (without the # symbol)
25692 this.on("select", this.handler, this.scope, true);
25695 Roo.extend(Roo.ColorPalette, Roo.Component, {
25697 * @cfg {String} itemCls
25698 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25700 itemCls : "x-color-palette",
25702 * @cfg {String} value
25703 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25704 * the hex codes are case-sensitive.
25707 clickEvent:'click',
25709 ctype: "Roo.ColorPalette",
25712 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25714 allowReselect : false,
25717 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25718 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25719 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25720 * of colors with the width setting until the box is symmetrical.</p>
25721 * <p>You can override individual colors if needed:</p>
25723 var cp = new Roo.ColorPalette();
25724 cp.colors[0] = "FF0000"; // change the first box to red
25727 Or you can provide a custom array of your own for complete control:
25729 var cp = new Roo.ColorPalette();
25730 cp.colors = ["000000", "993300", "333300"];
25735 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25736 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25737 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25738 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25739 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25743 onRender : function(container, position){
25744 var t = new Roo.MasterTemplate(
25745 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25747 var c = this.colors;
25748 for(var i = 0, len = c.length; i < len; i++){
25751 var el = document.createElement("div");
25752 el.className = this.itemCls;
25754 container.dom.insertBefore(el, position);
25755 this.el = Roo.get(el);
25756 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25757 if(this.clickEvent != 'click'){
25758 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25763 afterRender : function(){
25764 Roo.ColorPalette.superclass.afterRender.call(this);
25766 var s = this.value;
25773 handleClick : function(e, t){
25774 e.preventDefault();
25775 if(!this.disabled){
25776 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25777 this.select(c.toUpperCase());
25782 * Selects the specified color in the palette (fires the select event)
25783 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25785 select : function(color){
25786 color = color.replace("#", "");
25787 if(color != this.value || this.allowReselect){
25790 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25792 el.child("a.color-"+color).addClass("x-color-palette-sel");
25793 this.value = color;
25794 this.fireEvent("select", this, color);
25799 * Ext JS Library 1.1.1
25800 * Copyright(c) 2006-2007, Ext JS, LLC.
25802 * Originally Released Under LGPL - original licence link has changed is not relivant.
25805 * <script type="text/javascript">
25809 * @class Roo.DatePicker
25810 * @extends Roo.Component
25811 * Simple date picker class.
25813 * Create a new DatePicker
25814 * @param {Object} config The config object
25816 Roo.DatePicker = function(config){
25817 Roo.DatePicker.superclass.constructor.call(this, config);
25819 this.value = config && config.value ?
25820 config.value.clearTime() : new Date().clearTime();
25825 * Fires when a date is selected
25826 * @param {DatePicker} this
25827 * @param {Date} date The selected date
25831 * @event monthchange
25832 * Fires when the displayed month changes
25833 * @param {DatePicker} this
25834 * @param {Date} date The selected month
25836 'monthchange': true
25840 this.on("select", this.handler, this.scope || this);
25842 // build the disabledDatesRE
25843 if(!this.disabledDatesRE && this.disabledDates){
25844 var dd = this.disabledDates;
25846 for(var i = 0; i < dd.length; i++){
25848 if(i != dd.length-1) re += "|";
25850 this.disabledDatesRE = new RegExp(re + ")");
25854 Roo.extend(Roo.DatePicker, Roo.Component, {
25856 * @cfg {String} todayText
25857 * The text to display on the button that selects the current date (defaults to "Today")
25859 todayText : "Today",
25861 * @cfg {String} okText
25862 * The text to display on the ok button
25864 okText : " OK ", //   to give the user extra clicking room
25866 * @cfg {String} cancelText
25867 * The text to display on the cancel button
25869 cancelText : "Cancel",
25871 * @cfg {String} todayTip
25872 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25874 todayTip : "{0} (Spacebar)",
25876 * @cfg {Date} minDate
25877 * Minimum allowable date (JavaScript date object, defaults to null)
25881 * @cfg {Date} maxDate
25882 * Maximum allowable date (JavaScript date object, defaults to null)
25886 * @cfg {String} minText
25887 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25889 minText : "This date is before the minimum date",
25891 * @cfg {String} maxText
25892 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25894 maxText : "This date is after the maximum date",
25896 * @cfg {String} format
25897 * The default date format string which can be overriden for localization support. The format must be
25898 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25902 * @cfg {Array} disabledDays
25903 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25905 disabledDays : null,
25907 * @cfg {String} disabledDaysText
25908 * The tooltip to display when the date falls on a disabled day (defaults to "")
25910 disabledDaysText : "",
25912 * @cfg {RegExp} disabledDatesRE
25913 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25915 disabledDatesRE : null,
25917 * @cfg {String} disabledDatesText
25918 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25920 disabledDatesText : "",
25922 * @cfg {Boolean} constrainToViewport
25923 * True to constrain the date picker to the viewport (defaults to true)
25925 constrainToViewport : true,
25927 * @cfg {Array} monthNames
25928 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25930 monthNames : Date.monthNames,
25932 * @cfg {Array} dayNames
25933 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25935 dayNames : Date.dayNames,
25937 * @cfg {String} nextText
25938 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25940 nextText: 'Next Month (Control+Right)',
25942 * @cfg {String} prevText
25943 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25945 prevText: 'Previous Month (Control+Left)',
25947 * @cfg {String} monthYearText
25948 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25950 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25952 * @cfg {Number} startDay
25953 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25957 * @cfg {Bool} showClear
25958 * Show a clear button (usefull for date form elements that can be blank.)
25964 * Sets the value of the date field
25965 * @param {Date} value The date to set
25967 setValue : function(value){
25968 var old = this.value;
25970 if (typeof(value) == 'string') {
25972 value = Date.parseDate(value, this.format);
25975 value = new Date();
25978 this.value = value.clearTime(true);
25980 this.update(this.value);
25985 * Gets the current selected value of the date field
25986 * @return {Date} The selected date
25988 getValue : function(){
25993 focus : function(){
25995 this.update(this.activeDate);
26000 onRender : function(container, position){
26003 '<table cellspacing="0">',
26004 '<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>',
26005 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26006 var dn = this.dayNames;
26007 for(var i = 0; i < 7; i++){
26008 var d = this.startDay+i;
26012 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26014 m[m.length] = "</tr></thead><tbody><tr>";
26015 for(var i = 0; i < 42; i++) {
26016 if(i % 7 == 0 && i != 0){
26017 m[m.length] = "</tr><tr>";
26019 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26021 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26022 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26024 var el = document.createElement("div");
26025 el.className = "x-date-picker";
26026 el.innerHTML = m.join("");
26028 container.dom.insertBefore(el, position);
26030 this.el = Roo.get(el);
26031 this.eventEl = Roo.get(el.firstChild);
26033 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26034 handler: this.showPrevMonth,
26036 preventDefault:true,
26040 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26041 handler: this.showNextMonth,
26043 preventDefault:true,
26047 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26049 this.monthPicker = this.el.down('div.x-date-mp');
26050 this.monthPicker.enableDisplayMode('block');
26052 var kn = new Roo.KeyNav(this.eventEl, {
26053 "left" : function(e){
26055 this.showPrevMonth() :
26056 this.update(this.activeDate.add("d", -1));
26059 "right" : function(e){
26061 this.showNextMonth() :
26062 this.update(this.activeDate.add("d", 1));
26065 "up" : function(e){
26067 this.showNextYear() :
26068 this.update(this.activeDate.add("d", -7));
26071 "down" : function(e){
26073 this.showPrevYear() :
26074 this.update(this.activeDate.add("d", 7));
26077 "pageUp" : function(e){
26078 this.showNextMonth();
26081 "pageDown" : function(e){
26082 this.showPrevMonth();
26085 "enter" : function(e){
26086 e.stopPropagation();
26093 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26095 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26097 this.el.unselectable();
26099 this.cells = this.el.select("table.x-date-inner tbody td");
26100 this.textNodes = this.el.query("table.x-date-inner tbody span");
26102 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26104 tooltip: this.monthYearText
26107 this.mbtn.on('click', this.showMonthPicker, this);
26108 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26111 var today = (new Date()).dateFormat(this.format);
26113 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26114 if (this.showClear) {
26115 baseTb.add( new Roo.Toolbar.Fill());
26118 text: String.format(this.todayText, today),
26119 tooltip: String.format(this.todayTip, today),
26120 handler: this.selectToday,
26124 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26127 if (this.showClear) {
26129 baseTb.add( new Roo.Toolbar.Fill());
26132 cls: 'x-btn-icon x-btn-clear',
26133 handler: function() {
26135 this.fireEvent("select", this, '');
26145 this.update(this.value);
26148 createMonthPicker : function(){
26149 if(!this.monthPicker.dom.firstChild){
26150 var buf = ['<table border="0" cellspacing="0">'];
26151 for(var i = 0; i < 6; i++){
26153 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26154 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26156 '<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>' :
26157 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26161 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26163 '</button><button type="button" class="x-date-mp-cancel">',
26165 '</button></td></tr>',
26168 this.monthPicker.update(buf.join(''));
26169 this.monthPicker.on('click', this.onMonthClick, this);
26170 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26172 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26173 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26175 this.mpMonths.each(function(m, a, i){
26178 m.dom.xmonth = 5 + Math.round(i * .5);
26180 m.dom.xmonth = Math.round((i-1) * .5);
26186 showMonthPicker : function(){
26187 this.createMonthPicker();
26188 var size = this.el.getSize();
26189 this.monthPicker.setSize(size);
26190 this.monthPicker.child('table').setSize(size);
26192 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26193 this.updateMPMonth(this.mpSelMonth);
26194 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26195 this.updateMPYear(this.mpSelYear);
26197 this.monthPicker.slideIn('t', {duration:.2});
26200 updateMPYear : function(y){
26202 var ys = this.mpYears.elements;
26203 for(var i = 1; i <= 10; i++){
26204 var td = ys[i-1], y2;
26206 y2 = y + Math.round(i * .5);
26207 td.firstChild.innerHTML = y2;
26210 y2 = y - (5-Math.round(i * .5));
26211 td.firstChild.innerHTML = y2;
26214 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26218 updateMPMonth : function(sm){
26219 this.mpMonths.each(function(m, a, i){
26220 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26224 selectMPMonth: function(m){
26228 onMonthClick : function(e, t){
26230 var el = new Roo.Element(t), pn;
26231 if(el.is('button.x-date-mp-cancel')){
26232 this.hideMonthPicker();
26234 else if(el.is('button.x-date-mp-ok')){
26235 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26236 this.hideMonthPicker();
26238 else if(pn = el.up('td.x-date-mp-month', 2)){
26239 this.mpMonths.removeClass('x-date-mp-sel');
26240 pn.addClass('x-date-mp-sel');
26241 this.mpSelMonth = pn.dom.xmonth;
26243 else if(pn = el.up('td.x-date-mp-year', 2)){
26244 this.mpYears.removeClass('x-date-mp-sel');
26245 pn.addClass('x-date-mp-sel');
26246 this.mpSelYear = pn.dom.xyear;
26248 else if(el.is('a.x-date-mp-prev')){
26249 this.updateMPYear(this.mpyear-10);
26251 else if(el.is('a.x-date-mp-next')){
26252 this.updateMPYear(this.mpyear+10);
26256 onMonthDblClick : function(e, t){
26258 var el = new Roo.Element(t), pn;
26259 if(pn = el.up('td.x-date-mp-month', 2)){
26260 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26261 this.hideMonthPicker();
26263 else if(pn = el.up('td.x-date-mp-year', 2)){
26264 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26265 this.hideMonthPicker();
26269 hideMonthPicker : function(disableAnim){
26270 if(this.monthPicker){
26271 if(disableAnim === true){
26272 this.monthPicker.hide();
26274 this.monthPicker.slideOut('t', {duration:.2});
26280 showPrevMonth : function(e){
26281 this.update(this.activeDate.add("mo", -1));
26285 showNextMonth : function(e){
26286 this.update(this.activeDate.add("mo", 1));
26290 showPrevYear : function(){
26291 this.update(this.activeDate.add("y", -1));
26295 showNextYear : function(){
26296 this.update(this.activeDate.add("y", 1));
26300 handleMouseWheel : function(e){
26301 var delta = e.getWheelDelta();
26303 this.showPrevMonth();
26305 } else if(delta < 0){
26306 this.showNextMonth();
26312 handleDateClick : function(e, t){
26314 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26315 this.setValue(new Date(t.dateValue));
26316 this.fireEvent("select", this, this.value);
26321 selectToday : function(){
26322 this.setValue(new Date().clearTime());
26323 this.fireEvent("select", this, this.value);
26327 update : function(date)
26329 var vd = this.activeDate;
26330 this.activeDate = date;
26332 var t = date.getTime();
26333 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26334 this.cells.removeClass("x-date-selected");
26335 this.cells.each(function(c){
26336 if(c.dom.firstChild.dateValue == t){
26337 c.addClass("x-date-selected");
26338 setTimeout(function(){
26339 try{c.dom.firstChild.focus();}catch(e){}
26348 var days = date.getDaysInMonth();
26349 var firstOfMonth = date.getFirstDateOfMonth();
26350 var startingPos = firstOfMonth.getDay()-this.startDay;
26352 if(startingPos <= this.startDay){
26356 var pm = date.add("mo", -1);
26357 var prevStart = pm.getDaysInMonth()-startingPos;
26359 var cells = this.cells.elements;
26360 var textEls = this.textNodes;
26361 days += startingPos;
26363 // convert everything to numbers so it's fast
26364 var day = 86400000;
26365 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26366 var today = new Date().clearTime().getTime();
26367 var sel = date.clearTime().getTime();
26368 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26369 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26370 var ddMatch = this.disabledDatesRE;
26371 var ddText = this.disabledDatesText;
26372 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26373 var ddaysText = this.disabledDaysText;
26374 var format = this.format;
26376 var setCellClass = function(cal, cell){
26378 var t = d.getTime();
26379 cell.firstChild.dateValue = t;
26381 cell.className += " x-date-today";
26382 cell.title = cal.todayText;
26385 cell.className += " x-date-selected";
26386 setTimeout(function(){
26387 try{cell.firstChild.focus();}catch(e){}
26392 cell.className = " x-date-disabled";
26393 cell.title = cal.minText;
26397 cell.className = " x-date-disabled";
26398 cell.title = cal.maxText;
26402 if(ddays.indexOf(d.getDay()) != -1){
26403 cell.title = ddaysText;
26404 cell.className = " x-date-disabled";
26407 if(ddMatch && format){
26408 var fvalue = d.dateFormat(format);
26409 if(ddMatch.test(fvalue)){
26410 cell.title = ddText.replace("%0", fvalue);
26411 cell.className = " x-date-disabled";
26417 for(; i < startingPos; i++) {
26418 textEls[i].innerHTML = (++prevStart);
26419 d.setDate(d.getDate()+1);
26420 cells[i].className = "x-date-prevday";
26421 setCellClass(this, cells[i]);
26423 for(; i < days; i++){
26424 intDay = i - startingPos + 1;
26425 textEls[i].innerHTML = (intDay);
26426 d.setDate(d.getDate()+1);
26427 cells[i].className = "x-date-active";
26428 setCellClass(this, cells[i]);
26431 for(; i < 42; i++) {
26432 textEls[i].innerHTML = (++extraDays);
26433 d.setDate(d.getDate()+1);
26434 cells[i].className = "x-date-nextday";
26435 setCellClass(this, cells[i]);
26438 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26439 this.fireEvent('monthchange', this, date);
26441 if(!this.internalRender){
26442 var main = this.el.dom.firstChild;
26443 var w = main.offsetWidth;
26444 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26445 Roo.fly(main).setWidth(w);
26446 this.internalRender = true;
26447 // opera does not respect the auto grow header center column
26448 // then, after it gets a width opera refuses to recalculate
26449 // without a second pass
26450 if(Roo.isOpera && !this.secondPass){
26451 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26452 this.secondPass = true;
26453 this.update.defer(10, this, [date]);
26461 * Ext JS Library 1.1.1
26462 * Copyright(c) 2006-2007, Ext JS, LLC.
26464 * Originally Released Under LGPL - original licence link has changed is not relivant.
26467 * <script type="text/javascript">
26470 * @class Roo.TabPanel
26471 * @extends Roo.util.Observable
26472 * A lightweight tab container.
26476 // basic tabs 1, built from existing content
26477 var tabs = new Roo.TabPanel("tabs1");
26478 tabs.addTab("script", "View Script");
26479 tabs.addTab("markup", "View Markup");
26480 tabs.activate("script");
26482 // more advanced tabs, built from javascript
26483 var jtabs = new Roo.TabPanel("jtabs");
26484 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26486 // set up the UpdateManager
26487 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26488 var updater = tab2.getUpdateManager();
26489 updater.setDefaultUrl("ajax1.htm");
26490 tab2.on('activate', updater.refresh, updater, true);
26492 // Use setUrl for Ajax loading
26493 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26494 tab3.setUrl("ajax2.htm", null, true);
26497 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26500 jtabs.activate("jtabs-1");
26503 * Create a new TabPanel.
26504 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26505 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26507 Roo.TabPanel = function(container, config){
26509 * The container element for this TabPanel.
26510 * @type Roo.Element
26512 this.el = Roo.get(container, true);
26514 if(typeof config == "boolean"){
26515 this.tabPosition = config ? "bottom" : "top";
26517 Roo.apply(this, config);
26520 if(this.tabPosition == "bottom"){
26521 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26522 this.el.addClass("x-tabs-bottom");
26524 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26525 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26526 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26528 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26530 if(this.tabPosition != "bottom"){
26531 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26532 * @type Roo.Element
26534 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26535 this.el.addClass("x-tabs-top");
26539 this.bodyEl.setStyle("position", "relative");
26541 this.active = null;
26542 this.activateDelegate = this.activate.createDelegate(this);
26547 * Fires when the active tab changes
26548 * @param {Roo.TabPanel} this
26549 * @param {Roo.TabPanelItem} activePanel The new active tab
26553 * @event beforetabchange
26554 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26555 * @param {Roo.TabPanel} this
26556 * @param {Object} e Set cancel to true on this object to cancel the tab change
26557 * @param {Roo.TabPanelItem} tab The tab being changed to
26559 "beforetabchange" : true
26562 Roo.EventManager.onWindowResize(this.onResize, this);
26563 this.cpad = this.el.getPadding("lr");
26564 this.hiddenCount = 0;
26567 // toolbar on the tabbar support...
26568 if (this.toolbar) {
26569 var tcfg = this.toolbar;
26570 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26571 this.toolbar = new Roo.Toolbar(tcfg);
26572 if (Roo.isSafari) {
26573 var tbl = tcfg.container.child('table', true);
26574 tbl.setAttribute('width', '100%');
26581 Roo.TabPanel.superclass.constructor.call(this);
26584 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26586 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26588 tabPosition : "top",
26590 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26592 currentTabWidth : 0,
26594 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26598 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26602 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26604 preferredTabWidth : 175,
26606 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26608 resizeTabs : false,
26610 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26612 monitorResize : true,
26614 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26619 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26620 * @param {String} id The id of the div to use <b>or create</b>
26621 * @param {String} text The text for the tab
26622 * @param {String} content (optional) Content to put in the TabPanelItem body
26623 * @param {Boolean} closable (optional) True to create a close icon on the tab
26624 * @return {Roo.TabPanelItem} The created TabPanelItem
26626 addTab : function(id, text, content, closable){
26627 var item = new Roo.TabPanelItem(this, id, text, closable);
26628 this.addTabItem(item);
26630 item.setContent(content);
26636 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26637 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26638 * @return {Roo.TabPanelItem}
26640 getTab : function(id){
26641 return this.items[id];
26645 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26646 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26648 hideTab : function(id){
26649 var t = this.items[id];
26652 this.hiddenCount++;
26653 this.autoSizeTabs();
26658 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26659 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26661 unhideTab : function(id){
26662 var t = this.items[id];
26664 t.setHidden(false);
26665 this.hiddenCount--;
26666 this.autoSizeTabs();
26671 * Adds an existing {@link Roo.TabPanelItem}.
26672 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26674 addTabItem : function(item){
26675 this.items[item.id] = item;
26676 this.items.push(item);
26677 if(this.resizeTabs){
26678 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26679 this.autoSizeTabs();
26686 * Removes a {@link Roo.TabPanelItem}.
26687 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26689 removeTab : function(id){
26690 var items = this.items;
26691 var tab = items[id];
26692 if(!tab) { return; }
26693 var index = items.indexOf(tab);
26694 if(this.active == tab && items.length > 1){
26695 var newTab = this.getNextAvailable(index);
26700 this.stripEl.dom.removeChild(tab.pnode.dom);
26701 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26702 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26704 items.splice(index, 1);
26705 delete this.items[tab.id];
26706 tab.fireEvent("close", tab);
26707 tab.purgeListeners();
26708 this.autoSizeTabs();
26711 getNextAvailable : function(start){
26712 var items = this.items;
26714 // look for a next tab that will slide over to
26715 // replace the one being removed
26716 while(index < items.length){
26717 var item = items[++index];
26718 if(item && !item.isHidden()){
26722 // if one isn't found select the previous tab (on the left)
26725 var item = items[--index];
26726 if(item && !item.isHidden()){
26734 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26735 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26737 disableTab : function(id){
26738 var tab = this.items[id];
26739 if(tab && this.active != tab){
26745 * Enables a {@link Roo.TabPanelItem} that is disabled.
26746 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26748 enableTab : function(id){
26749 var tab = this.items[id];
26754 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26755 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26756 * @return {Roo.TabPanelItem} The TabPanelItem.
26758 activate : function(id){
26759 var tab = this.items[id];
26763 if(tab == this.active || tab.disabled){
26767 this.fireEvent("beforetabchange", this, e, tab);
26768 if(e.cancel !== true && !tab.disabled){
26770 this.active.hide();
26772 this.active = this.items[id];
26773 this.active.show();
26774 this.fireEvent("tabchange", this, this.active);
26780 * Gets the active {@link Roo.TabPanelItem}.
26781 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26783 getActiveTab : function(){
26784 return this.active;
26788 * Updates the tab body element to fit the height of the container element
26789 * for overflow scrolling
26790 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26792 syncHeight : function(targetHeight){
26793 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26794 var bm = this.bodyEl.getMargins();
26795 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26796 this.bodyEl.setHeight(newHeight);
26800 onResize : function(){
26801 if(this.monitorResize){
26802 this.autoSizeTabs();
26807 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26809 beginUpdate : function(){
26810 this.updating = true;
26814 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26816 endUpdate : function(){
26817 this.updating = false;
26818 this.autoSizeTabs();
26822 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26824 autoSizeTabs : function(){
26825 var count = this.items.length;
26826 var vcount = count - this.hiddenCount;
26827 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26828 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26829 var availWidth = Math.floor(w / vcount);
26830 var b = this.stripBody;
26831 if(b.getWidth() > w){
26832 var tabs = this.items;
26833 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26834 if(availWidth < this.minTabWidth){
26835 /*if(!this.sleft){ // incomplete scrolling code
26836 this.createScrollButtons();
26839 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26842 if(this.currentTabWidth < this.preferredTabWidth){
26843 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26849 * Returns the number of tabs in this TabPanel.
26852 getCount : function(){
26853 return this.items.length;
26857 * Resizes all the tabs to the passed width
26858 * @param {Number} The new width
26860 setTabWidth : function(width){
26861 this.currentTabWidth = width;
26862 for(var i = 0, len = this.items.length; i < len; i++) {
26863 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26868 * Destroys this TabPanel
26869 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26871 destroy : function(removeEl){
26872 Roo.EventManager.removeResizeListener(this.onResize, this);
26873 for(var i = 0, len = this.items.length; i < len; i++){
26874 this.items[i].purgeListeners();
26876 if(removeEl === true){
26877 this.el.update("");
26884 * @class Roo.TabPanelItem
26885 * @extends Roo.util.Observable
26886 * Represents an individual item (tab plus body) in a TabPanel.
26887 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26888 * @param {String} id The id of this TabPanelItem
26889 * @param {String} text The text for the tab of this TabPanelItem
26890 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26892 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26894 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26895 * @type Roo.TabPanel
26897 this.tabPanel = tabPanel;
26899 * The id for this TabPanelItem
26904 this.disabled = false;
26908 this.loaded = false;
26909 this.closable = closable;
26912 * The body element for this TabPanelItem.
26913 * @type Roo.Element
26915 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26916 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26917 this.bodyEl.setStyle("display", "block");
26918 this.bodyEl.setStyle("zoom", "1");
26921 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26923 this.el = Roo.get(els.el, true);
26924 this.inner = Roo.get(els.inner, true);
26925 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26926 this.pnode = Roo.get(els.el.parentNode, true);
26927 this.el.on("mousedown", this.onTabMouseDown, this);
26928 this.el.on("click", this.onTabClick, this);
26931 var c = Roo.get(els.close, true);
26932 c.dom.title = this.closeText;
26933 c.addClassOnOver("close-over");
26934 c.on("click", this.closeClick, this);
26940 * Fires when this tab becomes the active tab.
26941 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26942 * @param {Roo.TabPanelItem} this
26946 * @event beforeclose
26947 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26948 * @param {Roo.TabPanelItem} this
26949 * @param {Object} e Set cancel to true on this object to cancel the close.
26951 "beforeclose": true,
26954 * Fires when this tab is closed.
26955 * @param {Roo.TabPanelItem} this
26959 * @event deactivate
26960 * Fires when this tab is no longer the active tab.
26961 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26962 * @param {Roo.TabPanelItem} this
26964 "deactivate" : true
26966 this.hidden = false;
26968 Roo.TabPanelItem.superclass.constructor.call(this);
26971 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
26972 purgeListeners : function(){
26973 Roo.util.Observable.prototype.purgeListeners.call(this);
26974 this.el.removeAllListeners();
26977 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
26980 this.pnode.addClass("on");
26983 this.tabPanel.stripWrap.repaint();
26985 this.fireEvent("activate", this.tabPanel, this);
26989 * Returns true if this tab is the active tab.
26990 * @return {Boolean}
26992 isActive : function(){
26993 return this.tabPanel.getActiveTab() == this;
26997 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27000 this.pnode.removeClass("on");
27002 this.fireEvent("deactivate", this.tabPanel, this);
27005 hideAction : function(){
27006 this.bodyEl.hide();
27007 this.bodyEl.setStyle("position", "absolute");
27008 this.bodyEl.setLeft("-20000px");
27009 this.bodyEl.setTop("-20000px");
27012 showAction : function(){
27013 this.bodyEl.setStyle("position", "relative");
27014 this.bodyEl.setTop("");
27015 this.bodyEl.setLeft("");
27016 this.bodyEl.show();
27020 * Set the tooltip for the tab.
27021 * @param {String} tooltip The tab's tooltip
27023 setTooltip : function(text){
27024 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27025 this.textEl.dom.qtip = text;
27026 this.textEl.dom.removeAttribute('title');
27028 this.textEl.dom.title = text;
27032 onTabClick : function(e){
27033 e.preventDefault();
27034 this.tabPanel.activate(this.id);
27037 onTabMouseDown : function(e){
27038 e.preventDefault();
27039 this.tabPanel.activate(this.id);
27042 getWidth : function(){
27043 return this.inner.getWidth();
27046 setWidth : function(width){
27047 var iwidth = width - this.pnode.getPadding("lr");
27048 this.inner.setWidth(iwidth);
27049 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27050 this.pnode.setWidth(width);
27054 * Show or hide the tab
27055 * @param {Boolean} hidden True to hide or false to show.
27057 setHidden : function(hidden){
27058 this.hidden = hidden;
27059 this.pnode.setStyle("display", hidden ? "none" : "");
27063 * Returns true if this tab is "hidden"
27064 * @return {Boolean}
27066 isHidden : function(){
27067 return this.hidden;
27071 * Returns the text for this tab
27074 getText : function(){
27078 autoSize : function(){
27079 //this.el.beginMeasure();
27080 this.textEl.setWidth(1);
27081 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
27082 //this.el.endMeasure();
27086 * Sets the text for the tab (Note: this also sets the tooltip text)
27087 * @param {String} text The tab's text and tooltip
27089 setText : function(text){
27091 this.textEl.update(text);
27092 this.setTooltip(text);
27093 if(!this.tabPanel.resizeTabs){
27098 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27100 activate : function(){
27101 this.tabPanel.activate(this.id);
27105 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27107 disable : function(){
27108 if(this.tabPanel.active != this){
27109 this.disabled = true;
27110 this.pnode.addClass("disabled");
27115 * Enables this TabPanelItem if it was previously disabled.
27117 enable : function(){
27118 this.disabled = false;
27119 this.pnode.removeClass("disabled");
27123 * Sets the content for this TabPanelItem.
27124 * @param {String} content The content
27125 * @param {Boolean} loadScripts true to look for and load scripts
27127 setContent : function(content, loadScripts){
27128 this.bodyEl.update(content, loadScripts);
27132 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27133 * @return {Roo.UpdateManager} The UpdateManager
27135 getUpdateManager : function(){
27136 return this.bodyEl.getUpdateManager();
27140 * Set a URL to be used to load the content for this TabPanelItem.
27141 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27142 * @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)
27143 * @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)
27144 * @return {Roo.UpdateManager} The UpdateManager
27146 setUrl : function(url, params, loadOnce){
27147 if(this.refreshDelegate){
27148 this.un('activate', this.refreshDelegate);
27150 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27151 this.on("activate", this.refreshDelegate);
27152 return this.bodyEl.getUpdateManager();
27156 _handleRefresh : function(url, params, loadOnce){
27157 if(!loadOnce || !this.loaded){
27158 var updater = this.bodyEl.getUpdateManager();
27159 updater.update(url, params, this._setLoaded.createDelegate(this));
27164 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27165 * Will fail silently if the setUrl method has not been called.
27166 * This does not activate the panel, just updates its content.
27168 refresh : function(){
27169 if(this.refreshDelegate){
27170 this.loaded = false;
27171 this.refreshDelegate();
27176 _setLoaded : function(){
27177 this.loaded = true;
27181 closeClick : function(e){
27184 this.fireEvent("beforeclose", this, o);
27185 if(o.cancel !== true){
27186 this.tabPanel.removeTab(this.id);
27190 * The text displayed in the tooltip for the close icon.
27193 closeText : "Close this tab"
27197 Roo.TabPanel.prototype.createStrip = function(container){
27198 var strip = document.createElement("div");
27199 strip.className = "x-tabs-wrap";
27200 container.appendChild(strip);
27204 Roo.TabPanel.prototype.createStripList = function(strip){
27205 // div wrapper for retard IE
27206 // returns the "tr" element.
27207 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27208 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27209 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27210 return strip.firstChild.firstChild.firstChild.firstChild;
27213 Roo.TabPanel.prototype.createBody = function(container){
27214 var body = document.createElement("div");
27215 Roo.id(body, "tab-body");
27216 Roo.fly(body).addClass("x-tabs-body");
27217 container.appendChild(body);
27221 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27222 var body = Roo.getDom(id);
27224 body = document.createElement("div");
27227 Roo.fly(body).addClass("x-tabs-item-body");
27228 bodyEl.insertBefore(body, bodyEl.firstChild);
27232 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27233 var td = document.createElement("td");
27234 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27235 //stripEl.appendChild(td);
27237 td.className = "x-tabs-closable";
27238 if(!this.closeTpl){
27239 this.closeTpl = new Roo.Template(
27240 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27241 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27242 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27245 var el = this.closeTpl.overwrite(td, {"text": text});
27246 var close = el.getElementsByTagName("div")[0];
27247 var inner = el.getElementsByTagName("em")[0];
27248 return {"el": el, "close": close, "inner": inner};
27251 this.tabTpl = new Roo.Template(
27252 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27253 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27256 var el = this.tabTpl.overwrite(td, {"text": text});
27257 var inner = el.getElementsByTagName("em")[0];
27258 return {"el": el, "inner": inner};
27262 * Ext JS Library 1.1.1
27263 * Copyright(c) 2006-2007, Ext JS, LLC.
27265 * Originally Released Under LGPL - original licence link has changed is not relivant.
27268 * <script type="text/javascript">
27272 * @class Roo.Button
27273 * @extends Roo.util.Observable
27274 * Simple Button class
27275 * @cfg {String} text The button text
27276 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27277 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27278 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27279 * @cfg {Object} scope The scope of the handler
27280 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27281 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27282 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27283 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27284 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27285 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27286 applies if enableToggle = true)
27287 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27288 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27289 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27291 * Create a new button
27292 * @param {Object} config The config object
27294 Roo.Button = function(renderTo, config)
27298 renderTo = config.renderTo || false;
27301 Roo.apply(this, config);
27305 * Fires when this button is clicked
27306 * @param {Button} this
27307 * @param {EventObject} e The click event
27312 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27313 * @param {Button} this
27314 * @param {Boolean} pressed
27319 * Fires when the mouse hovers over the button
27320 * @param {Button} this
27321 * @param {Event} e The event object
27323 'mouseover' : true,
27326 * Fires when the mouse exits the button
27327 * @param {Button} this
27328 * @param {Event} e The event object
27333 * Fires when the button is rendered
27334 * @param {Button} this
27339 this.menu = Roo.menu.MenuMgr.get(this.menu);
27341 // register listeners first!! - so render can be captured..
27342 Roo.util.Observable.call(this);
27344 this.render(renderTo);
27350 Roo.extend(Roo.Button, Roo.util.Observable, {
27356 * Read-only. True if this button is hidden
27361 * Read-only. True if this button is disabled
27366 * Read-only. True if this button is pressed (only if enableToggle = true)
27372 * @cfg {Number} tabIndex
27373 * The DOM tabIndex for this button (defaults to undefined)
27375 tabIndex : undefined,
27378 * @cfg {Boolean} enableToggle
27379 * True to enable pressed/not pressed toggling (defaults to false)
27381 enableToggle: false,
27383 * @cfg {Mixed} menu
27384 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27388 * @cfg {String} menuAlign
27389 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27391 menuAlign : "tl-bl?",
27394 * @cfg {String} iconCls
27395 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27397 iconCls : undefined,
27399 * @cfg {String} type
27400 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27405 menuClassTarget: 'tr',
27408 * @cfg {String} clickEvent
27409 * The type of event to map to the button's event handler (defaults to 'click')
27411 clickEvent : 'click',
27414 * @cfg {Boolean} handleMouseEvents
27415 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27417 handleMouseEvents : true,
27420 * @cfg {String} tooltipType
27421 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27423 tooltipType : 'qtip',
27426 * @cfg {String} cls
27427 * A CSS class to apply to the button's main element.
27431 * @cfg {Roo.Template} template (Optional)
27432 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27433 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27434 * require code modifications if required elements (e.g. a button) aren't present.
27438 render : function(renderTo){
27440 if(this.hideParent){
27441 this.parentEl = Roo.get(renderTo);
27443 if(!this.dhconfig){
27444 if(!this.template){
27445 if(!Roo.Button.buttonTemplate){
27446 // hideous table template
27447 Roo.Button.buttonTemplate = new Roo.Template(
27448 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27449 '<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>',
27450 "</tr></tbody></table>");
27452 this.template = Roo.Button.buttonTemplate;
27454 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27455 var btnEl = btn.child("button:first");
27456 btnEl.on('focus', this.onFocus, this);
27457 btnEl.on('blur', this.onBlur, this);
27459 btn.addClass(this.cls);
27462 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27465 btnEl.addClass(this.iconCls);
27467 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27470 if(this.tabIndex !== undefined){
27471 btnEl.dom.tabIndex = this.tabIndex;
27474 if(typeof this.tooltip == 'object'){
27475 Roo.QuickTips.tips(Roo.apply({
27479 btnEl.dom[this.tooltipType] = this.tooltip;
27483 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27487 this.el.dom.id = this.el.id = this.id;
27490 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27491 this.menu.on("show", this.onMenuShow, this);
27492 this.menu.on("hide", this.onMenuHide, this);
27494 btn.addClass("x-btn");
27495 if(Roo.isIE && !Roo.isIE7){
27496 this.autoWidth.defer(1, this);
27500 if(this.handleMouseEvents){
27501 btn.on("mouseover", this.onMouseOver, this);
27502 btn.on("mouseout", this.onMouseOut, this);
27503 btn.on("mousedown", this.onMouseDown, this);
27505 btn.on(this.clickEvent, this.onClick, this);
27506 //btn.on("mouseup", this.onMouseUp, this);
27513 Roo.ButtonToggleMgr.register(this);
27515 this.el.addClass("x-btn-pressed");
27518 var repeater = new Roo.util.ClickRepeater(btn,
27519 typeof this.repeat == "object" ? this.repeat : {}
27521 repeater.on("click", this.onClick, this);
27524 this.fireEvent('render', this);
27528 * Returns the button's underlying element
27529 * @return {Roo.Element} The element
27531 getEl : function(){
27536 * Destroys this Button and removes any listeners.
27538 destroy : function(){
27539 Roo.ButtonToggleMgr.unregister(this);
27540 this.el.removeAllListeners();
27541 this.purgeListeners();
27546 autoWidth : function(){
27548 this.el.setWidth("auto");
27549 if(Roo.isIE7 && Roo.isStrict){
27550 var ib = this.el.child('button');
27551 if(ib && ib.getWidth() > 20){
27553 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27558 this.el.beginMeasure();
27560 if(this.el.getWidth() < this.minWidth){
27561 this.el.setWidth(this.minWidth);
27564 this.el.endMeasure();
27571 * Assigns this button's click handler
27572 * @param {Function} handler The function to call when the button is clicked
27573 * @param {Object} scope (optional) Scope for the function passed in
27575 setHandler : function(handler, scope){
27576 this.handler = handler;
27577 this.scope = scope;
27581 * Sets this button's text
27582 * @param {String} text The button text
27584 setText : function(text){
27587 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27593 * Gets the text for this button
27594 * @return {String} The button text
27596 getText : function(){
27604 this.hidden = false;
27606 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27614 this.hidden = true;
27616 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27621 * Convenience function for boolean show/hide
27622 * @param {Boolean} visible True to show, false to hide
27624 setVisible: function(visible){
27633 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27634 * @param {Boolean} state (optional) Force a particular state
27636 toggle : function(state){
27637 state = state === undefined ? !this.pressed : state;
27638 if(state != this.pressed){
27640 this.el.addClass("x-btn-pressed");
27641 this.pressed = true;
27642 this.fireEvent("toggle", this, true);
27644 this.el.removeClass("x-btn-pressed");
27645 this.pressed = false;
27646 this.fireEvent("toggle", this, false);
27648 if(this.toggleHandler){
27649 this.toggleHandler.call(this.scope || this, this, state);
27657 focus : function(){
27658 this.el.child('button:first').focus();
27662 * Disable this button
27664 disable : function(){
27666 this.el.addClass("x-btn-disabled");
27668 this.disabled = true;
27672 * Enable this button
27674 enable : function(){
27676 this.el.removeClass("x-btn-disabled");
27678 this.disabled = false;
27682 * Convenience function for boolean enable/disable
27683 * @param {Boolean} enabled True to enable, false to disable
27685 setDisabled : function(v){
27686 this[v !== true ? "enable" : "disable"]();
27690 onClick : function(e){
27692 e.preventDefault();
27697 if(!this.disabled){
27698 if(this.enableToggle){
27701 if(this.menu && !this.menu.isVisible()){
27702 this.menu.show(this.el, this.menuAlign);
27704 this.fireEvent("click", this, e);
27706 this.el.removeClass("x-btn-over");
27707 this.handler.call(this.scope || this, this, e);
27712 onMouseOver : function(e){
27713 if(!this.disabled){
27714 this.el.addClass("x-btn-over");
27715 this.fireEvent('mouseover', this, e);
27719 onMouseOut : function(e){
27720 if(!e.within(this.el, true)){
27721 this.el.removeClass("x-btn-over");
27722 this.fireEvent('mouseout', this, e);
27726 onFocus : function(e){
27727 if(!this.disabled){
27728 this.el.addClass("x-btn-focus");
27732 onBlur : function(e){
27733 this.el.removeClass("x-btn-focus");
27736 onMouseDown : function(e){
27737 if(!this.disabled && e.button == 0){
27738 this.el.addClass("x-btn-click");
27739 Roo.get(document).on('mouseup', this.onMouseUp, this);
27743 onMouseUp : function(e){
27745 this.el.removeClass("x-btn-click");
27746 Roo.get(document).un('mouseup', this.onMouseUp, this);
27750 onMenuShow : function(e){
27751 this.el.addClass("x-btn-menu-active");
27754 onMenuHide : function(e){
27755 this.el.removeClass("x-btn-menu-active");
27759 // Private utility class used by Button
27760 Roo.ButtonToggleMgr = function(){
27763 function toggleGroup(btn, state){
27765 var g = groups[btn.toggleGroup];
27766 for(var i = 0, l = g.length; i < l; i++){
27768 g[i].toggle(false);
27775 register : function(btn){
27776 if(!btn.toggleGroup){
27779 var g = groups[btn.toggleGroup];
27781 g = groups[btn.toggleGroup] = [];
27784 btn.on("toggle", toggleGroup);
27787 unregister : function(btn){
27788 if(!btn.toggleGroup){
27791 var g = groups[btn.toggleGroup];
27794 btn.un("toggle", toggleGroup);
27800 * Ext JS Library 1.1.1
27801 * Copyright(c) 2006-2007, Ext JS, LLC.
27803 * Originally Released Under LGPL - original licence link has changed is not relivant.
27806 * <script type="text/javascript">
27810 * @class Roo.SplitButton
27811 * @extends Roo.Button
27812 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27813 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27814 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27815 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27816 * @cfg {String} arrowTooltip The title attribute of the arrow
27818 * Create a new menu button
27819 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27820 * @param {Object} config The config object
27822 Roo.SplitButton = function(renderTo, config){
27823 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27825 * @event arrowclick
27826 * Fires when this button's arrow is clicked
27827 * @param {SplitButton} this
27828 * @param {EventObject} e The click event
27830 this.addEvents({"arrowclick":true});
27833 Roo.extend(Roo.SplitButton, Roo.Button, {
27834 render : function(renderTo){
27835 // this is one sweet looking template!
27836 var tpl = new Roo.Template(
27837 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27838 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27839 '<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>',
27840 "</tbody></table></td><td>",
27841 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27842 '<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>',
27843 "</tbody></table></td></tr></table>"
27845 var btn = tpl.append(renderTo, [this.text, this.type], true);
27846 var btnEl = btn.child("button");
27848 btn.addClass(this.cls);
27851 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27854 btnEl.addClass(this.iconCls);
27856 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27860 if(this.handleMouseEvents){
27861 btn.on("mouseover", this.onMouseOver, this);
27862 btn.on("mouseout", this.onMouseOut, this);
27863 btn.on("mousedown", this.onMouseDown, this);
27864 btn.on("mouseup", this.onMouseUp, this);
27866 btn.on(this.clickEvent, this.onClick, this);
27868 if(typeof this.tooltip == 'object'){
27869 Roo.QuickTips.tips(Roo.apply({
27873 btnEl.dom[this.tooltipType] = this.tooltip;
27876 if(this.arrowTooltip){
27877 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27886 this.el.addClass("x-btn-pressed");
27888 if(Roo.isIE && !Roo.isIE7){
27889 this.autoWidth.defer(1, this);
27894 this.menu.on("show", this.onMenuShow, this);
27895 this.menu.on("hide", this.onMenuHide, this);
27897 this.fireEvent('render', this);
27901 autoWidth : function(){
27903 var tbl = this.el.child("table:first");
27904 var tbl2 = this.el.child("table:last");
27905 this.el.setWidth("auto");
27906 tbl.setWidth("auto");
27907 if(Roo.isIE7 && Roo.isStrict){
27908 var ib = this.el.child('button:first');
27909 if(ib && ib.getWidth() > 20){
27911 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27916 this.el.beginMeasure();
27918 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27919 tbl.setWidth(this.minWidth-tbl2.getWidth());
27922 this.el.endMeasure();
27925 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27929 * Sets this button's click handler
27930 * @param {Function} handler The function to call when the button is clicked
27931 * @param {Object} scope (optional) Scope for the function passed above
27933 setHandler : function(handler, scope){
27934 this.handler = handler;
27935 this.scope = scope;
27939 * Sets this button's arrow click handler
27940 * @param {Function} handler The function to call when the arrow is clicked
27941 * @param {Object} scope (optional) Scope for the function passed above
27943 setArrowHandler : function(handler, scope){
27944 this.arrowHandler = handler;
27945 this.scope = scope;
27951 focus : function(){
27953 this.el.child("button:first").focus();
27958 onClick : function(e){
27959 e.preventDefault();
27960 if(!this.disabled){
27961 if(e.getTarget(".x-btn-menu-arrow-wrap")){
27962 if(this.menu && !this.menu.isVisible()){
27963 this.menu.show(this.el, this.menuAlign);
27965 this.fireEvent("arrowclick", this, e);
27966 if(this.arrowHandler){
27967 this.arrowHandler.call(this.scope || this, this, e);
27970 this.fireEvent("click", this, e);
27972 this.handler.call(this.scope || this, this, e);
27978 onMouseDown : function(e){
27979 if(!this.disabled){
27980 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
27984 onMouseUp : function(e){
27985 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
27990 // backwards compat
27991 Roo.MenuButton = Roo.SplitButton;/*
27993 * Ext JS Library 1.1.1
27994 * Copyright(c) 2006-2007, Ext JS, LLC.
27996 * Originally Released Under LGPL - original licence link has changed is not relivant.
27999 * <script type="text/javascript">
28003 * @class Roo.Toolbar
28004 * Basic Toolbar class.
28006 * Creates a new Toolbar
28007 * @param {Object} container The config object
28009 Roo.Toolbar = function(container, buttons, config)
28011 /// old consturctor format still supported..
28012 if(container instanceof Array){ // omit the container for later rendering
28013 buttons = container;
28017 if (typeof(container) == 'object' && container.xtype) {
28018 config = container;
28019 container = config.container;
28020 buttons = config.buttons || []; // not really - use items!!
28023 if (config && config.items) {
28024 xitems = config.items;
28025 delete config.items;
28027 Roo.apply(this, config);
28028 this.buttons = buttons;
28031 this.render(container);
28033 this.xitems = xitems;
28034 Roo.each(xitems, function(b) {
28040 Roo.Toolbar.prototype = {
28042 * @cfg {Array} items
28043 * array of button configs or elements to add (will be converted to a MixedCollection)
28047 * @cfg {String/HTMLElement/Element} container
28048 * The id or element that will contain the toolbar
28051 render : function(ct){
28052 this.el = Roo.get(ct);
28054 this.el.addClass(this.cls);
28056 // using a table allows for vertical alignment
28057 // 100% width is needed by Safari...
28058 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28059 this.tr = this.el.child("tr", true);
28061 this.items = new Roo.util.MixedCollection(false, function(o){
28062 return o.id || ("item" + (++autoId));
28065 this.add.apply(this, this.buttons);
28066 delete this.buttons;
28071 * Adds element(s) to the toolbar -- this function takes a variable number of
28072 * arguments of mixed type and adds them to the toolbar.
28073 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28075 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28076 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28077 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28078 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28079 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28080 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28081 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28082 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28083 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28085 * @param {Mixed} arg2
28086 * @param {Mixed} etc.
28089 var a = arguments, l = a.length;
28090 for(var i = 0; i < l; i++){
28095 _add : function(el) {
28098 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28101 if (el.applyTo){ // some kind of form field
28102 return this.addField(el);
28104 if (el.render){ // some kind of Toolbar.Item
28105 return this.addItem(el);
28107 if (typeof el == "string"){ // string
28108 if(el == "separator" || el == "-"){
28109 return this.addSeparator();
28112 return this.addSpacer();
28115 return this.addFill();
28117 return this.addText(el);
28120 if(el.tagName){ // element
28121 return this.addElement(el);
28123 if(typeof el == "object"){ // must be button config?
28124 return this.addButton(el);
28126 // and now what?!?!
28132 * Add an Xtype element
28133 * @param {Object} xtype Xtype Object
28134 * @return {Object} created Object
28136 addxtype : function(e){
28137 return this.add(e);
28141 * Returns the Element for this toolbar.
28142 * @return {Roo.Element}
28144 getEl : function(){
28150 * @return {Roo.Toolbar.Item} The separator item
28152 addSeparator : function(){
28153 return this.addItem(new Roo.Toolbar.Separator());
28157 * Adds a spacer element
28158 * @return {Roo.Toolbar.Spacer} The spacer item
28160 addSpacer : function(){
28161 return this.addItem(new Roo.Toolbar.Spacer());
28165 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28166 * @return {Roo.Toolbar.Fill} The fill item
28168 addFill : function(){
28169 return this.addItem(new Roo.Toolbar.Fill());
28173 * Adds any standard HTML element to the toolbar
28174 * @param {String/HTMLElement/Element} el The element or id of the element to add
28175 * @return {Roo.Toolbar.Item} The element's item
28177 addElement : function(el){
28178 return this.addItem(new Roo.Toolbar.Item(el));
28181 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28182 * @type Roo.util.MixedCollection
28187 * Adds any Toolbar.Item or subclass
28188 * @param {Roo.Toolbar.Item} item
28189 * @return {Roo.Toolbar.Item} The item
28191 addItem : function(item){
28192 var td = this.nextBlock();
28194 this.items.add(item);
28199 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28200 * @param {Object/Array} config A button config or array of configs
28201 * @return {Roo.Toolbar.Button/Array}
28203 addButton : function(config){
28204 if(config instanceof Array){
28206 for(var i = 0, len = config.length; i < len; i++) {
28207 buttons.push(this.addButton(config[i]));
28212 if(!(config instanceof Roo.Toolbar.Button)){
28214 new Roo.Toolbar.SplitButton(config) :
28215 new Roo.Toolbar.Button(config);
28217 var td = this.nextBlock();
28224 * Adds text to the toolbar
28225 * @param {String} text The text to add
28226 * @return {Roo.Toolbar.Item} The element's item
28228 addText : function(text){
28229 return this.addItem(new Roo.Toolbar.TextItem(text));
28233 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28234 * @param {Number} index The index where the item is to be inserted
28235 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28236 * @return {Roo.Toolbar.Button/Item}
28238 insertButton : function(index, item){
28239 if(item instanceof Array){
28241 for(var i = 0, len = item.length; i < len; i++) {
28242 buttons.push(this.insertButton(index + i, item[i]));
28246 if (!(item instanceof Roo.Toolbar.Button)){
28247 item = new Roo.Toolbar.Button(item);
28249 var td = document.createElement("td");
28250 this.tr.insertBefore(td, this.tr.childNodes[index]);
28252 this.items.insert(index, item);
28257 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28258 * @param {Object} config
28259 * @return {Roo.Toolbar.Item} The element's item
28261 addDom : function(config, returnEl){
28262 var td = this.nextBlock();
28263 Roo.DomHelper.overwrite(td, config);
28264 var ti = new Roo.Toolbar.Item(td.firstChild);
28266 this.items.add(ti);
28271 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28272 * @type Roo.util.MixedCollection
28277 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28278 * Note: the field should not have been rendered yet. For a field that has already been
28279 * rendered, use {@link #addElement}.
28280 * @param {Roo.form.Field} field
28281 * @return {Roo.ToolbarItem}
28285 addField : function(field) {
28286 if (!this.fields) {
28288 this.fields = new Roo.util.MixedCollection(false, function(o){
28289 return o.id || ("item" + (++autoId));
28294 var td = this.nextBlock();
28296 var ti = new Roo.Toolbar.Item(td.firstChild);
28298 this.items.add(ti);
28299 this.fields.add(field);
28310 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28311 this.el.child('div').hide();
28319 this.el.child('div').show();
28323 nextBlock : function(){
28324 var td = document.createElement("td");
28325 this.tr.appendChild(td);
28330 destroy : function(){
28331 if(this.items){ // rendered?
28332 Roo.destroy.apply(Roo, this.items.items);
28334 if(this.fields){ // rendered?
28335 Roo.destroy.apply(Roo, this.fields.items);
28337 Roo.Element.uncache(this.el, this.tr);
28342 * @class Roo.Toolbar.Item
28343 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28345 * Creates a new Item
28346 * @param {HTMLElement} el
28348 Roo.Toolbar.Item = function(el){
28349 this.el = Roo.getDom(el);
28350 this.id = Roo.id(this.el);
28351 this.hidden = false;
28354 Roo.Toolbar.Item.prototype = {
28357 * Get this item's HTML Element
28358 * @return {HTMLElement}
28360 getEl : function(){
28365 render : function(td){
28367 td.appendChild(this.el);
28371 * Removes and destroys this item.
28373 destroy : function(){
28374 this.td.parentNode.removeChild(this.td);
28381 this.hidden = false;
28382 this.td.style.display = "";
28389 this.hidden = true;
28390 this.td.style.display = "none";
28394 * Convenience function for boolean show/hide.
28395 * @param {Boolean} visible true to show/false to hide
28397 setVisible: function(visible){
28406 * Try to focus this item.
28408 focus : function(){
28409 Roo.fly(this.el).focus();
28413 * Disables this item.
28415 disable : function(){
28416 Roo.fly(this.td).addClass("x-item-disabled");
28417 this.disabled = true;
28418 this.el.disabled = true;
28422 * Enables this item.
28424 enable : function(){
28425 Roo.fly(this.td).removeClass("x-item-disabled");
28426 this.disabled = false;
28427 this.el.disabled = false;
28433 * @class Roo.Toolbar.Separator
28434 * @extends Roo.Toolbar.Item
28435 * A simple toolbar separator class
28437 * Creates a new Separator
28439 Roo.Toolbar.Separator = function(){
28440 var s = document.createElement("span");
28441 s.className = "ytb-sep";
28442 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
28444 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28445 enable:Roo.emptyFn,
28446 disable:Roo.emptyFn,
28451 * @class Roo.Toolbar.Spacer
28452 * @extends Roo.Toolbar.Item
28453 * A simple element that adds extra horizontal space to a toolbar.
28455 * Creates a new Spacer
28457 Roo.Toolbar.Spacer = function(){
28458 var s = document.createElement("div");
28459 s.className = "ytb-spacer";
28460 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
28462 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28463 enable:Roo.emptyFn,
28464 disable:Roo.emptyFn,
28469 * @class Roo.Toolbar.Fill
28470 * @extends Roo.Toolbar.Spacer
28471 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28473 * Creates a new Spacer
28475 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28477 render : function(td){
28478 td.style.width = '100%';
28479 Roo.Toolbar.Fill.superclass.render.call(this, td);
28484 * @class Roo.Toolbar.TextItem
28485 * @extends Roo.Toolbar.Item
28486 * A simple class that renders text directly into a toolbar.
28488 * Creates a new TextItem
28489 * @param {String} text
28491 Roo.Toolbar.TextItem = function(text){
28492 if (typeof(text) == 'object') {
28495 var s = document.createElement("span");
28496 s.className = "ytb-text";
28497 s.innerHTML = text;
28498 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28500 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28501 enable:Roo.emptyFn,
28502 disable:Roo.emptyFn,
28507 * @class Roo.Toolbar.Button
28508 * @extends Roo.Button
28509 * A button that renders into a toolbar.
28511 * Creates a new Button
28512 * @param {Object} config A standard {@link Roo.Button} config object
28514 Roo.Toolbar.Button = function(config){
28515 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28517 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28518 render : function(td){
28520 Roo.Toolbar.Button.superclass.render.call(this, td);
28524 * Removes and destroys this button
28526 destroy : function(){
28527 Roo.Toolbar.Button.superclass.destroy.call(this);
28528 this.td.parentNode.removeChild(this.td);
28532 * Shows this button
28535 this.hidden = false;
28536 this.td.style.display = "";
28540 * Hides this button
28543 this.hidden = true;
28544 this.td.style.display = "none";
28548 * Disables this item
28550 disable : function(){
28551 Roo.fly(this.td).addClass("x-item-disabled");
28552 this.disabled = true;
28556 * Enables this item
28558 enable : function(){
28559 Roo.fly(this.td).removeClass("x-item-disabled");
28560 this.disabled = false;
28563 // backwards compat
28564 Roo.ToolbarButton = Roo.Toolbar.Button;
28567 * @class Roo.Toolbar.SplitButton
28568 * @extends Roo.SplitButton
28569 * A menu button that renders into a toolbar.
28571 * Creates a new SplitButton
28572 * @param {Object} config A standard {@link Roo.SplitButton} config object
28574 Roo.Toolbar.SplitButton = function(config){
28575 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28577 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28578 render : function(td){
28580 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28584 * Removes and destroys this button
28586 destroy : function(){
28587 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28588 this.td.parentNode.removeChild(this.td);
28592 * Shows this button
28595 this.hidden = false;
28596 this.td.style.display = "";
28600 * Hides this button
28603 this.hidden = true;
28604 this.td.style.display = "none";
28608 // backwards compat
28609 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28611 * Ext JS Library 1.1.1
28612 * Copyright(c) 2006-2007, Ext JS, LLC.
28614 * Originally Released Under LGPL - original licence link has changed is not relivant.
28617 * <script type="text/javascript">
28621 * @class Roo.PagingToolbar
28622 * @extends Roo.Toolbar
28623 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28625 * Create a new PagingToolbar
28626 * @param {Object} config The config object
28628 Roo.PagingToolbar = function(el, ds, config)
28630 // old args format still supported... - xtype is prefered..
28631 if (typeof(el) == 'object' && el.xtype) {
28632 // created from xtype...
28634 ds = el.dataSource;
28635 el = config.container;
28638 if (config.items) {
28639 items = config.items;
28643 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28646 this.renderButtons(this.el);
28649 // supprot items array.
28651 Roo.each(items, function(e) {
28652 this.add(Roo.factory(e));
28657 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28659 * @cfg {Roo.data.Store} dataSource
28660 * The underlying data store providing the paged data
28663 * @cfg {String/HTMLElement/Element} container
28664 * container The id or element that will contain the toolbar
28667 * @cfg {Boolean} displayInfo
28668 * True to display the displayMsg (defaults to false)
28671 * @cfg {Number} pageSize
28672 * The number of records to display per page (defaults to 20)
28676 * @cfg {String} displayMsg
28677 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28679 displayMsg : 'Displaying {0} - {1} of {2}',
28681 * @cfg {String} emptyMsg
28682 * The message to display when no records are found (defaults to "No data to display")
28684 emptyMsg : 'No data to display',
28686 * Customizable piece of the default paging text (defaults to "Page")
28689 beforePageText : "Page",
28691 * Customizable piece of the default paging text (defaults to "of %0")
28694 afterPageText : "of {0}",
28696 * Customizable piece of the default paging text (defaults to "First Page")
28699 firstText : "First Page",
28701 * Customizable piece of the default paging text (defaults to "Previous Page")
28704 prevText : "Previous Page",
28706 * Customizable piece of the default paging text (defaults to "Next Page")
28709 nextText : "Next Page",
28711 * Customizable piece of the default paging text (defaults to "Last Page")
28714 lastText : "Last Page",
28716 * Customizable piece of the default paging text (defaults to "Refresh")
28719 refreshText : "Refresh",
28722 renderButtons : function(el){
28723 Roo.PagingToolbar.superclass.render.call(this, el);
28724 this.first = this.addButton({
28725 tooltip: this.firstText,
28726 cls: "x-btn-icon x-grid-page-first",
28728 handler: this.onClick.createDelegate(this, ["first"])
28730 this.prev = this.addButton({
28731 tooltip: this.prevText,
28732 cls: "x-btn-icon x-grid-page-prev",
28734 handler: this.onClick.createDelegate(this, ["prev"])
28736 //this.addSeparator();
28737 this.add(this.beforePageText);
28738 this.field = Roo.get(this.addDom({
28743 cls: "x-grid-page-number"
28745 this.field.on("keydown", this.onPagingKeydown, this);
28746 this.field.on("focus", function(){this.dom.select();});
28747 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28748 this.field.setHeight(18);
28749 //this.addSeparator();
28750 this.next = this.addButton({
28751 tooltip: this.nextText,
28752 cls: "x-btn-icon x-grid-page-next",
28754 handler: this.onClick.createDelegate(this, ["next"])
28756 this.last = this.addButton({
28757 tooltip: this.lastText,
28758 cls: "x-btn-icon x-grid-page-last",
28760 handler: this.onClick.createDelegate(this, ["last"])
28762 //this.addSeparator();
28763 this.loading = this.addButton({
28764 tooltip: this.refreshText,
28765 cls: "x-btn-icon x-grid-loading",
28766 handler: this.onClick.createDelegate(this, ["refresh"])
28769 if(this.displayInfo){
28770 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28775 updateInfo : function(){
28776 if(this.displayEl){
28777 var count = this.ds.getCount();
28778 var msg = count == 0 ?
28782 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28784 this.displayEl.update(msg);
28789 onLoad : function(ds, r, o){
28790 this.cursor = o.params ? o.params.start : 0;
28791 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28793 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28794 this.field.dom.value = ap;
28795 this.first.setDisabled(ap == 1);
28796 this.prev.setDisabled(ap == 1);
28797 this.next.setDisabled(ap == ps);
28798 this.last.setDisabled(ap == ps);
28799 this.loading.enable();
28804 getPageData : function(){
28805 var total = this.ds.getTotalCount();
28808 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28809 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28814 onLoadError : function(){
28815 this.loading.enable();
28819 onPagingKeydown : function(e){
28820 var k = e.getKey();
28821 var d = this.getPageData();
28823 var v = this.field.dom.value, pageNum;
28824 if(!v || isNaN(pageNum = parseInt(v, 10))){
28825 this.field.dom.value = d.activePage;
28828 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28829 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28832 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))
28834 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28835 this.field.dom.value = pageNum;
28836 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28839 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28841 var v = this.field.dom.value, pageNum;
28842 var increment = (e.shiftKey) ? 10 : 1;
28843 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28845 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28846 this.field.dom.value = d.activePage;
28849 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28851 this.field.dom.value = parseInt(v, 10) + increment;
28852 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28853 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28860 beforeLoad : function(){
28862 this.loading.disable();
28867 onClick : function(which){
28871 ds.load({params:{start: 0, limit: this.pageSize}});
28874 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28877 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28880 var total = ds.getTotalCount();
28881 var extra = total % this.pageSize;
28882 var lastStart = extra ? (total - extra) : total-this.pageSize;
28883 ds.load({params:{start: lastStart, limit: this.pageSize}});
28886 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28892 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28893 * @param {Roo.data.Store} store The data store to unbind
28895 unbind : function(ds){
28896 ds.un("beforeload", this.beforeLoad, this);
28897 ds.un("load", this.onLoad, this);
28898 ds.un("loadexception", this.onLoadError, this);
28899 ds.un("remove", this.updateInfo, this);
28900 ds.un("add", this.updateInfo, this);
28901 this.ds = undefined;
28905 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28906 * @param {Roo.data.Store} store The data store to bind
28908 bind : function(ds){
28909 ds.on("beforeload", this.beforeLoad, this);
28910 ds.on("load", this.onLoad, this);
28911 ds.on("loadexception", this.onLoadError, this);
28912 ds.on("remove", this.updateInfo, this);
28913 ds.on("add", this.updateInfo, this);
28918 * Ext JS Library 1.1.1
28919 * Copyright(c) 2006-2007, Ext JS, LLC.
28921 * Originally Released Under LGPL - original licence link has changed is not relivant.
28924 * <script type="text/javascript">
28928 * @class Roo.Resizable
28929 * @extends Roo.util.Observable
28930 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28931 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28932 * 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
28933 * the element will be wrapped for you automatically.</p>
28934 * <p>Here is the list of valid resize handles:</p>
28937 ------ -------------------
28946 'hd' horizontal drag
28949 * <p>Here's an example showing the creation of a typical Resizable:</p>
28951 var resizer = new Roo.Resizable("element-id", {
28959 resizer.on("resize", myHandler);
28961 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
28962 * resizer.east.setDisplayed(false);</p>
28963 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
28964 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
28965 * resize operation's new size (defaults to [0, 0])
28966 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
28967 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
28968 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
28969 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
28970 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
28971 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
28972 * @cfg {Number} width The width of the element in pixels (defaults to null)
28973 * @cfg {Number} height The height of the element in pixels (defaults to null)
28974 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
28975 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
28976 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
28977 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
28978 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
28979 * in favor of the handles config option (defaults to false)
28980 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
28981 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
28982 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
28983 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
28984 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
28985 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
28986 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
28987 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
28988 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
28989 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
28990 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
28992 * Create a new resizable component
28993 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
28994 * @param {Object} config configuration options
28996 Roo.Resizable = function(el, config)
28998 this.el = Roo.get(el);
29000 if(config && config.wrap){
29001 config.resizeChild = this.el;
29002 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29003 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29004 this.el.setStyle("overflow", "hidden");
29005 this.el.setPositioning(config.resizeChild.getPositioning());
29006 config.resizeChild.clearPositioning();
29007 if(!config.width || !config.height){
29008 var csize = config.resizeChild.getSize();
29009 this.el.setSize(csize.width, csize.height);
29011 if(config.pinned && !config.adjustments){
29012 config.adjustments = "auto";
29016 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29017 this.proxy.unselectable();
29018 this.proxy.enableDisplayMode('block');
29020 Roo.apply(this, config);
29023 this.disableTrackOver = true;
29024 this.el.addClass("x-resizable-pinned");
29026 // if the element isn't positioned, make it relative
29027 var position = this.el.getStyle("position");
29028 if(position != "absolute" && position != "fixed"){
29029 this.el.setStyle("position", "relative");
29031 if(!this.handles){ // no handles passed, must be legacy style
29032 this.handles = 's,e,se';
29033 if(this.multiDirectional){
29034 this.handles += ',n,w';
29037 if(this.handles == "all"){
29038 this.handles = "n s e w ne nw se sw";
29040 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29041 var ps = Roo.Resizable.positions;
29042 for(var i = 0, len = hs.length; i < len; i++){
29043 if(hs[i] && ps[hs[i]]){
29044 var pos = ps[hs[i]];
29045 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29049 this.corner = this.southeast;
29051 // updateBox = the box can move..
29052 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29053 this.updateBox = true;
29056 this.activeHandle = null;
29058 if(this.resizeChild){
29059 if(typeof this.resizeChild == "boolean"){
29060 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29062 this.resizeChild = Roo.get(this.resizeChild, true);
29066 if(this.adjustments == "auto"){
29067 var rc = this.resizeChild;
29068 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29069 if(rc && (hw || hn)){
29070 rc.position("relative");
29071 rc.setLeft(hw ? hw.el.getWidth() : 0);
29072 rc.setTop(hn ? hn.el.getHeight() : 0);
29074 this.adjustments = [
29075 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29076 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29080 if(this.draggable){
29081 this.dd = this.dynamic ?
29082 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29083 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29089 * @event beforeresize
29090 * Fired before resize is allowed. Set enabled to false to cancel resize.
29091 * @param {Roo.Resizable} this
29092 * @param {Roo.EventObject} e The mousedown event
29094 "beforeresize" : true,
29097 * Fired a resizing.
29098 * @param {Roo.Resizable} this
29099 * @param {Number} x The new x position
29100 * @param {Number} y The new y position
29101 * @param {Number} w The new w width
29102 * @param {Number} h The new h hight
29103 * @param {Roo.EventObject} e The mouseup event
29108 * Fired after a resize.
29109 * @param {Roo.Resizable} this
29110 * @param {Number} width The new width
29111 * @param {Number} height The new height
29112 * @param {Roo.EventObject} e The mouseup event
29117 if(this.width !== null && this.height !== null){
29118 this.resizeTo(this.width, this.height);
29120 this.updateChildSize();
29123 this.el.dom.style.zoom = 1;
29125 Roo.Resizable.superclass.constructor.call(this);
29128 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29129 resizeChild : false,
29130 adjustments : [0, 0],
29140 multiDirectional : false,
29141 disableTrackOver : false,
29142 easing : 'easeOutStrong',
29143 widthIncrement : 0,
29144 heightIncrement : 0,
29148 preserveRatio : false,
29149 transparent: false,
29155 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29157 constrainTo: undefined,
29159 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29161 resizeRegion: undefined,
29165 * Perform a manual resize
29166 * @param {Number} width
29167 * @param {Number} height
29169 resizeTo : function(width, height){
29170 this.el.setSize(width, height);
29171 this.updateChildSize();
29172 this.fireEvent("resize", this, width, height, null);
29176 startSizing : function(e, handle){
29177 this.fireEvent("beforeresize", this, e);
29178 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29181 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29182 this.overlay.unselectable();
29183 this.overlay.enableDisplayMode("block");
29184 this.overlay.on("mousemove", this.onMouseMove, this);
29185 this.overlay.on("mouseup", this.onMouseUp, this);
29187 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29189 this.resizing = true;
29190 this.startBox = this.el.getBox();
29191 this.startPoint = e.getXY();
29192 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29193 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29195 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29196 this.overlay.show();
29198 if(this.constrainTo) {
29199 var ct = Roo.get(this.constrainTo);
29200 this.resizeRegion = ct.getRegion().adjust(
29201 ct.getFrameWidth('t'),
29202 ct.getFrameWidth('l'),
29203 -ct.getFrameWidth('b'),
29204 -ct.getFrameWidth('r')
29208 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29210 this.proxy.setBox(this.startBox);
29212 this.proxy.setStyle('visibility', 'visible');
29218 onMouseDown : function(handle, e){
29221 this.activeHandle = handle;
29222 this.startSizing(e, handle);
29227 onMouseUp : function(e){
29228 var size = this.resizeElement();
29229 this.resizing = false;
29231 this.overlay.hide();
29233 this.fireEvent("resize", this, size.width, size.height, e);
29237 updateChildSize : function(){
29239 if(this.resizeChild){
29241 var child = this.resizeChild;
29242 var adj = this.adjustments;
29243 if(el.dom.offsetWidth){
29244 var b = el.getSize(true);
29245 child.setSize(b.width+adj[0], b.height+adj[1]);
29247 // Second call here for IE
29248 // The first call enables instant resizing and
29249 // the second call corrects scroll bars if they
29252 setTimeout(function(){
29253 if(el.dom.offsetWidth){
29254 var b = el.getSize(true);
29255 child.setSize(b.width+adj[0], b.height+adj[1]);
29263 snap : function(value, inc, min){
29264 if(!inc || !value) return value;
29265 var newValue = value;
29266 var m = value % inc;
29269 newValue = value + (inc-m);
29271 newValue = value - m;
29274 return Math.max(min, newValue);
29278 resizeElement : function(){
29279 var box = this.proxy.getBox();
29280 if(this.updateBox){
29281 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29283 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29285 this.updateChildSize();
29293 constrain : function(v, diff, m, mx){
29296 }else if(v - diff > mx){
29303 onMouseMove : function(e){
29306 try{// try catch so if something goes wrong the user doesn't get hung
29308 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29312 //var curXY = this.startPoint;
29313 var curSize = this.curSize || this.startBox;
29314 var x = this.startBox.x, y = this.startBox.y;
29315 var ox = x, oy = y;
29316 var w = curSize.width, h = curSize.height;
29317 var ow = w, oh = h;
29318 var mw = this.minWidth, mh = this.minHeight;
29319 var mxw = this.maxWidth, mxh = this.maxHeight;
29320 var wi = this.widthIncrement;
29321 var hi = this.heightIncrement;
29323 var eventXY = e.getXY();
29324 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29325 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29327 var pos = this.activeHandle.position;
29332 w = Math.min(Math.max(mw, w), mxw);
29337 h = Math.min(Math.max(mh, h), mxh);
29342 w = Math.min(Math.max(mw, w), mxw);
29343 h = Math.min(Math.max(mh, h), mxh);
29346 diffY = this.constrain(h, diffY, mh, mxh);
29353 var adiffX = Math.abs(diffX);
29354 var sub = (adiffX % wi); // how much
29355 if (sub > (wi/2)) { // far enough to snap
29356 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29358 // remove difference..
29359 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29363 x = Math.max(this.minX, x);
29366 diffX = this.constrain(w, diffX, mw, mxw);
29372 w = Math.min(Math.max(mw, w), mxw);
29373 diffY = this.constrain(h, diffY, mh, mxh);
29378 diffX = this.constrain(w, diffX, mw, mxw);
29379 diffY = this.constrain(h, diffY, mh, mxh);
29386 diffX = this.constrain(w, diffX, mw, mxw);
29388 h = Math.min(Math.max(mh, h), mxh);
29394 var sw = this.snap(w, wi, mw);
29395 var sh = this.snap(h, hi, mh);
29396 if(sw != w || sh != h){
29419 if(this.preserveRatio){
29424 h = Math.min(Math.max(mh, h), mxh);
29429 w = Math.min(Math.max(mw, w), mxw);
29434 w = Math.min(Math.max(mw, w), mxw);
29440 w = Math.min(Math.max(mw, w), mxw);
29446 h = Math.min(Math.max(mh, h), mxh);
29454 h = Math.min(Math.max(mh, h), mxh);
29464 h = Math.min(Math.max(mh, h), mxh);
29472 if (pos == 'hdrag') {
29475 this.proxy.setBounds(x, y, w, h);
29477 this.resizeElement();
29481 this.fireEvent("resizing", this, x, y, w, h, e);
29485 handleOver : function(){
29487 this.el.addClass("x-resizable-over");
29492 handleOut : function(){
29493 if(!this.resizing){
29494 this.el.removeClass("x-resizable-over");
29499 * Returns the element this component is bound to.
29500 * @return {Roo.Element}
29502 getEl : function(){
29507 * Returns the resizeChild element (or null).
29508 * @return {Roo.Element}
29510 getResizeChild : function(){
29511 return this.resizeChild;
29513 groupHandler : function()
29518 * Destroys this resizable. If the element was wrapped and
29519 * removeEl is not true then the element remains.
29520 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29522 destroy : function(removeEl){
29523 this.proxy.remove();
29525 this.overlay.removeAllListeners();
29526 this.overlay.remove();
29528 var ps = Roo.Resizable.positions;
29530 if(typeof ps[k] != "function" && this[ps[k]]){
29531 var h = this[ps[k]];
29532 h.el.removeAllListeners();
29537 this.el.update("");
29544 // hash to map config positions to true positions
29545 Roo.Resizable.positions = {
29546 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29551 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29553 // only initialize the template if resizable is used
29554 var tpl = Roo.DomHelper.createTemplate(
29555 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29558 Roo.Resizable.Handle.prototype.tpl = tpl;
29560 this.position = pos;
29562 // show north drag fro topdra
29563 var handlepos = pos == 'hdrag' ? 'north' : pos;
29565 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29566 if (pos == 'hdrag') {
29567 this.el.setStyle('cursor', 'pointer');
29569 this.el.unselectable();
29571 this.el.setOpacity(0);
29573 this.el.on("mousedown", this.onMouseDown, this);
29574 if(!disableTrackOver){
29575 this.el.on("mouseover", this.onMouseOver, this);
29576 this.el.on("mouseout", this.onMouseOut, this);
29581 Roo.Resizable.Handle.prototype = {
29582 afterResize : function(rz){
29587 onMouseDown : function(e){
29588 this.rz.onMouseDown(this, e);
29591 onMouseOver : function(e){
29592 this.rz.handleOver(this, e);
29595 onMouseOut : function(e){
29596 this.rz.handleOut(this, e);
29600 * Ext JS Library 1.1.1
29601 * Copyright(c) 2006-2007, Ext JS, LLC.
29603 * Originally Released Under LGPL - original licence link has changed is not relivant.
29606 * <script type="text/javascript">
29610 * @class Roo.Editor
29611 * @extends Roo.Component
29612 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29614 * Create a new Editor
29615 * @param {Roo.form.Field} field The Field object (or descendant)
29616 * @param {Object} config The config object
29618 Roo.Editor = function(field, config){
29619 Roo.Editor.superclass.constructor.call(this, config);
29620 this.field = field;
29623 * @event beforestartedit
29624 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29625 * false from the handler of this event.
29626 * @param {Editor} this
29627 * @param {Roo.Element} boundEl The underlying element bound to this editor
29628 * @param {Mixed} value The field value being set
29630 "beforestartedit" : true,
29633 * Fires when this editor is displayed
29634 * @param {Roo.Element} boundEl The underlying element bound to this editor
29635 * @param {Mixed} value The starting field value
29637 "startedit" : true,
29639 * @event beforecomplete
29640 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29641 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29642 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29643 * event will not fire since no edit actually occurred.
29644 * @param {Editor} this
29645 * @param {Mixed} value The current field value
29646 * @param {Mixed} startValue The original field value
29648 "beforecomplete" : true,
29651 * Fires after editing is complete and any changed value has been written to the underlying field.
29652 * @param {Editor} this
29653 * @param {Mixed} value The current field value
29654 * @param {Mixed} startValue The original field value
29658 * @event specialkey
29659 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29660 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29661 * @param {Roo.form.Field} this
29662 * @param {Roo.EventObject} e The event object
29664 "specialkey" : true
29668 Roo.extend(Roo.Editor, Roo.Component, {
29670 * @cfg {Boolean/String} autosize
29671 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29672 * or "height" to adopt the height only (defaults to false)
29675 * @cfg {Boolean} revertInvalid
29676 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29677 * validation fails (defaults to true)
29680 * @cfg {Boolean} ignoreNoChange
29681 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29682 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29683 * will never be ignored.
29686 * @cfg {Boolean} hideEl
29687 * False to keep the bound element visible while the editor is displayed (defaults to true)
29690 * @cfg {Mixed} value
29691 * The data value of the underlying field (defaults to "")
29695 * @cfg {String} alignment
29696 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29700 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29701 * for bottom-right shadow (defaults to "frame")
29705 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29709 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29711 completeOnEnter : false,
29713 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29715 cancelOnEsc : false,
29717 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29722 onRender : function(ct, position){
29723 this.el = new Roo.Layer({
29724 shadow: this.shadow,
29730 constrain: this.constrain
29732 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29733 if(this.field.msgTarget != 'title'){
29734 this.field.msgTarget = 'qtip';
29736 this.field.render(this.el);
29738 this.field.el.dom.setAttribute('autocomplete', 'off');
29740 this.field.on("specialkey", this.onSpecialKey, this);
29741 if(this.swallowKeys){
29742 this.field.el.swallowEvent(['keydown','keypress']);
29745 this.field.on("blur", this.onBlur, this);
29746 if(this.field.grow){
29747 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29751 onSpecialKey : function(field, e)
29753 //Roo.log('editor onSpecialKey');
29754 if(this.completeOnEnter && e.getKey() == e.ENTER){
29756 this.completeEdit();
29759 // do not fire special key otherwise it might hide close the editor...
29760 if(e.getKey() == e.ENTER){
29763 if(this.cancelOnEsc && e.getKey() == e.ESC){
29767 this.fireEvent('specialkey', field, e);
29772 * Starts the editing process and shows the editor.
29773 * @param {String/HTMLElement/Element} el The element to edit
29774 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29775 * to the innerHTML of el.
29777 startEdit : function(el, value){
29779 this.completeEdit();
29781 this.boundEl = Roo.get(el);
29782 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29783 if(!this.rendered){
29784 this.render(this.parentEl || document.body);
29786 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29789 this.startValue = v;
29790 this.field.setValue(v);
29792 var sz = this.boundEl.getSize();
29793 switch(this.autoSize){
29795 this.setSize(sz.width, "");
29798 this.setSize("", sz.height);
29801 this.setSize(sz.width, sz.height);
29804 this.el.alignTo(this.boundEl, this.alignment);
29805 this.editing = true;
29807 Roo.QuickTips.disable();
29813 * Sets the height and width of this editor.
29814 * @param {Number} width The new width
29815 * @param {Number} height The new height
29817 setSize : function(w, h){
29818 this.field.setSize(w, h);
29825 * Realigns the editor to the bound field based on the current alignment config value.
29827 realign : function(){
29828 this.el.alignTo(this.boundEl, this.alignment);
29832 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29833 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29835 completeEdit : function(remainVisible){
29839 var v = this.getValue();
29840 if(this.revertInvalid !== false && !this.field.isValid()){
29841 v = this.startValue;
29842 this.cancelEdit(true);
29844 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29845 this.editing = false;
29849 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29850 this.editing = false;
29851 if(this.updateEl && this.boundEl){
29852 this.boundEl.update(v);
29854 if(remainVisible !== true){
29857 this.fireEvent("complete", this, v, this.startValue);
29862 onShow : function(){
29864 if(this.hideEl !== false){
29865 this.boundEl.hide();
29868 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29869 this.fixIEFocus = true;
29870 this.deferredFocus.defer(50, this);
29872 this.field.focus();
29874 this.fireEvent("startedit", this.boundEl, this.startValue);
29877 deferredFocus : function(){
29879 this.field.focus();
29884 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29885 * reverted to the original starting value.
29886 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29887 * cancel (defaults to false)
29889 cancelEdit : function(remainVisible){
29891 this.setValue(this.startValue);
29892 if(remainVisible !== true){
29899 onBlur : function(){
29900 if(this.allowBlur !== true && this.editing){
29901 this.completeEdit();
29906 onHide : function(){
29908 this.completeEdit();
29912 if(this.field.collapse){
29913 this.field.collapse();
29916 if(this.hideEl !== false){
29917 this.boundEl.show();
29920 Roo.QuickTips.enable();
29925 * Sets the data value of the editor
29926 * @param {Mixed} value Any valid value supported by the underlying field
29928 setValue : function(v){
29929 this.field.setValue(v);
29933 * Gets the data value of the editor
29934 * @return {Mixed} The data value
29936 getValue : function(){
29937 return this.field.getValue();
29941 * Ext JS Library 1.1.1
29942 * Copyright(c) 2006-2007, Ext JS, LLC.
29944 * Originally Released Under LGPL - original licence link has changed is not relivant.
29947 * <script type="text/javascript">
29951 * @class Roo.BasicDialog
29952 * @extends Roo.util.Observable
29953 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29955 var dlg = new Roo.BasicDialog("my-dlg", {
29964 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
29965 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
29966 dlg.addButton('Cancel', dlg.hide, dlg);
29969 <b>A Dialog should always be a direct child of the body element.</b>
29970 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
29971 * @cfg {String} title Default text to display in the title bar (defaults to null)
29972 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29973 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29974 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
29975 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
29976 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
29977 * (defaults to null with no animation)
29978 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
29979 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
29980 * property for valid values (defaults to 'all')
29981 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
29982 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
29983 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
29984 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
29985 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
29986 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
29987 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
29988 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
29989 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
29990 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
29991 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
29992 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
29993 * draggable = true (defaults to false)
29994 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
29995 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
29996 * shadow (defaults to false)
29997 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
29998 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
29999 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30000 * @cfg {Array} buttons Array of buttons
30001 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30003 * Create a new BasicDialog.
30004 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30005 * @param {Object} config Configuration options
30007 Roo.BasicDialog = function(el, config){
30008 this.el = Roo.get(el);
30009 var dh = Roo.DomHelper;
30010 if(!this.el && config && config.autoCreate){
30011 if(typeof config.autoCreate == "object"){
30012 if(!config.autoCreate.id){
30013 config.autoCreate.id = el;
30015 this.el = dh.append(document.body,
30016 config.autoCreate, true);
30018 this.el = dh.append(document.body,
30019 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30023 el.setDisplayed(true);
30024 el.hide = this.hideAction;
30026 el.addClass("x-dlg");
30028 Roo.apply(this, config);
30030 this.proxy = el.createProxy("x-dlg-proxy");
30031 this.proxy.hide = this.hideAction;
30032 this.proxy.setOpacity(.5);
30036 el.setWidth(config.width);
30039 el.setHeight(config.height);
30041 this.size = el.getSize();
30042 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30043 this.xy = [config.x,config.y];
30045 this.xy = el.getCenterXY(true);
30047 /** The header element @type Roo.Element */
30048 this.header = el.child("> .x-dlg-hd");
30049 /** The body element @type Roo.Element */
30050 this.body = el.child("> .x-dlg-bd");
30051 /** The footer element @type Roo.Element */
30052 this.footer = el.child("> .x-dlg-ft");
30055 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30058 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30061 this.header.unselectable();
30063 this.header.update(this.title);
30065 // this element allows the dialog to be focused for keyboard event
30066 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30067 this.focusEl.swallowEvent("click", true);
30069 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30071 // wrap the body and footer for special rendering
30072 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30074 this.bwrap.dom.appendChild(this.footer.dom);
30077 this.bg = this.el.createChild({
30078 tag: "div", cls:"x-dlg-bg",
30079 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30081 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30084 if(this.autoScroll !== false && !this.autoTabs){
30085 this.body.setStyle("overflow", "auto");
30088 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30090 if(this.closable !== false){
30091 this.el.addClass("x-dlg-closable");
30092 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30093 this.close.on("click", this.closeClick, this);
30094 this.close.addClassOnOver("x-dlg-close-over");
30096 if(this.collapsible !== false){
30097 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30098 this.collapseBtn.on("click", this.collapseClick, this);
30099 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30100 this.header.on("dblclick", this.collapseClick, this);
30102 if(this.resizable !== false){
30103 this.el.addClass("x-dlg-resizable");
30104 this.resizer = new Roo.Resizable(el, {
30105 minWidth: this.minWidth || 80,
30106 minHeight:this.minHeight || 80,
30107 handles: this.resizeHandles || "all",
30110 this.resizer.on("beforeresize", this.beforeResize, this);
30111 this.resizer.on("resize", this.onResize, this);
30113 if(this.draggable !== false){
30114 el.addClass("x-dlg-draggable");
30115 if (!this.proxyDrag) {
30116 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30119 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30121 dd.setHandleElId(this.header.id);
30122 dd.endDrag = this.endMove.createDelegate(this);
30123 dd.startDrag = this.startMove.createDelegate(this);
30124 dd.onDrag = this.onDrag.createDelegate(this);
30129 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30130 this.mask.enableDisplayMode("block");
30132 this.el.addClass("x-dlg-modal");
30135 this.shadow = new Roo.Shadow({
30136 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30137 offset : this.shadowOffset
30140 this.shadowOffset = 0;
30142 if(Roo.useShims && this.shim !== false){
30143 this.shim = this.el.createShim();
30144 this.shim.hide = this.hideAction;
30152 if (this.buttons) {
30153 var bts= this.buttons;
30155 Roo.each(bts, function(b) {
30164 * Fires when a key is pressed
30165 * @param {Roo.BasicDialog} this
30166 * @param {Roo.EventObject} e
30171 * Fires when this dialog is moved by the user.
30172 * @param {Roo.BasicDialog} this
30173 * @param {Number} x The new page X
30174 * @param {Number} y The new page Y
30179 * Fires when this dialog is resized by the user.
30180 * @param {Roo.BasicDialog} this
30181 * @param {Number} width The new width
30182 * @param {Number} height The new height
30186 * @event beforehide
30187 * Fires before this dialog is hidden.
30188 * @param {Roo.BasicDialog} this
30190 "beforehide" : true,
30193 * Fires when this dialog is hidden.
30194 * @param {Roo.BasicDialog} this
30198 * @event beforeshow
30199 * Fires before this dialog is shown.
30200 * @param {Roo.BasicDialog} this
30202 "beforeshow" : true,
30205 * Fires when this dialog is shown.
30206 * @param {Roo.BasicDialog} this
30210 el.on("keydown", this.onKeyDown, this);
30211 el.on("mousedown", this.toFront, this);
30212 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30214 Roo.DialogManager.register(this);
30215 Roo.BasicDialog.superclass.constructor.call(this);
30218 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30219 shadowOffset: Roo.isIE ? 6 : 5,
30222 minButtonWidth: 75,
30223 defaultButton: null,
30224 buttonAlign: "right",
30229 * Sets the dialog title text
30230 * @param {String} text The title text to display
30231 * @return {Roo.BasicDialog} this
30233 setTitle : function(text){
30234 this.header.update(text);
30239 closeClick : function(){
30244 collapseClick : function(){
30245 this[this.collapsed ? "expand" : "collapse"]();
30249 * Collapses the dialog to its minimized state (only the title bar is visible).
30250 * Equivalent to the user clicking the collapse dialog button.
30252 collapse : function(){
30253 if(!this.collapsed){
30254 this.collapsed = true;
30255 this.el.addClass("x-dlg-collapsed");
30256 this.restoreHeight = this.el.getHeight();
30257 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30262 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30263 * clicking the expand dialog button.
30265 expand : function(){
30266 if(this.collapsed){
30267 this.collapsed = false;
30268 this.el.removeClass("x-dlg-collapsed");
30269 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30274 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30275 * @return {Roo.TabPanel} The tabs component
30277 initTabs : function(){
30278 var tabs = this.getTabs();
30279 while(tabs.getTab(0)){
30282 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30284 tabs.addTab(Roo.id(dom), dom.title);
30292 beforeResize : function(){
30293 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30297 onResize : function(){
30298 this.refreshSize();
30299 this.syncBodyHeight();
30300 this.adjustAssets();
30302 this.fireEvent("resize", this, this.size.width, this.size.height);
30306 onKeyDown : function(e){
30307 if(this.isVisible()){
30308 this.fireEvent("keydown", this, e);
30313 * Resizes the dialog.
30314 * @param {Number} width
30315 * @param {Number} height
30316 * @return {Roo.BasicDialog} this
30318 resizeTo : function(width, height){
30319 this.el.setSize(width, height);
30320 this.size = {width: width, height: height};
30321 this.syncBodyHeight();
30322 if(this.fixedcenter){
30325 if(this.isVisible()){
30326 this.constrainXY();
30327 this.adjustAssets();
30329 this.fireEvent("resize", this, width, height);
30335 * Resizes the dialog to fit the specified content size.
30336 * @param {Number} width
30337 * @param {Number} height
30338 * @return {Roo.BasicDialog} this
30340 setContentSize : function(w, h){
30341 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30342 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30343 //if(!this.el.isBorderBox()){
30344 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30345 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30348 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30349 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30351 this.resizeTo(w, h);
30356 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30357 * executed in response to a particular key being pressed while the dialog is active.
30358 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30359 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30360 * @param {Function} fn The function to call
30361 * @param {Object} scope (optional) The scope of the function
30362 * @return {Roo.BasicDialog} this
30364 addKeyListener : function(key, fn, scope){
30365 var keyCode, shift, ctrl, alt;
30366 if(typeof key == "object" && !(key instanceof Array)){
30367 keyCode = key["key"];
30368 shift = key["shift"];
30369 ctrl = key["ctrl"];
30374 var handler = function(dlg, e){
30375 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30376 var k = e.getKey();
30377 if(keyCode instanceof Array){
30378 for(var i = 0, len = keyCode.length; i < len; i++){
30379 if(keyCode[i] == k){
30380 fn.call(scope || window, dlg, k, e);
30386 fn.call(scope || window, dlg, k, e);
30391 this.on("keydown", handler);
30396 * Returns the TabPanel component (creates it if it doesn't exist).
30397 * Note: If you wish to simply check for the existence of tabs without creating them,
30398 * check for a null 'tabs' property.
30399 * @return {Roo.TabPanel} The tabs component
30401 getTabs : function(){
30403 this.el.addClass("x-dlg-auto-tabs");
30404 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30405 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30411 * Adds a button to the footer section of the dialog.
30412 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30413 * object or a valid Roo.DomHelper element config
30414 * @param {Function} handler The function called when the button is clicked
30415 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30416 * @return {Roo.Button} The new button
30418 addButton : function(config, handler, scope){
30419 var dh = Roo.DomHelper;
30421 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30423 if(!this.btnContainer){
30424 var tb = this.footer.createChild({
30426 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30427 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30429 this.btnContainer = tb.firstChild.firstChild.firstChild;
30434 minWidth: this.minButtonWidth,
30437 if(typeof config == "string"){
30438 bconfig.text = config;
30441 bconfig.dhconfig = config;
30443 Roo.apply(bconfig, config);
30447 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30448 bconfig.position = Math.max(0, bconfig.position);
30449 fc = this.btnContainer.childNodes[bconfig.position];
30452 var btn = new Roo.Button(
30454 this.btnContainer.insertBefore(document.createElement("td"),fc)
30455 : this.btnContainer.appendChild(document.createElement("td")),
30456 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30459 this.syncBodyHeight();
30462 * Array of all the buttons that have been added to this dialog via addButton
30467 this.buttons.push(btn);
30472 * Sets the default button to be focused when the dialog is displayed.
30473 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30474 * @return {Roo.BasicDialog} this
30476 setDefaultButton : function(btn){
30477 this.defaultButton = btn;
30482 getHeaderFooterHeight : function(safe){
30485 height += this.header.getHeight();
30488 var fm = this.footer.getMargins();
30489 height += (this.footer.getHeight()+fm.top+fm.bottom);
30491 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30492 height += this.centerBg.getPadding("tb");
30497 syncBodyHeight : function()
30499 var bd = this.body, // the text
30500 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30502 var height = this.size.height - this.getHeaderFooterHeight(false);
30503 bd.setHeight(height-bd.getMargins("tb"));
30504 var hh = this.header.getHeight();
30505 var h = this.size.height-hh;
30508 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30509 bw.setHeight(h-cb.getPadding("tb"));
30511 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30512 bd.setWidth(bw.getWidth(true));
30514 this.tabs.syncHeight();
30516 this.tabs.el.repaint();
30522 * Restores the previous state of the dialog if Roo.state is configured.
30523 * @return {Roo.BasicDialog} this
30525 restoreState : function(){
30526 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30527 if(box && box.width){
30528 this.xy = [box.x, box.y];
30529 this.resizeTo(box.width, box.height);
30535 beforeShow : function(){
30537 if(this.fixedcenter){
30538 this.xy = this.el.getCenterXY(true);
30541 Roo.get(document.body).addClass("x-body-masked");
30542 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30545 this.constrainXY();
30549 animShow : function(){
30550 var b = Roo.get(this.animateTarget).getBox();
30551 this.proxy.setSize(b.width, b.height);
30552 this.proxy.setLocation(b.x, b.y);
30554 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30555 true, .35, this.showEl.createDelegate(this));
30559 * Shows the dialog.
30560 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30561 * @return {Roo.BasicDialog} this
30563 show : function(animateTarget){
30564 if (this.fireEvent("beforeshow", this) === false){
30567 if(this.syncHeightBeforeShow){
30568 this.syncBodyHeight();
30569 }else if(this.firstShow){
30570 this.firstShow = false;
30571 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30573 this.animateTarget = animateTarget || this.animateTarget;
30574 if(!this.el.isVisible()){
30576 if(this.animateTarget && Roo.get(this.animateTarget)){
30586 showEl : function(){
30588 this.el.setXY(this.xy);
30590 this.adjustAssets(true);
30593 // IE peekaboo bug - fix found by Dave Fenwick
30597 this.fireEvent("show", this);
30601 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30602 * dialog itself will receive focus.
30604 focus : function(){
30605 if(this.defaultButton){
30606 this.defaultButton.focus();
30608 this.focusEl.focus();
30613 constrainXY : function(){
30614 if(this.constraintoviewport !== false){
30615 if(!this.viewSize){
30616 if(this.container){
30617 var s = this.container.getSize();
30618 this.viewSize = [s.width, s.height];
30620 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30623 var s = Roo.get(this.container||document).getScroll();
30625 var x = this.xy[0], y = this.xy[1];
30626 var w = this.size.width, h = this.size.height;
30627 var vw = this.viewSize[0], vh = this.viewSize[1];
30628 // only move it if it needs it
30630 // first validate right/bottom
30631 if(x + w > vw+s.left){
30635 if(y + h > vh+s.top){
30639 // then make sure top/left isn't negative
30651 if(this.isVisible()){
30652 this.el.setLocation(x, y);
30653 this.adjustAssets();
30660 onDrag : function(){
30661 if(!this.proxyDrag){
30662 this.xy = this.el.getXY();
30663 this.adjustAssets();
30668 adjustAssets : function(doShow){
30669 var x = this.xy[0], y = this.xy[1];
30670 var w = this.size.width, h = this.size.height;
30671 if(doShow === true){
30673 this.shadow.show(this.el);
30679 if(this.shadow && this.shadow.isVisible()){
30680 this.shadow.show(this.el);
30682 if(this.shim && this.shim.isVisible()){
30683 this.shim.setBounds(x, y, w, h);
30688 adjustViewport : function(w, h){
30690 w = Roo.lib.Dom.getViewWidth();
30691 h = Roo.lib.Dom.getViewHeight();
30694 this.viewSize = [w, h];
30695 if(this.modal && this.mask.isVisible()){
30696 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30697 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30699 if(this.isVisible()){
30700 this.constrainXY();
30705 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30706 * shadow, proxy, mask, etc.) Also removes all event listeners.
30707 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30709 destroy : function(removeEl){
30710 if(this.isVisible()){
30711 this.animateTarget = null;
30714 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30716 this.tabs.destroy(removeEl);
30729 for(var i = 0, len = this.buttons.length; i < len; i++){
30730 this.buttons[i].destroy();
30733 this.el.removeAllListeners();
30734 if(removeEl === true){
30735 this.el.update("");
30738 Roo.DialogManager.unregister(this);
30742 startMove : function(){
30743 if(this.proxyDrag){
30746 if(this.constraintoviewport !== false){
30747 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30752 endMove : function(){
30753 if(!this.proxyDrag){
30754 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30756 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30759 this.refreshSize();
30760 this.adjustAssets();
30762 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30766 * Brings this dialog to the front of any other visible dialogs
30767 * @return {Roo.BasicDialog} this
30769 toFront : function(){
30770 Roo.DialogManager.bringToFront(this);
30775 * Sends this dialog to the back (under) of any other visible dialogs
30776 * @return {Roo.BasicDialog} this
30778 toBack : function(){
30779 Roo.DialogManager.sendToBack(this);
30784 * Centers this dialog in the viewport
30785 * @return {Roo.BasicDialog} this
30787 center : function(){
30788 var xy = this.el.getCenterXY(true);
30789 this.moveTo(xy[0], xy[1]);
30794 * Moves the dialog's top-left corner to the specified point
30795 * @param {Number} x
30796 * @param {Number} y
30797 * @return {Roo.BasicDialog} this
30799 moveTo : function(x, y){
30801 if(this.isVisible()){
30802 this.el.setXY(this.xy);
30803 this.adjustAssets();
30809 * Aligns the dialog to the specified element
30810 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30811 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30812 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30813 * @return {Roo.BasicDialog} this
30815 alignTo : function(element, position, offsets){
30816 this.xy = this.el.getAlignToXY(element, position, offsets);
30817 if(this.isVisible()){
30818 this.el.setXY(this.xy);
30819 this.adjustAssets();
30825 * Anchors an element to another element and realigns it when the window is resized.
30826 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30827 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30828 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30829 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30830 * is a number, it is used as the buffer delay (defaults to 50ms).
30831 * @return {Roo.BasicDialog} this
30833 anchorTo : function(el, alignment, offsets, monitorScroll){
30834 var action = function(){
30835 this.alignTo(el, alignment, offsets);
30837 Roo.EventManager.onWindowResize(action, this);
30838 var tm = typeof monitorScroll;
30839 if(tm != 'undefined'){
30840 Roo.EventManager.on(window, 'scroll', action, this,
30841 {buffer: tm == 'number' ? monitorScroll : 50});
30848 * Returns true if the dialog is visible
30849 * @return {Boolean}
30851 isVisible : function(){
30852 return this.el.isVisible();
30856 animHide : function(callback){
30857 var b = Roo.get(this.animateTarget).getBox();
30859 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30861 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30862 this.hideEl.createDelegate(this, [callback]));
30866 * Hides the dialog.
30867 * @param {Function} callback (optional) Function to call when the dialog is hidden
30868 * @return {Roo.BasicDialog} this
30870 hide : function(callback){
30871 if (this.fireEvent("beforehide", this) === false){
30875 this.shadow.hide();
30880 // sometimes animateTarget seems to get set.. causing problems...
30881 // this just double checks..
30882 if(this.animateTarget && Roo.get(this.animateTarget)) {
30883 this.animHide(callback);
30886 this.hideEl(callback);
30892 hideEl : function(callback){
30896 Roo.get(document.body).removeClass("x-body-masked");
30898 this.fireEvent("hide", this);
30899 if(typeof callback == "function"){
30905 hideAction : function(){
30906 this.setLeft("-10000px");
30907 this.setTop("-10000px");
30908 this.setStyle("visibility", "hidden");
30912 refreshSize : function(){
30913 this.size = this.el.getSize();
30914 this.xy = this.el.getXY();
30915 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30919 // z-index is managed by the DialogManager and may be overwritten at any time
30920 setZIndex : function(index){
30922 this.mask.setStyle("z-index", index);
30925 this.shim.setStyle("z-index", ++index);
30928 this.shadow.setZIndex(++index);
30930 this.el.setStyle("z-index", ++index);
30932 this.proxy.setStyle("z-index", ++index);
30935 this.resizer.proxy.setStyle("z-index", ++index);
30938 this.lastZIndex = index;
30942 * Returns the element for this dialog
30943 * @return {Roo.Element} The underlying dialog Element
30945 getEl : function(){
30951 * @class Roo.DialogManager
30952 * Provides global access to BasicDialogs that have been created and
30953 * support for z-indexing (layering) multiple open dialogs.
30955 Roo.DialogManager = function(){
30957 var accessList = [];
30961 var sortDialogs = function(d1, d2){
30962 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
30966 var orderDialogs = function(){
30967 accessList.sort(sortDialogs);
30968 var seed = Roo.DialogManager.zseed;
30969 for(var i = 0, len = accessList.length; i < len; i++){
30970 var dlg = accessList[i];
30972 dlg.setZIndex(seed + (i*10));
30979 * The starting z-index for BasicDialogs (defaults to 9000)
30980 * @type Number The z-index value
30985 register : function(dlg){
30986 list[dlg.id] = dlg;
30987 accessList.push(dlg);
30991 unregister : function(dlg){
30992 delete list[dlg.id];
30995 if(!accessList.indexOf){
30996 for( i = 0, len = accessList.length; i < len; i++){
30997 if(accessList[i] == dlg){
30998 accessList.splice(i, 1);
31003 i = accessList.indexOf(dlg);
31005 accessList.splice(i, 1);
31011 * Gets a registered dialog by id
31012 * @param {String/Object} id The id of the dialog or a dialog
31013 * @return {Roo.BasicDialog} this
31015 get : function(id){
31016 return typeof id == "object" ? id : list[id];
31020 * Brings the specified dialog to the front
31021 * @param {String/Object} dlg The id of the dialog or a dialog
31022 * @return {Roo.BasicDialog} this
31024 bringToFront : function(dlg){
31025 dlg = this.get(dlg);
31028 dlg._lastAccess = new Date().getTime();
31035 * Sends the specified dialog to the back
31036 * @param {String/Object} dlg The id of the dialog or a dialog
31037 * @return {Roo.BasicDialog} this
31039 sendToBack : function(dlg){
31040 dlg = this.get(dlg);
31041 dlg._lastAccess = -(new Date().getTime());
31047 * Hides all dialogs
31049 hideAll : function(){
31050 for(var id in list){
31051 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31060 * @class Roo.LayoutDialog
31061 * @extends Roo.BasicDialog
31062 * Dialog which provides adjustments for working with a layout in a Dialog.
31063 * Add your necessary layout config options to the dialog's config.<br>
31064 * Example usage (including a nested layout):
31067 dialog = new Roo.LayoutDialog("download-dlg", {
31076 // layout config merges with the dialog config
31078 tabPosition: "top",
31079 alwaysShowTabs: true
31082 dialog.addKeyListener(27, dialog.hide, dialog);
31083 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31084 dialog.addButton("Build It!", this.getDownload, this);
31086 // we can even add nested layouts
31087 var innerLayout = new Roo.BorderLayout("dl-inner", {
31097 innerLayout.beginUpdate();
31098 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31099 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31100 innerLayout.endUpdate(true);
31102 var layout = dialog.getLayout();
31103 layout.beginUpdate();
31104 layout.add("center", new Roo.ContentPanel("standard-panel",
31105 {title: "Download the Source", fitToFrame:true}));
31106 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31107 {title: "Build your own roo.js"}));
31108 layout.getRegion("center").showPanel(sp);
31109 layout.endUpdate();
31113 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31114 * @param {Object} config configuration options
31116 Roo.LayoutDialog = function(el, cfg){
31119 if (typeof(cfg) == 'undefined') {
31120 config = Roo.apply({}, el);
31121 // not sure why we use documentElement here.. - it should always be body.
31122 // IE7 borks horribly if we use documentElement.
31123 // webkit also does not like documentElement - it creates a body element...
31124 el = Roo.get( document.body || document.documentElement ).createChild();
31125 //config.autoCreate = true;
31129 config.autoTabs = false;
31130 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31131 this.body.setStyle({overflow:"hidden", position:"relative"});
31132 this.layout = new Roo.BorderLayout(this.body.dom, config);
31133 this.layout.monitorWindowResize = false;
31134 this.el.addClass("x-dlg-auto-layout");
31135 // fix case when center region overwrites center function
31136 this.center = Roo.BasicDialog.prototype.center;
31137 this.on("show", this.layout.layout, this.layout, true);
31138 if (config.items) {
31139 var xitems = config.items;
31140 delete config.items;
31141 Roo.each(xitems, this.addxtype, this);
31146 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31148 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31151 endUpdate : function(){
31152 this.layout.endUpdate();
31156 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31159 beginUpdate : function(){
31160 this.layout.beginUpdate();
31164 * Get the BorderLayout for this dialog
31165 * @return {Roo.BorderLayout}
31167 getLayout : function(){
31168 return this.layout;
31171 showEl : function(){
31172 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31174 this.layout.layout();
31179 // Use the syncHeightBeforeShow config option to control this automatically
31180 syncBodyHeight : function(){
31181 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31182 if(this.layout){this.layout.layout();}
31186 * Add an xtype element (actually adds to the layout.)
31187 * @return {Object} xdata xtype object data.
31190 addxtype : function(c) {
31191 return this.layout.addxtype(c);
31195 * Ext JS Library 1.1.1
31196 * Copyright(c) 2006-2007, Ext JS, LLC.
31198 * Originally Released Under LGPL - original licence link has changed is not relivant.
31201 * <script type="text/javascript">
31205 * @class Roo.MessageBox
31206 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31210 Roo.Msg.alert('Status', 'Changes saved successfully.');
31212 // Prompt for user data:
31213 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31215 // process text value...
31219 // Show a dialog using config options:
31221 title:'Save Changes?',
31222 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31223 buttons: Roo.Msg.YESNOCANCEL,
31230 Roo.MessageBox = function(){
31231 var dlg, opt, mask, waitTimer;
31232 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31233 var buttons, activeTextEl, bwidth;
31236 var handleButton = function(button){
31238 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31242 var handleHide = function(){
31243 if(opt && opt.cls){
31244 dlg.el.removeClass(opt.cls);
31247 Roo.TaskMgr.stop(waitTimer);
31253 var updateButtons = function(b){
31256 buttons["ok"].hide();
31257 buttons["cancel"].hide();
31258 buttons["yes"].hide();
31259 buttons["no"].hide();
31260 dlg.footer.dom.style.display = 'none';
31263 dlg.footer.dom.style.display = '';
31264 for(var k in buttons){
31265 if(typeof buttons[k] != "function"){
31268 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31269 width += buttons[k].el.getWidth()+15;
31279 var handleEsc = function(d, k, e){
31280 if(opt && opt.closable !== false){
31290 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31291 * @return {Roo.BasicDialog} The BasicDialog element
31293 getDialog : function(){
31295 dlg = new Roo.BasicDialog("x-msg-box", {
31300 constraintoviewport:false,
31302 collapsible : false,
31305 width:400, height:100,
31306 buttonAlign:"center",
31307 closeClick : function(){
31308 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31309 handleButton("no");
31311 handleButton("cancel");
31315 dlg.on("hide", handleHide);
31317 dlg.addKeyListener(27, handleEsc);
31319 var bt = this.buttonText;
31320 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31321 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31322 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31323 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31324 bodyEl = dlg.body.createChild({
31326 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>'
31328 msgEl = bodyEl.dom.firstChild;
31329 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31330 textboxEl.enableDisplayMode();
31331 textboxEl.addKeyListener([10,13], function(){
31332 if(dlg.isVisible() && opt && opt.buttons){
31333 if(opt.buttons.ok){
31334 handleButton("ok");
31335 }else if(opt.buttons.yes){
31336 handleButton("yes");
31340 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31341 textareaEl.enableDisplayMode();
31342 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31343 progressEl.enableDisplayMode();
31344 var pf = progressEl.dom.firstChild;
31346 pp = Roo.get(pf.firstChild);
31347 pp.setHeight(pf.offsetHeight);
31355 * Updates the message box body text
31356 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31357 * the XHTML-compliant non-breaking space character '&#160;')
31358 * @return {Roo.MessageBox} This message box
31360 updateText : function(text){
31361 if(!dlg.isVisible() && !opt.width){
31362 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31364 msgEl.innerHTML = text || ' ';
31366 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31367 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31369 Math.min(opt.width || cw , this.maxWidth),
31370 Math.max(opt.minWidth || this.minWidth, bwidth)
31373 activeTextEl.setWidth(w);
31375 if(dlg.isVisible()){
31376 dlg.fixedcenter = false;
31378 // to big, make it scroll. = But as usual stupid IE does not support
31381 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31382 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31383 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31385 bodyEl.dom.style.height = '';
31386 bodyEl.dom.style.overflowY = '';
31389 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31391 bodyEl.dom.style.overflowX = '';
31394 dlg.setContentSize(w, bodyEl.getHeight());
31395 if(dlg.isVisible()){
31396 dlg.fixedcenter = true;
31402 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31403 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31404 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31405 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31406 * @return {Roo.MessageBox} This message box
31408 updateProgress : function(value, text){
31410 this.updateText(text);
31412 if (pp) { // weird bug on my firefox - for some reason this is not defined
31413 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31419 * Returns true if the message box is currently displayed
31420 * @return {Boolean} True if the message box is visible, else false
31422 isVisible : function(){
31423 return dlg && dlg.isVisible();
31427 * Hides the message box if it is displayed
31430 if(this.isVisible()){
31436 * Displays a new message box, or reinitializes an existing message box, based on the config options
31437 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31438 * The following config object properties are supported:
31440 Property Type Description
31441 ---------- --------------- ------------------------------------------------------------------------------------
31442 animEl String/Element An id or Element from which the message box should animate as it opens and
31443 closes (defaults to undefined)
31444 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31445 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31446 closable Boolean False to hide the top-right close button (defaults to true). Note that
31447 progress and wait dialogs will ignore this property and always hide the
31448 close button as they can only be closed programmatically.
31449 cls String A custom CSS class to apply to the message box element
31450 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31451 displayed (defaults to 75)
31452 fn Function A callback function to execute after closing the dialog. The arguments to the
31453 function will be btn (the name of the button that was clicked, if applicable,
31454 e.g. "ok"), and text (the value of the active text field, if applicable).
31455 Progress and wait dialogs will ignore this option since they do not respond to
31456 user actions and can only be closed programmatically, so any required function
31457 should be called by the same code after it closes the dialog.
31458 icon String A CSS class that provides a background image to be used as an icon for
31459 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31460 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31461 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31462 modal Boolean False to allow user interaction with the page while the message box is
31463 displayed (defaults to true)
31464 msg String A string that will replace the existing message box body text (defaults
31465 to the XHTML-compliant non-breaking space character ' ')
31466 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31467 progress Boolean True to display a progress bar (defaults to false)
31468 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31469 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31470 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31471 title String The title text
31472 value String The string value to set into the active textbox element if displayed
31473 wait Boolean True to display a progress bar (defaults to false)
31474 width Number The width of the dialog in pixels
31481 msg: 'Please enter your address:',
31483 buttons: Roo.MessageBox.OKCANCEL,
31486 animEl: 'addAddressBtn'
31489 * @param {Object} config Configuration options
31490 * @return {Roo.MessageBox} This message box
31492 show : function(options)
31495 // this causes nightmares if you show one dialog after another
31496 // especially on callbacks..
31498 if(this.isVisible()){
31501 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31502 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31503 Roo.log("New Dialog Message:" + options.msg )
31504 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31505 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31508 var d = this.getDialog();
31510 d.setTitle(opt.title || " ");
31511 d.close.setDisplayed(opt.closable !== false);
31512 activeTextEl = textboxEl;
31513 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31518 textareaEl.setHeight(typeof opt.multiline == "number" ?
31519 opt.multiline : this.defaultTextHeight);
31520 activeTextEl = textareaEl;
31529 progressEl.setDisplayed(opt.progress === true);
31530 this.updateProgress(0);
31531 activeTextEl.dom.value = opt.value || "";
31533 dlg.setDefaultButton(activeTextEl);
31535 var bs = opt.buttons;
31538 db = buttons["ok"];
31539 }else if(bs && bs.yes){
31540 db = buttons["yes"];
31542 dlg.setDefaultButton(db);
31544 bwidth = updateButtons(opt.buttons);
31545 this.updateText(opt.msg);
31547 d.el.addClass(opt.cls);
31549 d.proxyDrag = opt.proxyDrag === true;
31550 d.modal = opt.modal !== false;
31551 d.mask = opt.modal !== false ? mask : false;
31552 if(!d.isVisible()){
31553 // force it to the end of the z-index stack so it gets a cursor in FF
31554 document.body.appendChild(dlg.el.dom);
31555 d.animateTarget = null;
31556 d.show(options.animEl);
31562 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31563 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31564 * and closing the message box when the process is complete.
31565 * @param {String} title The title bar text
31566 * @param {String} msg The message box body text
31567 * @return {Roo.MessageBox} This message box
31569 progress : function(title, msg){
31576 minWidth: this.minProgressWidth,
31583 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31584 * If a callback function is passed it will be called after the user clicks the button, and the
31585 * id of the button that was clicked will be passed as the only parameter to the callback
31586 * (could also be the top-right close button).
31587 * @param {String} title The title bar text
31588 * @param {String} msg The message box body text
31589 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31590 * @param {Object} scope (optional) The scope of the callback function
31591 * @return {Roo.MessageBox} This message box
31593 alert : function(title, msg, fn, scope){
31606 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31607 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31608 * You are responsible for closing the message box when the process is complete.
31609 * @param {String} msg The message box body text
31610 * @param {String} title (optional) The title bar text
31611 * @return {Roo.MessageBox} This message box
31613 wait : function(msg, title){
31624 waitTimer = Roo.TaskMgr.start({
31626 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31634 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31635 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31636 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31637 * @param {String} title The title bar text
31638 * @param {String} msg The message box body text
31639 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31640 * @param {Object} scope (optional) The scope of the callback function
31641 * @return {Roo.MessageBox} This message box
31643 confirm : function(title, msg, fn, scope){
31647 buttons: this.YESNO,
31656 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31657 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31658 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31659 * (could also be the top-right close button) and the text that was entered will be passed as the two
31660 * parameters to the callback.
31661 * @param {String} title The title bar text
31662 * @param {String} msg The message box body text
31663 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31664 * @param {Object} scope (optional) The scope of the callback function
31665 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31666 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31667 * @return {Roo.MessageBox} This message box
31669 prompt : function(title, msg, fn, scope, multiline){
31673 buttons: this.OKCANCEL,
31678 multiline: multiline,
31685 * Button config that displays a single OK button
31690 * Button config that displays Yes and No buttons
31693 YESNO : {yes:true, no:true},
31695 * Button config that displays OK and Cancel buttons
31698 OKCANCEL : {ok:true, cancel:true},
31700 * Button config that displays Yes, No and Cancel buttons
31703 YESNOCANCEL : {yes:true, no:true, cancel:true},
31706 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31709 defaultTextHeight : 75,
31711 * The maximum width in pixels of the message box (defaults to 600)
31716 * The minimum width in pixels of the message box (defaults to 100)
31721 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31722 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31725 minProgressWidth : 250,
31727 * An object containing the default button text strings that can be overriden for localized language support.
31728 * Supported properties are: ok, cancel, yes and no.
31729 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31742 * Shorthand for {@link Roo.MessageBox}
31744 Roo.Msg = Roo.MessageBox;/*
31746 * Ext JS Library 1.1.1
31747 * Copyright(c) 2006-2007, Ext JS, LLC.
31749 * Originally Released Under LGPL - original licence link has changed is not relivant.
31752 * <script type="text/javascript">
31755 * @class Roo.QuickTips
31756 * Provides attractive and customizable tooltips for any element.
31759 Roo.QuickTips = function(){
31760 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31761 var ce, bd, xy, dd;
31762 var visible = false, disabled = true, inited = false;
31763 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31765 var onOver = function(e){
31769 var t = e.getTarget();
31770 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31773 if(ce && t == ce.el){
31774 clearTimeout(hideProc);
31777 if(t && tagEls[t.id]){
31778 tagEls[t.id].el = t;
31779 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31782 var ttp, et = Roo.fly(t);
31783 var ns = cfg.namespace;
31784 if(tm.interceptTitles && t.title){
31787 t.removeAttribute("title");
31788 e.preventDefault();
31790 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31793 showProc = show.defer(tm.showDelay, tm, [{
31796 width: et.getAttributeNS(ns, cfg.width),
31797 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31798 title: et.getAttributeNS(ns, cfg.title),
31799 cls: et.getAttributeNS(ns, cfg.cls)
31804 var onOut = function(e){
31805 clearTimeout(showProc);
31806 var t = e.getTarget();
31807 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31808 hideProc = setTimeout(hide, tm.hideDelay);
31812 var onMove = function(e){
31818 if(tm.trackMouse && ce){
31823 var onDown = function(e){
31824 clearTimeout(showProc);
31825 clearTimeout(hideProc);
31827 if(tm.hideOnClick){
31830 tm.enable.defer(100, tm);
31835 var getPad = function(){
31836 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31839 var show = function(o){
31843 clearTimeout(dismissProc);
31845 if(removeCls){ // in case manually hidden
31846 el.removeClass(removeCls);
31850 el.addClass(ce.cls);
31851 removeCls = ce.cls;
31854 tipTitle.update(ce.title);
31857 tipTitle.update('');
31860 el.dom.style.width = tm.maxWidth+'px';
31861 //tipBody.dom.style.width = '';
31862 tipBodyText.update(o.text);
31863 var p = getPad(), w = ce.width;
31865 var td = tipBodyText.dom;
31866 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31867 if(aw > tm.maxWidth){
31869 }else if(aw < tm.minWidth){
31875 //tipBody.setWidth(w);
31876 el.setWidth(parseInt(w, 10) + p);
31877 if(ce.autoHide === false){
31878 close.setDisplayed(true);
31883 close.setDisplayed(false);
31889 el.avoidY = xy[1]-18;
31894 el.setStyle("visibility", "visible");
31895 el.fadeIn({callback: afterShow});
31901 var afterShow = function(){
31905 if(tm.autoDismiss && ce.autoHide !== false){
31906 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31911 var hide = function(noanim){
31912 clearTimeout(dismissProc);
31913 clearTimeout(hideProc);
31915 if(el.isVisible()){
31917 if(noanim !== true && tm.animate){
31918 el.fadeOut({callback: afterHide});
31925 var afterHide = function(){
31928 el.removeClass(removeCls);
31935 * @cfg {Number} minWidth
31936 * The minimum width of the quick tip (defaults to 40)
31940 * @cfg {Number} maxWidth
31941 * The maximum width of the quick tip (defaults to 300)
31945 * @cfg {Boolean} interceptTitles
31946 * True to automatically use the element's DOM title value if available (defaults to false)
31948 interceptTitles : false,
31950 * @cfg {Boolean} trackMouse
31951 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31953 trackMouse : false,
31955 * @cfg {Boolean} hideOnClick
31956 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
31958 hideOnClick : true,
31960 * @cfg {Number} showDelay
31961 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
31965 * @cfg {Number} hideDelay
31966 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
31970 * @cfg {Boolean} autoHide
31971 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
31972 * Used in conjunction with hideDelay.
31977 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
31978 * (defaults to true). Used in conjunction with autoDismissDelay.
31980 autoDismiss : true,
31983 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
31985 autoDismissDelay : 5000,
31987 * @cfg {Boolean} animate
31988 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
31993 * @cfg {String} title
31994 * Title text to display (defaults to ''). This can be any valid HTML markup.
31998 * @cfg {String} text
31999 * Body text to display (defaults to ''). This can be any valid HTML markup.
32003 * @cfg {String} cls
32004 * A CSS class to apply to the base quick tip element (defaults to '').
32008 * @cfg {Number} width
32009 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32010 * minWidth or maxWidth.
32015 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32016 * or display QuickTips in a page.
32019 tm = Roo.QuickTips;
32020 cfg = tm.tagConfig;
32022 if(!Roo.isReady){ // allow calling of init() before onReady
32023 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32026 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32027 el.fxDefaults = {stopFx: true};
32028 // maximum custom styling
32029 //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>');
32030 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>');
32031 tipTitle = el.child('h3');
32032 tipTitle.enableDisplayMode("block");
32033 tipBody = el.child('div.x-tip-bd');
32034 tipBodyText = el.child('div.x-tip-bd-inner');
32035 //bdLeft = el.child('div.x-tip-bd-left');
32036 //bdRight = el.child('div.x-tip-bd-right');
32037 close = el.child('div.x-tip-close');
32038 close.enableDisplayMode("block");
32039 close.on("click", hide);
32040 var d = Roo.get(document);
32041 d.on("mousedown", onDown);
32042 d.on("mouseover", onOver);
32043 d.on("mouseout", onOut);
32044 d.on("mousemove", onMove);
32045 esc = d.addKeyListener(27, hide);
32048 dd = el.initDD("default", null, {
32049 onDrag : function(){
32053 dd.setHandleElId(tipTitle.id);
32062 * Configures a new quick tip instance and assigns it to a target element. The following config options
32065 Property Type Description
32066 ---------- --------------------- ------------------------------------------------------------------------
32067 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32069 * @param {Object} config The config object
32071 register : function(config){
32072 var cs = config instanceof Array ? config : arguments;
32073 for(var i = 0, len = cs.length; i < len; i++) {
32075 var target = c.target;
32077 if(target instanceof Array){
32078 for(var j = 0, jlen = target.length; j < jlen; j++){
32079 tagEls[target[j]] = c;
32082 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32089 * Removes this quick tip from its element and destroys it.
32090 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32092 unregister : function(el){
32093 delete tagEls[Roo.id(el)];
32097 * Enable this quick tip.
32099 enable : function(){
32100 if(inited && disabled){
32102 if(locks.length < 1){
32109 * Disable this quick tip.
32111 disable : function(){
32113 clearTimeout(showProc);
32114 clearTimeout(hideProc);
32115 clearTimeout(dismissProc);
32123 * Returns true if the quick tip is enabled, else false.
32125 isEnabled : function(){
32132 attribute : "qtip",
32142 // backwards compat
32143 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32145 * Ext JS Library 1.1.1
32146 * Copyright(c) 2006-2007, Ext JS, LLC.
32148 * Originally Released Under LGPL - original licence link has changed is not relivant.
32151 * <script type="text/javascript">
32156 * @class Roo.tree.TreePanel
32157 * @extends Roo.data.Tree
32159 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32160 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32161 * @cfg {Boolean} enableDD true to enable drag and drop
32162 * @cfg {Boolean} enableDrag true to enable just drag
32163 * @cfg {Boolean} enableDrop true to enable just drop
32164 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32165 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32166 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32167 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32168 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32169 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32170 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32171 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32172 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32173 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32174 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32175 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32176 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32177 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32178 * @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>
32179 * @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>
32182 * @param {String/HTMLElement/Element} el The container element
32183 * @param {Object} config
32185 Roo.tree.TreePanel = function(el, config){
32187 var loader = false;
32189 root = config.root;
32190 delete config.root;
32192 if (config.loader) {
32193 loader = config.loader;
32194 delete config.loader;
32197 Roo.apply(this, config);
32198 Roo.tree.TreePanel.superclass.constructor.call(this);
32199 this.el = Roo.get(el);
32200 this.el.addClass('x-tree');
32201 //console.log(root);
32203 this.setRootNode( Roo.factory(root, Roo.tree));
32206 this.loader = Roo.factory(loader, Roo.tree);
32209 * Read-only. The id of the container element becomes this TreePanel's id.
32211 this.id = this.el.id;
32214 * @event beforeload
32215 * Fires before a node is loaded, return false to cancel
32216 * @param {Node} node The node being loaded
32218 "beforeload" : true,
32221 * Fires when a node is loaded
32222 * @param {Node} node The node that was loaded
32226 * @event textchange
32227 * Fires when the text for a node is changed
32228 * @param {Node} node The node
32229 * @param {String} text The new text
32230 * @param {String} oldText The old text
32232 "textchange" : true,
32234 * @event beforeexpand
32235 * Fires before a node is expanded, return false to cancel.
32236 * @param {Node} node The node
32237 * @param {Boolean} deep
32238 * @param {Boolean} anim
32240 "beforeexpand" : true,
32242 * @event beforecollapse
32243 * Fires before a node is collapsed, return false to cancel.
32244 * @param {Node} node The node
32245 * @param {Boolean} deep
32246 * @param {Boolean} anim
32248 "beforecollapse" : true,
32251 * Fires when a node is expanded
32252 * @param {Node} node The node
32256 * @event disabledchange
32257 * Fires when the disabled status of a node changes
32258 * @param {Node} node The node
32259 * @param {Boolean} disabled
32261 "disabledchange" : true,
32264 * Fires when a node is collapsed
32265 * @param {Node} node The node
32269 * @event beforeclick
32270 * Fires before click processing on a node. Return false to cancel the default action.
32271 * @param {Node} node The node
32272 * @param {Roo.EventObject} e The event object
32274 "beforeclick":true,
32276 * @event checkchange
32277 * Fires when a node with a checkbox's checked property changes
32278 * @param {Node} this This node
32279 * @param {Boolean} checked
32281 "checkchange":true,
32284 * Fires when a node is clicked
32285 * @param {Node} node The node
32286 * @param {Roo.EventObject} e The event object
32291 * Fires when a node is double clicked
32292 * @param {Node} node The node
32293 * @param {Roo.EventObject} e The event object
32297 * @event contextmenu
32298 * Fires when a node is right clicked
32299 * @param {Node} node The node
32300 * @param {Roo.EventObject} e The event object
32302 "contextmenu":true,
32304 * @event beforechildrenrendered
32305 * Fires right before the child nodes for a node are rendered
32306 * @param {Node} node The node
32308 "beforechildrenrendered":true,
32311 * Fires when a node starts being dragged
32312 * @param {Roo.tree.TreePanel} this
32313 * @param {Roo.tree.TreeNode} node
32314 * @param {event} e The raw browser event
32316 "startdrag" : true,
32319 * Fires when a drag operation is complete
32320 * @param {Roo.tree.TreePanel} this
32321 * @param {Roo.tree.TreeNode} node
32322 * @param {event} e The raw browser event
32327 * Fires when a dragged node is dropped on a valid DD target
32328 * @param {Roo.tree.TreePanel} this
32329 * @param {Roo.tree.TreeNode} node
32330 * @param {DD} dd The dd it was dropped on
32331 * @param {event} e The raw browser event
32335 * @event beforenodedrop
32336 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32337 * passed to handlers has the following properties:<br />
32338 * <ul style="padding:5px;padding-left:16px;">
32339 * <li>tree - The TreePanel</li>
32340 * <li>target - The node being targeted for the drop</li>
32341 * <li>data - The drag data from the drag source</li>
32342 * <li>point - The point of the drop - append, above or below</li>
32343 * <li>source - The drag source</li>
32344 * <li>rawEvent - Raw mouse event</li>
32345 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32346 * to be inserted by setting them on this object.</li>
32347 * <li>cancel - Set this to true to cancel the drop.</li>
32349 * @param {Object} dropEvent
32351 "beforenodedrop" : true,
32354 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32355 * passed to handlers has the following properties:<br />
32356 * <ul style="padding:5px;padding-left:16px;">
32357 * <li>tree - The TreePanel</li>
32358 * <li>target - The node being targeted for the drop</li>
32359 * <li>data - The drag data from the drag source</li>
32360 * <li>point - The point of the drop - append, above or below</li>
32361 * <li>source - The drag source</li>
32362 * <li>rawEvent - Raw mouse event</li>
32363 * <li>dropNode - Dropped node(s).</li>
32365 * @param {Object} dropEvent
32369 * @event nodedragover
32370 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32371 * passed to handlers has the following properties:<br />
32372 * <ul style="padding:5px;padding-left:16px;">
32373 * <li>tree - The TreePanel</li>
32374 * <li>target - The node being targeted for the drop</li>
32375 * <li>data - The drag data from the drag source</li>
32376 * <li>point - The point of the drop - append, above or below</li>
32377 * <li>source - The drag source</li>
32378 * <li>rawEvent - Raw mouse event</li>
32379 * <li>dropNode - Drop node(s) provided by the source.</li>
32380 * <li>cancel - Set this to true to signal drop not allowed.</li>
32382 * @param {Object} dragOverEvent
32384 "nodedragover" : true
32387 if(this.singleExpand){
32388 this.on("beforeexpand", this.restrictExpand, this);
32391 this.editor.tree = this;
32392 this.editor = Roo.factory(this.editor, Roo.tree);
32395 if (this.selModel) {
32396 this.selModel = Roo.factory(this.selModel, Roo.tree);
32400 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32401 rootVisible : true,
32402 animate: Roo.enableFx,
32405 hlDrop : Roo.enableFx,
32409 rendererTip: false,
32411 restrictExpand : function(node){
32412 var p = node.parentNode;
32414 if(p.expandedChild && p.expandedChild.parentNode == p){
32415 p.expandedChild.collapse();
32417 p.expandedChild = node;
32421 // private override
32422 setRootNode : function(node){
32423 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32424 if(!this.rootVisible){
32425 node.ui = new Roo.tree.RootTreeNodeUI(node);
32431 * Returns the container element for this TreePanel
32433 getEl : function(){
32438 * Returns the default TreeLoader for this TreePanel
32440 getLoader : function(){
32441 return this.loader;
32447 expandAll : function(){
32448 this.root.expand(true);
32452 * Collapse all nodes
32454 collapseAll : function(){
32455 this.root.collapse(true);
32459 * Returns the selection model used by this TreePanel
32461 getSelectionModel : function(){
32462 if(!this.selModel){
32463 this.selModel = new Roo.tree.DefaultSelectionModel();
32465 return this.selModel;
32469 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32470 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32471 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32474 getChecked : function(a, startNode){
32475 startNode = startNode || this.root;
32477 var f = function(){
32478 if(this.attributes.checked){
32479 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32482 startNode.cascade(f);
32487 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32488 * @param {String} path
32489 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32490 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32491 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32493 expandPath : function(path, attr, callback){
32494 attr = attr || "id";
32495 var keys = path.split(this.pathSeparator);
32496 var curNode = this.root;
32497 if(curNode.attributes[attr] != keys[1]){ // invalid root
32499 callback(false, null);
32504 var f = function(){
32505 if(++index == keys.length){
32507 callback(true, curNode);
32511 var c = curNode.findChild(attr, keys[index]);
32514 callback(false, curNode);
32519 c.expand(false, false, f);
32521 curNode.expand(false, false, f);
32525 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32526 * @param {String} path
32527 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32528 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32529 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32531 selectPath : function(path, attr, callback){
32532 attr = attr || "id";
32533 var keys = path.split(this.pathSeparator);
32534 var v = keys.pop();
32535 if(keys.length > 0){
32536 var f = function(success, node){
32537 if(success && node){
32538 var n = node.findChild(attr, v);
32544 }else if(callback){
32545 callback(false, n);
32549 callback(false, n);
32553 this.expandPath(keys.join(this.pathSeparator), attr, f);
32555 this.root.select();
32557 callback(true, this.root);
32562 getTreeEl : function(){
32567 * Trigger rendering of this TreePanel
32569 render : function(){
32570 if (this.innerCt) {
32571 return this; // stop it rendering more than once!!
32574 this.innerCt = this.el.createChild({tag:"ul",
32575 cls:"x-tree-root-ct " +
32576 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32578 if(this.containerScroll){
32579 Roo.dd.ScrollManager.register(this.el);
32581 if((this.enableDD || this.enableDrop) && !this.dropZone){
32583 * The dropZone used by this tree if drop is enabled
32584 * @type Roo.tree.TreeDropZone
32586 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32587 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32590 if((this.enableDD || this.enableDrag) && !this.dragZone){
32592 * The dragZone used by this tree if drag is enabled
32593 * @type Roo.tree.TreeDragZone
32595 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32596 ddGroup: this.ddGroup || "TreeDD",
32597 scroll: this.ddScroll
32600 this.getSelectionModel().init(this);
32602 Roo.log("ROOT not set in tree");
32605 this.root.render();
32606 if(!this.rootVisible){
32607 this.root.renderChildren();
32613 * Ext JS Library 1.1.1
32614 * Copyright(c) 2006-2007, Ext JS, LLC.
32616 * Originally Released Under LGPL - original licence link has changed is not relivant.
32619 * <script type="text/javascript">
32624 * @class Roo.tree.DefaultSelectionModel
32625 * @extends Roo.util.Observable
32626 * The default single selection for a TreePanel.
32627 * @param {Object} cfg Configuration
32629 Roo.tree.DefaultSelectionModel = function(cfg){
32630 this.selNode = null;
32636 * @event selectionchange
32637 * Fires when the selected node changes
32638 * @param {DefaultSelectionModel} this
32639 * @param {TreeNode} node the new selection
32641 "selectionchange" : true,
32644 * @event beforeselect
32645 * Fires before the selected node changes, return false to cancel the change
32646 * @param {DefaultSelectionModel} this
32647 * @param {TreeNode} node the new selection
32648 * @param {TreeNode} node the old selection
32650 "beforeselect" : true
32653 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32656 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32657 init : function(tree){
32659 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32660 tree.on("click", this.onNodeClick, this);
32663 onNodeClick : function(node, e){
32664 if (e.ctrlKey && this.selNode == node) {
32665 this.unselect(node);
32673 * @param {TreeNode} node The node to select
32674 * @return {TreeNode} The selected node
32676 select : function(node){
32677 var last = this.selNode;
32678 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32680 last.ui.onSelectedChange(false);
32682 this.selNode = node;
32683 node.ui.onSelectedChange(true);
32684 this.fireEvent("selectionchange", this, node, last);
32691 * @param {TreeNode} node The node to unselect
32693 unselect : function(node){
32694 if(this.selNode == node){
32695 this.clearSelections();
32700 * Clear all selections
32702 clearSelections : function(){
32703 var n = this.selNode;
32705 n.ui.onSelectedChange(false);
32706 this.selNode = null;
32707 this.fireEvent("selectionchange", this, null);
32713 * Get the selected node
32714 * @return {TreeNode} The selected node
32716 getSelectedNode : function(){
32717 return this.selNode;
32721 * Returns true if the node is selected
32722 * @param {TreeNode} node The node to check
32723 * @return {Boolean}
32725 isSelected : function(node){
32726 return this.selNode == node;
32730 * Selects the node above the selected node in the tree, intelligently walking the nodes
32731 * @return TreeNode The new selection
32733 selectPrevious : function(){
32734 var s = this.selNode || this.lastSelNode;
32738 var ps = s.previousSibling;
32740 if(!ps.isExpanded() || ps.childNodes.length < 1){
32741 return this.select(ps);
32743 var lc = ps.lastChild;
32744 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32747 return this.select(lc);
32749 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32750 return this.select(s.parentNode);
32756 * Selects the node above the selected node in the tree, intelligently walking the nodes
32757 * @return TreeNode The new selection
32759 selectNext : function(){
32760 var s = this.selNode || this.lastSelNode;
32764 if(s.firstChild && s.isExpanded()){
32765 return this.select(s.firstChild);
32766 }else if(s.nextSibling){
32767 return this.select(s.nextSibling);
32768 }else if(s.parentNode){
32770 s.parentNode.bubble(function(){
32771 if(this.nextSibling){
32772 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32781 onKeyDown : function(e){
32782 var s = this.selNode || this.lastSelNode;
32783 // undesirable, but required
32788 var k = e.getKey();
32796 this.selectPrevious();
32799 e.preventDefault();
32800 if(s.hasChildNodes()){
32801 if(!s.isExpanded()){
32803 }else if(s.firstChild){
32804 this.select(s.firstChild, e);
32809 e.preventDefault();
32810 if(s.hasChildNodes() && s.isExpanded()){
32812 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32813 this.select(s.parentNode, e);
32821 * @class Roo.tree.MultiSelectionModel
32822 * @extends Roo.util.Observable
32823 * Multi selection for a TreePanel.
32824 * @param {Object} cfg Configuration
32826 Roo.tree.MultiSelectionModel = function(){
32827 this.selNodes = [];
32831 * @event selectionchange
32832 * Fires when the selected nodes change
32833 * @param {MultiSelectionModel} this
32834 * @param {Array} nodes Array of the selected nodes
32836 "selectionchange" : true
32838 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32842 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32843 init : function(tree){
32845 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32846 tree.on("click", this.onNodeClick, this);
32849 onNodeClick : function(node, e){
32850 this.select(node, e, e.ctrlKey);
32855 * @param {TreeNode} node The node to select
32856 * @param {EventObject} e (optional) An event associated with the selection
32857 * @param {Boolean} keepExisting True to retain existing selections
32858 * @return {TreeNode} The selected node
32860 select : function(node, e, keepExisting){
32861 if(keepExisting !== true){
32862 this.clearSelections(true);
32864 if(this.isSelected(node)){
32865 this.lastSelNode = node;
32868 this.selNodes.push(node);
32869 this.selMap[node.id] = node;
32870 this.lastSelNode = node;
32871 node.ui.onSelectedChange(true);
32872 this.fireEvent("selectionchange", this, this.selNodes);
32878 * @param {TreeNode} node The node to unselect
32880 unselect : function(node){
32881 if(this.selMap[node.id]){
32882 node.ui.onSelectedChange(false);
32883 var sn = this.selNodes;
32886 index = sn.indexOf(node);
32888 for(var i = 0, len = sn.length; i < len; i++){
32896 this.selNodes.splice(index, 1);
32898 delete this.selMap[node.id];
32899 this.fireEvent("selectionchange", this, this.selNodes);
32904 * Clear all selections
32906 clearSelections : function(suppressEvent){
32907 var sn = this.selNodes;
32909 for(var i = 0, len = sn.length; i < len; i++){
32910 sn[i].ui.onSelectedChange(false);
32912 this.selNodes = [];
32914 if(suppressEvent !== true){
32915 this.fireEvent("selectionchange", this, this.selNodes);
32921 * Returns true if the node is selected
32922 * @param {TreeNode} node The node to check
32923 * @return {Boolean}
32925 isSelected : function(node){
32926 return this.selMap[node.id] ? true : false;
32930 * Returns an array of the selected nodes
32933 getSelectedNodes : function(){
32934 return this.selNodes;
32937 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32939 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32941 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32944 * Ext JS Library 1.1.1
32945 * Copyright(c) 2006-2007, Ext JS, LLC.
32947 * Originally Released Under LGPL - original licence link has changed is not relivant.
32950 * <script type="text/javascript">
32954 * @class Roo.tree.TreeNode
32955 * @extends Roo.data.Node
32956 * @cfg {String} text The text for this node
32957 * @cfg {Boolean} expanded true to start the node expanded
32958 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
32959 * @cfg {Boolean} allowDrop false if this node cannot be drop on
32960 * @cfg {Boolean} disabled true to start the node disabled
32961 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
32962 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
32963 * @cfg {String} cls A css class to be added to the node
32964 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
32965 * @cfg {String} href URL of the link used for the node (defaults to #)
32966 * @cfg {String} hrefTarget target frame for the link
32967 * @cfg {String} qtip An Ext QuickTip for the node
32968 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
32969 * @cfg {Boolean} singleClickExpand True for single click expand on this node
32970 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
32971 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
32972 * (defaults to undefined with no checkbox rendered)
32974 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32976 Roo.tree.TreeNode = function(attributes){
32977 attributes = attributes || {};
32978 if(typeof attributes == "string"){
32979 attributes = {text: attributes};
32981 this.childrenRendered = false;
32982 this.rendered = false;
32983 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
32984 this.expanded = attributes.expanded === true;
32985 this.isTarget = attributes.isTarget !== false;
32986 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
32987 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
32990 * Read-only. The text for this node. To change it use setText().
32993 this.text = attributes.text;
32995 * True if this node is disabled.
32998 this.disabled = attributes.disabled === true;
33002 * @event textchange
33003 * Fires when the text for this node is changed
33004 * @param {Node} this This node
33005 * @param {String} text The new text
33006 * @param {String} oldText The old text
33008 "textchange" : true,
33010 * @event beforeexpand
33011 * Fires before this node is expanded, return false to cancel.
33012 * @param {Node} this This node
33013 * @param {Boolean} deep
33014 * @param {Boolean} anim
33016 "beforeexpand" : true,
33018 * @event beforecollapse
33019 * Fires before this node is collapsed, return false to cancel.
33020 * @param {Node} this This node
33021 * @param {Boolean} deep
33022 * @param {Boolean} anim
33024 "beforecollapse" : true,
33027 * Fires when this node is expanded
33028 * @param {Node} this This node
33032 * @event disabledchange
33033 * Fires when the disabled status of this node changes
33034 * @param {Node} this This node
33035 * @param {Boolean} disabled
33037 "disabledchange" : true,
33040 * Fires when this node is collapsed
33041 * @param {Node} this This node
33045 * @event beforeclick
33046 * Fires before click processing. Return false to cancel the default action.
33047 * @param {Node} this This node
33048 * @param {Roo.EventObject} e The event object
33050 "beforeclick":true,
33052 * @event checkchange
33053 * Fires when a node with a checkbox's checked property changes
33054 * @param {Node} this This node
33055 * @param {Boolean} checked
33057 "checkchange":true,
33060 * Fires when this node is clicked
33061 * @param {Node} this This node
33062 * @param {Roo.EventObject} e The event object
33067 * Fires when this node is double clicked
33068 * @param {Node} this This node
33069 * @param {Roo.EventObject} e The event object
33073 * @event contextmenu
33074 * Fires when this node is right clicked
33075 * @param {Node} this This node
33076 * @param {Roo.EventObject} e The event object
33078 "contextmenu":true,
33080 * @event beforechildrenrendered
33081 * Fires right before the child nodes for this node are rendered
33082 * @param {Node} this This node
33084 "beforechildrenrendered":true
33087 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33090 * Read-only. The UI for this node
33093 this.ui = new uiClass(this);
33095 // finally support items[]
33096 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33101 Roo.each(this.attributes.items, function(c) {
33102 this.appendChild(Roo.factory(c,Roo.Tree));
33104 delete this.attributes.items;
33109 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33110 preventHScroll: true,
33112 * Returns true if this node is expanded
33113 * @return {Boolean}
33115 isExpanded : function(){
33116 return this.expanded;
33120 * Returns the UI object for this node
33121 * @return {TreeNodeUI}
33123 getUI : function(){
33127 // private override
33128 setFirstChild : function(node){
33129 var of = this.firstChild;
33130 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33131 if(this.childrenRendered && of && node != of){
33132 of.renderIndent(true, true);
33135 this.renderIndent(true, true);
33139 // private override
33140 setLastChild : function(node){
33141 var ol = this.lastChild;
33142 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33143 if(this.childrenRendered && ol && node != ol){
33144 ol.renderIndent(true, true);
33147 this.renderIndent(true, true);
33151 // these methods are overridden to provide lazy rendering support
33152 // private override
33153 appendChild : function()
33155 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33156 if(node && this.childrenRendered){
33159 this.ui.updateExpandIcon();
33163 // private override
33164 removeChild : function(node){
33165 this.ownerTree.getSelectionModel().unselect(node);
33166 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33167 // if it's been rendered remove dom node
33168 if(this.childrenRendered){
33171 if(this.childNodes.length < 1){
33172 this.collapse(false, false);
33174 this.ui.updateExpandIcon();
33176 if(!this.firstChild) {
33177 this.childrenRendered = false;
33182 // private override
33183 insertBefore : function(node, refNode){
33184 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33185 if(newNode && refNode && this.childrenRendered){
33188 this.ui.updateExpandIcon();
33193 * Sets the text for this node
33194 * @param {String} text
33196 setText : function(text){
33197 var oldText = this.text;
33199 this.attributes.text = text;
33200 if(this.rendered){ // event without subscribing
33201 this.ui.onTextChange(this, text, oldText);
33203 this.fireEvent("textchange", this, text, oldText);
33207 * Triggers selection of this node
33209 select : function(){
33210 this.getOwnerTree().getSelectionModel().select(this);
33214 * Triggers deselection of this node
33216 unselect : function(){
33217 this.getOwnerTree().getSelectionModel().unselect(this);
33221 * Returns true if this node is selected
33222 * @return {Boolean}
33224 isSelected : function(){
33225 return this.getOwnerTree().getSelectionModel().isSelected(this);
33229 * Expand this node.
33230 * @param {Boolean} deep (optional) True to expand all children as well
33231 * @param {Boolean} anim (optional) false to cancel the default animation
33232 * @param {Function} callback (optional) A callback to be called when
33233 * expanding this node completes (does not wait for deep expand to complete).
33234 * Called with 1 parameter, this node.
33236 expand : function(deep, anim, callback){
33237 if(!this.expanded){
33238 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33241 if(!this.childrenRendered){
33242 this.renderChildren();
33244 this.expanded = true;
33245 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33246 this.ui.animExpand(function(){
33247 this.fireEvent("expand", this);
33248 if(typeof callback == "function"){
33252 this.expandChildNodes(true);
33254 }.createDelegate(this));
33258 this.fireEvent("expand", this);
33259 if(typeof callback == "function"){
33264 if(typeof callback == "function"){
33269 this.expandChildNodes(true);
33273 isHiddenRoot : function(){
33274 return this.isRoot && !this.getOwnerTree().rootVisible;
33278 * Collapse this node.
33279 * @param {Boolean} deep (optional) True to collapse all children as well
33280 * @param {Boolean} anim (optional) false to cancel the default animation
33282 collapse : function(deep, anim){
33283 if(this.expanded && !this.isHiddenRoot()){
33284 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33287 this.expanded = false;
33288 if((this.getOwnerTree().animate && anim !== false) || anim){
33289 this.ui.animCollapse(function(){
33290 this.fireEvent("collapse", this);
33292 this.collapseChildNodes(true);
33294 }.createDelegate(this));
33297 this.ui.collapse();
33298 this.fireEvent("collapse", this);
33302 var cs = this.childNodes;
33303 for(var i = 0, len = cs.length; i < len; i++) {
33304 cs[i].collapse(true, false);
33310 delayedExpand : function(delay){
33311 if(!this.expandProcId){
33312 this.expandProcId = this.expand.defer(delay, this);
33317 cancelExpand : function(){
33318 if(this.expandProcId){
33319 clearTimeout(this.expandProcId);
33321 this.expandProcId = false;
33325 * Toggles expanded/collapsed state of the node
33327 toggle : function(){
33336 * Ensures all parent nodes are expanded
33338 ensureVisible : function(callback){
33339 var tree = this.getOwnerTree();
33340 tree.expandPath(this.parentNode.getPath(), false, function(){
33341 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33342 Roo.callback(callback);
33343 }.createDelegate(this));
33347 * Expand all child nodes
33348 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33350 expandChildNodes : function(deep){
33351 var cs = this.childNodes;
33352 for(var i = 0, len = cs.length; i < len; i++) {
33353 cs[i].expand(deep);
33358 * Collapse all child nodes
33359 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33361 collapseChildNodes : function(deep){
33362 var cs = this.childNodes;
33363 for(var i = 0, len = cs.length; i < len; i++) {
33364 cs[i].collapse(deep);
33369 * Disables this node
33371 disable : function(){
33372 this.disabled = true;
33374 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33375 this.ui.onDisableChange(this, true);
33377 this.fireEvent("disabledchange", this, true);
33381 * Enables this node
33383 enable : function(){
33384 this.disabled = false;
33385 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33386 this.ui.onDisableChange(this, false);
33388 this.fireEvent("disabledchange", this, false);
33392 renderChildren : function(suppressEvent){
33393 if(suppressEvent !== false){
33394 this.fireEvent("beforechildrenrendered", this);
33396 var cs = this.childNodes;
33397 for(var i = 0, len = cs.length; i < len; i++){
33398 cs[i].render(true);
33400 this.childrenRendered = true;
33404 sort : function(fn, scope){
33405 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33406 if(this.childrenRendered){
33407 var cs = this.childNodes;
33408 for(var i = 0, len = cs.length; i < len; i++){
33409 cs[i].render(true);
33415 render : function(bulkRender){
33416 this.ui.render(bulkRender);
33417 if(!this.rendered){
33418 this.rendered = true;
33420 this.expanded = false;
33421 this.expand(false, false);
33427 renderIndent : function(deep, refresh){
33429 this.ui.childIndent = null;
33431 this.ui.renderIndent();
33432 if(deep === true && this.childrenRendered){
33433 var cs = this.childNodes;
33434 for(var i = 0, len = cs.length; i < len; i++){
33435 cs[i].renderIndent(true, refresh);
33441 * Ext JS Library 1.1.1
33442 * Copyright(c) 2006-2007, Ext JS, LLC.
33444 * Originally Released Under LGPL - original licence link has changed is not relivant.
33447 * <script type="text/javascript">
33451 * @class Roo.tree.AsyncTreeNode
33452 * @extends Roo.tree.TreeNode
33453 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33455 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33457 Roo.tree.AsyncTreeNode = function(config){
33458 this.loaded = false;
33459 this.loading = false;
33460 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33462 * @event beforeload
33463 * Fires before this node is loaded, return false to cancel
33464 * @param {Node} this This node
33466 this.addEvents({'beforeload':true, 'load': true});
33469 * Fires when this node is loaded
33470 * @param {Node} this This node
33473 * The loader used by this node (defaults to using the tree's defined loader)
33478 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33479 expand : function(deep, anim, callback){
33480 if(this.loading){ // if an async load is already running, waiting til it's done
33482 var f = function(){
33483 if(!this.loading){ // done loading
33484 clearInterval(timer);
33485 this.expand(deep, anim, callback);
33487 }.createDelegate(this);
33488 timer = setInterval(f, 200);
33492 if(this.fireEvent("beforeload", this) === false){
33495 this.loading = true;
33496 this.ui.beforeLoad(this);
33497 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33499 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33503 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33507 * Returns true if this node is currently loading
33508 * @return {Boolean}
33510 isLoading : function(){
33511 return this.loading;
33514 loadComplete : function(deep, anim, callback){
33515 this.loading = false;
33516 this.loaded = true;
33517 this.ui.afterLoad(this);
33518 this.fireEvent("load", this);
33519 this.expand(deep, anim, callback);
33523 * Returns true if this node has been loaded
33524 * @return {Boolean}
33526 isLoaded : function(){
33527 return this.loaded;
33530 hasChildNodes : function(){
33531 if(!this.isLeaf() && !this.loaded){
33534 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33539 * Trigger a reload for this node
33540 * @param {Function} callback
33542 reload : function(callback){
33543 this.collapse(false, false);
33544 while(this.firstChild){
33545 this.removeChild(this.firstChild);
33547 this.childrenRendered = false;
33548 this.loaded = false;
33549 if(this.isHiddenRoot()){
33550 this.expanded = false;
33552 this.expand(false, false, callback);
33556 * Ext JS Library 1.1.1
33557 * Copyright(c) 2006-2007, Ext JS, LLC.
33559 * Originally Released Under LGPL - original licence link has changed is not relivant.
33562 * <script type="text/javascript">
33566 * @class Roo.tree.TreeNodeUI
33568 * @param {Object} node The node to render
33569 * The TreeNode UI implementation is separate from the
33570 * tree implementation. Unless you are customizing the tree UI,
33571 * you should never have to use this directly.
33573 Roo.tree.TreeNodeUI = function(node){
33575 this.rendered = false;
33576 this.animating = false;
33577 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33580 Roo.tree.TreeNodeUI.prototype = {
33581 removeChild : function(node){
33583 this.ctNode.removeChild(node.ui.getEl());
33587 beforeLoad : function(){
33588 this.addClass("x-tree-node-loading");
33591 afterLoad : function(){
33592 this.removeClass("x-tree-node-loading");
33595 onTextChange : function(node, text, oldText){
33597 this.textNode.innerHTML = text;
33601 onDisableChange : function(node, state){
33602 this.disabled = state;
33604 this.addClass("x-tree-node-disabled");
33606 this.removeClass("x-tree-node-disabled");
33610 onSelectedChange : function(state){
33613 this.addClass("x-tree-selected");
33616 this.removeClass("x-tree-selected");
33620 onMove : function(tree, node, oldParent, newParent, index, refNode){
33621 this.childIndent = null;
33623 var targetNode = newParent.ui.getContainer();
33624 if(!targetNode){//target not rendered
33625 this.holder = document.createElement("div");
33626 this.holder.appendChild(this.wrap);
33629 var insertBefore = refNode ? refNode.ui.getEl() : null;
33631 targetNode.insertBefore(this.wrap, insertBefore);
33633 targetNode.appendChild(this.wrap);
33635 this.node.renderIndent(true);
33639 addClass : function(cls){
33641 Roo.fly(this.elNode).addClass(cls);
33645 removeClass : function(cls){
33647 Roo.fly(this.elNode).removeClass(cls);
33651 remove : function(){
33653 this.holder = document.createElement("div");
33654 this.holder.appendChild(this.wrap);
33658 fireEvent : function(){
33659 return this.node.fireEvent.apply(this.node, arguments);
33662 initEvents : function(){
33663 this.node.on("move", this.onMove, this);
33664 var E = Roo.EventManager;
33665 var a = this.anchor;
33667 var el = Roo.fly(a, '_treeui');
33669 if(Roo.isOpera){ // opera render bug ignores the CSS
33670 el.setStyle("text-decoration", "none");
33673 el.on("click", this.onClick, this);
33674 el.on("dblclick", this.onDblClick, this);
33677 Roo.EventManager.on(this.checkbox,
33678 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33681 el.on("contextmenu", this.onContextMenu, this);
33683 var icon = Roo.fly(this.iconNode);
33684 icon.on("click", this.onClick, this);
33685 icon.on("dblclick", this.onDblClick, this);
33686 icon.on("contextmenu", this.onContextMenu, this);
33687 E.on(this.ecNode, "click", this.ecClick, this, true);
33689 if(this.node.disabled){
33690 this.addClass("x-tree-node-disabled");
33692 if(this.node.hidden){
33693 this.addClass("x-tree-node-disabled");
33695 var ot = this.node.getOwnerTree();
33696 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33697 if(dd && (!this.node.isRoot || ot.rootVisible)){
33698 Roo.dd.Registry.register(this.elNode, {
33700 handles: this.getDDHandles(),
33706 getDDHandles : function(){
33707 return [this.iconNode, this.textNode];
33712 this.wrap.style.display = "none";
33718 this.wrap.style.display = "";
33722 onContextMenu : function(e){
33723 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33724 e.preventDefault();
33726 this.fireEvent("contextmenu", this.node, e);
33730 onClick : function(e){
33735 if(this.fireEvent("beforeclick", this.node, e) !== false){
33736 if(!this.disabled && this.node.attributes.href){
33737 this.fireEvent("click", this.node, e);
33740 e.preventDefault();
33745 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33746 this.node.toggle();
33749 this.fireEvent("click", this.node, e);
33755 onDblClick : function(e){
33756 e.preventDefault();
33761 this.toggleCheck();
33763 if(!this.animating && this.node.hasChildNodes()){
33764 this.node.toggle();
33766 this.fireEvent("dblclick", this.node, e);
33769 onCheckChange : function(){
33770 var checked = this.checkbox.checked;
33771 this.node.attributes.checked = checked;
33772 this.fireEvent('checkchange', this.node, checked);
33775 ecClick : function(e){
33776 if(!this.animating && this.node.hasChildNodes()){
33777 this.node.toggle();
33781 startDrop : function(){
33782 this.dropping = true;
33785 // delayed drop so the click event doesn't get fired on a drop
33786 endDrop : function(){
33787 setTimeout(function(){
33788 this.dropping = false;
33789 }.createDelegate(this), 50);
33792 expand : function(){
33793 this.updateExpandIcon();
33794 this.ctNode.style.display = "";
33797 focus : function(){
33798 if(!this.node.preventHScroll){
33799 try{this.anchor.focus();
33801 }else if(!Roo.isIE){
33803 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33804 var l = noscroll.scrollLeft;
33805 this.anchor.focus();
33806 noscroll.scrollLeft = l;
33811 toggleCheck : function(value){
33812 var cb = this.checkbox;
33814 cb.checked = (value === undefined ? !cb.checked : value);
33820 this.anchor.blur();
33824 animExpand : function(callback){
33825 var ct = Roo.get(this.ctNode);
33827 if(!this.node.hasChildNodes()){
33828 this.updateExpandIcon();
33829 this.ctNode.style.display = "";
33830 Roo.callback(callback);
33833 this.animating = true;
33834 this.updateExpandIcon();
33837 callback : function(){
33838 this.animating = false;
33839 Roo.callback(callback);
33842 duration: this.node.ownerTree.duration || .25
33846 highlight : function(){
33847 var tree = this.node.getOwnerTree();
33848 Roo.fly(this.wrap).highlight(
33849 tree.hlColor || "C3DAF9",
33850 {endColor: tree.hlBaseColor}
33854 collapse : function(){
33855 this.updateExpandIcon();
33856 this.ctNode.style.display = "none";
33859 animCollapse : function(callback){
33860 var ct = Roo.get(this.ctNode);
33861 ct.enableDisplayMode('block');
33864 this.animating = true;
33865 this.updateExpandIcon();
33868 callback : function(){
33869 this.animating = false;
33870 Roo.callback(callback);
33873 duration: this.node.ownerTree.duration || .25
33877 getContainer : function(){
33878 return this.ctNode;
33881 getEl : function(){
33885 appendDDGhost : function(ghostNode){
33886 ghostNode.appendChild(this.elNode.cloneNode(true));
33889 getDDRepairXY : function(){
33890 return Roo.lib.Dom.getXY(this.iconNode);
33893 onRender : function(){
33897 render : function(bulkRender){
33898 var n = this.node, a = n.attributes;
33899 var targetNode = n.parentNode ?
33900 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33902 if(!this.rendered){
33903 this.rendered = true;
33905 this.renderElements(n, a, targetNode, bulkRender);
33908 if(this.textNode.setAttributeNS){
33909 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33911 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33914 this.textNode.setAttribute("ext:qtip", a.qtip);
33916 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33919 }else if(a.qtipCfg){
33920 a.qtipCfg.target = Roo.id(this.textNode);
33921 Roo.QuickTips.register(a.qtipCfg);
33924 if(!this.node.expanded){
33925 this.updateExpandIcon();
33928 if(bulkRender === true) {
33929 targetNode.appendChild(this.wrap);
33934 renderElements : function(n, a, targetNode, bulkRender)
33936 // add some indent caching, this helps performance when rendering a large tree
33937 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33938 var t = n.getOwnerTree();
33939 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33940 if (typeof(n.attributes.html) != 'undefined') {
33941 txt = n.attributes.html;
33943 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33944 var cb = typeof a.checked == 'boolean';
33945 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33946 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33947 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33948 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33949 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33950 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33951 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33952 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33953 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33954 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33957 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33958 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33959 n.nextSibling.ui.getEl(), buf.join(""));
33961 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33964 this.elNode = this.wrap.childNodes[0];
33965 this.ctNode = this.wrap.childNodes[1];
33966 var cs = this.elNode.childNodes;
33967 this.indentNode = cs[0];
33968 this.ecNode = cs[1];
33969 this.iconNode = cs[2];
33972 this.checkbox = cs[3];
33975 this.anchor = cs[index];
33976 this.textNode = cs[index].firstChild;
33979 getAnchor : function(){
33980 return this.anchor;
33983 getTextEl : function(){
33984 return this.textNode;
33987 getIconEl : function(){
33988 return this.iconNode;
33991 isChecked : function(){
33992 return this.checkbox ? this.checkbox.checked : false;
33995 updateExpandIcon : function(){
33997 var n = this.node, c1, c2;
33998 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
33999 var hasChild = n.hasChildNodes();
34003 c1 = "x-tree-node-collapsed";
34004 c2 = "x-tree-node-expanded";
34007 c1 = "x-tree-node-expanded";
34008 c2 = "x-tree-node-collapsed";
34011 this.removeClass("x-tree-node-leaf");
34012 this.wasLeaf = false;
34014 if(this.c1 != c1 || this.c2 != c2){
34015 Roo.fly(this.elNode).replaceClass(c1, c2);
34016 this.c1 = c1; this.c2 = c2;
34019 // this changes non-leafs into leafs if they have no children.
34020 // it's not very rational behaviour..
34022 if(!this.wasLeaf && this.node.leaf){
34023 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34026 this.wasLeaf = true;
34029 var ecc = "x-tree-ec-icon "+cls;
34030 if(this.ecc != ecc){
34031 this.ecNode.className = ecc;
34037 getChildIndent : function(){
34038 if(!this.childIndent){
34042 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34044 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34046 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34051 this.childIndent = buf.join("");
34053 return this.childIndent;
34056 renderIndent : function(){
34059 var p = this.node.parentNode;
34061 indent = p.ui.getChildIndent();
34063 if(this.indentMarkup != indent){ // don't rerender if not required
34064 this.indentNode.innerHTML = indent;
34065 this.indentMarkup = indent;
34067 this.updateExpandIcon();
34072 Roo.tree.RootTreeNodeUI = function(){
34073 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34075 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34076 render : function(){
34077 if(!this.rendered){
34078 var targetNode = this.node.ownerTree.innerCt.dom;
34079 this.node.expanded = true;
34080 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34081 this.wrap = this.ctNode = targetNode.firstChild;
34084 collapse : function(){
34086 expand : function(){
34090 * Ext JS Library 1.1.1
34091 * Copyright(c) 2006-2007, Ext JS, LLC.
34093 * Originally Released Under LGPL - original licence link has changed is not relivant.
34096 * <script type="text/javascript">
34099 * @class Roo.tree.TreeLoader
34100 * @extends Roo.util.Observable
34101 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34102 * nodes from a specified URL. The response must be a javascript Array definition
34103 * who's elements are node definition objects. eg:
34108 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34109 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34116 * The old style respose with just an array is still supported, but not recommended.
34119 * A server request is sent, and child nodes are loaded only when a node is expanded.
34120 * The loading node's id is passed to the server under the parameter name "node" to
34121 * enable the server to produce the correct child nodes.
34123 * To pass extra parameters, an event handler may be attached to the "beforeload"
34124 * event, and the parameters specified in the TreeLoader's baseParams property:
34126 myTreeLoader.on("beforeload", function(treeLoader, node) {
34127 this.baseParams.category = node.attributes.category;
34130 * This would pass an HTTP parameter called "category" to the server containing
34131 * the value of the Node's "category" attribute.
34133 * Creates a new Treeloader.
34134 * @param {Object} config A config object containing config properties.
34136 Roo.tree.TreeLoader = function(config){
34137 this.baseParams = {};
34138 this.requestMethod = "POST";
34139 Roo.apply(this, config);
34144 * @event beforeload
34145 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34146 * @param {Object} This TreeLoader object.
34147 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34148 * @param {Object} callback The callback function specified in the {@link #load} call.
34153 * Fires when the node has been successfuly loaded.
34154 * @param {Object} This TreeLoader object.
34155 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34156 * @param {Object} response The response object containing the data from the server.
34160 * @event loadexception
34161 * Fires if the network request failed.
34162 * @param {Object} This TreeLoader object.
34163 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34164 * @param {Object} response The response object containing the data from the server.
34166 loadexception : true,
34169 * Fires before a node is created, enabling you to return custom Node types
34170 * @param {Object} This TreeLoader object.
34171 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34176 Roo.tree.TreeLoader.superclass.constructor.call(this);
34179 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34181 * @cfg {String} dataUrl The URL from which to request a Json string which
34182 * specifies an array of node definition object representing the child nodes
34186 * @cfg {String} requestMethod either GET or POST
34187 * defaults to POST (due to BC)
34191 * @cfg {Object} baseParams (optional) An object containing properties which
34192 * specify HTTP parameters to be passed to each request for child nodes.
34195 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34196 * created by this loader. If the attributes sent by the server have an attribute in this object,
34197 * they take priority.
34200 * @cfg {Object} uiProviders (optional) An object containing properties which
34202 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34203 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34204 * <i>uiProvider</i> attribute of a returned child node is a string rather
34205 * than a reference to a TreeNodeUI implementation, this that string value
34206 * is used as a property name in the uiProviders object. You can define the provider named
34207 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34212 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34213 * child nodes before loading.
34215 clearOnLoad : true,
34218 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34219 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34220 * Grid query { data : [ .....] }
34225 * @cfg {String} queryParam (optional)
34226 * Name of the query as it will be passed on the querystring (defaults to 'node')
34227 * eg. the request will be ?node=[id]
34234 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34235 * This is called automatically when a node is expanded, but may be used to reload
34236 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34237 * @param {Roo.tree.TreeNode} node
34238 * @param {Function} callback
34240 load : function(node, callback){
34241 if(this.clearOnLoad){
34242 while(node.firstChild){
34243 node.removeChild(node.firstChild);
34246 if(node.attributes.children){ // preloaded json children
34247 var cs = node.attributes.children;
34248 for(var i = 0, len = cs.length; i < len; i++){
34249 node.appendChild(this.createNode(cs[i]));
34251 if(typeof callback == "function"){
34254 }else if(this.dataUrl){
34255 this.requestData(node, callback);
34259 getParams: function(node){
34260 var buf = [], bp = this.baseParams;
34261 for(var key in bp){
34262 if(typeof bp[key] != "function"){
34263 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34266 var n = this.queryParam === false ? 'node' : this.queryParam;
34267 buf.push(n + "=", encodeURIComponent(node.id));
34268 return buf.join("");
34271 requestData : function(node, callback){
34272 if(this.fireEvent("beforeload", this, node, callback) !== false){
34273 this.transId = Roo.Ajax.request({
34274 method:this.requestMethod,
34275 url: this.dataUrl||this.url,
34276 success: this.handleResponse,
34277 failure: this.handleFailure,
34279 argument: {callback: callback, node: node},
34280 params: this.getParams(node)
34283 // if the load is cancelled, make sure we notify
34284 // the node that we are done
34285 if(typeof callback == "function"){
34291 isLoading : function(){
34292 return this.transId ? true : false;
34295 abort : function(){
34296 if(this.isLoading()){
34297 Roo.Ajax.abort(this.transId);
34302 createNode : function(attr)
34304 // apply baseAttrs, nice idea Corey!
34305 if(this.baseAttrs){
34306 Roo.applyIf(attr, this.baseAttrs);
34308 if(this.applyLoader !== false){
34309 attr.loader = this;
34311 // uiProvider = depreciated..
34313 if(typeof(attr.uiProvider) == 'string'){
34314 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34315 /** eval:var:attr */ eval(attr.uiProvider);
34317 if(typeof(this.uiProviders['default']) != 'undefined') {
34318 attr.uiProvider = this.uiProviders['default'];
34321 this.fireEvent('create', this, attr);
34323 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34325 new Roo.tree.TreeNode(attr) :
34326 new Roo.tree.AsyncTreeNode(attr));
34329 processResponse : function(response, node, callback)
34331 var json = response.responseText;
34334 var o = Roo.decode(json);
34336 if (this.root === false && typeof(o.success) != undefined) {
34337 this.root = 'data'; // the default behaviour for list like data..
34340 if (this.root !== false && !o.success) {
34341 // it's a failure condition.
34342 var a = response.argument;
34343 this.fireEvent("loadexception", this, a.node, response);
34344 Roo.log("Load failed - should have a handler really");
34350 if (this.root !== false) {
34354 for(var i = 0, len = o.length; i < len; i++){
34355 var n = this.createNode(o[i]);
34357 node.appendChild(n);
34360 if(typeof callback == "function"){
34361 callback(this, node);
34364 this.handleFailure(response);
34368 handleResponse : function(response){
34369 this.transId = false;
34370 var a = response.argument;
34371 this.processResponse(response, a.node, a.callback);
34372 this.fireEvent("load", this, a.node, response);
34375 handleFailure : function(response)
34377 // should handle failure better..
34378 this.transId = false;
34379 var a = response.argument;
34380 this.fireEvent("loadexception", this, a.node, response);
34381 if(typeof a.callback == "function"){
34382 a.callback(this, a.node);
34387 * Ext JS Library 1.1.1
34388 * Copyright(c) 2006-2007, Ext JS, LLC.
34390 * Originally Released Under LGPL - original licence link has changed is not relivant.
34393 * <script type="text/javascript">
34397 * @class Roo.tree.TreeFilter
34398 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34399 * @param {TreePanel} tree
34400 * @param {Object} config (optional)
34402 Roo.tree.TreeFilter = function(tree, config){
34404 this.filtered = {};
34405 Roo.apply(this, config);
34408 Roo.tree.TreeFilter.prototype = {
34415 * Filter the data by a specific attribute.
34416 * @param {String/RegExp} value Either string that the attribute value
34417 * should start with or a RegExp to test against the attribute
34418 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34419 * @param {TreeNode} startNode (optional) The node to start the filter at.
34421 filter : function(value, attr, startNode){
34422 attr = attr || "text";
34424 if(typeof value == "string"){
34425 var vlen = value.length;
34426 // auto clear empty filter
34427 if(vlen == 0 && this.clearBlank){
34431 value = value.toLowerCase();
34433 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34435 }else if(value.exec){ // regex?
34437 return value.test(n.attributes[attr]);
34440 throw 'Illegal filter type, must be string or regex';
34442 this.filterBy(f, null, startNode);
34446 * Filter by a function. The passed function will be called with each
34447 * node in the tree (or from the startNode). If the function returns true, the node is kept
34448 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34449 * @param {Function} fn The filter function
34450 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34452 filterBy : function(fn, scope, startNode){
34453 startNode = startNode || this.tree.root;
34454 if(this.autoClear){
34457 var af = this.filtered, rv = this.reverse;
34458 var f = function(n){
34459 if(n == startNode){
34465 var m = fn.call(scope || n, n);
34473 startNode.cascade(f);
34476 if(typeof id != "function"){
34478 if(n && n.parentNode){
34479 n.parentNode.removeChild(n);
34487 * Clears the current filter. Note: with the "remove" option
34488 * set a filter cannot be cleared.
34490 clear : function(){
34492 var af = this.filtered;
34494 if(typeof id != "function"){
34501 this.filtered = {};
34506 * Ext JS Library 1.1.1
34507 * Copyright(c) 2006-2007, Ext JS, LLC.
34509 * Originally Released Under LGPL - original licence link has changed is not relivant.
34512 * <script type="text/javascript">
34517 * @class Roo.tree.TreeSorter
34518 * Provides sorting of nodes in a TreePanel
34520 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34521 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34522 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34523 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34524 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34525 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34527 * @param {TreePanel} tree
34528 * @param {Object} config
34530 Roo.tree.TreeSorter = function(tree, config){
34531 Roo.apply(this, config);
34532 tree.on("beforechildrenrendered", this.doSort, this);
34533 tree.on("append", this.updateSort, this);
34534 tree.on("insert", this.updateSort, this);
34536 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34537 var p = this.property || "text";
34538 var sortType = this.sortType;
34539 var fs = this.folderSort;
34540 var cs = this.caseSensitive === true;
34541 var leafAttr = this.leafAttr || 'leaf';
34543 this.sortFn = function(n1, n2){
34545 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34548 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34552 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34553 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34555 return dsc ? +1 : -1;
34557 return dsc ? -1 : +1;
34564 Roo.tree.TreeSorter.prototype = {
34565 doSort : function(node){
34566 node.sort(this.sortFn);
34569 compareNodes : function(n1, n2){
34570 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34573 updateSort : function(tree, node){
34574 if(node.childrenRendered){
34575 this.doSort.defer(1, this, [node]);
34580 * Ext JS Library 1.1.1
34581 * Copyright(c) 2006-2007, Ext JS, LLC.
34583 * Originally Released Under LGPL - original licence link has changed is not relivant.
34586 * <script type="text/javascript">
34589 if(Roo.dd.DropZone){
34591 Roo.tree.TreeDropZone = function(tree, config){
34592 this.allowParentInsert = false;
34593 this.allowContainerDrop = false;
34594 this.appendOnly = false;
34595 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34597 this.lastInsertClass = "x-tree-no-status";
34598 this.dragOverData = {};
34601 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34602 ddGroup : "TreeDD",
34605 expandDelay : 1000,
34607 expandNode : function(node){
34608 if(node.hasChildNodes() && !node.isExpanded()){
34609 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34613 queueExpand : function(node){
34614 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34617 cancelExpand : function(){
34618 if(this.expandProcId){
34619 clearTimeout(this.expandProcId);
34620 this.expandProcId = false;
34624 isValidDropPoint : function(n, pt, dd, e, data){
34625 if(!n || !data){ return false; }
34626 var targetNode = n.node;
34627 var dropNode = data.node;
34628 // default drop rules
34629 if(!(targetNode && targetNode.isTarget && pt)){
34632 if(pt == "append" && targetNode.allowChildren === false){
34635 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34638 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34641 // reuse the object
34642 var overEvent = this.dragOverData;
34643 overEvent.tree = this.tree;
34644 overEvent.target = targetNode;
34645 overEvent.data = data;
34646 overEvent.point = pt;
34647 overEvent.source = dd;
34648 overEvent.rawEvent = e;
34649 overEvent.dropNode = dropNode;
34650 overEvent.cancel = false;
34651 var result = this.tree.fireEvent("nodedragover", overEvent);
34652 return overEvent.cancel === false && result !== false;
34655 getDropPoint : function(e, n, dd)
34659 return tn.allowChildren !== false ? "append" : false; // always append for root
34661 var dragEl = n.ddel;
34662 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34663 var y = Roo.lib.Event.getPageY(e);
34664 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34666 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34667 var noAppend = tn.allowChildren === false;
34668 if(this.appendOnly || tn.parentNode.allowChildren === false){
34669 return noAppend ? false : "append";
34671 var noBelow = false;
34672 if(!this.allowParentInsert){
34673 noBelow = tn.hasChildNodes() && tn.isExpanded();
34675 var q = (b - t) / (noAppend ? 2 : 3);
34676 if(y >= t && y < (t + q)){
34678 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34685 onNodeEnter : function(n, dd, e, data)
34687 this.cancelExpand();
34690 onNodeOver : function(n, dd, e, data)
34693 var pt = this.getDropPoint(e, n, dd);
34696 // auto node expand check
34697 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34698 this.queueExpand(node);
34699 }else if(pt != "append"){
34700 this.cancelExpand();
34703 // set the insert point style on the target node
34704 var returnCls = this.dropNotAllowed;
34705 if(this.isValidDropPoint(n, pt, dd, e, data)){
34710 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34711 cls = "x-tree-drag-insert-above";
34712 }else if(pt == "below"){
34713 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34714 cls = "x-tree-drag-insert-below";
34716 returnCls = "x-tree-drop-ok-append";
34717 cls = "x-tree-drag-append";
34719 if(this.lastInsertClass != cls){
34720 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34721 this.lastInsertClass = cls;
34728 onNodeOut : function(n, dd, e, data){
34730 this.cancelExpand();
34731 this.removeDropIndicators(n);
34734 onNodeDrop : function(n, dd, e, data){
34735 var point = this.getDropPoint(e, n, dd);
34736 var targetNode = n.node;
34737 targetNode.ui.startDrop();
34738 if(!this.isValidDropPoint(n, point, dd, e, data)){
34739 targetNode.ui.endDrop();
34742 // first try to find the drop node
34743 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34746 target: targetNode,
34751 dropNode: dropNode,
34754 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34755 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34756 targetNode.ui.endDrop();
34759 // allow target changing
34760 targetNode = dropEvent.target;
34761 if(point == "append" && !targetNode.isExpanded()){
34762 targetNode.expand(false, null, function(){
34763 this.completeDrop(dropEvent);
34764 }.createDelegate(this));
34766 this.completeDrop(dropEvent);
34771 completeDrop : function(de){
34772 var ns = de.dropNode, p = de.point, t = de.target;
34773 if(!(ns instanceof Array)){
34777 for(var i = 0, len = ns.length; i < len; i++){
34780 t.parentNode.insertBefore(n, t);
34781 }else if(p == "below"){
34782 t.parentNode.insertBefore(n, t.nextSibling);
34788 if(this.tree.hlDrop){
34792 this.tree.fireEvent("nodedrop", de);
34795 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34796 if(this.tree.hlDrop){
34797 dropNode.ui.focus();
34798 dropNode.ui.highlight();
34800 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34803 getTree : function(){
34807 removeDropIndicators : function(n){
34810 Roo.fly(el).removeClass([
34811 "x-tree-drag-insert-above",
34812 "x-tree-drag-insert-below",
34813 "x-tree-drag-append"]);
34814 this.lastInsertClass = "_noclass";
34818 beforeDragDrop : function(target, e, id){
34819 this.cancelExpand();
34823 afterRepair : function(data){
34824 if(data && Roo.enableFx){
34825 data.node.ui.highlight();
34835 * Ext JS Library 1.1.1
34836 * Copyright(c) 2006-2007, Ext JS, LLC.
34838 * Originally Released Under LGPL - original licence link has changed is not relivant.
34841 * <script type="text/javascript">
34845 if(Roo.dd.DragZone){
34846 Roo.tree.TreeDragZone = function(tree, config){
34847 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34851 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34852 ddGroup : "TreeDD",
34854 onBeforeDrag : function(data, e){
34856 return n && n.draggable && !n.disabled;
34860 onInitDrag : function(e){
34861 var data = this.dragData;
34862 this.tree.getSelectionModel().select(data.node);
34863 this.proxy.update("");
34864 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34865 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34868 getRepairXY : function(e, data){
34869 return data.node.ui.getDDRepairXY();
34872 onEndDrag : function(data, e){
34873 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34878 onValidDrop : function(dd, e, id){
34879 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34883 beforeInvalidDrop : function(e, id){
34884 // this scrolls the original position back into view
34885 var sm = this.tree.getSelectionModel();
34886 sm.clearSelections();
34887 sm.select(this.dragData.node);
34892 * Ext JS Library 1.1.1
34893 * Copyright(c) 2006-2007, Ext JS, LLC.
34895 * Originally Released Under LGPL - original licence link has changed is not relivant.
34898 * <script type="text/javascript">
34901 * @class Roo.tree.TreeEditor
34902 * @extends Roo.Editor
34903 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34904 * as the editor field.
34906 * @param {Object} config (used to be the tree panel.)
34907 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34909 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34910 * @cfg {Roo.form.TextField|Object} field The field configuration
34914 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34917 if (oldconfig) { // old style..
34918 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34921 tree = config.tree;
34922 config.field = config.field || {};
34923 config.field.xtype = 'TextField';
34924 field = Roo.factory(config.field, Roo.form);
34926 config = config || {};
34931 * @event beforenodeedit
34932 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34933 * false from the handler of this event.
34934 * @param {Editor} this
34935 * @param {Roo.tree.Node} node
34937 "beforenodeedit" : true
34941 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34945 tree.on('beforeclick', this.beforeNodeClick, this);
34946 tree.getTreeEl().on('mousedown', this.hide, this);
34947 this.on('complete', this.updateNode, this);
34948 this.on('beforestartedit', this.fitToTree, this);
34949 this.on('startedit', this.bindScroll, this, {delay:10});
34950 this.on('specialkey', this.onSpecialKey, this);
34953 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34955 * @cfg {String} alignment
34956 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
34962 * @cfg {Boolean} hideEl
34963 * True to hide the bound element while the editor is displayed (defaults to false)
34967 * @cfg {String} cls
34968 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
34970 cls: "x-small-editor x-tree-editor",
34972 * @cfg {Boolean} shim
34973 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
34979 * @cfg {Number} maxWidth
34980 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
34981 * the containing tree element's size, it will be automatically limited for you to the container width, taking
34982 * scroll and client offsets into account prior to each edit.
34989 fitToTree : function(ed, el){
34990 var td = this.tree.getTreeEl().dom, nd = el.dom;
34991 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
34992 td.scrollLeft = nd.offsetLeft;
34996 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
34997 this.setSize(w, '');
34999 return this.fireEvent('beforenodeedit', this, this.editNode);
35004 triggerEdit : function(node){
35005 this.completeEdit();
35006 this.editNode = node;
35007 this.startEdit(node.ui.textNode, node.text);
35011 bindScroll : function(){
35012 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35016 beforeNodeClick : function(node, e){
35017 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35018 this.lastClick = new Date();
35019 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35021 this.triggerEdit(node);
35028 updateNode : function(ed, value){
35029 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35030 this.editNode.setText(value);
35034 onHide : function(){
35035 Roo.tree.TreeEditor.superclass.onHide.call(this);
35037 this.editNode.ui.focus();
35042 onSpecialKey : function(field, e){
35043 var k = e.getKey();
35047 }else if(k == e.ENTER && !e.hasModifier()){
35049 this.completeEdit();
35052 });//<Script type="text/javascript">
35055 * Ext JS Library 1.1.1
35056 * Copyright(c) 2006-2007, Ext JS, LLC.
35058 * Originally Released Under LGPL - original licence link has changed is not relivant.
35061 * <script type="text/javascript">
35065 * Not documented??? - probably should be...
35068 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35069 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35071 renderElements : function(n, a, targetNode, bulkRender){
35072 //consel.log("renderElements?");
35073 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35075 var t = n.getOwnerTree();
35076 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35078 var cols = t.columns;
35079 var bw = t.borderWidth;
35081 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35082 var cb = typeof a.checked == "boolean";
35083 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35084 var colcls = 'x-t-' + tid + '-c0';
35086 '<li class="x-tree-node">',
35089 '<div class="x-tree-node-el ', a.cls,'">',
35091 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35094 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35095 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35096 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35097 (a.icon ? ' x-tree-node-inline-icon' : ''),
35098 (a.iconCls ? ' '+a.iconCls : ''),
35099 '" unselectable="on" />',
35100 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35101 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35103 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35104 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35105 '<span unselectable="on" qtip="' + tx + '">',
35109 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35110 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35112 for(var i = 1, len = cols.length; i < len; i++){
35114 colcls = 'x-t-' + tid + '-c' +i;
35115 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35116 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35117 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35123 '<div class="x-clear"></div></div>',
35124 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35127 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35128 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35129 n.nextSibling.ui.getEl(), buf.join(""));
35131 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35133 var el = this.wrap.firstChild;
35135 this.elNode = el.firstChild;
35136 this.ranchor = el.childNodes[1];
35137 this.ctNode = this.wrap.childNodes[1];
35138 var cs = el.firstChild.childNodes;
35139 this.indentNode = cs[0];
35140 this.ecNode = cs[1];
35141 this.iconNode = cs[2];
35144 this.checkbox = cs[3];
35147 this.anchor = cs[index];
35149 this.textNode = cs[index].firstChild;
35151 //el.on("click", this.onClick, this);
35152 //el.on("dblclick", this.onDblClick, this);
35155 // console.log(this);
35157 initEvents : function(){
35158 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35161 var a = this.ranchor;
35163 var el = Roo.get(a);
35165 if(Roo.isOpera){ // opera render bug ignores the CSS
35166 el.setStyle("text-decoration", "none");
35169 el.on("click", this.onClick, this);
35170 el.on("dblclick", this.onDblClick, this);
35171 el.on("contextmenu", this.onContextMenu, this);
35175 /*onSelectedChange : function(state){
35178 this.addClass("x-tree-selected");
35181 this.removeClass("x-tree-selected");
35184 addClass : function(cls){
35186 Roo.fly(this.elRow).addClass(cls);
35192 removeClass : function(cls){
35194 Roo.fly(this.elRow).removeClass(cls);
35200 });//<Script type="text/javascript">
35204 * Ext JS Library 1.1.1
35205 * Copyright(c) 2006-2007, Ext JS, LLC.
35207 * Originally Released Under LGPL - original licence link has changed is not relivant.
35210 * <script type="text/javascript">
35215 * @class Roo.tree.ColumnTree
35216 * @extends Roo.data.TreePanel
35217 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35218 * @cfg {int} borderWidth compined right/left border allowance
35220 * @param {String/HTMLElement/Element} el The container element
35221 * @param {Object} config
35223 Roo.tree.ColumnTree = function(el, config)
35225 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35229 * Fire this event on a container when it resizes
35230 * @param {int} w Width
35231 * @param {int} h Height
35235 this.on('resize', this.onResize, this);
35238 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35242 borderWidth: Roo.isBorderBox ? 0 : 2,
35245 render : function(){
35246 // add the header.....
35248 Roo.tree.ColumnTree.superclass.render.apply(this);
35250 this.el.addClass('x-column-tree');
35252 this.headers = this.el.createChild(
35253 {cls:'x-tree-headers'},this.innerCt.dom);
35255 var cols = this.columns, c;
35256 var totalWidth = 0;
35258 var len = cols.length;
35259 for(var i = 0; i < len; i++){
35261 totalWidth += c.width;
35262 this.headEls.push(this.headers.createChild({
35263 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35265 cls:'x-tree-hd-text',
35268 style:'width:'+(c.width-this.borderWidth)+'px;'
35271 this.headers.createChild({cls:'x-clear'});
35272 // prevent floats from wrapping when clipped
35273 this.headers.setWidth(totalWidth);
35274 //this.innerCt.setWidth(totalWidth);
35275 this.innerCt.setStyle({ overflow: 'auto' });
35276 this.onResize(this.width, this.height);
35280 onResize : function(w,h)
35285 this.innerCt.setWidth(this.width);
35286 this.innerCt.setHeight(this.height-20);
35289 var cols = this.columns, c;
35290 var totalWidth = 0;
35292 var len = cols.length;
35293 for(var i = 0; i < len; i++){
35295 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35296 // it's the expander..
35297 expEl = this.headEls[i];
35300 totalWidth += c.width;
35304 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35306 this.headers.setWidth(w-20);
35315 * Ext JS Library 1.1.1
35316 * Copyright(c) 2006-2007, Ext JS, LLC.
35318 * Originally Released Under LGPL - original licence link has changed is not relivant.
35321 * <script type="text/javascript">
35325 * @class Roo.menu.Menu
35326 * @extends Roo.util.Observable
35327 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35328 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35330 * Creates a new Menu
35331 * @param {Object} config Configuration options
35333 Roo.menu.Menu = function(config){
35334 Roo.apply(this, config);
35335 this.id = this.id || Roo.id();
35338 * @event beforeshow
35339 * Fires before this menu is displayed
35340 * @param {Roo.menu.Menu} this
35344 * @event beforehide
35345 * Fires before this menu is hidden
35346 * @param {Roo.menu.Menu} this
35351 * Fires after this menu is displayed
35352 * @param {Roo.menu.Menu} this
35357 * Fires after this menu is hidden
35358 * @param {Roo.menu.Menu} this
35363 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35364 * @param {Roo.menu.Menu} this
35365 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35366 * @param {Roo.EventObject} e
35371 * Fires when the mouse is hovering over this menu
35372 * @param {Roo.menu.Menu} this
35373 * @param {Roo.EventObject} e
35374 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35379 * Fires when the mouse exits this menu
35380 * @param {Roo.menu.Menu} this
35381 * @param {Roo.EventObject} e
35382 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35387 * Fires when a menu item contained in this menu is clicked
35388 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35389 * @param {Roo.EventObject} e
35393 if (this.registerMenu) {
35394 Roo.menu.MenuMgr.register(this);
35397 var mis = this.items;
35398 this.items = new Roo.util.MixedCollection();
35400 this.add.apply(this, mis);
35404 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35406 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35410 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35411 * for bottom-right shadow (defaults to "sides")
35415 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35416 * this menu (defaults to "tl-tr?")
35418 subMenuAlign : "tl-tr?",
35420 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35421 * relative to its element of origin (defaults to "tl-bl?")
35423 defaultAlign : "tl-bl?",
35425 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35427 allowOtherMenus : false,
35429 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35431 registerMenu : true,
35436 render : function(){
35440 var el = this.el = new Roo.Layer({
35442 shadow:this.shadow,
35444 parentEl: this.parentEl || document.body,
35448 this.keyNav = new Roo.menu.MenuNav(this);
35451 el.addClass("x-menu-plain");
35454 el.addClass(this.cls);
35456 // generic focus element
35457 this.focusEl = el.createChild({
35458 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35460 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35461 ul.on("click", this.onClick, this);
35462 ul.on("mouseover", this.onMouseOver, this);
35463 ul.on("mouseout", this.onMouseOut, this);
35464 this.items.each(function(item){
35469 var li = document.createElement("li");
35470 li.className = "x-menu-list-item";
35471 ul.dom.appendChild(li);
35472 item.render(li, this);
35479 autoWidth : function(){
35480 var el = this.el, ul = this.ul;
35484 var w = this.width;
35487 }else if(Roo.isIE){
35488 el.setWidth(this.minWidth);
35489 var t = el.dom.offsetWidth; // force recalc
35490 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35495 delayAutoWidth : function(){
35498 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35500 this.awTask.delay(20);
35505 findTargetItem : function(e){
35506 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35507 if(t && t.menuItemId){
35508 return this.items.get(t.menuItemId);
35513 onClick : function(e){
35515 if(t = this.findTargetItem(e)){
35517 this.fireEvent("click", this, t, e);
35522 setActiveItem : function(item, autoExpand){
35523 if(item != this.activeItem){
35524 if(this.activeItem){
35525 this.activeItem.deactivate();
35527 this.activeItem = item;
35528 item.activate(autoExpand);
35529 }else if(autoExpand){
35535 tryActivate : function(start, step){
35536 var items = this.items;
35537 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35538 var item = items.get(i);
35539 if(!item.disabled && item.canActivate){
35540 this.setActiveItem(item, false);
35548 onMouseOver : function(e){
35550 if(t = this.findTargetItem(e)){
35551 if(t.canActivate && !t.disabled){
35552 this.setActiveItem(t, true);
35555 this.fireEvent("mouseover", this, e, t);
35559 onMouseOut : function(e){
35561 if(t = this.findTargetItem(e)){
35562 if(t == this.activeItem && t.shouldDeactivate(e)){
35563 this.activeItem.deactivate();
35564 delete this.activeItem;
35567 this.fireEvent("mouseout", this, e, t);
35571 * Read-only. Returns true if the menu is currently displayed, else false.
35574 isVisible : function(){
35575 return this.el && !this.hidden;
35579 * Displays this menu relative to another element
35580 * @param {String/HTMLElement/Roo.Element} element The element to align to
35581 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35582 * the element (defaults to this.defaultAlign)
35583 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35585 show : function(el, pos, parentMenu){
35586 this.parentMenu = parentMenu;
35590 this.fireEvent("beforeshow", this);
35591 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35595 * Displays this menu at a specific xy position
35596 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35597 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35599 showAt : function(xy, parentMenu, /* private: */_e){
35600 this.parentMenu = parentMenu;
35605 this.fireEvent("beforeshow", this);
35606 xy = this.el.adjustForConstraints(xy);
35610 this.hidden = false;
35612 this.fireEvent("show", this);
35615 focus : function(){
35617 this.doFocus.defer(50, this);
35621 doFocus : function(){
35623 this.focusEl.focus();
35628 * Hides this menu and optionally all parent menus
35629 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35631 hide : function(deep){
35632 if(this.el && this.isVisible()){
35633 this.fireEvent("beforehide", this);
35634 if(this.activeItem){
35635 this.activeItem.deactivate();
35636 this.activeItem = null;
35639 this.hidden = true;
35640 this.fireEvent("hide", this);
35642 if(deep === true && this.parentMenu){
35643 this.parentMenu.hide(true);
35648 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35649 * Any of the following are valid:
35651 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35652 * <li>An HTMLElement object which will be converted to a menu item</li>
35653 * <li>A menu item config object that will be created as a new menu item</li>
35654 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35655 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35660 var menu = new Roo.menu.Menu();
35662 // Create a menu item to add by reference
35663 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35665 // Add a bunch of items at once using different methods.
35666 // Only the last item added will be returned.
35667 var item = menu.add(
35668 menuItem, // add existing item by ref
35669 'Dynamic Item', // new TextItem
35670 '-', // new separator
35671 { text: 'Config Item' } // new item by config
35674 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35675 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35678 var a = arguments, l = a.length, item;
35679 for(var i = 0; i < l; i++){
35681 if ((typeof(el) == "object") && el.xtype && el.xns) {
35682 el = Roo.factory(el, Roo.menu);
35685 if(el.render){ // some kind of Item
35686 item = this.addItem(el);
35687 }else if(typeof el == "string"){ // string
35688 if(el == "separator" || el == "-"){
35689 item = this.addSeparator();
35691 item = this.addText(el);
35693 }else if(el.tagName || el.el){ // element
35694 item = this.addElement(el);
35695 }else if(typeof el == "object"){ // must be menu item config?
35696 item = this.addMenuItem(el);
35703 * Returns this menu's underlying {@link Roo.Element} object
35704 * @return {Roo.Element} The element
35706 getEl : function(){
35714 * Adds a separator bar to the menu
35715 * @return {Roo.menu.Item} The menu item that was added
35717 addSeparator : function(){
35718 return this.addItem(new Roo.menu.Separator());
35722 * Adds an {@link Roo.Element} object to the menu
35723 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35724 * @return {Roo.menu.Item} The menu item that was added
35726 addElement : function(el){
35727 return this.addItem(new Roo.menu.BaseItem(el));
35731 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35732 * @param {Roo.menu.Item} item The menu item to add
35733 * @return {Roo.menu.Item} The menu item that was added
35735 addItem : function(item){
35736 this.items.add(item);
35738 var li = document.createElement("li");
35739 li.className = "x-menu-list-item";
35740 this.ul.dom.appendChild(li);
35741 item.render(li, this);
35742 this.delayAutoWidth();
35748 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35749 * @param {Object} config A MenuItem config object
35750 * @return {Roo.menu.Item} The menu item that was added
35752 addMenuItem : function(config){
35753 if(!(config instanceof Roo.menu.Item)){
35754 if(typeof config.checked == "boolean"){ // must be check menu item config?
35755 config = new Roo.menu.CheckItem(config);
35757 config = new Roo.menu.Item(config);
35760 return this.addItem(config);
35764 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35765 * @param {String} text The text to display in the menu item
35766 * @return {Roo.menu.Item} The menu item that was added
35768 addText : function(text){
35769 return this.addItem(new Roo.menu.TextItem({ text : text }));
35773 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35774 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35775 * @param {Roo.menu.Item} item The menu item to add
35776 * @return {Roo.menu.Item} The menu item that was added
35778 insert : function(index, item){
35779 this.items.insert(index, item);
35781 var li = document.createElement("li");
35782 li.className = "x-menu-list-item";
35783 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35784 item.render(li, this);
35785 this.delayAutoWidth();
35791 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35792 * @param {Roo.menu.Item} item The menu item to remove
35794 remove : function(item){
35795 this.items.removeKey(item.id);
35800 * Removes and destroys all items in the menu
35802 removeAll : function(){
35804 while(f = this.items.first()){
35810 // MenuNav is a private utility class used internally by the Menu
35811 Roo.menu.MenuNav = function(menu){
35812 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35813 this.scope = this.menu = menu;
35816 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35817 doRelay : function(e, h){
35818 var k = e.getKey();
35819 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35820 this.menu.tryActivate(0, 1);
35823 return h.call(this.scope || this, e, this.menu);
35826 up : function(e, m){
35827 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35828 m.tryActivate(m.items.length-1, -1);
35832 down : function(e, m){
35833 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35834 m.tryActivate(0, 1);
35838 right : function(e, m){
35840 m.activeItem.expandMenu(true);
35844 left : function(e, m){
35846 if(m.parentMenu && m.parentMenu.activeItem){
35847 m.parentMenu.activeItem.activate();
35851 enter : function(e, m){
35853 e.stopPropagation();
35854 m.activeItem.onClick(e);
35855 m.fireEvent("click", this, m.activeItem);
35861 * Ext JS Library 1.1.1
35862 * Copyright(c) 2006-2007, Ext JS, LLC.
35864 * Originally Released Under LGPL - original licence link has changed is not relivant.
35867 * <script type="text/javascript">
35871 * @class Roo.menu.MenuMgr
35872 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35875 Roo.menu.MenuMgr = function(){
35876 var menus, active, groups = {}, attached = false, lastShow = new Date();
35878 // private - called when first menu is created
35881 active = new Roo.util.MixedCollection();
35882 Roo.get(document).addKeyListener(27, function(){
35883 if(active.length > 0){
35890 function hideAll(){
35891 if(active && active.length > 0){
35892 var c = active.clone();
35893 c.each(function(m){
35900 function onHide(m){
35902 if(active.length < 1){
35903 Roo.get(document).un("mousedown", onMouseDown);
35909 function onShow(m){
35910 var last = active.last();
35911 lastShow = new Date();
35914 Roo.get(document).on("mousedown", onMouseDown);
35918 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35919 m.parentMenu.activeChild = m;
35920 }else if(last && last.isVisible()){
35921 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35926 function onBeforeHide(m){
35928 m.activeChild.hide();
35930 if(m.autoHideTimer){
35931 clearTimeout(m.autoHideTimer);
35932 delete m.autoHideTimer;
35937 function onBeforeShow(m){
35938 var pm = m.parentMenu;
35939 if(!pm && !m.allowOtherMenus){
35941 }else if(pm && pm.activeChild && active != m){
35942 pm.activeChild.hide();
35947 function onMouseDown(e){
35948 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
35954 function onBeforeCheck(mi, state){
35956 var g = groups[mi.group];
35957 for(var i = 0, l = g.length; i < l; i++){
35959 g[i].setChecked(false);
35968 * Hides all menus that are currently visible
35970 hideAll : function(){
35975 register : function(menu){
35979 menus[menu.id] = menu;
35980 menu.on("beforehide", onBeforeHide);
35981 menu.on("hide", onHide);
35982 menu.on("beforeshow", onBeforeShow);
35983 menu.on("show", onShow);
35984 var g = menu.group;
35985 if(g && menu.events["checkchange"]){
35989 groups[g].push(menu);
35990 menu.on("checkchange", onCheck);
35995 * Returns a {@link Roo.menu.Menu} object
35996 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
35997 * be used to generate and return a new Menu instance.
35999 get : function(menu){
36000 if(typeof menu == "string"){ // menu id
36001 return menus[menu];
36002 }else if(menu.events){ // menu instance
36004 }else if(typeof menu.length == 'number'){ // array of menu items?
36005 return new Roo.menu.Menu({items:menu});
36006 }else{ // otherwise, must be a config
36007 return new Roo.menu.Menu(menu);
36012 unregister : function(menu){
36013 delete menus[menu.id];
36014 menu.un("beforehide", onBeforeHide);
36015 menu.un("hide", onHide);
36016 menu.un("beforeshow", onBeforeShow);
36017 menu.un("show", onShow);
36018 var g = menu.group;
36019 if(g && menu.events["checkchange"]){
36020 groups[g].remove(menu);
36021 menu.un("checkchange", onCheck);
36026 registerCheckable : function(menuItem){
36027 var g = menuItem.group;
36032 groups[g].push(menuItem);
36033 menuItem.on("beforecheckchange", onBeforeCheck);
36038 unregisterCheckable : function(menuItem){
36039 var g = menuItem.group;
36041 groups[g].remove(menuItem);
36042 menuItem.un("beforecheckchange", onBeforeCheck);
36048 * Ext JS Library 1.1.1
36049 * Copyright(c) 2006-2007, Ext JS, LLC.
36051 * Originally Released Under LGPL - original licence link has changed is not relivant.
36054 * <script type="text/javascript">
36059 * @class Roo.menu.BaseItem
36060 * @extends Roo.Component
36061 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36062 * management and base configuration options shared by all menu components.
36064 * Creates a new BaseItem
36065 * @param {Object} config Configuration options
36067 Roo.menu.BaseItem = function(config){
36068 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36073 * Fires when this item is clicked
36074 * @param {Roo.menu.BaseItem} this
36075 * @param {Roo.EventObject} e
36080 * Fires when this item is activated
36081 * @param {Roo.menu.BaseItem} this
36085 * @event deactivate
36086 * Fires when this item is deactivated
36087 * @param {Roo.menu.BaseItem} this
36093 this.on("click", this.handler, this.scope, true);
36097 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36099 * @cfg {Function} handler
36100 * A function that will handle the click event of this menu item (defaults to undefined)
36103 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36105 canActivate : false,
36108 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36113 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36115 activeClass : "x-menu-item-active",
36117 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36119 hideOnClick : true,
36121 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36126 ctype: "Roo.menu.BaseItem",
36129 actionMode : "container",
36132 render : function(container, parentMenu){
36133 this.parentMenu = parentMenu;
36134 Roo.menu.BaseItem.superclass.render.call(this, container);
36135 this.container.menuItemId = this.id;
36139 onRender : function(container, position){
36140 this.el = Roo.get(this.el);
36141 container.dom.appendChild(this.el.dom);
36145 onClick : function(e){
36146 if(!this.disabled && this.fireEvent("click", this, e) !== false
36147 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36148 this.handleClick(e);
36155 activate : function(){
36159 var li = this.container;
36160 li.addClass(this.activeClass);
36161 this.region = li.getRegion().adjust(2, 2, -2, -2);
36162 this.fireEvent("activate", this);
36167 deactivate : function(){
36168 this.container.removeClass(this.activeClass);
36169 this.fireEvent("deactivate", this);
36173 shouldDeactivate : function(e){
36174 return !this.region || !this.region.contains(e.getPoint());
36178 handleClick : function(e){
36179 if(this.hideOnClick){
36180 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36185 expandMenu : function(autoActivate){
36190 hideMenu : function(){
36195 * Ext JS Library 1.1.1
36196 * Copyright(c) 2006-2007, Ext JS, LLC.
36198 * Originally Released Under LGPL - original licence link has changed is not relivant.
36201 * <script type="text/javascript">
36205 * @class Roo.menu.Adapter
36206 * @extends Roo.menu.BaseItem
36207 * 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.
36208 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36210 * Creates a new Adapter
36211 * @param {Object} config Configuration options
36213 Roo.menu.Adapter = function(component, config){
36214 Roo.menu.Adapter.superclass.constructor.call(this, config);
36215 this.component = component;
36217 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36219 canActivate : true,
36222 onRender : function(container, position){
36223 this.component.render(container);
36224 this.el = this.component.getEl();
36228 activate : function(){
36232 this.component.focus();
36233 this.fireEvent("activate", this);
36238 deactivate : function(){
36239 this.fireEvent("deactivate", this);
36243 disable : function(){
36244 this.component.disable();
36245 Roo.menu.Adapter.superclass.disable.call(this);
36249 enable : function(){
36250 this.component.enable();
36251 Roo.menu.Adapter.superclass.enable.call(this);
36255 * Ext JS Library 1.1.1
36256 * Copyright(c) 2006-2007, Ext JS, LLC.
36258 * Originally Released Under LGPL - original licence link has changed is not relivant.
36261 * <script type="text/javascript">
36265 * @class Roo.menu.TextItem
36266 * @extends Roo.menu.BaseItem
36267 * Adds a static text string to a menu, usually used as either a heading or group separator.
36268 * Note: old style constructor with text is still supported.
36271 * Creates a new TextItem
36272 * @param {Object} cfg Configuration
36274 Roo.menu.TextItem = function(cfg){
36275 if (typeof(cfg) == 'string') {
36278 Roo.apply(this,cfg);
36281 Roo.menu.TextItem.superclass.constructor.call(this);
36284 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36286 * @cfg {Boolean} text Text to show on item.
36291 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36293 hideOnClick : false,
36295 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36297 itemCls : "x-menu-text",
36300 onRender : function(){
36301 var s = document.createElement("span");
36302 s.className = this.itemCls;
36303 s.innerHTML = this.text;
36305 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36309 * Ext JS Library 1.1.1
36310 * Copyright(c) 2006-2007, Ext JS, LLC.
36312 * Originally Released Under LGPL - original licence link has changed is not relivant.
36315 * <script type="text/javascript">
36319 * @class Roo.menu.Separator
36320 * @extends Roo.menu.BaseItem
36321 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36322 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36324 * @param {Object} config Configuration options
36326 Roo.menu.Separator = function(config){
36327 Roo.menu.Separator.superclass.constructor.call(this, config);
36330 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36332 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36334 itemCls : "x-menu-sep",
36336 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36338 hideOnClick : false,
36341 onRender : function(li){
36342 var s = document.createElement("span");
36343 s.className = this.itemCls;
36344 s.innerHTML = " ";
36346 li.addClass("x-menu-sep-li");
36347 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36351 * Ext JS Library 1.1.1
36352 * Copyright(c) 2006-2007, Ext JS, LLC.
36354 * Originally Released Under LGPL - original licence link has changed is not relivant.
36357 * <script type="text/javascript">
36360 * @class Roo.menu.Item
36361 * @extends Roo.menu.BaseItem
36362 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36363 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36364 * activation and click handling.
36366 * Creates a new Item
36367 * @param {Object} config Configuration options
36369 Roo.menu.Item = function(config){
36370 Roo.menu.Item.superclass.constructor.call(this, config);
36372 this.menu = Roo.menu.MenuMgr.get(this.menu);
36375 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36378 * @cfg {String} text
36379 * The text to show on the menu item.
36383 * @cfg {String} HTML to render in menu
36384 * The text to show on the menu item (HTML version).
36388 * @cfg {String} icon
36389 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36393 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36395 itemCls : "x-menu-item",
36397 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36399 canActivate : true,
36401 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36404 // doc'd in BaseItem
36408 ctype: "Roo.menu.Item",
36411 onRender : function(container, position){
36412 var el = document.createElement("a");
36413 el.hideFocus = true;
36414 el.unselectable = "on";
36415 el.href = this.href || "#";
36416 if(this.hrefTarget){
36417 el.target = this.hrefTarget;
36419 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36421 var html = this.html.length ? this.html : String.format('{0}',this.text);
36423 el.innerHTML = String.format(
36424 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36425 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36427 Roo.menu.Item.superclass.onRender.call(this, container, position);
36431 * Sets the text to display in this menu item
36432 * @param {String} text The text to display
36433 * @param {Boolean} isHTML true to indicate text is pure html.
36435 setText : function(text, isHTML){
36443 var html = this.html.length ? this.html : String.format('{0}',this.text);
36445 this.el.update(String.format(
36446 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36447 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36448 this.parentMenu.autoWidth();
36453 handleClick : function(e){
36454 if(!this.href){ // if no link defined, stop the event automatically
36457 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36461 activate : function(autoExpand){
36462 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36472 shouldDeactivate : function(e){
36473 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36474 if(this.menu && this.menu.isVisible()){
36475 return !this.menu.getEl().getRegion().contains(e.getPoint());
36483 deactivate : function(){
36484 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36489 expandMenu : function(autoActivate){
36490 if(!this.disabled && this.menu){
36491 clearTimeout(this.hideTimer);
36492 delete this.hideTimer;
36493 if(!this.menu.isVisible() && !this.showTimer){
36494 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36495 }else if (this.menu.isVisible() && autoActivate){
36496 this.menu.tryActivate(0, 1);
36502 deferExpand : function(autoActivate){
36503 delete this.showTimer;
36504 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36506 this.menu.tryActivate(0, 1);
36511 hideMenu : function(){
36512 clearTimeout(this.showTimer);
36513 delete this.showTimer;
36514 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36515 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36520 deferHide : function(){
36521 delete this.hideTimer;
36526 * Ext JS Library 1.1.1
36527 * Copyright(c) 2006-2007, Ext JS, LLC.
36529 * Originally Released Under LGPL - original licence link has changed is not relivant.
36532 * <script type="text/javascript">
36536 * @class Roo.menu.CheckItem
36537 * @extends Roo.menu.Item
36538 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36540 * Creates a new CheckItem
36541 * @param {Object} config Configuration options
36543 Roo.menu.CheckItem = function(config){
36544 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36547 * @event beforecheckchange
36548 * Fires before the checked value is set, providing an opportunity to cancel if needed
36549 * @param {Roo.menu.CheckItem} this
36550 * @param {Boolean} checked The new checked value that will be set
36552 "beforecheckchange" : true,
36554 * @event checkchange
36555 * Fires after the checked value has been set
36556 * @param {Roo.menu.CheckItem} this
36557 * @param {Boolean} checked The checked value that was set
36559 "checkchange" : true
36561 if(this.checkHandler){
36562 this.on('checkchange', this.checkHandler, this.scope);
36565 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36567 * @cfg {String} group
36568 * All check items with the same group name will automatically be grouped into a single-select
36569 * radio button group (defaults to '')
36572 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36574 itemCls : "x-menu-item x-menu-check-item",
36576 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36578 groupClass : "x-menu-group-item",
36581 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36582 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36583 * initialized with checked = true will be rendered as checked.
36588 ctype: "Roo.menu.CheckItem",
36591 onRender : function(c){
36592 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36594 this.el.addClass(this.groupClass);
36596 Roo.menu.MenuMgr.registerCheckable(this);
36598 this.checked = false;
36599 this.setChecked(true, true);
36604 destroy : function(){
36606 Roo.menu.MenuMgr.unregisterCheckable(this);
36608 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36612 * Set the checked state of this item
36613 * @param {Boolean} checked The new checked value
36614 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36616 setChecked : function(state, suppressEvent){
36617 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36618 if(this.container){
36619 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36621 this.checked = state;
36622 if(suppressEvent !== true){
36623 this.fireEvent("checkchange", this, state);
36629 handleClick : function(e){
36630 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36631 this.setChecked(!this.checked);
36633 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36637 * Ext JS Library 1.1.1
36638 * Copyright(c) 2006-2007, Ext JS, LLC.
36640 * Originally Released Under LGPL - original licence link has changed is not relivant.
36643 * <script type="text/javascript">
36647 * @class Roo.menu.DateItem
36648 * @extends Roo.menu.Adapter
36649 * A menu item that wraps the {@link Roo.DatPicker} component.
36651 * Creates a new DateItem
36652 * @param {Object} config Configuration options
36654 Roo.menu.DateItem = function(config){
36655 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36656 /** The Roo.DatePicker object @type Roo.DatePicker */
36657 this.picker = this.component;
36658 this.addEvents({select: true});
36660 this.picker.on("render", function(picker){
36661 picker.getEl().swallowEvent("click");
36662 picker.container.addClass("x-menu-date-item");
36665 this.picker.on("select", this.onSelect, this);
36668 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36670 onSelect : function(picker, date){
36671 this.fireEvent("select", this, date, picker);
36672 Roo.menu.DateItem.superclass.handleClick.call(this);
36676 * Ext JS Library 1.1.1
36677 * Copyright(c) 2006-2007, Ext JS, LLC.
36679 * Originally Released Under LGPL - original licence link has changed is not relivant.
36682 * <script type="text/javascript">
36686 * @class Roo.menu.ColorItem
36687 * @extends Roo.menu.Adapter
36688 * A menu item that wraps the {@link Roo.ColorPalette} component.
36690 * Creates a new ColorItem
36691 * @param {Object} config Configuration options
36693 Roo.menu.ColorItem = function(config){
36694 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36695 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36696 this.palette = this.component;
36697 this.relayEvents(this.palette, ["select"]);
36698 if(this.selectHandler){
36699 this.on('select', this.selectHandler, this.scope);
36702 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36704 * Ext JS Library 1.1.1
36705 * Copyright(c) 2006-2007, Ext JS, LLC.
36707 * Originally Released Under LGPL - original licence link has changed is not relivant.
36710 * <script type="text/javascript">
36715 * @class Roo.menu.DateMenu
36716 * @extends Roo.menu.Menu
36717 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36719 * Creates a new DateMenu
36720 * @param {Object} config Configuration options
36722 Roo.menu.DateMenu = function(config){
36723 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36725 var di = new Roo.menu.DateItem(config);
36728 * The {@link Roo.DatePicker} instance for this DateMenu
36731 this.picker = di.picker;
36734 * @param {DatePicker} picker
36735 * @param {Date} date
36737 this.relayEvents(di, ["select"]);
36738 this.on('beforeshow', function(){
36740 this.picker.hideMonthPicker(false);
36744 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36748 * Ext JS Library 1.1.1
36749 * Copyright(c) 2006-2007, Ext JS, LLC.
36751 * Originally Released Under LGPL - original licence link has changed is not relivant.
36754 * <script type="text/javascript">
36759 * @class Roo.menu.ColorMenu
36760 * @extends Roo.menu.Menu
36761 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36763 * Creates a new ColorMenu
36764 * @param {Object} config Configuration options
36766 Roo.menu.ColorMenu = function(config){
36767 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36769 var ci = new Roo.menu.ColorItem(config);
36772 * The {@link Roo.ColorPalette} instance for this ColorMenu
36773 * @type ColorPalette
36775 this.palette = ci.palette;
36778 * @param {ColorPalette} palette
36779 * @param {String} color
36781 this.relayEvents(ci, ["select"]);
36783 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36785 * Ext JS Library 1.1.1
36786 * Copyright(c) 2006-2007, Ext JS, LLC.
36788 * Originally Released Under LGPL - original licence link has changed is not relivant.
36791 * <script type="text/javascript">
36795 * @class Roo.form.Field
36796 * @extends Roo.BoxComponent
36797 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36799 * Creates a new Field
36800 * @param {Object} config Configuration options
36802 Roo.form.Field = function(config){
36803 Roo.form.Field.superclass.constructor.call(this, config);
36806 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36808 * @cfg {String} fieldLabel Label to use when rendering a form.
36811 * @cfg {String} qtip Mouse over tip
36815 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36817 invalidClass : "x-form-invalid",
36819 * @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")
36821 invalidText : "The value in this field is invalid",
36823 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36825 focusClass : "x-form-focus",
36827 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36828 automatic validation (defaults to "keyup").
36830 validationEvent : "keyup",
36832 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36834 validateOnBlur : true,
36836 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36838 validationDelay : 250,
36840 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36841 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36843 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36845 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36847 fieldClass : "x-form-field",
36849 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36852 ----------- ----------------------------------------------------------------------
36853 qtip Display a quick tip when the user hovers over the field
36854 title Display a default browser title attribute popup
36855 under Add a block div beneath the field containing the error text
36856 side Add an error icon to the right of the field with a popup on hover
36857 [element id] Add the error text directly to the innerHTML of the specified element
36860 msgTarget : 'qtip',
36862 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36867 * @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.
36872 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36877 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36879 inputType : undefined,
36882 * @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).
36884 tabIndex : undefined,
36887 isFormField : true,
36892 * @property {Roo.Element} fieldEl
36893 * Element Containing the rendered Field (with label etc.)
36896 * @cfg {Mixed} value A value to initialize this field with.
36901 * @cfg {String} name The field's HTML name attribute.
36904 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36908 initComponent : function(){
36909 Roo.form.Field.superclass.initComponent.call(this);
36913 * Fires when this field receives input focus.
36914 * @param {Roo.form.Field} this
36919 * Fires when this field loses input focus.
36920 * @param {Roo.form.Field} this
36924 * @event specialkey
36925 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36926 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36927 * @param {Roo.form.Field} this
36928 * @param {Roo.EventObject} e The event object
36933 * Fires just before the field blurs if the field value has changed.
36934 * @param {Roo.form.Field} this
36935 * @param {Mixed} newValue The new value
36936 * @param {Mixed} oldValue The original value
36941 * Fires after the field has been marked as invalid.
36942 * @param {Roo.form.Field} this
36943 * @param {String} msg The validation message
36948 * Fires after the field has been validated with no errors.
36949 * @param {Roo.form.Field} this
36954 * Fires after the key up
36955 * @param {Roo.form.Field} this
36956 * @param {Roo.EventObject} e The event Object
36963 * Returns the name attribute of the field if available
36964 * @return {String} name The field name
36966 getName: function(){
36967 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
36971 onRender : function(ct, position){
36972 Roo.form.Field.superclass.onRender.call(this, ct, position);
36974 var cfg = this.getAutoCreate();
36976 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
36978 if (!cfg.name.length) {
36981 if(this.inputType){
36982 cfg.type = this.inputType;
36984 this.el = ct.createChild(cfg, position);
36986 var type = this.el.dom.type;
36988 if(type == 'password'){
36991 this.el.addClass('x-form-'+type);
36994 this.el.dom.readOnly = true;
36996 if(this.tabIndex !== undefined){
36997 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37000 this.el.addClass([this.fieldClass, this.cls]);
37005 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37006 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37007 * @return {Roo.form.Field} this
37009 applyTo : function(target){
37010 this.allowDomMove = false;
37011 this.el = Roo.get(target);
37012 this.render(this.el.dom.parentNode);
37017 initValue : function(){
37018 if(this.value !== undefined){
37019 this.setValue(this.value);
37020 }else if(this.el.dom.value.length > 0){
37021 this.setValue(this.el.dom.value);
37026 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37028 isDirty : function() {
37029 if(this.disabled) {
37032 return String(this.getValue()) !== String(this.originalValue);
37036 afterRender : function(){
37037 Roo.form.Field.superclass.afterRender.call(this);
37042 fireKey : function(e){
37043 //Roo.log('field ' + e.getKey());
37044 if(e.isNavKeyPress()){
37045 this.fireEvent("specialkey", this, e);
37050 * Resets the current field value to the originally loaded value and clears any validation messages
37052 reset : function(){
37053 this.setValue(this.resetValue);
37054 this.clearInvalid();
37058 initEvents : function(){
37059 // safari killled keypress - so keydown is now used..
37060 this.el.on("keydown" , this.fireKey, this);
37061 this.el.on("focus", this.onFocus, this);
37062 this.el.on("blur", this.onBlur, this);
37063 this.el.relayEvent('keyup', this);
37065 // reference to original value for reset
37066 this.originalValue = this.getValue();
37067 this.resetValue = this.getValue();
37071 onFocus : function(){
37072 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37073 this.el.addClass(this.focusClass);
37075 if(!this.hasFocus){
37076 this.hasFocus = true;
37077 this.startValue = this.getValue();
37078 this.fireEvent("focus", this);
37082 beforeBlur : Roo.emptyFn,
37085 onBlur : function(){
37087 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37088 this.el.removeClass(this.focusClass);
37090 this.hasFocus = false;
37091 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37094 var v = this.getValue();
37095 if(String(v) !== String(this.startValue)){
37096 this.fireEvent('change', this, v, this.startValue);
37098 this.fireEvent("blur", this);
37102 * Returns whether or not the field value is currently valid
37103 * @param {Boolean} preventMark True to disable marking the field invalid
37104 * @return {Boolean} True if the value is valid, else false
37106 isValid : function(preventMark){
37110 var restore = this.preventMark;
37111 this.preventMark = preventMark === true;
37112 var v = this.validateValue(this.processValue(this.getRawValue()));
37113 this.preventMark = restore;
37118 * Validates the field value
37119 * @return {Boolean} True if the value is valid, else false
37121 validate : function(){
37122 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37123 this.clearInvalid();
37129 processValue : function(value){
37134 // Subclasses should provide the validation implementation by overriding this
37135 validateValue : function(value){
37140 * Mark this field as invalid
37141 * @param {String} msg The validation message
37143 markInvalid : function(msg){
37144 if(!this.rendered || this.preventMark){ // not rendered
37148 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37150 obj.el.addClass(this.invalidClass);
37151 msg = msg || this.invalidText;
37152 switch(this.msgTarget){
37154 obj.el.dom.qtip = msg;
37155 obj.el.dom.qclass = 'x-form-invalid-tip';
37156 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37157 Roo.QuickTips.enable();
37161 this.el.dom.title = msg;
37165 var elp = this.el.findParent('.x-form-element', 5, true);
37166 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37167 this.errorEl.setWidth(elp.getWidth(true)-20);
37169 this.errorEl.update(msg);
37170 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37173 if(!this.errorIcon){
37174 var elp = this.el.findParent('.x-form-element', 5, true);
37175 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37177 this.alignErrorIcon();
37178 this.errorIcon.dom.qtip = msg;
37179 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37180 this.errorIcon.show();
37181 this.on('resize', this.alignErrorIcon, this);
37184 var t = Roo.getDom(this.msgTarget);
37186 t.style.display = this.msgDisplay;
37189 this.fireEvent('invalid', this, msg);
37193 alignErrorIcon : function(){
37194 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37198 * Clear any invalid styles/messages for this field
37200 clearInvalid : function(){
37201 if(!this.rendered || this.preventMark){ // not rendered
37204 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37206 obj.el.removeClass(this.invalidClass);
37207 switch(this.msgTarget){
37209 obj.el.dom.qtip = '';
37212 this.el.dom.title = '';
37216 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37220 if(this.errorIcon){
37221 this.errorIcon.dom.qtip = '';
37222 this.errorIcon.hide();
37223 this.un('resize', this.alignErrorIcon, this);
37227 var t = Roo.getDom(this.msgTarget);
37229 t.style.display = 'none';
37232 this.fireEvent('valid', this);
37236 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37237 * @return {Mixed} value The field value
37239 getRawValue : function(){
37240 var v = this.el.getValue();
37246 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37247 * @return {Mixed} value The field value
37249 getValue : function(){
37250 var v = this.el.getValue();
37256 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37257 * @param {Mixed} value The value to set
37259 setRawValue : function(v){
37260 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37264 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37265 * @param {Mixed} value The value to set
37267 setValue : function(v){
37270 this.el.dom.value = (v === null || v === undefined ? '' : v);
37275 adjustSize : function(w, h){
37276 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37277 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37281 adjustWidth : function(tag, w){
37282 tag = tag.toLowerCase();
37283 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37284 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37285 if(tag == 'input'){
37288 if(tag == 'textarea'){
37291 }else if(Roo.isOpera){
37292 if(tag == 'input'){
37295 if(tag == 'textarea'){
37305 // anything other than normal should be considered experimental
37306 Roo.form.Field.msgFx = {
37308 show: function(msgEl, f){
37309 msgEl.setDisplayed('block');
37312 hide : function(msgEl, f){
37313 msgEl.setDisplayed(false).update('');
37318 show: function(msgEl, f){
37319 msgEl.slideIn('t', {stopFx:true});
37322 hide : function(msgEl, f){
37323 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37328 show: function(msgEl, f){
37329 msgEl.fixDisplay();
37330 msgEl.alignTo(f.el, 'tl-tr');
37331 msgEl.slideIn('l', {stopFx:true});
37334 hide : function(msgEl, f){
37335 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37340 * Ext JS Library 1.1.1
37341 * Copyright(c) 2006-2007, Ext JS, LLC.
37343 * Originally Released Under LGPL - original licence link has changed is not relivant.
37346 * <script type="text/javascript">
37351 * @class Roo.form.TextField
37352 * @extends Roo.form.Field
37353 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37354 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37356 * Creates a new TextField
37357 * @param {Object} config Configuration options
37359 Roo.form.TextField = function(config){
37360 Roo.form.TextField.superclass.constructor.call(this, config);
37364 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37365 * according to the default logic, but this event provides a hook for the developer to apply additional
37366 * logic at runtime to resize the field if needed.
37367 * @param {Roo.form.Field} this This text field
37368 * @param {Number} width The new field width
37374 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37376 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37380 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37384 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37388 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37392 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37396 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37398 disableKeyFilter : false,
37400 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37404 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37408 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37410 maxLength : Number.MAX_VALUE,
37412 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37414 minLengthText : "The minimum length for this field is {0}",
37416 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37418 maxLengthText : "The maximum length for this field is {0}",
37420 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37422 selectOnFocus : false,
37424 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37426 blankText : "This field is required",
37428 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37429 * If available, this function will be called only after the basic validators all return true, and will be passed the
37430 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37434 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37435 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37436 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37440 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37444 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37450 initEvents : function()
37452 if (this.emptyText) {
37453 this.el.attr('placeholder', this.emptyText);
37456 Roo.form.TextField.superclass.initEvents.call(this);
37457 if(this.validationEvent == 'keyup'){
37458 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37459 this.el.on('keyup', this.filterValidation, this);
37461 else if(this.validationEvent !== false){
37462 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37465 if(this.selectOnFocus){
37466 this.on("focus", this.preFocus, this);
37469 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37470 this.el.on("keypress", this.filterKeys, this);
37473 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37474 this.el.on("click", this.autoSize, this);
37476 if(this.el.is('input[type=password]') && Roo.isSafari){
37477 this.el.on('keydown', this.SafariOnKeyDown, this);
37481 processValue : function(value){
37482 if(this.stripCharsRe){
37483 var newValue = value.replace(this.stripCharsRe, '');
37484 if(newValue !== value){
37485 this.setRawValue(newValue);
37492 filterValidation : function(e){
37493 if(!e.isNavKeyPress()){
37494 this.validationTask.delay(this.validationDelay);
37499 onKeyUp : function(e){
37500 if(!e.isNavKeyPress()){
37506 * Resets the current field value to the originally-loaded value and clears any validation messages.
37509 reset : function(){
37510 Roo.form.TextField.superclass.reset.call(this);
37516 preFocus : function(){
37518 if(this.selectOnFocus){
37519 this.el.dom.select();
37525 filterKeys : function(e){
37526 var k = e.getKey();
37527 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37530 var c = e.getCharCode(), cc = String.fromCharCode(c);
37531 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37534 if(!this.maskRe.test(cc)){
37539 setValue : function(v){
37541 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37547 * Validates a value according to the field's validation rules and marks the field as invalid
37548 * if the validation fails
37549 * @param {Mixed} value The value to validate
37550 * @return {Boolean} True if the value is valid, else false
37552 validateValue : function(value){
37553 if(value.length < 1) { // if it's blank
37554 if(this.allowBlank){
37555 this.clearInvalid();
37558 this.markInvalid(this.blankText);
37562 if(value.length < this.minLength){
37563 this.markInvalid(String.format(this.minLengthText, this.minLength));
37566 if(value.length > this.maxLength){
37567 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37571 var vt = Roo.form.VTypes;
37572 if(!vt[this.vtype](value, this)){
37573 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37577 if(typeof this.validator == "function"){
37578 var msg = this.validator(value);
37580 this.markInvalid(msg);
37584 if(this.regex && !this.regex.test(value)){
37585 this.markInvalid(this.regexText);
37592 * Selects text in this field
37593 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37594 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37596 selectText : function(start, end){
37597 var v = this.getRawValue();
37599 start = start === undefined ? 0 : start;
37600 end = end === undefined ? v.length : end;
37601 var d = this.el.dom;
37602 if(d.setSelectionRange){
37603 d.setSelectionRange(start, end);
37604 }else if(d.createTextRange){
37605 var range = d.createTextRange();
37606 range.moveStart("character", start);
37607 range.moveEnd("character", v.length-end);
37614 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37615 * This only takes effect if grow = true, and fires the autosize event.
37617 autoSize : function(){
37618 if(!this.grow || !this.rendered){
37622 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37625 var v = el.dom.value;
37626 var d = document.createElement('div');
37627 d.appendChild(document.createTextNode(v));
37631 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37632 this.el.setWidth(w);
37633 this.fireEvent("autosize", this, w);
37637 SafariOnKeyDown : function(event)
37639 // this is a workaround for a password hang bug on chrome/ webkit.
37641 var isSelectAll = false;
37643 if(this.el.dom.selectionEnd > 0){
37644 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37646 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37647 event.preventDefault();
37652 if(isSelectAll){ // backspace and delete key
37654 event.preventDefault();
37655 // this is very hacky as keydown always get's upper case.
37657 var cc = String.fromCharCode(event.getCharCode());
37658 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37666 * Ext JS Library 1.1.1
37667 * Copyright(c) 2006-2007, Ext JS, LLC.
37669 * Originally Released Under LGPL - original licence link has changed is not relivant.
37672 * <script type="text/javascript">
37676 * @class Roo.form.Hidden
37677 * @extends Roo.form.TextField
37678 * Simple Hidden element used on forms
37680 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37683 * Creates a new Hidden form element.
37684 * @param {Object} config Configuration options
37689 // easy hidden field...
37690 Roo.form.Hidden = function(config){
37691 Roo.form.Hidden.superclass.constructor.call(this, config);
37694 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37696 inputType: 'hidden',
37699 labelSeparator: '',
37701 itemCls : 'x-form-item-display-none'
37709 * Ext JS Library 1.1.1
37710 * Copyright(c) 2006-2007, Ext JS, LLC.
37712 * Originally Released Under LGPL - original licence link has changed is not relivant.
37715 * <script type="text/javascript">
37719 * @class Roo.form.TriggerField
37720 * @extends Roo.form.TextField
37721 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37722 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37723 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37724 * for which you can provide a custom implementation. For example:
37726 var trigger = new Roo.form.TriggerField();
37727 trigger.onTriggerClick = myTriggerFn;
37728 trigger.applyTo('my-field');
37731 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37732 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37733 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37734 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37736 * Create a new TriggerField.
37737 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37738 * to the base TextField)
37740 Roo.form.TriggerField = function(config){
37741 this.mimicing = false;
37742 Roo.form.TriggerField.superclass.constructor.call(this, config);
37745 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37747 * @cfg {String} triggerClass A CSS class to apply to the trigger
37750 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37751 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37753 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37755 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37759 /** @cfg {Boolean} grow @hide */
37760 /** @cfg {Number} growMin @hide */
37761 /** @cfg {Number} growMax @hide */
37767 autoSize: Roo.emptyFn,
37771 deferHeight : true,
37774 actionMode : 'wrap',
37776 onResize : function(w, h){
37777 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37778 if(typeof w == 'number'){
37779 var x = w - this.trigger.getWidth();
37780 this.el.setWidth(this.adjustWidth('input', x));
37781 this.trigger.setStyle('left', x+'px');
37786 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37789 getResizeEl : function(){
37794 getPositionEl : function(){
37799 alignErrorIcon : function(){
37800 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37804 onRender : function(ct, position){
37805 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37806 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37807 this.trigger = this.wrap.createChild(this.triggerConfig ||
37808 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37809 if(this.hideTrigger){
37810 this.trigger.setDisplayed(false);
37812 this.initTrigger();
37814 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37819 initTrigger : function(){
37820 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37821 this.trigger.addClassOnOver('x-form-trigger-over');
37822 this.trigger.addClassOnClick('x-form-trigger-click');
37826 onDestroy : function(){
37828 this.trigger.removeAllListeners();
37829 this.trigger.remove();
37832 this.wrap.remove();
37834 Roo.form.TriggerField.superclass.onDestroy.call(this);
37838 onFocus : function(){
37839 Roo.form.TriggerField.superclass.onFocus.call(this);
37840 if(!this.mimicing){
37841 this.wrap.addClass('x-trigger-wrap-focus');
37842 this.mimicing = true;
37843 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37844 if(this.monitorTab){
37845 this.el.on("keydown", this.checkTab, this);
37851 checkTab : function(e){
37852 if(e.getKey() == e.TAB){
37853 this.triggerBlur();
37858 onBlur : function(){
37863 mimicBlur : function(e, t){
37864 if(!this.wrap.contains(t) && this.validateBlur()){
37865 this.triggerBlur();
37870 triggerBlur : function(){
37871 this.mimicing = false;
37872 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37873 if(this.monitorTab){
37874 this.el.un("keydown", this.checkTab, this);
37876 this.wrap.removeClass('x-trigger-wrap-focus');
37877 Roo.form.TriggerField.superclass.onBlur.call(this);
37881 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37882 validateBlur : function(e, t){
37887 onDisable : function(){
37888 Roo.form.TriggerField.superclass.onDisable.call(this);
37890 this.wrap.addClass('x-item-disabled');
37895 onEnable : function(){
37896 Roo.form.TriggerField.superclass.onEnable.call(this);
37898 this.wrap.removeClass('x-item-disabled');
37903 onShow : function(){
37904 var ae = this.getActionEl();
37907 ae.dom.style.display = '';
37908 ae.dom.style.visibility = 'visible';
37914 onHide : function(){
37915 var ae = this.getActionEl();
37916 ae.dom.style.display = 'none';
37920 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37921 * by an implementing function.
37923 * @param {EventObject} e
37925 onTriggerClick : Roo.emptyFn
37928 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37929 // to be extended by an implementing class. For an example of implementing this class, see the custom
37930 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37931 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37932 initComponent : function(){
37933 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37935 this.triggerConfig = {
37936 tag:'span', cls:'x-form-twin-triggers', cn:[
37937 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37938 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
37942 getTrigger : function(index){
37943 return this.triggers[index];
37946 initTrigger : function(){
37947 var ts = this.trigger.select('.x-form-trigger', true);
37948 this.wrap.setStyle('overflow', 'hidden');
37949 var triggerField = this;
37950 ts.each(function(t, all, index){
37951 t.hide = function(){
37952 var w = triggerField.wrap.getWidth();
37953 this.dom.style.display = 'none';
37954 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37956 t.show = function(){
37957 var w = triggerField.wrap.getWidth();
37958 this.dom.style.display = '';
37959 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37961 var triggerIndex = 'Trigger'+(index+1);
37963 if(this['hide'+triggerIndex]){
37964 t.dom.style.display = 'none';
37966 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
37967 t.addClassOnOver('x-form-trigger-over');
37968 t.addClassOnClick('x-form-trigger-click');
37970 this.triggers = ts.elements;
37973 onTrigger1Click : Roo.emptyFn,
37974 onTrigger2Click : Roo.emptyFn
37977 * Ext JS Library 1.1.1
37978 * Copyright(c) 2006-2007, Ext JS, LLC.
37980 * Originally Released Under LGPL - original licence link has changed is not relivant.
37983 * <script type="text/javascript">
37987 * @class Roo.form.TextArea
37988 * @extends Roo.form.TextField
37989 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
37990 * support for auto-sizing.
37992 * Creates a new TextArea
37993 * @param {Object} config Configuration options
37995 Roo.form.TextArea = function(config){
37996 Roo.form.TextArea.superclass.constructor.call(this, config);
37997 // these are provided exchanges for backwards compat
37998 // minHeight/maxHeight were replaced by growMin/growMax to be
37999 // compatible with TextField growing config values
38000 if(this.minHeight !== undefined){
38001 this.growMin = this.minHeight;
38003 if(this.maxHeight !== undefined){
38004 this.growMax = this.maxHeight;
38008 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38010 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38014 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38018 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38019 * in the field (equivalent to setting overflow: hidden, defaults to false)
38021 preventScrollbars: false,
38023 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38024 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38028 onRender : function(ct, position){
38030 this.defaultAutoCreate = {
38032 style:"width:300px;height:60px;",
38033 autocomplete: "off"
38036 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38038 this.textSizeEl = Roo.DomHelper.append(document.body, {
38039 tag: "pre", cls: "x-form-grow-sizer"
38041 if(this.preventScrollbars){
38042 this.el.setStyle("overflow", "hidden");
38044 this.el.setHeight(this.growMin);
38048 onDestroy : function(){
38049 if(this.textSizeEl){
38050 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38052 Roo.form.TextArea.superclass.onDestroy.call(this);
38056 onKeyUp : function(e){
38057 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38063 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38064 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38066 autoSize : function(){
38067 if(!this.grow || !this.textSizeEl){
38071 var v = el.dom.value;
38072 var ts = this.textSizeEl;
38075 ts.appendChild(document.createTextNode(v));
38078 Roo.fly(ts).setWidth(this.el.getWidth());
38080 v = "  ";
38083 v = v.replace(/\n/g, '<p> </p>');
38085 v += " \n ";
38088 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38089 if(h != this.lastHeight){
38090 this.lastHeight = h;
38091 this.el.setHeight(h);
38092 this.fireEvent("autosize", this, h);
38097 * Ext JS Library 1.1.1
38098 * Copyright(c) 2006-2007, Ext JS, LLC.
38100 * Originally Released Under LGPL - original licence link has changed is not relivant.
38103 * <script type="text/javascript">
38108 * @class Roo.form.NumberField
38109 * @extends Roo.form.TextField
38110 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38112 * Creates a new NumberField
38113 * @param {Object} config Configuration options
38115 Roo.form.NumberField = function(config){
38116 Roo.form.NumberField.superclass.constructor.call(this, config);
38119 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38121 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38123 fieldClass: "x-form-field x-form-num-field",
38125 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38127 allowDecimals : true,
38129 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38131 decimalSeparator : ".",
38133 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38135 decimalPrecision : 2,
38137 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38139 allowNegative : true,
38141 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38143 minValue : Number.NEGATIVE_INFINITY,
38145 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38147 maxValue : Number.MAX_VALUE,
38149 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38151 minText : "The minimum value for this field is {0}",
38153 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38155 maxText : "The maximum value for this field is {0}",
38157 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38158 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38160 nanText : "{0} is not a valid number",
38163 initEvents : function(){
38164 Roo.form.NumberField.superclass.initEvents.call(this);
38165 var allowed = "0123456789";
38166 if(this.allowDecimals){
38167 allowed += this.decimalSeparator;
38169 if(this.allowNegative){
38172 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38173 var keyPress = function(e){
38174 var k = e.getKey();
38175 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38178 var c = e.getCharCode();
38179 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38183 this.el.on("keypress", keyPress, this);
38187 validateValue : function(value){
38188 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38191 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38194 var num = this.parseValue(value);
38196 this.markInvalid(String.format(this.nanText, value));
38199 if(num < this.minValue){
38200 this.markInvalid(String.format(this.minText, this.minValue));
38203 if(num > this.maxValue){
38204 this.markInvalid(String.format(this.maxText, this.maxValue));
38210 getValue : function(){
38211 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38215 parseValue : function(value){
38216 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38217 return isNaN(value) ? '' : value;
38221 fixPrecision : function(value){
38222 var nan = isNaN(value);
38223 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38224 return nan ? '' : value;
38226 return parseFloat(value).toFixed(this.decimalPrecision);
38229 setValue : function(v){
38230 v = this.fixPrecision(v);
38231 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38235 decimalPrecisionFcn : function(v){
38236 return Math.floor(v);
38239 beforeBlur : function(){
38240 var v = this.parseValue(this.getRawValue());
38247 * Ext JS Library 1.1.1
38248 * Copyright(c) 2006-2007, Ext JS, LLC.
38250 * Originally Released Under LGPL - original licence link has changed is not relivant.
38253 * <script type="text/javascript">
38257 * @class Roo.form.DateField
38258 * @extends Roo.form.TriggerField
38259 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38261 * Create a new DateField
38262 * @param {Object} config
38264 Roo.form.DateField = function(config){
38265 Roo.form.DateField.superclass.constructor.call(this, config);
38271 * Fires when a date is selected
38272 * @param {Roo.form.DateField} combo This combo box
38273 * @param {Date} date The date selected
38280 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38281 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38282 this.ddMatch = null;
38283 if(this.disabledDates){
38284 var dd = this.disabledDates;
38286 for(var i = 0; i < dd.length; i++){
38288 if(i != dd.length-1) re += "|";
38290 this.ddMatch = new RegExp(re + ")");
38294 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38296 * @cfg {String} format
38297 * The default date format string which can be overriden for localization support. The format must be
38298 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38302 * @cfg {String} altFormats
38303 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38304 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38306 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38308 * @cfg {Array} disabledDays
38309 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38311 disabledDays : null,
38313 * @cfg {String} disabledDaysText
38314 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38316 disabledDaysText : "Disabled",
38318 * @cfg {Array} disabledDates
38319 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38320 * expression so they are very powerful. Some examples:
38322 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38323 * <li>["03/08", "09/16"] would disable those days for every year</li>
38324 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38325 * <li>["03/../2006"] would disable every day in March 2006</li>
38326 * <li>["^03"] would disable every day in every March</li>
38328 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38329 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38331 disabledDates : null,
38333 * @cfg {String} disabledDatesText
38334 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38336 disabledDatesText : "Disabled",
38338 * @cfg {Date/String} minValue
38339 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38340 * valid format (defaults to null).
38344 * @cfg {Date/String} maxValue
38345 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38346 * valid format (defaults to null).
38350 * @cfg {String} minText
38351 * The error text to display when the date in the cell is before minValue (defaults to
38352 * 'The date in this field must be after {minValue}').
38354 minText : "The date in this field must be equal to or after {0}",
38356 * @cfg {String} maxText
38357 * The error text to display when the date in the cell is after maxValue (defaults to
38358 * 'The date in this field must be before {maxValue}').
38360 maxText : "The date in this field must be equal to or before {0}",
38362 * @cfg {String} invalidText
38363 * The error text to display when the date in the field is invalid (defaults to
38364 * '{value} is not a valid date - it must be in the format {format}').
38366 invalidText : "{0} is not a valid date - it must be in the format {1}",
38368 * @cfg {String} triggerClass
38369 * An additional CSS class used to style the trigger button. The trigger will always get the
38370 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38371 * which displays a calendar icon).
38373 triggerClass : 'x-form-date-trigger',
38377 * @cfg {Boolean} useIso
38378 * if enabled, then the date field will use a hidden field to store the
38379 * real value as iso formated date. default (false)
38383 * @cfg {String/Object} autoCreate
38384 * A DomHelper element spec, or true for a default element spec (defaults to
38385 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38388 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38391 hiddenField: false,
38393 onRender : function(ct, position)
38395 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38397 //this.el.dom.removeAttribute('name');
38398 Roo.log("Changing name?");
38399 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38400 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38402 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38403 // prevent input submission
38404 this.hiddenName = this.name;
38411 validateValue : function(value)
38413 value = this.formatDate(value);
38414 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38415 Roo.log('super failed');
38418 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38421 var svalue = value;
38422 value = this.parseDate(value);
38424 Roo.log('parse date failed' + svalue);
38425 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38428 var time = value.getTime();
38429 if(this.minValue && time < this.minValue.getTime()){
38430 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38433 if(this.maxValue && time > this.maxValue.getTime()){
38434 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38437 if(this.disabledDays){
38438 var day = value.getDay();
38439 for(var i = 0; i < this.disabledDays.length; i++) {
38440 if(day === this.disabledDays[i]){
38441 this.markInvalid(this.disabledDaysText);
38446 var fvalue = this.formatDate(value);
38447 if(this.ddMatch && this.ddMatch.test(fvalue)){
38448 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38455 // Provides logic to override the default TriggerField.validateBlur which just returns true
38456 validateBlur : function(){
38457 return !this.menu || !this.menu.isVisible();
38460 getName: function()
38462 // returns hidden if it's set..
38463 if (!this.rendered) {return ''};
38464 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38469 * Returns the current date value of the date field.
38470 * @return {Date} The date value
38472 getValue : function(){
38474 return this.hiddenField ?
38475 this.hiddenField.value :
38476 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38480 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38481 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38482 * (the default format used is "m/d/y").
38485 //All of these calls set the same date value (May 4, 2006)
38487 //Pass a date object:
38488 var dt = new Date('5/4/06');
38489 dateField.setValue(dt);
38491 //Pass a date string (default format):
38492 dateField.setValue('5/4/06');
38494 //Pass a date string (custom format):
38495 dateField.format = 'Y-m-d';
38496 dateField.setValue('2006-5-4');
38498 * @param {String/Date} date The date or valid date string
38500 setValue : function(date){
38501 if (this.hiddenField) {
38502 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38504 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38505 // make sure the value field is always stored as a date..
38506 this.value = this.parseDate(date);
38512 parseDate : function(value){
38513 if(!value || value instanceof Date){
38516 var v = Date.parseDate(value, this.format);
38517 if (!v && this.useIso) {
38518 v = Date.parseDate(value, 'Y-m-d');
38520 if(!v && this.altFormats){
38521 if(!this.altFormatsArray){
38522 this.altFormatsArray = this.altFormats.split("|");
38524 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38525 v = Date.parseDate(value, this.altFormatsArray[i]);
38532 formatDate : function(date, fmt){
38533 return (!date || !(date instanceof Date)) ?
38534 date : date.dateFormat(fmt || this.format);
38539 select: function(m, d){
38542 this.fireEvent('select', this, d);
38544 show : function(){ // retain focus styling
38548 this.focus.defer(10, this);
38549 var ml = this.menuListeners;
38550 this.menu.un("select", ml.select, this);
38551 this.menu.un("show", ml.show, this);
38552 this.menu.un("hide", ml.hide, this);
38557 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38558 onTriggerClick : function(){
38562 if(this.menu == null){
38563 this.menu = new Roo.menu.DateMenu();
38565 Roo.apply(this.menu.picker, {
38566 showClear: this.allowBlank,
38567 minDate : this.minValue,
38568 maxDate : this.maxValue,
38569 disabledDatesRE : this.ddMatch,
38570 disabledDatesText : this.disabledDatesText,
38571 disabledDays : this.disabledDays,
38572 disabledDaysText : this.disabledDaysText,
38573 format : this.useIso ? 'Y-m-d' : this.format,
38574 minText : String.format(this.minText, this.formatDate(this.minValue)),
38575 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38577 this.menu.on(Roo.apply({}, this.menuListeners, {
38580 this.menu.picker.setValue(this.getValue() || new Date());
38581 this.menu.show(this.el, "tl-bl?");
38584 beforeBlur : function(){
38585 var v = this.parseDate(this.getRawValue());
38595 isDirty : function() {
38596 if(this.disabled) {
38600 if(typeof(this.startValue) === 'undefined'){
38604 return String(this.getValue()) !== String(this.startValue);
38609 * Ext JS Library 1.1.1
38610 * Copyright(c) 2006-2007, Ext JS, LLC.
38612 * Originally Released Under LGPL - original licence link has changed is not relivant.
38615 * <script type="text/javascript">
38619 * @class Roo.form.MonthField
38620 * @extends Roo.form.TriggerField
38621 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38623 * Create a new MonthField
38624 * @param {Object} config
38626 Roo.form.MonthField = function(config){
38628 Roo.form.MonthField.superclass.constructor.call(this, config);
38634 * Fires when a date is selected
38635 * @param {Roo.form.MonthFieeld} combo This combo box
38636 * @param {Date} date The date selected
38643 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38644 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38645 this.ddMatch = null;
38646 if(this.disabledDates){
38647 var dd = this.disabledDates;
38649 for(var i = 0; i < dd.length; i++){
38651 if(i != dd.length-1) re += "|";
38653 this.ddMatch = new RegExp(re + ")");
38657 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38659 * @cfg {String} format
38660 * The default date format string which can be overriden for localization support. The format must be
38661 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38665 * @cfg {String} altFormats
38666 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38667 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38669 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38671 * @cfg {Array} disabledDays
38672 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38674 disabledDays : [0,1,2,3,4,5,6],
38676 * @cfg {String} disabledDaysText
38677 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38679 disabledDaysText : "Disabled",
38681 * @cfg {Array} disabledDates
38682 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38683 * expression so they are very powerful. Some examples:
38685 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38686 * <li>["03/08", "09/16"] would disable those days for every year</li>
38687 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38688 * <li>["03/../2006"] would disable every day in March 2006</li>
38689 * <li>["^03"] would disable every day in every March</li>
38691 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38692 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38694 disabledDates : null,
38696 * @cfg {String} disabledDatesText
38697 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38699 disabledDatesText : "Disabled",
38701 * @cfg {Date/String} minValue
38702 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38703 * valid format (defaults to null).
38707 * @cfg {Date/String} maxValue
38708 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38709 * valid format (defaults to null).
38713 * @cfg {String} minText
38714 * The error text to display when the date in the cell is before minValue (defaults to
38715 * 'The date in this field must be after {minValue}').
38717 minText : "The date in this field must be equal to or after {0}",
38719 * @cfg {String} maxTextf
38720 * The error text to display when the date in the cell is after maxValue (defaults to
38721 * 'The date in this field must be before {maxValue}').
38723 maxText : "The date in this field must be equal to or before {0}",
38725 * @cfg {String} invalidText
38726 * The error text to display when the date in the field is invalid (defaults to
38727 * '{value} is not a valid date - it must be in the format {format}').
38729 invalidText : "{0} is not a valid date - it must be in the format {1}",
38731 * @cfg {String} triggerClass
38732 * An additional CSS class used to style the trigger button. The trigger will always get the
38733 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38734 * which displays a calendar icon).
38736 triggerClass : 'x-form-date-trigger',
38740 * @cfg {Boolean} useIso
38741 * if enabled, then the date field will use a hidden field to store the
38742 * real value as iso formated date. default (true)
38746 * @cfg {String/Object} autoCreate
38747 * A DomHelper element spec, or true for a default element spec (defaults to
38748 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38751 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38754 hiddenField: false,
38756 hideMonthPicker : false,
38758 onRender : function(ct, position)
38760 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38762 this.el.dom.removeAttribute('name');
38763 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38765 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38766 // prevent input submission
38767 this.hiddenName = this.name;
38774 validateValue : function(value)
38776 value = this.formatDate(value);
38777 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38780 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38783 var svalue = value;
38784 value = this.parseDate(value);
38786 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38789 var time = value.getTime();
38790 if(this.minValue && time < this.minValue.getTime()){
38791 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38794 if(this.maxValue && time > this.maxValue.getTime()){
38795 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38798 /*if(this.disabledDays){
38799 var day = value.getDay();
38800 for(var i = 0; i < this.disabledDays.length; i++) {
38801 if(day === this.disabledDays[i]){
38802 this.markInvalid(this.disabledDaysText);
38808 var fvalue = this.formatDate(value);
38809 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38810 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38818 // Provides logic to override the default TriggerField.validateBlur which just returns true
38819 validateBlur : function(){
38820 return !this.menu || !this.menu.isVisible();
38824 * Returns the current date value of the date field.
38825 * @return {Date} The date value
38827 getValue : function(){
38831 return this.hiddenField ?
38832 this.hiddenField.value :
38833 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38837 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38838 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38839 * (the default format used is "m/d/y").
38842 //All of these calls set the same date value (May 4, 2006)
38844 //Pass a date object:
38845 var dt = new Date('5/4/06');
38846 monthField.setValue(dt);
38848 //Pass a date string (default format):
38849 monthField.setValue('5/4/06');
38851 //Pass a date string (custom format):
38852 monthField.format = 'Y-m-d';
38853 monthField.setValue('2006-5-4');
38855 * @param {String/Date} date The date or valid date string
38857 setValue : function(date){
38858 Roo.log('month setValue' + date);
38859 // can only be first of month..
38861 var val = this.parseDate(date);
38863 if (this.hiddenField) {
38864 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38866 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38867 this.value = this.parseDate(date);
38871 parseDate : function(value){
38872 if(!value || value instanceof Date){
38873 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38876 var v = Date.parseDate(value, this.format);
38877 if (!v && this.useIso) {
38878 v = Date.parseDate(value, 'Y-m-d');
38882 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38886 if(!v && this.altFormats){
38887 if(!this.altFormatsArray){
38888 this.altFormatsArray = this.altFormats.split("|");
38890 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38891 v = Date.parseDate(value, this.altFormatsArray[i]);
38898 formatDate : function(date, fmt){
38899 return (!date || !(date instanceof Date)) ?
38900 date : date.dateFormat(fmt || this.format);
38905 select: function(m, d){
38907 this.fireEvent('select', this, d);
38909 show : function(){ // retain focus styling
38913 this.focus.defer(10, this);
38914 var ml = this.menuListeners;
38915 this.menu.un("select", ml.select, this);
38916 this.menu.un("show", ml.show, this);
38917 this.menu.un("hide", ml.hide, this);
38921 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38922 onTriggerClick : function(){
38926 if(this.menu == null){
38927 this.menu = new Roo.menu.DateMenu();
38931 Roo.apply(this.menu.picker, {
38933 showClear: this.allowBlank,
38934 minDate : this.minValue,
38935 maxDate : this.maxValue,
38936 disabledDatesRE : this.ddMatch,
38937 disabledDatesText : this.disabledDatesText,
38939 format : this.useIso ? 'Y-m-d' : this.format,
38940 minText : String.format(this.minText, this.formatDate(this.minValue)),
38941 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38944 this.menu.on(Roo.apply({}, this.menuListeners, {
38952 // hide month picker get's called when we called by 'before hide';
38954 var ignorehide = true;
38955 p.hideMonthPicker = function(disableAnim){
38959 if(this.monthPicker){
38960 Roo.log("hideMonthPicker called");
38961 if(disableAnim === true){
38962 this.monthPicker.hide();
38964 this.monthPicker.slideOut('t', {duration:.2});
38965 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
38966 p.fireEvent("select", this, this.value);
38972 Roo.log('picker set value');
38973 Roo.log(this.getValue());
38974 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
38975 m.show(this.el, 'tl-bl?');
38976 ignorehide = false;
38977 // this will trigger hideMonthPicker..
38980 // hidden the day picker
38981 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
38987 p.showMonthPicker.defer(100, p);
38993 beforeBlur : function(){
38994 var v = this.parseDate(this.getRawValue());
39000 /** @cfg {Boolean} grow @hide */
39001 /** @cfg {Number} growMin @hide */
39002 /** @cfg {Number} growMax @hide */
39009 * Ext JS Library 1.1.1
39010 * Copyright(c) 2006-2007, Ext JS, LLC.
39012 * Originally Released Under LGPL - original licence link has changed is not relivant.
39015 * <script type="text/javascript">
39020 * @class Roo.form.ComboBox
39021 * @extends Roo.form.TriggerField
39022 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39024 * Create a new ComboBox.
39025 * @param {Object} config Configuration options
39027 Roo.form.ComboBox = function(config){
39028 Roo.form.ComboBox.superclass.constructor.call(this, config);
39032 * Fires when the dropdown list is expanded
39033 * @param {Roo.form.ComboBox} combo This combo box
39038 * Fires when the dropdown list is collapsed
39039 * @param {Roo.form.ComboBox} combo This combo box
39043 * @event beforeselect
39044 * Fires before a list item is selected. Return false to cancel the selection.
39045 * @param {Roo.form.ComboBox} combo This combo box
39046 * @param {Roo.data.Record} record The data record returned from the underlying store
39047 * @param {Number} index The index of the selected item in the dropdown list
39049 'beforeselect' : true,
39052 * Fires when a list item is selected
39053 * @param {Roo.form.ComboBox} combo This combo box
39054 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39055 * @param {Number} index The index of the selected item in the dropdown list
39059 * @event beforequery
39060 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39061 * The event object passed has these properties:
39062 * @param {Roo.form.ComboBox} combo This combo box
39063 * @param {String} query The query
39064 * @param {Boolean} forceAll true to force "all" query
39065 * @param {Boolean} cancel true to cancel the query
39066 * @param {Object} e The query event object
39068 'beforequery': true,
39071 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39072 * @param {Roo.form.ComboBox} combo This combo box
39077 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39078 * @param {Roo.form.ComboBox} combo This combo box
39079 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39085 if(this.transform){
39086 this.allowDomMove = false;
39087 var s = Roo.getDom(this.transform);
39088 if(!this.hiddenName){
39089 this.hiddenName = s.name;
39092 this.mode = 'local';
39093 var d = [], opts = s.options;
39094 for(var i = 0, len = opts.length;i < len; i++){
39096 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39098 this.value = value;
39100 d.push([value, o.text]);
39102 this.store = new Roo.data.SimpleStore({
39104 fields: ['value', 'text'],
39107 this.valueField = 'value';
39108 this.displayField = 'text';
39110 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39111 if(!this.lazyRender){
39112 this.target = true;
39113 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39114 s.parentNode.removeChild(s); // remove it
39115 this.render(this.el.parentNode);
39117 s.parentNode.removeChild(s); // remove it
39122 this.store = Roo.factory(this.store, Roo.data);
39125 this.selectedIndex = -1;
39126 if(this.mode == 'local'){
39127 if(config.queryDelay === undefined){
39128 this.queryDelay = 10;
39130 if(config.minChars === undefined){
39136 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39138 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39141 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39142 * rendering into an Roo.Editor, defaults to false)
39145 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39146 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39149 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39152 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39153 * the dropdown list (defaults to undefined, with no header element)
39157 * @cfg {String/Roo.Template} tpl The template to use to render the output
39161 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39163 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39165 listWidth: undefined,
39167 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39168 * mode = 'remote' or 'text' if mode = 'local')
39170 displayField: undefined,
39172 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39173 * mode = 'remote' or 'value' if mode = 'local').
39174 * Note: use of a valueField requires the user make a selection
39175 * in order for a value to be mapped.
39177 valueField: undefined,
39181 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39182 * field's data value (defaults to the underlying DOM element's name)
39184 hiddenName: undefined,
39186 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39190 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39192 selectedClass: 'x-combo-selected',
39194 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39195 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39196 * which displays a downward arrow icon).
39198 triggerClass : 'x-form-arrow-trigger',
39200 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39204 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39205 * anchor positions (defaults to 'tl-bl')
39207 listAlign: 'tl-bl?',
39209 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39213 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39214 * query specified by the allQuery config option (defaults to 'query')
39216 triggerAction: 'query',
39218 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39219 * (defaults to 4, does not apply if editable = false)
39223 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39224 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39228 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39229 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39233 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39234 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39238 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39239 * when editable = true (defaults to false)
39241 selectOnFocus:false,
39243 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39245 queryParam: 'query',
39247 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39248 * when mode = 'remote' (defaults to 'Loading...')
39250 loadingText: 'Loading...',
39252 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39256 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39260 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39261 * traditional select (defaults to true)
39265 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39269 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39273 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39274 * listWidth has a higher value)
39278 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39279 * allow the user to set arbitrary text into the field (defaults to false)
39281 forceSelection:false,
39283 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39284 * if typeAhead = true (defaults to 250)
39286 typeAheadDelay : 250,
39288 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39289 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39291 valueNotFoundText : undefined,
39293 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39295 blockFocus : false,
39298 * @cfg {Boolean} disableClear Disable showing of clear button.
39300 disableClear : false,
39302 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39304 alwaysQuery : false,
39310 // element that contains real text value.. (when hidden is used..)
39313 onRender : function(ct, position){
39314 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39315 if(this.hiddenName){
39316 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39318 this.hiddenField.value =
39319 this.hiddenValue !== undefined ? this.hiddenValue :
39320 this.value !== undefined ? this.value : '';
39322 // prevent input submission
39323 this.el.dom.removeAttribute('name');
39328 this.el.dom.setAttribute('autocomplete', 'off');
39331 var cls = 'x-combo-list';
39333 this.list = new Roo.Layer({
39334 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39337 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39338 this.list.setWidth(lw);
39339 this.list.swallowEvent('mousewheel');
39340 this.assetHeight = 0;
39343 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39344 this.assetHeight += this.header.getHeight();
39347 this.innerList = this.list.createChild({cls:cls+'-inner'});
39348 this.innerList.on('mouseover', this.onViewOver, this);
39349 this.innerList.on('mousemove', this.onViewMove, this);
39350 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39352 if(this.allowBlank && !this.pageSize && !this.disableClear){
39353 this.footer = this.list.createChild({cls:cls+'-ft'});
39354 this.pageTb = new Roo.Toolbar(this.footer);
39358 this.footer = this.list.createChild({cls:cls+'-ft'});
39359 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39360 {pageSize: this.pageSize});
39364 if (this.pageTb && this.allowBlank && !this.disableClear) {
39366 this.pageTb.add(new Roo.Toolbar.Fill(), {
39367 cls: 'x-btn-icon x-btn-clear',
39369 handler: function()
39372 _this.clearValue();
39373 _this.onSelect(false, -1);
39378 this.assetHeight += this.footer.getHeight();
39383 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39386 this.view = new Roo.View(this.innerList, this.tpl, {
39387 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39390 this.view.on('click', this.onViewClick, this);
39392 this.store.on('beforeload', this.onBeforeLoad, this);
39393 this.store.on('load', this.onLoad, this);
39394 this.store.on('loadexception', this.onLoadException, this);
39396 if(this.resizable){
39397 this.resizer = new Roo.Resizable(this.list, {
39398 pinned:true, handles:'se'
39400 this.resizer.on('resize', function(r, w, h){
39401 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39402 this.listWidth = w;
39403 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39404 this.restrictHeight();
39406 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39408 if(!this.editable){
39409 this.editable = true;
39410 this.setEditable(false);
39414 if (typeof(this.events.add.listeners) != 'undefined') {
39416 this.addicon = this.wrap.createChild(
39417 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39419 this.addicon.on('click', function(e) {
39420 this.fireEvent('add', this);
39423 if (typeof(this.events.edit.listeners) != 'undefined') {
39425 this.editicon = this.wrap.createChild(
39426 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39427 if (this.addicon) {
39428 this.editicon.setStyle('margin-left', '40px');
39430 this.editicon.on('click', function(e) {
39432 // we fire even if inothing is selected..
39433 this.fireEvent('edit', this, this.lastData );
39443 initEvents : function(){
39444 Roo.form.ComboBox.superclass.initEvents.call(this);
39446 this.keyNav = new Roo.KeyNav(this.el, {
39447 "up" : function(e){
39448 this.inKeyMode = true;
39452 "down" : function(e){
39453 if(!this.isExpanded()){
39454 this.onTriggerClick();
39456 this.inKeyMode = true;
39461 "enter" : function(e){
39462 this.onViewClick();
39466 "esc" : function(e){
39470 "tab" : function(e){
39471 this.onViewClick(false);
39472 this.fireEvent("specialkey", this, e);
39478 doRelay : function(foo, bar, hname){
39479 if(hname == 'down' || this.scope.isExpanded()){
39480 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39487 this.queryDelay = Math.max(this.queryDelay || 10,
39488 this.mode == 'local' ? 10 : 250);
39489 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39490 if(this.typeAhead){
39491 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39493 if(this.editable !== false){
39494 this.el.on("keyup", this.onKeyUp, this);
39496 if(this.forceSelection){
39497 this.on('blur', this.doForce, this);
39501 onDestroy : function(){
39503 this.view.setStore(null);
39504 this.view.el.removeAllListeners();
39505 this.view.el.remove();
39506 this.view.purgeListeners();
39509 this.list.destroy();
39512 this.store.un('beforeload', this.onBeforeLoad, this);
39513 this.store.un('load', this.onLoad, this);
39514 this.store.un('loadexception', this.onLoadException, this);
39516 Roo.form.ComboBox.superclass.onDestroy.call(this);
39520 fireKey : function(e){
39521 if(e.isNavKeyPress() && !this.list.isVisible()){
39522 this.fireEvent("specialkey", this, e);
39527 onResize: function(w, h){
39528 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39530 if(typeof w != 'number'){
39531 // we do not handle it!?!?
39534 var tw = this.trigger.getWidth();
39535 tw += this.addicon ? this.addicon.getWidth() : 0;
39536 tw += this.editicon ? this.editicon.getWidth() : 0;
39538 this.el.setWidth( this.adjustWidth('input', x));
39540 this.trigger.setStyle('left', x+'px');
39542 if(this.list && this.listWidth === undefined){
39543 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39544 this.list.setWidth(lw);
39545 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39553 * Allow or prevent the user from directly editing the field text. If false is passed,
39554 * the user will only be able to select from the items defined in the dropdown list. This method
39555 * is the runtime equivalent of setting the 'editable' config option at config time.
39556 * @param {Boolean} value True to allow the user to directly edit the field text
39558 setEditable : function(value){
39559 if(value == this.editable){
39562 this.editable = value;
39564 this.el.dom.setAttribute('readOnly', true);
39565 this.el.on('mousedown', this.onTriggerClick, this);
39566 this.el.addClass('x-combo-noedit');
39568 this.el.dom.setAttribute('readOnly', false);
39569 this.el.un('mousedown', this.onTriggerClick, this);
39570 this.el.removeClass('x-combo-noedit');
39575 onBeforeLoad : function(){
39576 if(!this.hasFocus){
39579 this.innerList.update(this.loadingText ?
39580 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39581 this.restrictHeight();
39582 this.selectedIndex = -1;
39586 onLoad : function(){
39587 if(!this.hasFocus){
39590 if(this.store.getCount() > 0){
39592 this.restrictHeight();
39593 if(this.lastQuery == this.allQuery){
39595 this.el.dom.select();
39597 if(!this.selectByValue(this.value, true)){
39598 this.select(0, true);
39602 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39603 this.taTask.delay(this.typeAheadDelay);
39607 this.onEmptyResults();
39612 onLoadException : function()
39615 Roo.log(this.store.reader.jsonData);
39616 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39617 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39623 onTypeAhead : function(){
39624 if(this.store.getCount() > 0){
39625 var r = this.store.getAt(0);
39626 var newValue = r.data[this.displayField];
39627 var len = newValue.length;
39628 var selStart = this.getRawValue().length;
39629 if(selStart != len){
39630 this.setRawValue(newValue);
39631 this.selectText(selStart, newValue.length);
39637 onSelect : function(record, index){
39638 if(this.fireEvent('beforeselect', this, record, index) !== false){
39639 this.setFromData(index > -1 ? record.data : false);
39641 this.fireEvent('select', this, record, index);
39646 * Returns the currently selected field value or empty string if no value is set.
39647 * @return {String} value The selected value
39649 getValue : function(){
39650 if(this.valueField){
39651 return typeof this.value != 'undefined' ? this.value : '';
39653 return Roo.form.ComboBox.superclass.getValue.call(this);
39658 * Clears any text/value currently set in the field
39660 clearValue : function(){
39661 if(this.hiddenField){
39662 this.hiddenField.value = '';
39665 this.setRawValue('');
39666 this.lastSelectionText = '';
39671 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39672 * will be displayed in the field. If the value does not match the data value of an existing item,
39673 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39674 * Otherwise the field will be blank (although the value will still be set).
39675 * @param {String} value The value to match
39677 setValue : function(v){
39679 if(this.valueField){
39680 var r = this.findRecord(this.valueField, v);
39682 text = r.data[this.displayField];
39683 }else if(this.valueNotFoundText !== undefined){
39684 text = this.valueNotFoundText;
39687 this.lastSelectionText = text;
39688 if(this.hiddenField){
39689 this.hiddenField.value = v;
39691 Roo.form.ComboBox.superclass.setValue.call(this, text);
39695 * @property {Object} the last set data for the element
39700 * Sets the value of the field based on a object which is related to the record format for the store.
39701 * @param {Object} value the value to set as. or false on reset?
39703 setFromData : function(o){
39704 var dv = ''; // display value
39705 var vv = ''; // value value..
39707 if (this.displayField) {
39708 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39710 // this is an error condition!!!
39711 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39714 if(this.valueField){
39715 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39717 if(this.hiddenField){
39718 this.hiddenField.value = vv;
39720 this.lastSelectionText = dv;
39721 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39725 // no hidden field.. - we store the value in 'value', but still display
39726 // display field!!!!
39727 this.lastSelectionText = dv;
39728 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39734 reset : function(){
39735 // overridden so that last data is reset..
39736 this.setValue(this.resetValue);
39737 this.clearInvalid();
39738 this.lastData = false;
39740 this.view.clearSelections();
39744 findRecord : function(prop, value){
39746 if(this.store.getCount() > 0){
39747 this.store.each(function(r){
39748 if(r.data[prop] == value){
39758 getName: function()
39760 // returns hidden if it's set..
39761 if (!this.rendered) {return ''};
39762 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39766 onViewMove : function(e, t){
39767 this.inKeyMode = false;
39771 onViewOver : function(e, t){
39772 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39775 var item = this.view.findItemFromChild(t);
39777 var index = this.view.indexOf(item);
39778 this.select(index, false);
39783 onViewClick : function(doFocus)
39785 var index = this.view.getSelectedIndexes()[0];
39786 var r = this.store.getAt(index);
39788 this.onSelect(r, index);
39790 if(doFocus !== false && !this.blockFocus){
39796 restrictHeight : function(){
39797 this.innerList.dom.style.height = '';
39798 var inner = this.innerList.dom;
39799 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39800 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39801 this.list.beginUpdate();
39802 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39803 this.list.alignTo(this.el, this.listAlign);
39804 this.list.endUpdate();
39808 onEmptyResults : function(){
39813 * Returns true if the dropdown list is expanded, else false.
39815 isExpanded : function(){
39816 return this.list.isVisible();
39820 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39821 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39822 * @param {String} value The data value of the item to select
39823 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39824 * selected item if it is not currently in view (defaults to true)
39825 * @return {Boolean} True if the value matched an item in the list, else false
39827 selectByValue : function(v, scrollIntoView){
39828 if(v !== undefined && v !== null){
39829 var r = this.findRecord(this.valueField || this.displayField, v);
39831 this.select(this.store.indexOf(r), scrollIntoView);
39839 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39840 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39841 * @param {Number} index The zero-based index of the list item to select
39842 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39843 * selected item if it is not currently in view (defaults to true)
39845 select : function(index, scrollIntoView){
39846 this.selectedIndex = index;
39847 this.view.select(index);
39848 if(scrollIntoView !== false){
39849 var el = this.view.getNode(index);
39851 this.innerList.scrollChildIntoView(el, false);
39857 selectNext : function(){
39858 var ct = this.store.getCount();
39860 if(this.selectedIndex == -1){
39862 }else if(this.selectedIndex < ct-1){
39863 this.select(this.selectedIndex+1);
39869 selectPrev : function(){
39870 var ct = this.store.getCount();
39872 if(this.selectedIndex == -1){
39874 }else if(this.selectedIndex != 0){
39875 this.select(this.selectedIndex-1);
39881 onKeyUp : function(e){
39882 if(this.editable !== false && !e.isSpecialKey()){
39883 this.lastKey = e.getKey();
39884 this.dqTask.delay(this.queryDelay);
39889 validateBlur : function(){
39890 return !this.list || !this.list.isVisible();
39894 initQuery : function(){
39895 this.doQuery(this.getRawValue());
39899 doForce : function(){
39900 if(this.el.dom.value.length > 0){
39901 this.el.dom.value =
39902 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39908 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39909 * query allowing the query action to be canceled if needed.
39910 * @param {String} query The SQL query to execute
39911 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39912 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39913 * saved in the current store (defaults to false)
39915 doQuery : function(q, forceAll){
39916 if(q === undefined || q === null){
39921 forceAll: forceAll,
39925 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39929 forceAll = qe.forceAll;
39930 if(forceAll === true || (q.length >= this.minChars)){
39931 if(this.lastQuery != q || this.alwaysQuery){
39932 this.lastQuery = q;
39933 if(this.mode == 'local'){
39934 this.selectedIndex = -1;
39936 this.store.clearFilter();
39938 this.store.filter(this.displayField, q);
39942 this.store.baseParams[this.queryParam] = q;
39944 params: this.getParams(q)
39949 this.selectedIndex = -1;
39956 getParams : function(q){
39958 //p[this.queryParam] = q;
39961 p.limit = this.pageSize;
39967 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
39969 collapse : function(){
39970 if(!this.isExpanded()){
39974 Roo.get(document).un('mousedown', this.collapseIf, this);
39975 Roo.get(document).un('mousewheel', this.collapseIf, this);
39976 if (!this.editable) {
39977 Roo.get(document).un('keydown', this.listKeyPress, this);
39979 this.fireEvent('collapse', this);
39983 collapseIf : function(e){
39984 if(!e.within(this.wrap) && !e.within(this.list)){
39990 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
39992 expand : function(){
39993 if(this.isExpanded() || !this.hasFocus){
39996 this.list.alignTo(this.el, this.listAlign);
39998 Roo.get(document).on('mousedown', this.collapseIf, this);
39999 Roo.get(document).on('mousewheel', this.collapseIf, this);
40000 if (!this.editable) {
40001 Roo.get(document).on('keydown', this.listKeyPress, this);
40004 this.fireEvent('expand', this);
40008 // Implements the default empty TriggerField.onTriggerClick function
40009 onTriggerClick : function(){
40013 if(this.isExpanded()){
40015 if (!this.blockFocus) {
40020 this.hasFocus = true;
40021 if(this.triggerAction == 'all') {
40022 this.doQuery(this.allQuery, true);
40024 this.doQuery(this.getRawValue());
40026 if (!this.blockFocus) {
40031 listKeyPress : function(e)
40033 //Roo.log('listkeypress');
40034 // scroll to first matching element based on key pres..
40035 if (e.isSpecialKey()) {
40038 var k = String.fromCharCode(e.getKey()).toUpperCase();
40041 var csel = this.view.getSelectedNodes();
40042 var cselitem = false;
40044 var ix = this.view.indexOf(csel[0]);
40045 cselitem = this.store.getAt(ix);
40046 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40052 this.store.each(function(v) {
40054 // start at existing selection.
40055 if (cselitem.id == v.id) {
40061 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40062 match = this.store.indexOf(v);
40067 if (match === false) {
40068 return true; // no more action?
40071 this.view.select(match);
40072 var sn = Roo.get(this.view.getSelectedNodes()[0])
40073 sn.scrollIntoView(sn.dom.parentNode, false);
40077 * @cfg {Boolean} grow
40081 * @cfg {Number} growMin
40085 * @cfg {Number} growMax
40093 * Copyright(c) 2010-2012, Roo J Solutions Limited
40100 * @class Roo.form.ComboBoxArray
40101 * @extends Roo.form.TextField
40102 * A facebook style adder... for lists of email / people / countries etc...
40103 * pick multiple items from a combo box, and shows each one.
40105 * Fred [x] Brian [x] [Pick another |v]
40108 * For this to work: it needs various extra information
40109 * - normal combo problay has
40111 * + displayField, valueField
40113 * For our purpose...
40116 * If we change from 'extends' to wrapping...
40123 * Create a new ComboBoxArray.
40124 * @param {Object} config Configuration options
40128 Roo.form.ComboBoxArray = function(config)
40131 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40133 this.items = new Roo.util.MixedCollection(false);
40135 // construct the child combo...
40145 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40148 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40153 // behavies liek a hiddne field
40154 inputType: 'hidden',
40156 * @cfg {Number} width The width of the box that displays the selected element
40163 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40167 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40169 hiddenName : false,
40172 // private the array of items that are displayed..
40174 // private - the hidden field el.
40176 // private - the filed el..
40179 //validateValue : function() { return true; }, // all values are ok!
40180 //onAddClick: function() { },
40182 onRender : function(ct, position)
40185 // create the standard hidden element
40186 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40189 // give fake names to child combo;
40190 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40191 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40193 this.combo = Roo.factory(this.combo, Roo.form);
40194 this.combo.onRender(ct, position);
40195 if (typeof(this.combo.width) != 'undefined') {
40196 this.combo.onResize(this.combo.width,0);
40199 this.combo.initEvents();
40201 // assigned so form know we need to do this..
40202 this.store = this.combo.store;
40203 this.valueField = this.combo.valueField;
40204 this.displayField = this.combo.displayField ;
40207 this.combo.wrap.addClass('x-cbarray-grp');
40209 var cbwrap = this.combo.wrap.createChild(
40210 {tag: 'div', cls: 'x-cbarray-cb'},
40215 this.hiddenEl = this.combo.wrap.createChild({
40216 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40218 this.el = this.combo.wrap.createChild({
40219 tag: 'input', type:'hidden' , name: this.name, value : ''
40221 // this.el.dom.removeAttribute("name");
40224 this.outerWrap = this.combo.wrap;
40225 this.wrap = cbwrap;
40227 this.outerWrap.setWidth(this.width);
40228 this.outerWrap.dom.removeChild(this.el.dom);
40230 this.wrap.dom.appendChild(this.el.dom);
40231 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40232 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40234 this.combo.trigger.setStyle('position','relative');
40235 this.combo.trigger.setStyle('left', '0px');
40236 this.combo.trigger.setStyle('top', '2px');
40238 this.combo.el.setStyle('vertical-align', 'text-bottom');
40240 //this.trigger.setStyle('vertical-align', 'top');
40242 // this should use the code from combo really... on('add' ....)
40246 this.adder = this.outerWrap.createChild(
40247 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40249 this.adder.on('click', function(e) {
40250 _t.fireEvent('adderclick', this, e);
40254 //this.adder.on('click', this.onAddClick, _t);
40257 this.combo.on('select', function(cb, rec, ix) {
40258 this.addItem(rec.data);
40261 cb.el.dom.value = '';
40262 //cb.lastData = rec.data;
40271 getName: function()
40273 // returns hidden if it's set..
40274 if (!this.rendered) {return ''};
40275 return this.hiddenName ? this.hiddenName : this.name;
40280 onResize: function(w, h){
40283 // not sure if this is needed..
40284 //this.combo.onResize(w,h);
40286 if(typeof w != 'number'){
40287 // we do not handle it!?!?
40290 var tw = this.combo.trigger.getWidth();
40291 tw += this.addicon ? this.addicon.getWidth() : 0;
40292 tw += this.editicon ? this.editicon.getWidth() : 0;
40294 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40296 this.combo.trigger.setStyle('left', '0px');
40298 if(this.list && this.listWidth === undefined){
40299 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40300 this.list.setWidth(lw);
40301 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40308 addItem: function(rec)
40310 var valueField = this.combo.valueField;
40311 var displayField = this.combo.displayField;
40312 if (this.items.indexOfKey(rec[valueField]) > -1) {
40313 //console.log("GOT " + rec.data.id);
40317 var x = new Roo.form.ComboBoxArray.Item({
40318 //id : rec[this.idField],
40320 displayField : displayField ,
40321 tipField : displayField ,
40325 this.items.add(rec[valueField],x);
40326 // add it before the element..
40327 this.updateHiddenEl();
40328 x.render(this.outerWrap, this.wrap.dom);
40329 // add the image handler..
40332 updateHiddenEl : function()
40335 if (!this.hiddenEl) {
40339 var idField = this.combo.valueField;
40341 this.items.each(function(f) {
40342 ar.push(f.data[idField]);
40345 this.hiddenEl.dom.value = ar.join(',');
40351 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40352 this.items.each(function(f) {
40355 this.el.dom.value = '';
40356 if (this.hiddenEl) {
40357 this.hiddenEl.dom.value = '';
40361 getValue: function()
40363 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40365 setValue: function(v) // not a valid action - must use addItems..
40372 if (this.store.isLocal && (typeof(v) == 'string')) {
40373 // then we can use the store to find the values..
40374 // comma seperated at present.. this needs to allow JSON based encoding..
40375 this.hiddenEl.value = v;
40377 Roo.each(v.split(','), function(k) {
40378 Roo.log("CHECK " + this.valueField + ',' + k);
40379 var li = this.store.query(this.valueField, k);
40384 add[this.valueField] = k;
40385 add[this.displayField] = li.item(0).data[this.displayField];
40391 if (typeof(v) == 'object') {
40392 // then let's assume it's an array of objects..
40393 Roo.each(v, function(l) {
40401 setFromData: function(v)
40403 // this recieves an object, if setValues is called.
40405 this.el.dom.value = v[this.displayField];
40406 this.hiddenEl.dom.value = v[this.valueField];
40407 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40410 var kv = v[this.valueField];
40411 var dv = v[this.displayField];
40412 kv = typeof(kv) != 'string' ? '' : kv;
40413 dv = typeof(dv) != 'string' ? '' : dv;
40416 var keys = kv.split(',');
40417 var display = dv.split(',');
40418 for (var i = 0 ; i < keys.length; i++) {
40421 add[this.valueField] = keys[i];
40422 add[this.displayField] = display[i];
40430 * Validates the combox array value
40431 * @return {Boolean} True if the value is valid, else false
40433 validate : function(){
40434 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40435 this.clearInvalid();
40441 validateValue : function(value){
40442 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40450 isDirty : function() {
40451 if(this.disabled) {
40456 var d = Roo.decode(String(this.originalValue));
40458 return String(this.getValue()) !== String(this.originalValue);
40461 var originalValue = [];
40463 for (var i = 0; i < d.length; i++){
40464 originalValue.push(d[i][this.valueField]);
40467 return String(this.getValue()) !== String(originalValue.join(','));
40476 * @class Roo.form.ComboBoxArray.Item
40477 * @extends Roo.BoxComponent
40478 * A selected item in the list
40479 * Fred [x] Brian [x] [Pick another |v]
40482 * Create a new item.
40483 * @param {Object} config Configuration options
40486 Roo.form.ComboBoxArray.Item = function(config) {
40487 config.id = Roo.id();
40488 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40491 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40494 displayField : false,
40498 defaultAutoCreate : {
40500 cls: 'x-cbarray-item',
40507 src : Roo.BLANK_IMAGE_URL ,
40515 onRender : function(ct, position)
40517 Roo.form.Field.superclass.onRender.call(this, ct, position);
40520 var cfg = this.getAutoCreate();
40521 this.el = ct.createChild(cfg, position);
40524 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40526 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40527 this.cb.renderer(this.data) :
40528 String.format('{0}',this.data[this.displayField]);
40531 this.el.child('div').dom.setAttribute('qtip',
40532 String.format('{0}',this.data[this.tipField])
40535 this.el.child('img').on('click', this.remove, this);
40539 remove : function()
40542 this.cb.items.remove(this);
40543 this.el.child('img').un('click', this.remove, this);
40545 this.cb.updateHiddenEl();
40549 * Ext JS Library 1.1.1
40550 * Copyright(c) 2006-2007, Ext JS, LLC.
40552 * Originally Released Under LGPL - original licence link has changed is not relivant.
40555 * <script type="text/javascript">
40558 * @class Roo.form.Checkbox
40559 * @extends Roo.form.Field
40560 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40562 * Creates a new Checkbox
40563 * @param {Object} config Configuration options
40565 Roo.form.Checkbox = function(config){
40566 Roo.form.Checkbox.superclass.constructor.call(this, config);
40570 * Fires when the checkbox is checked or unchecked.
40571 * @param {Roo.form.Checkbox} this This checkbox
40572 * @param {Boolean} checked The new checked value
40578 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40580 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40582 focusClass : undefined,
40584 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40586 fieldClass: "x-form-field",
40588 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40592 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40593 * {tag: "input", type: "checkbox", autocomplete: "off"})
40595 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40597 * @cfg {String} boxLabel The text that appears beside the checkbox
40601 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40605 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40607 valueOff: '0', // value when not checked..
40609 actionMode : 'viewEl',
40612 itemCls : 'x-menu-check-item x-form-item',
40613 groupClass : 'x-menu-group-item',
40614 inputType : 'hidden',
40617 inSetChecked: false, // check that we are not calling self...
40619 inputElement: false, // real input element?
40620 basedOn: false, // ????
40622 isFormField: true, // not sure where this is needed!!!!
40624 onResize : function(){
40625 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40626 if(!this.boxLabel){
40627 this.el.alignTo(this.wrap, 'c-c');
40631 initEvents : function(){
40632 Roo.form.Checkbox.superclass.initEvents.call(this);
40633 this.el.on("click", this.onClick, this);
40634 this.el.on("change", this.onClick, this);
40638 getResizeEl : function(){
40642 getPositionEl : function(){
40647 onRender : function(ct, position){
40648 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40650 if(this.inputValue !== undefined){
40651 this.el.dom.value = this.inputValue;
40654 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40655 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40656 var viewEl = this.wrap.createChild({
40657 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40658 this.viewEl = viewEl;
40659 this.wrap.on('click', this.onClick, this);
40661 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40662 this.el.on('propertychange', this.setFromHidden, this); //ie
40667 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40668 // viewEl.on('click', this.onClick, this);
40670 //if(this.checked){
40671 this.setChecked(this.checked);
40673 //this.checked = this.el.dom;
40679 initValue : Roo.emptyFn,
40682 * Returns the checked state of the checkbox.
40683 * @return {Boolean} True if checked, else false
40685 getValue : function(){
40687 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40689 return this.valueOff;
40694 onClick : function(){
40695 this.setChecked(!this.checked);
40697 //if(this.el.dom.checked != this.checked){
40698 // this.setValue(this.el.dom.checked);
40703 * Sets the checked state of the checkbox.
40704 * On is always based on a string comparison between inputValue and the param.
40705 * @param {Boolean/String} value - the value to set
40706 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40708 setValue : function(v,suppressEvent){
40711 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40712 //if(this.el && this.el.dom){
40713 // this.el.dom.checked = this.checked;
40714 // this.el.dom.defaultChecked = this.checked;
40716 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40717 //this.fireEvent("check", this, this.checked);
40720 setChecked : function(state,suppressEvent)
40722 if (this.inSetChecked) {
40723 this.checked = state;
40729 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40731 this.checked = state;
40732 if(suppressEvent !== true){
40733 this.fireEvent('check', this, state);
40735 this.inSetChecked = true;
40736 this.el.dom.value = state ? this.inputValue : this.valueOff;
40737 this.inSetChecked = false;
40740 // handle setting of hidden value by some other method!!?!?
40741 setFromHidden: function()
40746 //console.log("SET FROM HIDDEN");
40747 //alert('setFrom hidden');
40748 this.setValue(this.el.dom.value);
40751 onDestroy : function()
40754 Roo.get(this.viewEl).remove();
40757 Roo.form.Checkbox.superclass.onDestroy.call(this);
40762 * Ext JS Library 1.1.1
40763 * Copyright(c) 2006-2007, Ext JS, LLC.
40765 * Originally Released Under LGPL - original licence link has changed is not relivant.
40768 * <script type="text/javascript">
40772 * @class Roo.form.Radio
40773 * @extends Roo.form.Checkbox
40774 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40775 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40777 * Creates a new Radio
40778 * @param {Object} config Configuration options
40780 Roo.form.Radio = function(){
40781 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40783 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40784 inputType: 'radio',
40787 * If this radio is part of a group, it will return the selected value
40790 getGroupValue : function(){
40791 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40795 onRender : function(ct, position){
40796 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40798 if(this.inputValue !== undefined){
40799 this.el.dom.value = this.inputValue;
40802 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40803 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40804 //var viewEl = this.wrap.createChild({
40805 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40806 //this.viewEl = viewEl;
40807 //this.wrap.on('click', this.onClick, this);
40809 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40810 //this.el.on('propertychange', this.setFromHidden, this); //ie
40815 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40816 // viewEl.on('click', this.onClick, this);
40819 this.el.dom.checked = 'checked' ;
40825 });//<script type="text/javascript">
40828 * Ext JS Library 1.1.1
40829 * Copyright(c) 2006-2007, Ext JS, LLC.
40830 * licensing@extjs.com
40832 * http://www.extjs.com/license
40838 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
40839 * - IE ? - no idea how much works there.
40847 * @class Ext.form.HtmlEditor
40848 * @extends Ext.form.Field
40849 * Provides a lightweight HTML Editor component.
40851 * This has been tested on Fireforx / Chrome.. IE may not be so great..
40853 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
40854 * supported by this editor.</b><br/><br/>
40855 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
40856 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40858 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
40860 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
40864 * @cfg {String} createLinkText The default text for the create link prompt
40866 createLinkText : 'Please enter the URL for the link:',
40868 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
40870 defaultLinkValue : 'http:/'+'/',
40873 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40878 * @cfg {Number} height (in pixels)
40882 * @cfg {Number} width (in pixels)
40887 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
40890 stylesheets: false,
40895 // private properties
40896 validationEvent : false,
40898 initialized : false,
40900 sourceEditMode : false,
40901 onFocus : Roo.emptyFn,
40903 hideMode:'offsets',
40905 defaultAutoCreate : { // modified by initCompnoent..
40907 style:"width:500px;height:300px;",
40908 autocomplete: "off"
40912 initComponent : function(){
40915 * @event initialize
40916 * Fires when the editor is fully initialized (including the iframe)
40917 * @param {HtmlEditor} this
40922 * Fires when the editor is first receives the focus. Any insertion must wait
40923 * until after this event.
40924 * @param {HtmlEditor} this
40928 * @event beforesync
40929 * Fires before the textarea is updated with content from the editor iframe. Return false
40930 * to cancel the sync.
40931 * @param {HtmlEditor} this
40932 * @param {String} html
40936 * @event beforepush
40937 * Fires before the iframe editor is updated with content from the textarea. Return false
40938 * to cancel the push.
40939 * @param {HtmlEditor} this
40940 * @param {String} html
40945 * Fires when the textarea is updated with content from the editor iframe.
40946 * @param {HtmlEditor} this
40947 * @param {String} html
40952 * Fires when the iframe editor is updated with content from the textarea.
40953 * @param {HtmlEditor} this
40954 * @param {String} html
40958 * @event editmodechange
40959 * Fires when the editor switches edit modes
40960 * @param {HtmlEditor} this
40961 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
40963 editmodechange: true,
40965 * @event editorevent
40966 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40967 * @param {HtmlEditor} this
40971 this.defaultAutoCreate = {
40973 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
40974 autocomplete: "off"
40979 * Protected method that will not generally be called directly. It
40980 * is called when the editor creates its toolbar. Override this method if you need to
40981 * add custom toolbar buttons.
40982 * @param {HtmlEditor} editor
40984 createToolbar : function(editor){
40985 if (!editor.toolbars || !editor.toolbars.length) {
40986 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
40989 for (var i =0 ; i < editor.toolbars.length;i++) {
40990 editor.toolbars[i] = Roo.factory(
40991 typeof(editor.toolbars[i]) == 'string' ?
40992 { xtype: editor.toolbars[i]} : editor.toolbars[i],
40993 Roo.form.HtmlEditor);
40994 editor.toolbars[i].init(editor);
41001 * Protected method that will not generally be called directly. It
41002 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41003 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41005 getDocMarkup : function(){
41008 if (this.stylesheets === false) {
41010 Roo.get(document.head).select('style').each(function(node) {
41011 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41014 Roo.get(document.head).select('link').each(function(node) {
41015 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41018 } else if (!this.stylesheets.length) {
41020 st = '<style type="text/css">' +
41021 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41024 Roo.each(this.stylesheets, function(s) {
41025 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
41030 st += '<style type="text/css">' +
41031 'IMG { cursor: pointer } ' +
41035 return '<html><head>' + st +
41036 //<style type="text/css">' +
41037 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41039 ' </head><body class="roo-htmleditor-body"></body></html>';
41043 onRender : function(ct, position)
41046 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
41047 this.el.dom.style.border = '0 none';
41048 this.el.dom.setAttribute('tabIndex', -1);
41049 this.el.addClass('x-hidden');
41050 if(Roo.isIE){ // fix IE 1px bogus margin
41051 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41053 this.wrap = this.el.wrap({
41054 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
41057 if (this.resizable) {
41058 this.resizeEl = new Roo.Resizable(this.wrap, {
41062 minHeight : this.height,
41063 height: this.height,
41064 handles : this.resizable,
41067 resize : function(r, w, h) {
41068 _t.onResize(w,h); // -something
41075 this.frameId = Roo.id();
41077 this.createToolbar(this);
41081 var iframe = this.wrap.createChild({
41084 name: this.frameId,
41085 frameBorder : 'no',
41086 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41090 // console.log(iframe);
41091 //this.wrap.dom.appendChild(iframe);
41093 this.iframe = iframe.dom;
41095 this.assignDocWin();
41097 this.doc.designMode = 'on';
41100 this.doc.write(this.getDocMarkup());
41104 var task = { // must defer to wait for browser to be ready
41106 //console.log("run task?" + this.doc.readyState);
41107 this.assignDocWin();
41108 if(this.doc.body || this.doc.readyState == 'complete'){
41110 this.doc.designMode="on";
41114 Roo.TaskMgr.stop(task);
41115 this.initEditor.defer(10, this);
41122 Roo.TaskMgr.start(task);
41125 this.setSize(this.wrap.getSize());
41127 if (this.resizeEl) {
41128 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
41129 // should trigger onReize..
41134 onResize : function(w, h)
41136 //Roo.log('resize: ' +w + ',' + h );
41137 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
41138 if(this.el && this.iframe){
41139 if(typeof w == 'number'){
41140 var aw = w - this.wrap.getFrameWidth('lr');
41141 this.el.setWidth(this.adjustWidth('textarea', aw));
41142 this.iframe.style.width = aw + 'px';
41144 if(typeof h == 'number'){
41146 for (var i =0; i < this.toolbars.length;i++) {
41147 // fixme - ask toolbars for heights?
41148 tbh += this.toolbars[i].tb.el.getHeight();
41149 if (this.toolbars[i].footer) {
41150 tbh += this.toolbars[i].footer.el.getHeight();
41157 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
41158 ah -= 5; // knock a few pixes off for look..
41159 this.el.setHeight(this.adjustWidth('textarea', ah));
41160 this.iframe.style.height = ah + 'px';
41162 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
41169 * Toggles the editor between standard and source edit mode.
41170 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41172 toggleSourceEdit : function(sourceEditMode){
41174 this.sourceEditMode = sourceEditMode === true;
41176 if(this.sourceEditMode){
41178 // Roo.log(this.syncValue());
41180 this.iframe.className = 'x-hidden';
41181 this.el.removeClass('x-hidden');
41182 this.el.dom.removeAttribute('tabIndex');
41186 // Roo.log(this.pushValue());
41188 this.iframe.className = '';
41189 this.el.addClass('x-hidden');
41190 this.el.dom.setAttribute('tabIndex', -1);
41193 this.setSize(this.wrap.getSize());
41194 this.fireEvent('editmodechange', this, this.sourceEditMode);
41197 // private used internally
41198 createLink : function(){
41199 var url = prompt(this.createLinkText, this.defaultLinkValue);
41200 if(url && url != 'http:/'+'/'){
41201 this.relayCmd('createlink', url);
41205 // private (for BoxComponent)
41206 adjustSize : Roo.BoxComponent.prototype.adjustSize,
41208 // private (for BoxComponent)
41209 getResizeEl : function(){
41213 // private (for BoxComponent)
41214 getPositionEl : function(){
41219 initEvents : function(){
41220 this.originalValue = this.getValue();
41224 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
41227 markInvalid : Roo.emptyFn,
41229 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
41232 clearInvalid : Roo.emptyFn,
41234 setValue : function(v){
41235 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
41240 * Protected method that will not generally be called directly. If you need/want
41241 * custom HTML cleanup, this is the method you should override.
41242 * @param {String} html The HTML to be cleaned
41243 * return {String} The cleaned HTML
41245 cleanHtml : function(html){
41246 html = String(html);
41247 if(html.length > 5){
41248 if(Roo.isSafari){ // strip safari nonsense
41249 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41252 if(html == ' '){
41259 * Protected method that will not generally be called directly. Syncs the contents
41260 * of the editor iframe with the textarea.
41262 syncValue : function(){
41263 if(this.initialized){
41264 var bd = (this.doc.body || this.doc.documentElement);
41265 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41266 var html = bd.innerHTML;
41268 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41269 var m = bs.match(/text-align:(.*?);/i);
41271 html = '<div style="'+m[0]+'">' + html + '</div>';
41274 html = this.cleanHtml(html);
41275 // fix up the special chars.. normaly like back quotes in word...
41276 // however we do not want to do this with chinese..
41277 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41278 var cc = b.charCodeAt();
41280 (cc >= 0x4E00 && cc < 0xA000 ) ||
41281 (cc >= 0x3400 && cc < 0x4E00 ) ||
41282 (cc >= 0xf900 && cc < 0xfb00 )
41288 if(this.fireEvent('beforesync', this, html) !== false){
41289 this.el.dom.value = html;
41290 this.fireEvent('sync', this, html);
41296 * Protected method that will not generally be called directly. Pushes the value of the textarea
41297 * into the iframe editor.
41299 pushValue : function(){
41300 if(this.initialized){
41301 var v = this.el.dom.value;
41307 if(this.fireEvent('beforepush', this, v) !== false){
41308 var d = (this.doc.body || this.doc.documentElement);
41310 this.cleanUpPaste();
41311 this.el.dom.value = d.innerHTML;
41312 this.fireEvent('push', this, v);
41318 deferFocus : function(){
41319 this.focus.defer(10, this);
41323 focus : function(){
41324 if(this.win && !this.sourceEditMode){
41331 assignDocWin: function()
41333 var iframe = this.iframe;
41336 this.doc = iframe.contentWindow.document;
41337 this.win = iframe.contentWindow;
41339 if (!Roo.get(this.frameId)) {
41342 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41343 this.win = Roo.get(this.frameId).dom.contentWindow;
41348 initEditor : function(){
41349 //console.log("INIT EDITOR");
41350 this.assignDocWin();
41354 this.doc.designMode="on";
41356 this.doc.write(this.getDocMarkup());
41359 var dbody = (this.doc.body || this.doc.documentElement);
41360 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41361 // this copies styles from the containing element into thsi one..
41362 // not sure why we need all of this..
41363 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41364 ss['background-attachment'] = 'fixed'; // w3c
41365 dbody.bgProperties = 'fixed'; // ie
41366 Roo.DomHelper.applyStyles(dbody, ss);
41367 Roo.EventManager.on(this.doc, {
41368 //'mousedown': this.onEditorEvent,
41369 'mouseup': this.onEditorEvent,
41370 'dblclick': this.onEditorEvent,
41371 'click': this.onEditorEvent,
41372 'keyup': this.onEditorEvent,
41377 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41379 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41380 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41382 this.initialized = true;
41384 this.fireEvent('initialize', this);
41389 onDestroy : function(){
41395 for (var i =0; i < this.toolbars.length;i++) {
41396 // fixme - ask toolbars for heights?
41397 this.toolbars[i].onDestroy();
41400 this.wrap.dom.innerHTML = '';
41401 this.wrap.remove();
41406 onFirstFocus : function(){
41408 this.assignDocWin();
41411 this.activated = true;
41412 for (var i =0; i < this.toolbars.length;i++) {
41413 this.toolbars[i].onFirstFocus();
41416 if(Roo.isGecko){ // prevent silly gecko errors
41418 var s = this.win.getSelection();
41419 if(!s.focusNode || s.focusNode.nodeType != 3){
41420 var r = s.getRangeAt(0);
41421 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41426 this.execCmd('useCSS', true);
41427 this.execCmd('styleWithCSS', false);
41430 this.fireEvent('activate', this);
41434 adjustFont: function(btn){
41435 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41436 //if(Roo.isSafari){ // safari
41439 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41440 if(Roo.isSafari){ // safari
41441 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41442 v = (v < 10) ? 10 : v;
41443 v = (v > 48) ? 48 : v;
41444 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41449 v = Math.max(1, v+adjust);
41451 this.execCmd('FontSize', v );
41454 onEditorEvent : function(e){
41455 this.fireEvent('editorevent', this, e);
41456 // this.updateToolbar();
41457 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41460 insertTag : function(tg)
41462 // could be a bit smarter... -> wrap the current selected tRoo..
41463 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41465 range = this.createRange(this.getSelection());
41466 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41467 wrappingNode.appendChild(range.extractContents());
41468 range.insertNode(wrappingNode);
41475 this.execCmd("formatblock", tg);
41479 insertText : function(txt)
41483 var range = this.createRange();
41484 range.deleteContents();
41485 //alert(Sender.getAttribute('label'));
41487 range.insertNode(this.doc.createTextNode(txt));
41491 relayBtnCmd : function(btn){
41492 this.relayCmd(btn.cmd);
41496 * Executes a Midas editor command on the editor document and performs necessary focus and
41497 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41498 * @param {String} cmd The Midas command
41499 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41501 relayCmd : function(cmd, value){
41503 this.execCmd(cmd, value);
41504 this.fireEvent('editorevent', this);
41505 //this.updateToolbar();
41510 * Executes a Midas editor command directly on the editor document.
41511 * For visual commands, you should use {@link #relayCmd} instead.
41512 * <b>This should only be called after the editor is initialized.</b>
41513 * @param {String} cmd The Midas command
41514 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41516 execCmd : function(cmd, value){
41517 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41524 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41526 * @param {String} text | dom node..
41528 insertAtCursor : function(text)
41533 if(!this.activated){
41539 var r = this.doc.selection.createRange();
41550 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41554 // from jquery ui (MIT licenced)
41556 var win = this.win;
41558 if (win.getSelection && win.getSelection().getRangeAt) {
41559 range = win.getSelection().getRangeAt(0);
41560 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41561 range.insertNode(node);
41562 } else if (win.document.selection && win.document.selection.createRange) {
41563 // no firefox support
41564 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41565 win.document.selection.createRange().pasteHTML(txt);
41567 // no firefox support
41568 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41569 this.execCmd('InsertHTML', txt);
41578 mozKeyPress : function(e){
41580 var c = e.getCharCode(), cmd;
41583 c = String.fromCharCode(c).toLowerCase();
41597 this.cleanUpPaste.defer(100, this);
41605 e.preventDefault();
41613 fixKeys : function(){ // load time branching for fastest keydown performance
41615 return function(e){
41616 var k = e.getKey(), r;
41619 r = this.doc.selection.createRange();
41622 r.pasteHTML('    ');
41629 r = this.doc.selection.createRange();
41631 var target = r.parentElement();
41632 if(!target || target.tagName.toLowerCase() != 'li'){
41634 r.pasteHTML('<br />');
41640 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41641 this.cleanUpPaste.defer(100, this);
41647 }else if(Roo.isOpera){
41648 return function(e){
41649 var k = e.getKey();
41653 this.execCmd('InsertHTML','    ');
41656 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41657 this.cleanUpPaste.defer(100, this);
41662 }else if(Roo.isSafari){
41663 return function(e){
41664 var k = e.getKey();
41668 this.execCmd('InsertText','\t');
41672 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41673 this.cleanUpPaste.defer(100, this);
41681 getAllAncestors: function()
41683 var p = this.getSelectedNode();
41686 a.push(p); // push blank onto stack..
41687 p = this.getParentElement();
41691 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41695 a.push(this.doc.body);
41699 lastSelNode : false,
41702 getSelection : function()
41704 this.assignDocWin();
41705 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41708 getSelectedNode: function()
41710 // this may only work on Gecko!!!
41712 // should we cache this!!!!
41717 var range = this.createRange(this.getSelection()).cloneRange();
41720 var parent = range.parentElement();
41722 var testRange = range.duplicate();
41723 testRange.moveToElementText(parent);
41724 if (testRange.inRange(range)) {
41727 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41730 parent = parent.parentElement;
41735 // is ancestor a text element.
41736 var ac = range.commonAncestorContainer;
41737 if (ac.nodeType == 3) {
41738 ac = ac.parentNode;
41741 var ar = ac.childNodes;
41744 var other_nodes = [];
41745 var has_other_nodes = false;
41746 for (var i=0;i<ar.length;i++) {
41747 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41750 // fullly contained node.
41752 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41757 // probably selected..
41758 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41759 other_nodes.push(ar[i]);
41763 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41768 has_other_nodes = true;
41770 if (!nodes.length && other_nodes.length) {
41771 nodes= other_nodes;
41773 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41779 createRange: function(sel)
41781 // this has strange effects when using with
41782 // top toolbar - not sure if it's a great idea.
41783 //this.editor.contentWindow.focus();
41784 if (typeof sel != "undefined") {
41786 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41788 return this.doc.createRange();
41791 return this.doc.createRange();
41794 getParentElement: function()
41797 this.assignDocWin();
41798 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41800 var range = this.createRange(sel);
41803 var p = range.commonAncestorContainer;
41804 while (p.nodeType == 3) { // text node
41815 * Range intersection.. the hard stuff...
41819 * [ -- selected range --- ]
41823 * if end is before start or hits it. fail.
41824 * if start is after end or hits it fail.
41826 * if either hits (but other is outside. - then it's not
41832 // @see http://www.thismuchiknow.co.uk/?p=64.
41833 rangeIntersectsNode : function(range, node)
41835 var nodeRange = node.ownerDocument.createRange();
41837 nodeRange.selectNode(node);
41839 nodeRange.selectNodeContents(node);
41842 var rangeStartRange = range.cloneRange();
41843 rangeStartRange.collapse(true);
41845 var rangeEndRange = range.cloneRange();
41846 rangeEndRange.collapse(false);
41848 var nodeStartRange = nodeRange.cloneRange();
41849 nodeStartRange.collapse(true);
41851 var nodeEndRange = nodeRange.cloneRange();
41852 nodeEndRange.collapse(false);
41854 return rangeStartRange.compareBoundaryPoints(
41855 Range.START_TO_START, nodeEndRange) == -1 &&
41856 rangeEndRange.compareBoundaryPoints(
41857 Range.START_TO_START, nodeStartRange) == 1;
41861 rangeCompareNode : function(range, node)
41863 var nodeRange = node.ownerDocument.createRange();
41865 nodeRange.selectNode(node);
41867 nodeRange.selectNodeContents(node);
41871 range.collapse(true);
41873 nodeRange.collapse(true);
41875 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41876 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41878 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41880 var nodeIsBefore = ss == 1;
41881 var nodeIsAfter = ee == -1;
41883 if (nodeIsBefore && nodeIsAfter)
41885 if (!nodeIsBefore && nodeIsAfter)
41886 return 1; //right trailed.
41888 if (nodeIsBefore && !nodeIsAfter)
41889 return 2; // left trailed.
41894 // private? - in a new class?
41895 cleanUpPaste : function()
41897 // cleans up the whole document..
41898 Roo.log('cleanuppaste');
41899 this.cleanUpChildren(this.doc.body);
41900 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41901 if (clean != this.doc.body.innerHTML) {
41902 this.doc.body.innerHTML = clean;
41907 cleanWordChars : function(input) {// change the chars to hex code
41908 var he = Roo.form.HtmlEditor;
41910 var output = input;
41911 Roo.each(he.swapCodes, function(sw) {
41912 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41914 output = output.replace(swapper, sw[1]);
41921 cleanUpChildren : function (n)
41923 if (!n.childNodes.length) {
41926 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41927 this.cleanUpChild(n.childNodes[i]);
41934 cleanUpChild : function (node)
41937 //console.log(node);
41938 if (node.nodeName == "#text") {
41939 // clean up silly Windows -- stuff?
41942 if (node.nodeName == "#comment") {
41943 node.parentNode.removeChild(node);
41944 // clean up silly Windows -- stuff?
41948 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
41950 node.parentNode.removeChild(node);
41955 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
41957 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41958 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41960 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41961 // remove_keep_children = true;
41964 if (remove_keep_children) {
41965 this.cleanUpChildren(node);
41966 // inserts everything just before this node...
41967 while (node.childNodes.length) {
41968 var cn = node.childNodes[0];
41969 node.removeChild(cn);
41970 node.parentNode.insertBefore(cn, node);
41972 node.parentNode.removeChild(node);
41976 if (!node.attributes || !node.attributes.length) {
41977 this.cleanUpChildren(node);
41981 function cleanAttr(n,v)
41984 if (v.match(/^\./) || v.match(/^\//)) {
41987 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41990 if (v.match(/^#/)) {
41993 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41994 node.removeAttribute(n);
41998 function cleanStyle(n,v)
42000 if (v.match(/expression/)) { //XSS?? should we even bother..
42001 node.removeAttribute(n);
42004 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.form.HtmlEditor.cwhite : ed.cwhite;
42005 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.form.HtmlEditor.cblack : ed.cblack;
42008 var parts = v.split(/;/);
42011 Roo.each(parts, function(p) {
42012 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42016 var l = p.split(':').shift().replace(/\s+/g,'');
42017 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42020 if ( cblack.indexOf(l) > -1) {
42021 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42022 //node.removeAttribute(n);
42026 // only allow 'c whitelisted system attributes'
42027 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42028 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42029 //node.removeAttribute(n);
42039 if (clean.length) {
42040 node.setAttribute(n, clean.join(';'));
42042 node.removeAttribute(n);
42048 for (var i = node.attributes.length-1; i > -1 ; i--) {
42049 var a = node.attributes[i];
42052 if (a.name.toLowerCase().substr(0,2)=='on') {
42053 node.removeAttribute(a.name);
42056 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
42057 node.removeAttribute(a.name);
42060 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
42061 cleanAttr(a.name,a.value); // fixme..
42064 if (a.name == 'style') {
42065 cleanStyle(a.name,a.value);
42068 /// clean up MS crap..
42069 // tecnically this should be a list of valid class'es..
42072 if (a.name == 'class') {
42073 if (a.value.match(/^Mso/)) {
42074 node.className = '';
42077 if (a.value.match(/body/)) {
42078 node.className = '';
42089 this.cleanUpChildren(node);
42095 // hide stuff that is not compatible
42109 * @event specialkey
42113 * @cfg {String} fieldClass @hide
42116 * @cfg {String} focusClass @hide
42119 * @cfg {String} autoCreate @hide
42122 * @cfg {String} inputType @hide
42125 * @cfg {String} invalidClass @hide
42128 * @cfg {String} invalidText @hide
42131 * @cfg {String} msgFx @hide
42134 * @cfg {String} validateOnBlur @hide
42138 Roo.form.HtmlEditor.white = [
42139 'area', 'br', 'img', 'input', 'hr', 'wbr',
42141 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42142 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42143 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42144 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42145 'table', 'ul', 'xmp',
42147 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42150 'dir', 'menu', 'ol', 'ul', 'dl',
42156 Roo.form.HtmlEditor.black = [
42157 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42159 'base', 'basefont', 'bgsound', 'blink', 'body',
42160 'frame', 'frameset', 'head', 'html', 'ilayer',
42161 'iframe', 'layer', 'link', 'meta', 'object',
42162 'script', 'style' ,'title', 'xml' // clean later..
42164 Roo.form.HtmlEditor.clean = [
42165 'script', 'style', 'title', 'xml'
42167 Roo.form.HtmlEditor.remove = [
42172 Roo.form.HtmlEditor.ablack = [
42176 Roo.form.HtmlEditor.aclean = [
42177 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42181 Roo.form.HtmlEditor.pwhite= [
42182 'http', 'https', 'mailto'
42185 // white listed style attributes.
42186 Roo.form.HtmlEditor.cwhite= [
42187 // 'text-align', /// default is to allow most things..
42193 // black listed style attributes.
42194 Roo.form.HtmlEditor.cblack= [
42195 // 'font-size' -- this can be set by the project
42199 Roo.form.HtmlEditor.swapCodes =[
42210 // <script type="text/javascript">
42213 * Ext JS Library 1.1.1
42214 * Copyright(c) 2006-2007, Ext JS, LLC.
42220 * @class Roo.form.HtmlEditorToolbar1
42225 new Roo.form.HtmlEditor({
42228 new Roo.form.HtmlEditorToolbar1({
42229 disable : { fonts: 1 , format: 1, ..., ... , ...],
42235 * @cfg {Object} disable List of elements to disable..
42236 * @cfg {Array} btns List of additional buttons.
42240 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
42243 Roo.form.HtmlEditor.ToolbarStandard = function(config)
42246 Roo.apply(this, config);
42248 // default disabled, based on 'good practice'..
42249 this.disable = this.disable || {};
42250 Roo.applyIf(this.disable, {
42253 specialElements : true
42257 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42258 // dont call parent... till later.
42261 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
42269 * @cfg {Object} disable List of toolbar elements to disable
42274 * @cfg {Array} fontFamilies An array of available font families
42292 // "á" , ?? a acute?
42297 "°" // , // degrees
42299 // "é" , // e ecute
42300 // "ú" , // u ecute?
42303 specialElements : [
42305 text: "Insert Table",
42308 ihtml : '<table><tr><td>Cell</td></tr></table>'
42312 text: "Insert Image",
42315 ihtml : '<img src="about:blank"/>'
42324 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
42325 "input:submit", "input:button", "select", "textarea", "label" ],
42328 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
42330 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
42338 * @cfg {String} defaultFont default font to use.
42340 defaultFont: 'tahoma',
42342 fontSelect : false,
42345 formatCombo : false,
42347 init : function(editor)
42349 this.editor = editor;
42352 var fid = editor.frameId;
42354 function btn(id, toggle, handler){
42355 var xid = fid + '-'+ id ;
42359 cls : 'x-btn-icon x-edit-'+id,
42360 enableToggle:toggle !== false,
42361 scope: editor, // was editor...
42362 handler:handler||editor.relayBtnCmd,
42363 clickEvent:'mousedown',
42364 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42371 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
42373 // stop form submits
42374 tb.el.on('click', function(e){
42375 e.preventDefault(); // what does this do?
42378 if(!this.disable.font) { // && !Roo.isSafari){
42379 /* why no safari for fonts
42380 editor.fontSelect = tb.el.createChild({
42383 cls:'x-font-select',
42384 html: this.createFontOptions()
42387 editor.fontSelect.on('change', function(){
42388 var font = editor.fontSelect.dom.value;
42389 editor.relayCmd('fontname', font);
42390 editor.deferFocus();
42394 editor.fontSelect.dom,
42400 if(!this.disable.formats){
42401 this.formatCombo = new Roo.form.ComboBox({
42402 store: new Roo.data.SimpleStore({
42405 data : this.formats // from states.js
42409 //autoCreate : {tag: "div", size: "20"},
42410 displayField:'tag',
42414 triggerAction: 'all',
42415 emptyText:'Add tag',
42416 selectOnFocus:true,
42419 'select': function(c, r, i) {
42420 editor.insertTag(r.get('tag'));
42426 tb.addField(this.formatCombo);
42430 if(!this.disable.format){
42437 if(!this.disable.fontSize){
42442 btn('increasefontsize', false, editor.adjustFont),
42443 btn('decreasefontsize', false, editor.adjustFont)
42448 if(!this.disable.colors){
42451 id:editor.frameId +'-forecolor',
42452 cls:'x-btn-icon x-edit-forecolor',
42453 clickEvent:'mousedown',
42454 tooltip: this.buttonTips['forecolor'] || undefined,
42456 menu : new Roo.menu.ColorMenu({
42457 allowReselect: true,
42458 focus: Roo.emptyFn,
42461 selectHandler: function(cp, color){
42462 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
42463 editor.deferFocus();
42466 clickEvent:'mousedown'
42469 id:editor.frameId +'backcolor',
42470 cls:'x-btn-icon x-edit-backcolor',
42471 clickEvent:'mousedown',
42472 tooltip: this.buttonTips['backcolor'] || undefined,
42474 menu : new Roo.menu.ColorMenu({
42475 focus: Roo.emptyFn,
42478 allowReselect: true,
42479 selectHandler: function(cp, color){
42481 editor.execCmd('useCSS', false);
42482 editor.execCmd('hilitecolor', color);
42483 editor.execCmd('useCSS', true);
42484 editor.deferFocus();
42486 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
42487 Roo.isSafari || Roo.isIE ? '#'+color : color);
42488 editor.deferFocus();
42492 clickEvent:'mousedown'
42497 // now add all the items...
42500 if(!this.disable.alignments){
42503 btn('justifyleft'),
42504 btn('justifycenter'),
42505 btn('justifyright')
42509 //if(!Roo.isSafari){
42510 if(!this.disable.links){
42513 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
42517 if(!this.disable.lists){
42520 btn('insertorderedlist'),
42521 btn('insertunorderedlist')
42524 if(!this.disable.sourceEdit){
42527 btn('sourceedit', true, function(btn){
42528 this.toggleSourceEdit(btn.pressed);
42535 // special menu.. - needs to be tidied up..
42536 if (!this.disable.special) {
42539 cls: 'x-edit-none',
42545 for (var i =0; i < this.specialChars.length; i++) {
42546 smenu.menu.items.push({
42548 html: this.specialChars[i],
42549 handler: function(a,b) {
42550 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
42551 //editor.insertAtCursor(a.html);
42565 if (!this.disable.cleanStyles) {
42567 cls: 'x-btn-icon x-btn-clear',
42573 for (var i =0; i < this.cleanStyles.length; i++) {
42574 cmenu.menu.items.push({
42575 actiontype : this.cleanStyles[i],
42576 html: 'Remove ' + this.cleanStyles[i],
42577 handler: function(a,b) {
42580 var c = Roo.get(editor.doc.body);
42581 c.select('[style]').each(function(s) {
42582 s.dom.style.removeProperty(a.actiontype);
42593 if (!this.disable.specialElements) {
42596 cls: 'x-edit-none',
42601 for (var i =0; i < this.specialElements.length; i++) {
42602 semenu.menu.items.push(
42604 handler: function(a,b) {
42605 editor.insertAtCursor(this.ihtml);
42607 }, this.specialElements[i])
42619 for(var i =0; i< this.btns.length;i++) {
42620 var b = Roo.factory(this.btns[i],Roo.form);
42621 b.cls = 'x-edit-none';
42630 // disable everything...
42632 this.tb.items.each(function(item){
42633 if(item.id != editor.frameId+ '-sourceedit'){
42637 this.rendered = true;
42639 // the all the btns;
42640 editor.on('editorevent', this.updateToolbar, this);
42641 // other toolbars need to implement this..
42642 //editor.on('editmodechange', this.updateToolbar, this);
42648 * Protected method that will not generally be called directly. It triggers
42649 * a toolbar update by reading the markup state of the current selection in the editor.
42651 updateToolbar: function(){
42653 if(!this.editor.activated){
42654 this.editor.onFirstFocus();
42658 var btns = this.tb.items.map,
42659 doc = this.editor.doc,
42660 frameId = this.editor.frameId;
42662 if(!this.disable.font && !Roo.isSafari){
42664 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
42665 if(name != this.fontSelect.dom.value){
42666 this.fontSelect.dom.value = name;
42670 if(!this.disable.format){
42671 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
42672 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
42673 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
42675 if(!this.disable.alignments){
42676 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
42677 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
42678 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
42680 if(!Roo.isSafari && !this.disable.lists){
42681 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
42682 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
42685 var ans = this.editor.getAllAncestors();
42686 if (this.formatCombo) {
42689 var store = this.formatCombo.store;
42690 this.formatCombo.setValue("");
42691 for (var i =0; i < ans.length;i++) {
42692 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
42694 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
42702 // hides menus... - so this cant be on a menu...
42703 Roo.menu.MenuMgr.hideAll();
42705 //this.editorsyncValue();
42709 createFontOptions : function(){
42710 var buf = [], fs = this.fontFamilies, ff, lc;
42714 for(var i = 0, len = fs.length; i< len; i++){
42716 lc = ff.toLowerCase();
42718 '<option value="',lc,'" style="font-family:',ff,';"',
42719 (this.defaultFont == lc ? ' selected="true">' : '>'),
42724 return buf.join('');
42727 toggleSourceEdit : function(sourceEditMode){
42728 if(sourceEditMode === undefined){
42729 sourceEditMode = !this.sourceEditMode;
42731 this.sourceEditMode = sourceEditMode === true;
42732 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
42733 // just toggle the button?
42734 if(btn.pressed !== this.editor.sourceEditMode){
42735 btn.toggle(this.editor.sourceEditMode);
42739 if(this.sourceEditMode){
42740 this.tb.items.each(function(item){
42741 if(item.cmd != 'sourceedit'){
42747 if(this.initialized){
42748 this.tb.items.each(function(item){
42754 // tell the editor that it's been pressed..
42755 this.editor.toggleSourceEdit(sourceEditMode);
42759 * Object collection of toolbar tooltips for the buttons in the editor. The key
42760 * is the command id associated with that button and the value is a valid QuickTips object.
42765 title: 'Bold (Ctrl+B)',
42766 text: 'Make the selected text bold.',
42767 cls: 'x-html-editor-tip'
42770 title: 'Italic (Ctrl+I)',
42771 text: 'Make the selected text italic.',
42772 cls: 'x-html-editor-tip'
42780 title: 'Bold (Ctrl+B)',
42781 text: 'Make the selected text bold.',
42782 cls: 'x-html-editor-tip'
42785 title: 'Italic (Ctrl+I)',
42786 text: 'Make the selected text italic.',
42787 cls: 'x-html-editor-tip'
42790 title: 'Underline (Ctrl+U)',
42791 text: 'Underline the selected text.',
42792 cls: 'x-html-editor-tip'
42794 increasefontsize : {
42795 title: 'Grow Text',
42796 text: 'Increase the font size.',
42797 cls: 'x-html-editor-tip'
42799 decreasefontsize : {
42800 title: 'Shrink Text',
42801 text: 'Decrease the font size.',
42802 cls: 'x-html-editor-tip'
42805 title: 'Text Highlight Color',
42806 text: 'Change the background color of the selected text.',
42807 cls: 'x-html-editor-tip'
42810 title: 'Font Color',
42811 text: 'Change the color of the selected text.',
42812 cls: 'x-html-editor-tip'
42815 title: 'Align Text Left',
42816 text: 'Align text to the left.',
42817 cls: 'x-html-editor-tip'
42820 title: 'Center Text',
42821 text: 'Center text in the editor.',
42822 cls: 'x-html-editor-tip'
42825 title: 'Align Text Right',
42826 text: 'Align text to the right.',
42827 cls: 'x-html-editor-tip'
42829 insertunorderedlist : {
42830 title: 'Bullet List',
42831 text: 'Start a bulleted list.',
42832 cls: 'x-html-editor-tip'
42834 insertorderedlist : {
42835 title: 'Numbered List',
42836 text: 'Start a numbered list.',
42837 cls: 'x-html-editor-tip'
42840 title: 'Hyperlink',
42841 text: 'Make the selected text a hyperlink.',
42842 cls: 'x-html-editor-tip'
42845 title: 'Source Edit',
42846 text: 'Switch to source editing mode.',
42847 cls: 'x-html-editor-tip'
42851 onDestroy : function(){
42854 this.tb.items.each(function(item){
42856 item.menu.removeAll();
42858 item.menu.el.destroy();
42866 onFirstFocus: function() {
42867 this.tb.items.each(function(item){
42876 // <script type="text/javascript">
42879 * Ext JS Library 1.1.1
42880 * Copyright(c) 2006-2007, Ext JS, LLC.
42887 * @class Roo.form.HtmlEditor.ToolbarContext
42892 new Roo.form.HtmlEditor({
42895 { xtype: 'ToolbarStandard', styles : {} }
42896 { xtype: 'ToolbarContext', disable : {} }
42902 * @config : {Object} disable List of elements to disable.. (not done yet.)
42903 * @config : {Object} styles Map of styles available.
42907 Roo.form.HtmlEditor.ToolbarContext = function(config)
42910 Roo.apply(this, config);
42911 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42912 // dont call parent... till later.
42913 this.styles = this.styles || {};
42918 Roo.form.HtmlEditor.ToolbarContext.types = {
42930 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
42996 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
43001 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
43011 style : 'fontFamily',
43012 displayField: 'display',
43013 optname : 'font-family',
43062 // should we really allow this??
43063 // should this just be
43074 style : 'fontFamily',
43075 displayField: 'display',
43076 optname : 'font-family',
43083 style : 'fontFamily',
43084 displayField: 'display',
43085 optname : 'font-family',
43092 style : 'fontFamily',
43093 displayField: 'display',
43094 optname : 'font-family',
43105 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
43106 Roo.form.HtmlEditor.ToolbarContext.stores = false;
43108 Roo.form.HtmlEditor.ToolbarContext.options = {
43110 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
43111 [ 'Courier New', 'Courier New'],
43112 [ 'Tahoma', 'Tahoma'],
43113 [ 'Times New Roman,serif', 'Times'],
43114 [ 'Verdana','Verdana' ]
43118 // fixme - these need to be configurable..
43121 Roo.form.HtmlEditor.ToolbarContext.types
43124 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
43132 * @cfg {Object} disable List of toolbar elements to disable
43137 * @cfg {Object} styles List of styles
43138 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
43140 * These must be defined in the page, so they get rendered correctly..
43151 init : function(editor)
43153 this.editor = editor;
43156 var fid = editor.frameId;
43158 function btn(id, toggle, handler){
43159 var xid = fid + '-'+ id ;
43163 cls : 'x-btn-icon x-edit-'+id,
43164 enableToggle:toggle !== false,
43165 scope: editor, // was editor...
43166 handler:handler||editor.relayBtnCmd,
43167 clickEvent:'mousedown',
43168 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43172 // create a new element.
43173 var wdiv = editor.wrap.createChild({
43175 }, editor.wrap.dom.firstChild.nextSibling, true);
43177 // can we do this more than once??
43179 // stop form submits
43182 // disable everything...
43183 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43184 this.toolbars = {};
43186 for (var i in ty) {
43188 this.toolbars[i] = this.buildToolbar(ty[i],i);
43190 this.tb = this.toolbars.BODY;
43192 this.buildFooter();
43193 this.footer.show();
43194 editor.on('hide', function( ) { this.footer.hide() }, this);
43195 editor.on('show', function( ) { this.footer.show() }, this);
43198 this.rendered = true;
43200 // the all the btns;
43201 editor.on('editorevent', this.updateToolbar, this);
43202 // other toolbars need to implement this..
43203 //editor.on('editmodechange', this.updateToolbar, this);
43209 * Protected method that will not generally be called directly. It triggers
43210 * a toolbar update by reading the markup state of the current selection in the editor.
43212 updateToolbar: function(editor,ev,sel){
43215 // capture mouse up - this is handy for selecting images..
43216 // perhaps should go somewhere else...
43217 if(!this.editor.activated){
43218 this.editor.onFirstFocus();
43222 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
43223 // selectNode - might want to handle IE?
43225 (ev.type == 'mouseup' || ev.type == 'click' ) &&
43226 ev.target && ev.target.tagName == 'IMG') {
43227 // they have click on an image...
43228 // let's see if we can change the selection...
43231 var nodeRange = sel.ownerDocument.createRange();
43233 nodeRange.selectNode(sel);
43235 nodeRange.selectNodeContents(sel);
43237 //nodeRange.collapse(true);
43238 var s = editor.win.getSelection();
43239 s.removeAllRanges();
43240 s.addRange(nodeRange);
43244 var updateFooter = sel ? false : true;
43247 var ans = this.editor.getAllAncestors();
43250 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43253 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
43254 sel = sel ? sel : this.editor.doc.body;
43255 sel = sel.tagName.length ? sel : this.editor.doc.body;
43258 // pick a menu that exists..
43259 var tn = sel.tagName.toUpperCase();
43260 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
43262 tn = sel.tagName.toUpperCase();
43264 var lastSel = this.tb.selectedNode
43266 this.tb.selectedNode = sel;
43268 // if current menu does not match..
43269 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
43272 ///console.log("show: " + tn);
43273 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
43276 this.tb.items.first().el.innerHTML = tn + ': ';
43279 // update attributes
43280 if (this.tb.fields) {
43281 this.tb.fields.each(function(e) {
43283 e.setValue(sel.style[e.stylename]);
43286 e.setValue(sel.getAttribute(e.attrname));
43290 var hasStyles = false;
43291 for(var i in this.styles) {
43298 var st = this.tb.fields.item(0);
43300 st.store.removeAll();
43303 var cn = sel.className.split(/\s+/);
43306 if (this.styles['*']) {
43308 Roo.each(this.styles['*'], function(v) {
43309 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43312 if (this.styles[tn]) {
43313 Roo.each(this.styles[tn], function(v) {
43314 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43318 st.store.loadData(avs);
43322 // flag our selected Node.
43323 this.tb.selectedNode = sel;
43326 Roo.menu.MenuMgr.hideAll();
43330 if (!updateFooter) {
43331 //this.footDisp.dom.innerHTML = '';
43334 // update the footer
43338 this.footerEls = ans.reverse();
43339 Roo.each(this.footerEls, function(a,i) {
43340 if (!a) { return; }
43341 html += html.length ? ' > ' : '';
43343 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
43348 var sz = this.footDisp.up('td').getSize();
43349 this.footDisp.dom.style.width = (sz.width -10) + 'px';
43350 this.footDisp.dom.style.marginLeft = '5px';
43352 this.footDisp.dom.style.overflow = 'hidden';
43354 this.footDisp.dom.innerHTML = html;
43356 //this.editorsyncValue();
43363 onDestroy : function(){
43366 this.tb.items.each(function(item){
43368 item.menu.removeAll();
43370 item.menu.el.destroy();
43378 onFirstFocus: function() {
43379 // need to do this for all the toolbars..
43380 this.tb.items.each(function(item){
43384 buildToolbar: function(tlist, nm)
43386 var editor = this.editor;
43387 // create a new element.
43388 var wdiv = editor.wrap.createChild({
43390 }, editor.wrap.dom.firstChild.nextSibling, true);
43393 var tb = new Roo.Toolbar(wdiv);
43396 tb.add(nm+ ": ");
43399 for(var i in this.styles) {
43404 if (styles && styles.length) {
43406 // this needs a multi-select checkbox...
43407 tb.addField( new Roo.form.ComboBox({
43408 store: new Roo.data.SimpleStore({
43410 fields: ['val', 'selected'],
43413 name : '-roo-edit-className',
43414 attrname : 'className',
43415 displayField: 'val',
43419 triggerAction: 'all',
43420 emptyText:'Select Style',
43421 selectOnFocus:true,
43424 'select': function(c, r, i) {
43425 // initial support only for on class per el..
43426 tb.selectedNode.className = r ? r.get('val') : '';
43427 editor.syncValue();
43434 var tbc = Roo.form.HtmlEditor.ToolbarContext;
43435 var tbops = tbc.options;
43437 for (var i in tlist) {
43439 var item = tlist[i];
43440 tb.add(item.title + ": ");
43443 //optname == used so you can configure the options available..
43444 var opts = item.opts ? item.opts : false;
43445 if (item.optname) {
43446 opts = tbops[item.optname];
43451 // opts == pulldown..
43452 tb.addField( new Roo.form.ComboBox({
43453 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
43455 fields: ['val', 'display'],
43458 name : '-roo-edit-' + i,
43460 stylename : item.style ? item.style : false,
43461 displayField: item.displayField ? item.displayField : 'val',
43462 valueField : 'val',
43464 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
43466 triggerAction: 'all',
43467 emptyText:'Select',
43468 selectOnFocus:true,
43469 width: item.width ? item.width : 130,
43471 'select': function(c, r, i) {
43473 tb.selectedNode.style[c.stylename] = r.get('val');
43476 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
43485 tb.addField( new Roo.form.TextField({
43488 //allowBlank:false,
43493 tb.addField( new Roo.form.TextField({
43494 name: '-roo-edit-' + i,
43501 'change' : function(f, nv, ov) {
43502 tb.selectedNode.setAttribute(f.attrname, nv);
43511 text: 'Remove Tag',
43514 click : function ()
43517 // undo does not work.
43519 var sn = tb.selectedNode;
43521 var pn = sn.parentNode;
43523 var stn = sn.childNodes[0];
43524 var en = sn.childNodes[sn.childNodes.length - 1 ];
43525 while (sn.childNodes.length) {
43526 var node = sn.childNodes[0];
43527 sn.removeChild(node);
43529 pn.insertBefore(node, sn);
43532 pn.removeChild(sn);
43533 var range = editor.createRange();
43535 range.setStart(stn,0);
43536 range.setEnd(en,0); //????
43537 //range.selectNode(sel);
43540 var selection = editor.getSelection();
43541 selection.removeAllRanges();
43542 selection.addRange(range);
43546 //_this.updateToolbar(null, null, pn);
43547 _this.updateToolbar(null, null, null);
43548 _this.footDisp.dom.innerHTML = '';
43558 tb.el.on('click', function(e){
43559 e.preventDefault(); // what does this do?
43561 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
43564 // dont need to disable them... as they will get hidden
43569 buildFooter : function()
43572 var fel = this.editor.wrap.createChild();
43573 this.footer = new Roo.Toolbar(fel);
43574 // toolbar has scrolly on left / right?
43575 var footDisp= new Roo.Toolbar.Fill();
43581 handler : function() {
43582 _t.footDisp.scrollTo('left',0,true)
43586 this.footer.add( footDisp );
43591 handler : function() {
43593 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
43597 var fel = Roo.get(footDisp.el);
43598 fel.addClass('x-editor-context');
43599 this.footDispWrap = fel;
43600 this.footDispWrap.overflow = 'hidden';
43602 this.footDisp = fel.createChild();
43603 this.footDispWrap.on('click', this.onContextClick, this)
43607 onContextClick : function (ev,dom)
43609 ev.preventDefault();
43610 var cn = dom.className;
43612 if (!cn.match(/x-ed-loc-/)) {
43615 var n = cn.split('-').pop();
43616 var ans = this.footerEls;
43620 var range = this.editor.createRange();
43622 range.selectNodeContents(sel);
43623 //range.selectNode(sel);
43626 var selection = this.editor.getSelection();
43627 selection.removeAllRanges();
43628 selection.addRange(range);
43632 this.updateToolbar(null, null, sel);
43649 * Ext JS Library 1.1.1
43650 * Copyright(c) 2006-2007, Ext JS, LLC.
43652 * Originally Released Under LGPL - original licence link has changed is not relivant.
43655 * <script type="text/javascript">
43659 * @class Roo.form.BasicForm
43660 * @extends Roo.util.Observable
43661 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
43663 * @param {String/HTMLElement/Roo.Element} el The form element or its id
43664 * @param {Object} config Configuration options
43666 Roo.form.BasicForm = function(el, config){
43667 this.allItems = [];
43668 this.childForms = [];
43669 Roo.apply(this, config);
43671 * The Roo.form.Field items in this form.
43672 * @type MixedCollection
43676 this.items = new Roo.util.MixedCollection(false, function(o){
43677 return o.id || (o.id = Roo.id());
43681 * @event beforeaction
43682 * Fires before any action is performed. Return false to cancel the action.
43683 * @param {Form} this
43684 * @param {Action} action The action to be performed
43686 beforeaction: true,
43688 * @event actionfailed
43689 * Fires when an action fails.
43690 * @param {Form} this
43691 * @param {Action} action The action that failed
43693 actionfailed : true,
43695 * @event actioncomplete
43696 * Fires when an action is completed.
43697 * @param {Form} this
43698 * @param {Action} action The action that completed
43700 actioncomplete : true
43705 Roo.form.BasicForm.superclass.constructor.call(this);
43708 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
43710 * @cfg {String} method
43711 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
43714 * @cfg {DataReader} reader
43715 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
43716 * This is optional as there is built-in support for processing JSON.
43719 * @cfg {DataReader} errorReader
43720 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
43721 * This is completely optional as there is built-in support for processing JSON.
43724 * @cfg {String} url
43725 * The URL to use for form actions if one isn't supplied in the action options.
43728 * @cfg {Boolean} fileUpload
43729 * Set to true if this form is a file upload.
43733 * @cfg {Object} baseParams
43734 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
43739 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
43744 activeAction : null,
43747 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
43748 * or setValues() data instead of when the form was first created.
43750 trackResetOnLoad : false,
43754 * childForms - used for multi-tab forms
43757 childForms : false,
43760 * allItems - full list of fields.
43766 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
43767 * element by passing it or its id or mask the form itself by passing in true.
43770 waitMsgTarget : false,
43773 initEl : function(el){
43774 this.el = Roo.get(el);
43775 this.id = this.el.id || Roo.id();
43776 this.el.on('submit', this.onSubmit, this);
43777 this.el.addClass('x-form');
43781 onSubmit : function(e){
43786 * Returns true if client-side validation on the form is successful.
43789 isValid : function(){
43791 this.items.each(function(f){
43800 * Returns true if any fields in this form have changed since their original load.
43803 isDirty : function(){
43805 this.items.each(function(f){
43815 * Performs a predefined action (submit or load) or custom actions you define on this form.
43816 * @param {String} actionName The name of the action type
43817 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
43818 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
43819 * accept other config options):
43821 Property Type Description
43822 ---------------- --------------- ----------------------------------------------------------------------------------
43823 url String The url for the action (defaults to the form's url)
43824 method String The form method to use (defaults to the form's method, or POST if not defined)
43825 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
43826 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
43827 validate the form on the client (defaults to false)
43829 * @return {BasicForm} this
43831 doAction : function(action, options){
43832 if(typeof action == 'string'){
43833 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
43835 if(this.fireEvent('beforeaction', this, action) !== false){
43836 this.beforeAction(action);
43837 action.run.defer(100, action);
43843 * Shortcut to do a submit action.
43844 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43845 * @return {BasicForm} this
43847 submit : function(options){
43848 this.doAction('submit', options);
43853 * Shortcut to do a load action.
43854 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43855 * @return {BasicForm} this
43857 load : function(options){
43858 this.doAction('load', options);
43863 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
43864 * @param {Record} record The record to edit
43865 * @return {BasicForm} this
43867 updateRecord : function(record){
43868 record.beginEdit();
43869 var fs = record.fields;
43870 fs.each(function(f){
43871 var field = this.findField(f.name);
43873 record.set(f.name, field.getValue());
43881 * Loads an Roo.data.Record into this form.
43882 * @param {Record} record The record to load
43883 * @return {BasicForm} this
43885 loadRecord : function(record){
43886 this.setValues(record.data);
43891 beforeAction : function(action){
43892 var o = action.options;
43895 if(this.waitMsgTarget === true){
43896 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
43897 }else if(this.waitMsgTarget){
43898 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
43899 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
43901 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
43907 afterAction : function(action, success){
43908 this.activeAction = null;
43909 var o = action.options;
43911 if(this.waitMsgTarget === true){
43913 }else if(this.waitMsgTarget){
43914 this.waitMsgTarget.unmask();
43916 Roo.MessageBox.updateProgress(1);
43917 Roo.MessageBox.hide();
43924 Roo.callback(o.success, o.scope, [this, action]);
43925 this.fireEvent('actioncomplete', this, action);
43929 // failure condition..
43930 // we have a scenario where updates need confirming.
43931 // eg. if a locking scenario exists..
43932 // we look for { errors : { needs_confirm : true }} in the response.
43934 (typeof(action.result) != 'undefined') &&
43935 (typeof(action.result.errors) != 'undefined') &&
43936 (typeof(action.result.errors.needs_confirm) != 'undefined')
43939 Roo.MessageBox.confirm(
43940 "Change requires confirmation",
43941 action.result.errorMsg,
43946 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
43956 Roo.callback(o.failure, o.scope, [this, action]);
43957 // show an error message if no failed handler is set..
43958 if (!this.hasListener('actionfailed')) {
43959 Roo.MessageBox.alert("Error",
43960 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
43961 action.result.errorMsg :
43962 "Saving Failed, please check your entries or try again"
43966 this.fireEvent('actionfailed', this, action);
43972 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
43973 * @param {String} id The value to search for
43976 findField : function(id){
43977 var field = this.items.get(id);
43979 this.items.each(function(f){
43980 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
43986 return field || null;
43990 * Add a secondary form to this one,
43991 * Used to provide tabbed forms. One form is primary, with hidden values
43992 * which mirror the elements from the other forms.
43994 * @param {Roo.form.Form} form to add.
43997 addForm : function(form)
44000 if (this.childForms.indexOf(form) > -1) {
44004 this.childForms.push(form);
44006 Roo.each(form.allItems, function (fe) {
44008 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
44009 if (this.findField(n)) { // already added..
44012 var add = new Roo.form.Hidden({
44015 add.render(this.el);
44022 * Mark fields in this form invalid in bulk.
44023 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
44024 * @return {BasicForm} this
44026 markInvalid : function(errors){
44027 if(errors instanceof Array){
44028 for(var i = 0, len = errors.length; i < len; i++){
44029 var fieldError = errors[i];
44030 var f = this.findField(fieldError.id);
44032 f.markInvalid(fieldError.msg);
44038 if(typeof errors[id] != 'function' && (field = this.findField(id))){
44039 field.markInvalid(errors[id]);
44043 Roo.each(this.childForms || [], function (f) {
44044 f.markInvalid(errors);
44051 * Set values for fields in this form in bulk.
44052 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
44053 * @return {BasicForm} this
44055 setValues : function(values){
44056 if(values instanceof Array){ // array of objects
44057 for(var i = 0, len = values.length; i < len; i++){
44059 var f = this.findField(v.id);
44061 f.setValue(v.value);
44062 if(this.trackResetOnLoad){
44063 f.originalValue = f.getValue();
44067 }else{ // object hash
44070 if(typeof values[id] != 'function' && (field = this.findField(id))){
44072 if (field.setFromData &&
44073 field.valueField &&
44074 field.displayField &&
44075 // combos' with local stores can
44076 // be queried via setValue()
44077 // to set their value..
44078 (field.store && !field.store.isLocal)
44082 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44083 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44084 field.setFromData(sd);
44087 field.setValue(values[id]);
44091 if(this.trackResetOnLoad){
44092 field.originalValue = field.getValue();
44098 Roo.each(this.childForms || [], function (f) {
44099 f.setValues(values);
44106 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
44107 * they are returned as an array.
44108 * @param {Boolean} asString
44111 getValues : function(asString){
44112 if (this.childForms) {
44113 // copy values from the child forms
44114 Roo.each(this.childForms, function (f) {
44115 this.setValues(f.getValues());
44121 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
44122 if(asString === true){
44125 return Roo.urlDecode(fs);
44129 * Returns the fields in this form as an object with key/value pairs.
44130 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
44133 getFieldValues : function(with_hidden)
44135 if (this.childForms) {
44136 // copy values from the child forms
44137 // should this call getFieldValues - probably not as we do not currently copy
44138 // hidden fields when we generate..
44139 Roo.each(this.childForms, function (f) {
44140 this.setValues(f.getValues());
44145 this.items.each(function(f){
44146 if (!f.getName()) {
44149 var v = f.getValue();
44150 if (f.inputType =='radio') {
44151 if (typeof(ret[f.getName()]) == 'undefined') {
44152 ret[f.getName()] = ''; // empty..
44155 if (!f.el.dom.checked) {
44159 v = f.el.dom.value;
44163 // not sure if this supported any more..
44164 if ((typeof(v) == 'object') && f.getRawValue) {
44165 v = f.getRawValue() ; // dates..
44167 // combo boxes where name != hiddenName...
44168 if (f.name != f.getName()) {
44169 ret[f.name] = f.getRawValue();
44171 ret[f.getName()] = v;
44178 * Clears all invalid messages in this form.
44179 * @return {BasicForm} this
44181 clearInvalid : function(){
44182 this.items.each(function(f){
44186 Roo.each(this.childForms || [], function (f) {
44195 * Resets this form.
44196 * @return {BasicForm} this
44198 reset : function(){
44199 this.items.each(function(f){
44203 Roo.each(this.childForms || [], function (f) {
44212 * Add Roo.form components to this form.
44213 * @param {Field} field1
44214 * @param {Field} field2 (optional)
44215 * @param {Field} etc (optional)
44216 * @return {BasicForm} this
44219 this.items.addAll(Array.prototype.slice.call(arguments, 0));
44225 * Removes a field from the items collection (does NOT remove its markup).
44226 * @param {Field} field
44227 * @return {BasicForm} this
44229 remove : function(field){
44230 this.items.remove(field);
44235 * Looks at the fields in this form, checks them for an id attribute,
44236 * and calls applyTo on the existing dom element with that id.
44237 * @return {BasicForm} this
44239 render : function(){
44240 this.items.each(function(f){
44241 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
44249 * Calls {@link Ext#apply} for all fields in this form with the passed object.
44250 * @param {Object} values
44251 * @return {BasicForm} this
44253 applyToFields : function(o){
44254 this.items.each(function(f){
44261 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
44262 * @param {Object} values
44263 * @return {BasicForm} this
44265 applyIfToFields : function(o){
44266 this.items.each(function(f){
44274 Roo.BasicForm = Roo.form.BasicForm;/*
44276 * Ext JS Library 1.1.1
44277 * Copyright(c) 2006-2007, Ext JS, LLC.
44279 * Originally Released Under LGPL - original licence link has changed is not relivant.
44282 * <script type="text/javascript">
44286 * @class Roo.form.Form
44287 * @extends Roo.form.BasicForm
44288 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
44290 * @param {Object} config Configuration options
44292 Roo.form.Form = function(config){
44294 if (config.items) {
44295 xitems = config.items;
44296 delete config.items;
44300 Roo.form.Form.superclass.constructor.call(this, null, config);
44301 this.url = this.url || this.action;
44303 this.root = new Roo.form.Layout(Roo.applyIf({
44307 this.active = this.root;
44309 * Array of all the buttons that have been added to this form via {@link addButton}
44313 this.allItems = [];
44316 * @event clientvalidation
44317 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
44318 * @param {Form} this
44319 * @param {Boolean} valid true if the form has passed client-side validation
44321 clientvalidation: true,
44324 * Fires when the form is rendered
44325 * @param {Roo.form.Form} form
44330 if (this.progressUrl) {
44331 // push a hidden field onto the list of fields..
44335 name : 'UPLOAD_IDENTIFIER'
44340 Roo.each(xitems, this.addxtype, this);
44346 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
44348 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
44351 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
44354 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
44356 buttonAlign:'center',
44359 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
44364 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
44365 * This property cascades to child containers if not set.
44370 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
44371 * fires a looping event with that state. This is required to bind buttons to the valid
44372 * state using the config value formBind:true on the button.
44374 monitorValid : false,
44377 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
44382 * @cfg {String} progressUrl - Url to return progress data
44385 progressUrl : false,
44388 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
44389 * fields are added and the column is closed. If no fields are passed the column remains open
44390 * until end() is called.
44391 * @param {Object} config The config to pass to the column
44392 * @param {Field} field1 (optional)
44393 * @param {Field} field2 (optional)
44394 * @param {Field} etc (optional)
44395 * @return Column The column container object
44397 column : function(c){
44398 var col = new Roo.form.Column(c);
44400 if(arguments.length > 1){ // duplicate code required because of Opera
44401 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44408 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
44409 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
44410 * until end() is called.
44411 * @param {Object} config The config to pass to the fieldset
44412 * @param {Field} field1 (optional)
44413 * @param {Field} field2 (optional)
44414 * @param {Field} etc (optional)
44415 * @return FieldSet The fieldset container object
44417 fieldset : function(c){
44418 var fs = new Roo.form.FieldSet(c);
44420 if(arguments.length > 1){ // duplicate code required because of Opera
44421 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44428 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
44429 * fields are added and the container is closed. If no fields are passed the container remains open
44430 * until end() is called.
44431 * @param {Object} config The config to pass to the Layout
44432 * @param {Field} field1 (optional)
44433 * @param {Field} field2 (optional)
44434 * @param {Field} etc (optional)
44435 * @return Layout The container object
44437 container : function(c){
44438 var l = new Roo.form.Layout(c);
44440 if(arguments.length > 1){ // duplicate code required because of Opera
44441 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44448 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
44449 * @param {Object} container A Roo.form.Layout or subclass of Layout
44450 * @return {Form} this
44452 start : function(c){
44453 // cascade label info
44454 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
44455 this.active.stack.push(c);
44456 c.ownerCt = this.active;
44462 * Closes the current open container
44463 * @return {Form} this
44466 if(this.active == this.root){
44469 this.active = this.active.ownerCt;
44474 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
44475 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
44476 * as the label of the field.
44477 * @param {Field} field1
44478 * @param {Field} field2 (optional)
44479 * @param {Field} etc. (optional)
44480 * @return {Form} this
44483 this.active.stack.push.apply(this.active.stack, arguments);
44484 this.allItems.push.apply(this.allItems,arguments);
44486 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
44487 if(a[i].isFormField){
44492 Roo.form.Form.superclass.add.apply(this, r);
44502 * Find any element that has been added to a form, using it's ID or name
44503 * This can include framesets, columns etc. along with regular fields..
44504 * @param {String} id - id or name to find.
44506 * @return {Element} e - or false if nothing found.
44508 findbyId : function(id)
44514 Roo.each(this.allItems, function(f){
44515 if (f.id == id || f.name == id ){
44526 * Render this form into the passed container. This should only be called once!
44527 * @param {String/HTMLElement/Element} container The element this component should be rendered into
44528 * @return {Form} this
44530 render : function(ct)
44536 var o = this.autoCreate || {
44538 method : this.method || 'POST',
44539 id : this.id || Roo.id()
44541 this.initEl(ct.createChild(o));
44543 this.root.render(this.el);
44547 this.items.each(function(f){
44548 f.render('x-form-el-'+f.id);
44551 if(this.buttons.length > 0){
44552 // tables are required to maintain order and for correct IE layout
44553 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
44554 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
44555 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
44557 var tr = tb.getElementsByTagName('tr')[0];
44558 for(var i = 0, len = this.buttons.length; i < len; i++) {
44559 var b = this.buttons[i];
44560 var td = document.createElement('td');
44561 td.className = 'x-form-btn-td';
44562 b.render(tr.appendChild(td));
44565 if(this.monitorValid){ // initialize after render
44566 this.startMonitoring();
44568 this.fireEvent('rendered', this);
44573 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
44574 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
44575 * object or a valid Roo.DomHelper element config
44576 * @param {Function} handler The function called when the button is clicked
44577 * @param {Object} scope (optional) The scope of the handler function
44578 * @return {Roo.Button}
44580 addButton : function(config, handler, scope){
44584 minWidth: this.minButtonWidth,
44587 if(typeof config == "string"){
44590 Roo.apply(bc, config);
44592 var btn = new Roo.Button(null, bc);
44593 this.buttons.push(btn);
44598 * Adds a series of form elements (using the xtype property as the factory method.
44599 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
44600 * @param {Object} config
44603 addxtype : function()
44605 var ar = Array.prototype.slice.call(arguments, 0);
44607 for(var i = 0; i < ar.length; i++) {
44609 continue; // skip -- if this happends something invalid got sent, we
44610 // should ignore it, as basically that interface element will not show up
44611 // and that should be pretty obvious!!
44614 if (Roo.form[ar[i].xtype]) {
44616 var fe = Roo.factory(ar[i], Roo.form);
44622 fe.store.form = this;
44627 this.allItems.push(fe);
44628 if (fe.items && fe.addxtype) {
44629 fe.addxtype.apply(fe, fe.items);
44639 // console.log('adding ' + ar[i].xtype);
44641 if (ar[i].xtype == 'Button') {
44642 //console.log('adding button');
44643 //console.log(ar[i]);
44644 this.addButton(ar[i]);
44645 this.allItems.push(fe);
44649 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
44650 alert('end is not supported on xtype any more, use items');
44652 // //console.log('adding end');
44660 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
44661 * option "monitorValid"
44663 startMonitoring : function(){
44666 Roo.TaskMgr.start({
44667 run : this.bindHandler,
44668 interval : this.monitorPoll || 200,
44675 * Stops monitoring of the valid state of this form
44677 stopMonitoring : function(){
44678 this.bound = false;
44682 bindHandler : function(){
44684 return false; // stops binding
44687 this.items.each(function(f){
44688 if(!f.isValid(true)){
44693 for(var i = 0, len = this.buttons.length; i < len; i++){
44694 var btn = this.buttons[i];
44695 if(btn.formBind === true && btn.disabled === valid){
44696 btn.setDisabled(!valid);
44699 this.fireEvent('clientvalidation', this, valid);
44713 Roo.Form = Roo.form.Form;
44716 * Ext JS Library 1.1.1
44717 * Copyright(c) 2006-2007, Ext JS, LLC.
44719 * Originally Released Under LGPL - original licence link has changed is not relivant.
44722 * <script type="text/javascript">
44725 // as we use this in bootstrap.
44726 Roo.namespace('Roo.form');
44728 * @class Roo.form.Action
44729 * Internal Class used to handle form actions
44731 * @param {Roo.form.BasicForm} el The form element or its id
44732 * @param {Object} config Configuration options
44737 // define the action interface
44738 Roo.form.Action = function(form, options){
44740 this.options = options || {};
44743 * Client Validation Failed
44746 Roo.form.Action.CLIENT_INVALID = 'client';
44748 * Server Validation Failed
44751 Roo.form.Action.SERVER_INVALID = 'server';
44753 * Connect to Server Failed
44756 Roo.form.Action.CONNECT_FAILURE = 'connect';
44758 * Reading Data from Server Failed
44761 Roo.form.Action.LOAD_FAILURE = 'load';
44763 Roo.form.Action.prototype = {
44765 failureType : undefined,
44766 response : undefined,
44767 result : undefined,
44769 // interface method
44770 run : function(options){
44774 // interface method
44775 success : function(response){
44779 // interface method
44780 handleResponse : function(response){
44784 // default connection failure
44785 failure : function(response){
44787 this.response = response;
44788 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44789 this.form.afterAction(this, false);
44792 processResponse : function(response){
44793 this.response = response;
44794 if(!response.responseText){
44797 this.result = this.handleResponse(response);
44798 return this.result;
44801 // utility functions used internally
44802 getUrl : function(appendParams){
44803 var url = this.options.url || this.form.url || this.form.el.dom.action;
44805 var p = this.getParams();
44807 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
44813 getMethod : function(){
44814 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
44817 getParams : function(){
44818 var bp = this.form.baseParams;
44819 var p = this.options.params;
44821 if(typeof p == "object"){
44822 p = Roo.urlEncode(Roo.applyIf(p, bp));
44823 }else if(typeof p == 'string' && bp){
44824 p += '&' + Roo.urlEncode(bp);
44827 p = Roo.urlEncode(bp);
44832 createCallback : function(){
44834 success: this.success,
44835 failure: this.failure,
44837 timeout: (this.form.timeout*1000),
44838 upload: this.form.fileUpload ? this.success : undefined
44843 Roo.form.Action.Submit = function(form, options){
44844 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
44847 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
44850 haveProgress : false,
44851 uploadComplete : false,
44853 // uploadProgress indicator.
44854 uploadProgress : function()
44856 if (!this.form.progressUrl) {
44860 if (!this.haveProgress) {
44861 Roo.MessageBox.progress("Uploading", "Uploading");
44863 if (this.uploadComplete) {
44864 Roo.MessageBox.hide();
44868 this.haveProgress = true;
44870 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
44872 var c = new Roo.data.Connection();
44874 url : this.form.progressUrl,
44879 success : function(req){
44880 //console.log(data);
44884 rdata = Roo.decode(req.responseText)
44886 Roo.log("Invalid data from server..");
44890 if (!rdata || !rdata.success) {
44892 Roo.MessageBox.alert(Roo.encode(rdata));
44895 var data = rdata.data;
44897 if (this.uploadComplete) {
44898 Roo.MessageBox.hide();
44903 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
44904 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
44907 this.uploadProgress.defer(2000,this);
44910 failure: function(data) {
44911 Roo.log('progress url failed ');
44922 // run get Values on the form, so it syncs any secondary forms.
44923 this.form.getValues();
44925 var o = this.options;
44926 var method = this.getMethod();
44927 var isPost = method == 'POST';
44928 if(o.clientValidation === false || this.form.isValid()){
44930 if (this.form.progressUrl) {
44931 this.form.findField('UPLOAD_IDENTIFIER').setValue(
44932 (new Date() * 1) + '' + Math.random());
44937 Roo.Ajax.request(Roo.apply(this.createCallback(), {
44938 form:this.form.el.dom,
44939 url:this.getUrl(!isPost),
44941 params:isPost ? this.getParams() : null,
44942 isUpload: this.form.fileUpload
44945 this.uploadProgress();
44947 }else if (o.clientValidation !== false){ // client validation failed
44948 this.failureType = Roo.form.Action.CLIENT_INVALID;
44949 this.form.afterAction(this, false);
44953 success : function(response)
44955 this.uploadComplete= true;
44956 if (this.haveProgress) {
44957 Roo.MessageBox.hide();
44961 var result = this.processResponse(response);
44962 if(result === true || result.success){
44963 this.form.afterAction(this, true);
44967 this.form.markInvalid(result.errors);
44968 this.failureType = Roo.form.Action.SERVER_INVALID;
44970 this.form.afterAction(this, false);
44972 failure : function(response)
44974 this.uploadComplete= true;
44975 if (this.haveProgress) {
44976 Roo.MessageBox.hide();
44979 this.response = response;
44980 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44981 this.form.afterAction(this, false);
44984 handleResponse : function(response){
44985 if(this.form.errorReader){
44986 var rs = this.form.errorReader.read(response);
44989 for(var i = 0, len = rs.records.length; i < len; i++) {
44990 var r = rs.records[i];
44991 errors[i] = r.data;
44994 if(errors.length < 1){
44998 success : rs.success,
45004 ret = Roo.decode(response.responseText);
45008 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
45018 Roo.form.Action.Load = function(form, options){
45019 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
45020 this.reader = this.form.reader;
45023 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
45028 Roo.Ajax.request(Roo.apply(
45029 this.createCallback(), {
45030 method:this.getMethod(),
45031 url:this.getUrl(false),
45032 params:this.getParams()
45036 success : function(response){
45038 var result = this.processResponse(response);
45039 if(result === true || !result.success || !result.data){
45040 this.failureType = Roo.form.Action.LOAD_FAILURE;
45041 this.form.afterAction(this, false);
45044 this.form.clearInvalid();
45045 this.form.setValues(result.data);
45046 this.form.afterAction(this, true);
45049 handleResponse : function(response){
45050 if(this.form.reader){
45051 var rs = this.form.reader.read(response);
45052 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
45054 success : rs.success,
45058 return Roo.decode(response.responseText);
45062 Roo.form.Action.ACTION_TYPES = {
45063 'load' : Roo.form.Action.Load,
45064 'submit' : Roo.form.Action.Submit
45067 * Ext JS Library 1.1.1
45068 * Copyright(c) 2006-2007, Ext JS, LLC.
45070 * Originally Released Under LGPL - original licence link has changed is not relivant.
45073 * <script type="text/javascript">
45077 * @class Roo.form.Layout
45078 * @extends Roo.Component
45079 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45081 * @param {Object} config Configuration options
45083 Roo.form.Layout = function(config){
45085 if (config.items) {
45086 xitems = config.items;
45087 delete config.items;
45089 Roo.form.Layout.superclass.constructor.call(this, config);
45091 Roo.each(xitems, this.addxtype, this);
45095 Roo.extend(Roo.form.Layout, Roo.Component, {
45097 * @cfg {String/Object} autoCreate
45098 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
45101 * @cfg {String/Object/Function} style
45102 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
45103 * a function which returns such a specification.
45106 * @cfg {String} labelAlign
45107 * Valid values are "left," "top" and "right" (defaults to "left")
45110 * @cfg {Number} labelWidth
45111 * Fixed width in pixels of all field labels (defaults to undefined)
45114 * @cfg {Boolean} clear
45115 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
45119 * @cfg {String} labelSeparator
45120 * The separator to use after field labels (defaults to ':')
45122 labelSeparator : ':',
45124 * @cfg {Boolean} hideLabels
45125 * True to suppress the display of field labels in this layout (defaults to false)
45127 hideLabels : false,
45130 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
45135 onRender : function(ct, position){
45136 if(this.el){ // from markup
45137 this.el = Roo.get(this.el);
45138 }else { // generate
45139 var cfg = this.getAutoCreate();
45140 this.el = ct.createChild(cfg, position);
45143 this.el.applyStyles(this.style);
45145 if(this.labelAlign){
45146 this.el.addClass('x-form-label-'+this.labelAlign);
45148 if(this.hideLabels){
45149 this.labelStyle = "display:none";
45150 this.elementStyle = "padding-left:0;";
45152 if(typeof this.labelWidth == 'number'){
45153 this.labelStyle = "width:"+this.labelWidth+"px;";
45154 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
45156 if(this.labelAlign == 'top'){
45157 this.labelStyle = "width:auto;";
45158 this.elementStyle = "padding-left:0;";
45161 var stack = this.stack;
45162 var slen = stack.length;
45164 if(!this.fieldTpl){
45165 var t = new Roo.Template(
45166 '<div class="x-form-item {5}">',
45167 '<label for="{0}" style="{2}">{1}{4}</label>',
45168 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45170 '</div><div class="x-form-clear-left"></div>'
45172 t.disableFormats = true;
45174 Roo.form.Layout.prototype.fieldTpl = t;
45176 for(var i = 0; i < slen; i++) {
45177 if(stack[i].isFormField){
45178 this.renderField(stack[i]);
45180 this.renderComponent(stack[i]);
45185 this.el.createChild({cls:'x-form-clear'});
45190 renderField : function(f){
45191 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
45194 f.labelStyle||this.labelStyle||'', //2
45195 this.elementStyle||'', //3
45196 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
45197 f.itemCls||this.itemCls||'' //5
45198 ], true).getPrevSibling());
45202 renderComponent : function(c){
45203 c.render(c.isLayout ? this.el : this.el.createChild());
45206 * Adds a object form elements (using the xtype property as the factory method.)
45207 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
45208 * @param {Object} config
45210 addxtype : function(o)
45212 // create the lement.
45213 o.form = this.form;
45214 var fe = Roo.factory(o, Roo.form);
45215 this.form.allItems.push(fe);
45216 this.stack.push(fe);
45218 if (fe.isFormField) {
45219 this.form.items.add(fe);
45227 * @class Roo.form.Column
45228 * @extends Roo.form.Layout
45229 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
45231 * @param {Object} config Configuration options
45233 Roo.form.Column = function(config){
45234 Roo.form.Column.superclass.constructor.call(this, config);
45237 Roo.extend(Roo.form.Column, Roo.form.Layout, {
45239 * @cfg {Number/String} width
45240 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45243 * @cfg {String/Object} autoCreate
45244 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
45248 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
45251 onRender : function(ct, position){
45252 Roo.form.Column.superclass.onRender.call(this, ct, position);
45254 this.el.setWidth(this.width);
45261 * @class Roo.form.Row
45262 * @extends Roo.form.Layout
45263 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
45265 * @param {Object} config Configuration options
45269 Roo.form.Row = function(config){
45270 Roo.form.Row.superclass.constructor.call(this, config);
45273 Roo.extend(Roo.form.Row, Roo.form.Layout, {
45275 * @cfg {Number/String} width
45276 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45279 * @cfg {Number/String} height
45280 * The fixed height of the column in pixels or CSS value (defaults to "auto")
45282 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
45286 onRender : function(ct, position){
45287 //console.log('row render');
45289 var t = new Roo.Template(
45290 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
45291 '<label for="{0}" style="{2}">{1}{4}</label>',
45292 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45296 t.disableFormats = true;
45298 Roo.form.Layout.prototype.rowTpl = t;
45300 this.fieldTpl = this.rowTpl;
45302 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
45303 var labelWidth = 100;
45305 if ((this.labelAlign != 'top')) {
45306 if (typeof this.labelWidth == 'number') {
45307 labelWidth = this.labelWidth
45309 this.padWidth = 20 + labelWidth;
45313 Roo.form.Column.superclass.onRender.call(this, ct, position);
45315 this.el.setWidth(this.width);
45318 this.el.setHeight(this.height);
45323 renderField : function(f){
45324 f.fieldEl = this.fieldTpl.append(this.el, [
45325 f.id, f.fieldLabel,
45326 f.labelStyle||this.labelStyle||'',
45327 this.elementStyle||'',
45328 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
45329 f.itemCls||this.itemCls||'',
45330 f.width ? f.width + this.padWidth : 160 + this.padWidth
45337 * @class Roo.form.FieldSet
45338 * @extends Roo.form.Layout
45339 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
45341 * @param {Object} config Configuration options
45343 Roo.form.FieldSet = function(config){
45344 Roo.form.FieldSet.superclass.constructor.call(this, config);
45347 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
45349 * @cfg {String} legend
45350 * The text to display as the legend for the FieldSet (defaults to '')
45353 * @cfg {String/Object} autoCreate
45354 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
45358 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
45361 onRender : function(ct, position){
45362 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
45364 this.setLegend(this.legend);
45369 setLegend : function(text){
45371 this.el.child('legend').update(text);
45376 * Ext JS Library 1.1.1
45377 * Copyright(c) 2006-2007, Ext JS, LLC.
45379 * Originally Released Under LGPL - original licence link has changed is not relivant.
45382 * <script type="text/javascript">
45385 * @class Roo.form.VTypes
45386 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
45389 Roo.form.VTypes = function(){
45390 // closure these in so they are only created once.
45391 var alpha = /^[a-zA-Z_]+$/;
45392 var alphanum = /^[a-zA-Z0-9_]+$/;
45393 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
45394 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
45396 // All these messages and functions are configurable
45399 * The function used to validate email addresses
45400 * @param {String} value The email address
45402 'email' : function(v){
45403 return email.test(v);
45406 * The error text to display when the email validation function returns false
45409 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
45411 * The keystroke filter mask to be applied on email input
45414 'emailMask' : /[a-z0-9_\.\-@]/i,
45417 * The function used to validate URLs
45418 * @param {String} value The URL
45420 'url' : function(v){
45421 return url.test(v);
45424 * The error text to display when the url validation function returns false
45427 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
45430 * The function used to validate alpha values
45431 * @param {String} value The value
45433 'alpha' : function(v){
45434 return alpha.test(v);
45437 * The error text to display when the alpha validation function returns false
45440 'alphaText' : 'This field should only contain letters and _',
45442 * The keystroke filter mask to be applied on alpha input
45445 'alphaMask' : /[a-z_]/i,
45448 * The function used to validate alphanumeric values
45449 * @param {String} value The value
45451 'alphanum' : function(v){
45452 return alphanum.test(v);
45455 * The error text to display when the alphanumeric validation function returns false
45458 'alphanumText' : 'This field should only contain letters, numbers and _',
45460 * The keystroke filter mask to be applied on alphanumeric input
45463 'alphanumMask' : /[a-z0-9_]/i
45465 }();//<script type="text/javascript">
45468 * @class Roo.form.FCKeditor
45469 * @extends Roo.form.TextArea
45470 * Wrapper around the FCKEditor http://www.fckeditor.net
45472 * Creates a new FCKeditor
45473 * @param {Object} config Configuration options
45475 Roo.form.FCKeditor = function(config){
45476 Roo.form.FCKeditor.superclass.constructor.call(this, config);
45479 * @event editorinit
45480 * Fired when the editor is initialized - you can add extra handlers here..
45481 * @param {FCKeditor} this
45482 * @param {Object} the FCK object.
45489 Roo.form.FCKeditor.editors = { };
45490 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
45492 //defaultAutoCreate : {
45493 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
45497 * @cfg {Object} fck options - see fck manual for details.
45502 * @cfg {Object} fck toolbar set (Basic or Default)
45504 toolbarSet : 'Basic',
45506 * @cfg {Object} fck BasePath
45508 basePath : '/fckeditor/',
45516 onRender : function(ct, position)
45519 this.defaultAutoCreate = {
45521 style:"width:300px;height:60px;",
45522 autocomplete: "off"
45525 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
45528 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
45529 if(this.preventScrollbars){
45530 this.el.setStyle("overflow", "hidden");
45532 this.el.setHeight(this.growMin);
45535 //console.log('onrender' + this.getId() );
45536 Roo.form.FCKeditor.editors[this.getId()] = this;
45539 this.replaceTextarea() ;
45543 getEditor : function() {
45544 return this.fckEditor;
45547 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
45548 * @param {Mixed} value The value to set
45552 setValue : function(value)
45554 //console.log('setValue: ' + value);
45556 if(typeof(value) == 'undefined') { // not sure why this is happending...
45559 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
45561 //if(!this.el || !this.getEditor()) {
45562 // this.value = value;
45563 //this.setValue.defer(100,this,[value]);
45567 if(!this.getEditor()) {
45571 this.getEditor().SetData(value);
45578 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
45579 * @return {Mixed} value The field value
45581 getValue : function()
45584 if (this.frame && this.frame.dom.style.display == 'none') {
45585 return Roo.form.FCKeditor.superclass.getValue.call(this);
45588 if(!this.el || !this.getEditor()) {
45590 // this.getValue.defer(100,this);
45595 var value=this.getEditor().GetData();
45596 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
45597 return Roo.form.FCKeditor.superclass.getValue.call(this);
45603 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
45604 * @return {Mixed} value The field value
45606 getRawValue : function()
45608 if (this.frame && this.frame.dom.style.display == 'none') {
45609 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
45612 if(!this.el || !this.getEditor()) {
45613 //this.getRawValue.defer(100,this);
45620 var value=this.getEditor().GetData();
45621 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
45622 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
45626 setSize : function(w,h) {
45630 //if (this.frame && this.frame.dom.style.display == 'none') {
45631 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
45634 //if(!this.el || !this.getEditor()) {
45635 // this.setSize.defer(100,this, [w,h]);
45641 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
45643 this.frame.dom.setAttribute('width', w);
45644 this.frame.dom.setAttribute('height', h);
45645 this.frame.setSize(w,h);
45649 toggleSourceEdit : function(value) {
45653 this.el.dom.style.display = value ? '' : 'none';
45654 this.frame.dom.style.display = value ? 'none' : '';
45659 focus: function(tag)
45661 if (this.frame.dom.style.display == 'none') {
45662 return Roo.form.FCKeditor.superclass.focus.call(this);
45664 if(!this.el || !this.getEditor()) {
45665 this.focus.defer(100,this, [tag]);
45672 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
45673 this.getEditor().Focus();
45675 if (!this.getEditor().Selection.GetSelection()) {
45676 this.focus.defer(100,this, [tag]);
45681 var r = this.getEditor().EditorDocument.createRange();
45682 r.setStart(tgs[0],0);
45683 r.setEnd(tgs[0],0);
45684 this.getEditor().Selection.GetSelection().removeAllRanges();
45685 this.getEditor().Selection.GetSelection().addRange(r);
45686 this.getEditor().Focus();
45693 replaceTextarea : function()
45695 if ( document.getElementById( this.getId() + '___Frame' ) )
45697 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
45699 // We must check the elements firstly using the Id and then the name.
45700 var oTextarea = document.getElementById( this.getId() );
45702 var colElementsByName = document.getElementsByName( this.getId() ) ;
45704 oTextarea.style.display = 'none' ;
45706 if ( oTextarea.tabIndex ) {
45707 this.TabIndex = oTextarea.tabIndex ;
45710 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
45711 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
45712 this.frame = Roo.get(this.getId() + '___Frame')
45715 _getConfigHtml : function()
45719 for ( var o in this.fckconfig ) {
45720 sConfig += sConfig.length > 0 ? '&' : '';
45721 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
45724 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
45728 _getIFrameHtml : function()
45730 var sFile = 'fckeditor.html' ;
45731 /* no idea what this is about..
45734 if ( (/fcksource=true/i).test( window.top.location.search ) )
45735 sFile = 'fckeditor.original.html' ;
45740 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
45741 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
45744 var html = '<iframe id="' + this.getId() +
45745 '___Frame" src="' + sLink +
45746 '" width="' + this.width +
45747 '" height="' + this.height + '"' +
45748 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
45749 ' frameborder="0" scrolling="no"></iframe>' ;
45754 _insertHtmlBefore : function( html, element )
45756 if ( element.insertAdjacentHTML ) {
45758 element.insertAdjacentHTML( 'beforeBegin', html ) ;
45760 var oRange = document.createRange() ;
45761 oRange.setStartBefore( element ) ;
45762 var oFragment = oRange.createContextualFragment( html );
45763 element.parentNode.insertBefore( oFragment, element ) ;
45776 //Roo.reg('fckeditor', Roo.form.FCKeditor);
45778 function FCKeditor_OnComplete(editorInstance){
45779 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
45780 f.fckEditor = editorInstance;
45781 //console.log("loaded");
45782 f.fireEvent('editorinit', f, editorInstance);
45802 //<script type="text/javascript">
45804 * @class Roo.form.GridField
45805 * @extends Roo.form.Field
45806 * Embed a grid (or editable grid into a form)
45809 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
45811 * xgrid.store = Roo.data.Store
45812 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
45813 * xgrid.store.reader = Roo.data.JsonReader
45817 * Creates a new GridField
45818 * @param {Object} config Configuration options
45820 Roo.form.GridField = function(config){
45821 Roo.form.GridField.superclass.constructor.call(this, config);
45825 Roo.extend(Roo.form.GridField, Roo.form.Field, {
45827 * @cfg {Number} width - used to restrict width of grid..
45831 * @cfg {Number} height - used to restrict height of grid..
45835 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
45841 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45842 * {tag: "input", type: "checkbox", autocomplete: "off"})
45844 // defaultAutoCreate : { tag: 'div' },
45845 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45847 * @cfg {String} addTitle Text to include for adding a title.
45851 onResize : function(){
45852 Roo.form.Field.superclass.onResize.apply(this, arguments);
45855 initEvents : function(){
45856 // Roo.form.Checkbox.superclass.initEvents.call(this);
45857 // has no events...
45862 getResizeEl : function(){
45866 getPositionEl : function(){
45871 onRender : function(ct, position){
45873 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
45874 var style = this.style;
45877 Roo.form.GridField.superclass.onRender.call(this, ct, position);
45878 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
45879 this.viewEl = this.wrap.createChild({ tag: 'div' });
45881 this.viewEl.applyStyles(style);
45884 this.viewEl.setWidth(this.width);
45887 this.viewEl.setHeight(this.height);
45889 //if(this.inputValue !== undefined){
45890 //this.setValue(this.value);
45893 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
45896 this.grid.render();
45897 this.grid.getDataSource().on('remove', this.refreshValue, this);
45898 this.grid.getDataSource().on('update', this.refreshValue, this);
45899 this.grid.on('afteredit', this.refreshValue, this);
45905 * Sets the value of the item.
45906 * @param {String} either an object or a string..
45908 setValue : function(v){
45910 v = v || []; // empty set..
45911 // this does not seem smart - it really only affects memoryproxy grids..
45912 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
45913 var ds = this.grid.getDataSource();
45914 // assumes a json reader..
45916 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
45917 ds.loadData( data);
45919 // clear selection so it does not get stale.
45920 if (this.grid.sm) {
45921 this.grid.sm.clearSelections();
45924 Roo.form.GridField.superclass.setValue.call(this, v);
45925 this.refreshValue();
45926 // should load data in the grid really....
45930 refreshValue: function() {
45932 this.grid.getDataSource().each(function(r) {
45935 this.el.dom.value = Roo.encode(val);
45943 * Ext JS Library 1.1.1
45944 * Copyright(c) 2006-2007, Ext JS, LLC.
45946 * Originally Released Under LGPL - original licence link has changed is not relivant.
45949 * <script type="text/javascript">
45952 * @class Roo.form.DisplayField
45953 * @extends Roo.form.Field
45954 * A generic Field to display non-editable data.
45956 * Creates a new Display Field item.
45957 * @param {Object} config Configuration options
45959 Roo.form.DisplayField = function(config){
45960 Roo.form.DisplayField.superclass.constructor.call(this, config);
45964 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
45965 inputType: 'hidden',
45971 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45973 focusClass : undefined,
45975 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45977 fieldClass: 'x-form-field',
45980 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
45982 valueRenderer: undefined,
45986 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45987 * {tag: "input", type: "checkbox", autocomplete: "off"})
45990 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45992 onResize : function(){
45993 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
45997 initEvents : function(){
45998 // Roo.form.Checkbox.superclass.initEvents.call(this);
45999 // has no events...
46004 getResizeEl : function(){
46008 getPositionEl : function(){
46013 onRender : function(ct, position){
46015 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
46016 //if(this.inputValue !== undefined){
46017 this.wrap = this.el.wrap();
46019 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
46021 if (this.bodyStyle) {
46022 this.viewEl.applyStyles(this.bodyStyle);
46024 //this.viewEl.setStyle('padding', '2px');
46026 this.setValue(this.value);
46031 initValue : Roo.emptyFn,
46036 onClick : function(){
46041 * Sets the checked state of the checkbox.
46042 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
46044 setValue : function(v){
46046 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
46047 // this might be called before we have a dom element..
46048 if (!this.viewEl) {
46051 this.viewEl.dom.innerHTML = html;
46052 Roo.form.DisplayField.superclass.setValue.call(this, v);
46062 * @class Roo.form.DayPicker
46063 * @extends Roo.form.Field
46064 * A Day picker show [M] [T] [W] ....
46066 * Creates a new Day Picker
46067 * @param {Object} config Configuration options
46069 Roo.form.DayPicker= function(config){
46070 Roo.form.DayPicker.superclass.constructor.call(this, config);
46074 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
46076 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46078 focusClass : undefined,
46080 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46082 fieldClass: "x-form-field",
46085 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46086 * {tag: "input", type: "checkbox", autocomplete: "off"})
46088 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
46091 actionMode : 'viewEl',
46095 inputType : 'hidden',
46098 inputElement: false, // real input element?
46099 basedOn: false, // ????
46101 isFormField: true, // not sure where this is needed!!!!
46103 onResize : function(){
46104 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
46105 if(!this.boxLabel){
46106 this.el.alignTo(this.wrap, 'c-c');
46110 initEvents : function(){
46111 Roo.form.Checkbox.superclass.initEvents.call(this);
46112 this.el.on("click", this.onClick, this);
46113 this.el.on("change", this.onClick, this);
46117 getResizeEl : function(){
46121 getPositionEl : function(){
46127 onRender : function(ct, position){
46128 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
46130 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
46132 var r1 = '<table><tr>';
46133 var r2 = '<tr class="x-form-daypick-icons">';
46134 for (var i=0; i < 7; i++) {
46135 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
46136 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
46139 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
46140 viewEl.select('img').on('click', this.onClick, this);
46141 this.viewEl = viewEl;
46144 // this will not work on Chrome!!!
46145 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
46146 this.el.on('propertychange', this.setFromHidden, this); //ie
46154 initValue : Roo.emptyFn,
46157 * Returns the checked state of the checkbox.
46158 * @return {Boolean} True if checked, else false
46160 getValue : function(){
46161 return this.el.dom.value;
46166 onClick : function(e){
46167 //this.setChecked(!this.checked);
46168 Roo.get(e.target).toggleClass('x-menu-item-checked');
46169 this.refreshValue();
46170 //if(this.el.dom.checked != this.checked){
46171 // this.setValue(this.el.dom.checked);
46176 refreshValue : function()
46179 this.viewEl.select('img',true).each(function(e,i,n) {
46180 val += e.is(".x-menu-item-checked") ? String(n) : '';
46182 this.setValue(val, true);
46186 * Sets the checked state of the checkbox.
46187 * On is always based on a string comparison between inputValue and the param.
46188 * @param {Boolean/String} value - the value to set
46189 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
46191 setValue : function(v,suppressEvent){
46192 if (!this.el.dom) {
46195 var old = this.el.dom.value ;
46196 this.el.dom.value = v;
46197 if (suppressEvent) {
46201 // update display..
46202 this.viewEl.select('img',true).each(function(e,i,n) {
46204 var on = e.is(".x-menu-item-checked");
46205 var newv = v.indexOf(String(n)) > -1;
46207 e.toggleClass('x-menu-item-checked');
46213 this.fireEvent('change', this, v, old);
46218 // handle setting of hidden value by some other method!!?!?
46219 setFromHidden: function()
46224 //console.log("SET FROM HIDDEN");
46225 //alert('setFrom hidden');
46226 this.setValue(this.el.dom.value);
46229 onDestroy : function()
46232 Roo.get(this.viewEl).remove();
46235 Roo.form.DayPicker.superclass.onDestroy.call(this);
46239 * RooJS Library 1.1.1
46240 * Copyright(c) 2008-2011 Alan Knowles
46247 * @class Roo.form.ComboCheck
46248 * @extends Roo.form.ComboBox
46249 * A combobox for multiple select items.
46251 * FIXME - could do with a reset button..
46254 * Create a new ComboCheck
46255 * @param {Object} config Configuration options
46257 Roo.form.ComboCheck = function(config){
46258 Roo.form.ComboCheck.superclass.constructor.call(this, config);
46259 // should verify some data...
46261 // hiddenName = required..
46262 // displayField = required
46263 // valudField == required
46264 var req= [ 'hiddenName', 'displayField', 'valueField' ];
46266 Roo.each(req, function(e) {
46267 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
46268 throw "Roo.form.ComboCheck : missing value for: " + e;
46275 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
46280 selectedClass: 'x-menu-item-checked',
46283 onRender : function(ct, position){
46289 var cls = 'x-combo-list';
46292 this.tpl = new Roo.Template({
46293 html : '<div class="'+cls+'-item x-menu-check-item">' +
46294 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
46295 '<span>{' + this.displayField + '}</span>' +
46302 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
46303 this.view.singleSelect = false;
46304 this.view.multiSelect = true;
46305 this.view.toggleSelect = true;
46306 this.pageTb.add(new Roo.Toolbar.Fill(), {
46309 handler: function()
46316 onViewOver : function(e, t){
46322 onViewClick : function(doFocus,index){
46326 select: function () {
46327 //Roo.log("SELECT CALLED");
46330 selectByValue : function(xv, scrollIntoView){
46331 var ar = this.getValueArray();
46334 Roo.each(ar, function(v) {
46335 if(v === undefined || v === null){
46338 var r = this.findRecord(this.valueField, v);
46340 sels.push(this.store.indexOf(r))
46344 this.view.select(sels);
46350 onSelect : function(record, index){
46351 // Roo.log("onselect Called");
46352 // this is only called by the clear button now..
46353 this.view.clearSelections();
46354 this.setValue('[]');
46355 if (this.value != this.valueBefore) {
46356 this.fireEvent('change', this, this.value, this.valueBefore);
46357 this.valueBefore = this.value;
46360 getValueArray : function()
46365 //Roo.log(this.value);
46366 if (typeof(this.value) == 'undefined') {
46369 var ar = Roo.decode(this.value);
46370 return ar instanceof Array ? ar : []; //?? valid?
46373 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
46378 expand : function ()
46381 Roo.form.ComboCheck.superclass.expand.call(this);
46382 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
46383 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
46388 collapse : function(){
46389 Roo.form.ComboCheck.superclass.collapse.call(this);
46390 var sl = this.view.getSelectedIndexes();
46391 var st = this.store;
46395 Roo.each(sl, function(i) {
46397 nv.push(r.get(this.valueField));
46399 this.setValue(Roo.encode(nv));
46400 if (this.value != this.valueBefore) {
46402 this.fireEvent('change', this, this.value, this.valueBefore);
46403 this.valueBefore = this.value;
46408 setValue : function(v){
46412 var vals = this.getValueArray();
46414 Roo.each(vals, function(k) {
46415 var r = this.findRecord(this.valueField, k);
46417 tv.push(r.data[this.displayField]);
46418 }else if(this.valueNotFoundText !== undefined){
46419 tv.push( this.valueNotFoundText );
46424 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
46425 this.hiddenField.value = v;
46431 * Ext JS Library 1.1.1
46432 * Copyright(c) 2006-2007, Ext JS, LLC.
46434 * Originally Released Under LGPL - original licence link has changed is not relivant.
46437 * <script type="text/javascript">
46441 * @class Roo.form.Signature
46442 * @extends Roo.form.Field
46446 * @param {Object} config Configuration options
46449 Roo.form.Signature = function(config){
46450 Roo.form.Signature.superclass.constructor.call(this, config);
46452 this.addEvents({// not in used??
46455 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
46456 * @param {Roo.form.Signature} combo This combo box
46461 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
46462 * @param {Roo.form.ComboBox} combo This combo box
46463 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
46469 Roo.extend(Roo.form.Signature, Roo.form.Field, {
46471 * @cfg {Object} labels Label to use when rendering a form.
46475 * confirm : "Confirm"
46480 confirm : "Confirm"
46483 * @cfg {Number} width The signature panel width (defaults to 300)
46487 * @cfg {Number} height The signature panel height (defaults to 100)
46491 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
46493 allowBlank : false,
46496 // {Object} signPanel The signature SVG panel element (defaults to {})
46498 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
46499 isMouseDown : false,
46500 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
46501 isConfirmed : false,
46502 // {String} signatureTmp SVG mapping string (defaults to empty string)
46506 defaultAutoCreate : { // modified by initCompnoent..
46512 onRender : function(ct, position){
46514 Roo.form.Signature.superclass.onRender.call(this, ct, position);
46516 this.wrap = this.el.wrap({
46517 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
46520 this.createToolbar(this);
46521 this.signPanel = this.wrap.createChild({
46523 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
46527 this.svgID = Roo.id();
46528 this.svgEl = this.signPanel.createChild({
46529 xmlns : 'http://www.w3.org/2000/svg',
46531 id : this.svgID + "-svg",
46533 height: this.height,
46534 viewBox: '0 0 '+this.width+' '+this.height,
46538 id: this.svgID + "-svg-r",
46540 height: this.height,
46545 id: this.svgID + "-svg-l",
46547 y1: (this.height*0.8), // start set the line in 80% of height
46548 x2: this.width, // end
46549 y2: (this.height*0.8), // end set the line in 80% of height
46551 'stroke-width': "1",
46552 'stroke-dasharray': "3",
46553 'shape-rendering': "crispEdges",
46554 'pointer-events': "none"
46558 id: this.svgID + "-svg-p",
46560 'stroke-width': "3",
46562 'pointer-events': 'none'
46567 this.svgBox = this.svgEl.dom.getScreenCTM();
46569 createSVG : function(){
46570 var svg = this.signPanel;
46571 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
46574 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
46575 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
46576 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
46577 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
46578 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
46579 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
46580 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
46583 isTouchEvent : function(e){
46584 return e.type.match(/^touch/);
46586 getCoords : function (e) {
46587 var pt = this.svgEl.dom.createSVGPoint();
46590 if (this.isTouchEvent(e)) {
46591 pt.x = e.targetTouches[0].clientX
46592 pt.y = e.targetTouches[0].clientY;
46594 var a = this.svgEl.dom.getScreenCTM();
46595 var b = a.inverse();
46596 var mx = pt.matrixTransform(b);
46597 return mx.x + ',' + mx.y;
46599 //mouse event headler
46600 down : function (e) {
46601 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
46602 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
46604 this.isMouseDown = true;
46606 e.preventDefault();
46608 move : function (e) {
46609 if (this.isMouseDown) {
46610 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
46611 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
46614 e.preventDefault();
46616 up : function (e) {
46617 this.isMouseDown = false;
46618 var sp = this.signatureTmp.split(' ');
46621 if(!sp[sp.length-2].match(/^L/)){
46625 this.signatureTmp = sp.join(" ");
46628 if(this.getValue() != this.signatureTmp){
46629 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46630 this.isConfirmed = false;
46632 e.preventDefault();
46636 * Protected method that will not generally be called directly. It
46637 * is called when the editor creates its toolbar. Override this method if you need to
46638 * add custom toolbar buttons.
46639 * @param {HtmlEditor} editor
46641 createToolbar : function(editor){
46642 function btn(id, toggle, handler){
46643 var xid = fid + '-'+ id ;
46647 cls : 'x-btn-icon x-edit-'+id,
46648 enableToggle:toggle !== false,
46649 scope: editor, // was editor...
46650 handler:handler||editor.relayBtnCmd,
46651 clickEvent:'mousedown',
46652 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46658 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46662 cls : ' x-signature-btn x-signature-'+id,
46663 scope: editor, // was editor...
46664 handler: this.reset,
46665 clickEvent:'mousedown',
46666 text: this.labels.clear
46673 cls : ' x-signature-btn x-signature-'+id,
46674 scope: editor, // was editor...
46675 handler: this.confirmHandler,
46676 clickEvent:'mousedown',
46677 text: this.labels.confirm
46684 * when user is clicked confirm then show this image.....
46686 * @return {String} Image Data URI
46688 getImageDataURI : function(){
46689 var svg = this.svgEl.dom.parentNode.innerHTML;
46690 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
46695 * @return {Boolean} this.isConfirmed
46697 getConfirmed : function(){
46698 return this.isConfirmed;
46702 * @return {Number} this.width
46704 getWidth : function(){
46709 * @return {Number} this.height
46711 getHeight : function(){
46712 return this.height;
46715 getSignature : function(){
46716 return this.signatureTmp;
46719 reset : function(){
46720 this.signatureTmp = '';
46721 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46722 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
46723 this.isConfirmed = false;
46724 Roo.form.Signature.superclass.reset.call(this);
46726 setSignature : function(s){
46727 this.signatureTmp = s;
46728 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46729 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
46731 this.isConfirmed = false;
46732 Roo.form.Signature.superclass.reset.call(this);
46735 // Roo.log(this.signPanel.dom.contentWindow.up())
46738 setConfirmed : function(){
46742 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
46745 confirmHandler : function(){
46746 if(!this.getSignature()){
46750 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
46751 this.setValue(this.getSignature());
46752 this.isConfirmed = true;
46754 this.fireEvent('confirm', this);
46757 // Subclasses should provide the validation implementation by overriding this
46758 validateValue : function(value){
46759 if(this.allowBlank){
46763 if(this.isConfirmed){
46770 * Ext JS Library 1.1.1
46771 * Copyright(c) 2006-2007, Ext JS, LLC.
46773 * Originally Released Under LGPL - original licence link has changed is not relivant.
46776 * <script type="text/javascript">
46781 * @class Roo.form.ComboBox
46782 * @extends Roo.form.TriggerField
46783 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
46785 * Create a new ComboBox.
46786 * @param {Object} config Configuration options
46788 Roo.form.Select = function(config){
46789 Roo.form.Select.superclass.constructor.call(this, config);
46793 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
46795 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
46798 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
46799 * rendering into an Roo.Editor, defaults to false)
46802 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
46803 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
46806 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
46809 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
46810 * the dropdown list (defaults to undefined, with no header element)
46814 * @cfg {String/Roo.Template} tpl The template to use to render the output
46818 defaultAutoCreate : {tag: "select" },
46820 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
46822 listWidth: undefined,
46824 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
46825 * mode = 'remote' or 'text' if mode = 'local')
46827 displayField: undefined,
46829 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
46830 * mode = 'remote' or 'value' if mode = 'local').
46831 * Note: use of a valueField requires the user make a selection
46832 * in order for a value to be mapped.
46834 valueField: undefined,
46838 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
46839 * field's data value (defaults to the underlying DOM element's name)
46841 hiddenName: undefined,
46843 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
46847 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
46849 selectedClass: 'x-combo-selected',
46851 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
46852 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
46853 * which displays a downward arrow icon).
46855 triggerClass : 'x-form-arrow-trigger',
46857 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
46861 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
46862 * anchor positions (defaults to 'tl-bl')
46864 listAlign: 'tl-bl?',
46866 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
46870 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
46871 * query specified by the allQuery config option (defaults to 'query')
46873 triggerAction: 'query',
46875 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
46876 * (defaults to 4, does not apply if editable = false)
46880 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
46881 * delay (typeAheadDelay) if it matches a known value (defaults to false)
46885 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
46886 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
46890 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
46891 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
46895 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
46896 * when editable = true (defaults to false)
46898 selectOnFocus:false,
46900 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
46902 queryParam: 'query',
46904 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
46905 * when mode = 'remote' (defaults to 'Loading...')
46907 loadingText: 'Loading...',
46909 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
46913 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
46917 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
46918 * traditional select (defaults to true)
46922 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
46926 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
46930 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
46931 * listWidth has a higher value)
46935 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
46936 * allow the user to set arbitrary text into the field (defaults to false)
46938 forceSelection:false,
46940 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
46941 * if typeAhead = true (defaults to 250)
46943 typeAheadDelay : 250,
46945 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
46946 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
46948 valueNotFoundText : undefined,
46951 * @cfg {String} defaultValue The value displayed after loading the store.
46956 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
46958 blockFocus : false,
46961 * @cfg {Boolean} disableClear Disable showing of clear button.
46963 disableClear : false,
46965 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
46967 alwaysQuery : false,
46973 // element that contains real text value.. (when hidden is used..)
46976 onRender : function(ct, position){
46977 Roo.form.Field.prototype.onRender.call(this, ct, position);
46980 this.store.on('beforeload', this.onBeforeLoad, this);
46981 this.store.on('load', this.onLoad, this);
46982 this.store.on('loadexception', this.onLoadException, this);
46983 this.store.load({});
46991 initEvents : function(){
46992 //Roo.form.ComboBox.superclass.initEvents.call(this);
46996 onDestroy : function(){
46999 this.store.un('beforeload', this.onBeforeLoad, this);
47000 this.store.un('load', this.onLoad, this);
47001 this.store.un('loadexception', this.onLoadException, this);
47003 //Roo.form.ComboBox.superclass.onDestroy.call(this);
47007 fireKey : function(e){
47008 if(e.isNavKeyPress() && !this.list.isVisible()){
47009 this.fireEvent("specialkey", this, e);
47014 onResize: function(w, h){
47022 * Allow or prevent the user from directly editing the field text. If false is passed,
47023 * the user will only be able to select from the items defined in the dropdown list. This method
47024 * is the runtime equivalent of setting the 'editable' config option at config time.
47025 * @param {Boolean} value True to allow the user to directly edit the field text
47027 setEditable : function(value){
47032 onBeforeLoad : function(){
47034 Roo.log("Select before load");
47037 this.innerList.update(this.loadingText ?
47038 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
47039 //this.restrictHeight();
47040 this.selectedIndex = -1;
47044 onLoad : function(){
47047 var dom = this.el.dom;
47048 dom.innerHTML = '';
47049 var od = dom.ownerDocument;
47051 if (this.emptyText) {
47052 var op = od.createElement('option');
47053 op.setAttribute('value', '');
47054 op.innerHTML = String.format('{0}', this.emptyText);
47055 dom.appendChild(op);
47057 if(this.store.getCount() > 0){
47059 var vf = this.valueField;
47060 var df = this.displayField;
47061 this.store.data.each(function(r) {
47062 // which colmsn to use... testing - cdoe / title..
47063 var op = od.createElement('option');
47064 op.setAttribute('value', r.data[vf]);
47065 op.innerHTML = String.format('{0}', r.data[df]);
47066 dom.appendChild(op);
47068 if (typeof(this.defaultValue != 'undefined')) {
47069 this.setValue(this.defaultValue);
47074 //this.onEmptyResults();
47079 onLoadException : function()
47081 dom.innerHTML = '';
47083 Roo.log("Select on load exception");
47087 Roo.log(this.store.reader.jsonData);
47088 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
47089 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
47095 onTypeAhead : function(){
47100 onSelect : function(record, index){
47101 Roo.log('on select?');
47103 if(this.fireEvent('beforeselect', this, record, index) !== false){
47104 this.setFromData(index > -1 ? record.data : false);
47106 this.fireEvent('select', this, record, index);
47111 * Returns the currently selected field value or empty string if no value is set.
47112 * @return {String} value The selected value
47114 getValue : function(){
47115 var dom = this.el.dom;
47116 this.value = dom.options[dom.selectedIndex].value;
47122 * Clears any text/value currently set in the field
47124 clearValue : function(){
47126 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
47131 * Sets the specified value into the field. If the value finds a match, the corresponding record text
47132 * will be displayed in the field. If the value does not match the data value of an existing item,
47133 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
47134 * Otherwise the field will be blank (although the value will still be set).
47135 * @param {String} value The value to match
47137 setValue : function(v){
47138 var d = this.el.dom;
47139 for (var i =0; i < d.options.length;i++) {
47140 if (v == d.options[i].value) {
47141 d.selectedIndex = i;
47149 * @property {Object} the last set data for the element
47154 * Sets the value of the field based on a object which is related to the record format for the store.
47155 * @param {Object} value the value to set as. or false on reset?
47157 setFromData : function(o){
47158 Roo.log('setfrom data?');
47164 reset : function(){
47168 findRecord : function(prop, value){
47173 if(this.store.getCount() > 0){
47174 this.store.each(function(r){
47175 if(r.data[prop] == value){
47185 getName: function()
47187 // returns hidden if it's set..
47188 if (!this.rendered) {return ''};
47189 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
47197 onEmptyResults : function(){
47198 Roo.log('empty results');
47203 * Returns true if the dropdown list is expanded, else false.
47205 isExpanded : function(){
47210 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
47211 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47212 * @param {String} value The data value of the item to select
47213 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47214 * selected item if it is not currently in view (defaults to true)
47215 * @return {Boolean} True if the value matched an item in the list, else false
47217 selectByValue : function(v, scrollIntoView){
47218 Roo.log('select By Value');
47221 if(v !== undefined && v !== null){
47222 var r = this.findRecord(this.valueField || this.displayField, v);
47224 this.select(this.store.indexOf(r), scrollIntoView);
47232 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
47233 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47234 * @param {Number} index The zero-based index of the list item to select
47235 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47236 * selected item if it is not currently in view (defaults to true)
47238 select : function(index, scrollIntoView){
47239 Roo.log('select ');
47242 this.selectedIndex = index;
47243 this.view.select(index);
47244 if(scrollIntoView !== false){
47245 var el = this.view.getNode(index);
47247 this.innerList.scrollChildIntoView(el, false);
47255 validateBlur : function(){
47262 initQuery : function(){
47263 this.doQuery(this.getRawValue());
47267 doForce : function(){
47268 if(this.el.dom.value.length > 0){
47269 this.el.dom.value =
47270 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
47276 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
47277 * query allowing the query action to be canceled if needed.
47278 * @param {String} query The SQL query to execute
47279 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
47280 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
47281 * saved in the current store (defaults to false)
47283 doQuery : function(q, forceAll){
47285 Roo.log('doQuery?');
47286 if(q === undefined || q === null){
47291 forceAll: forceAll,
47295 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
47299 forceAll = qe.forceAll;
47300 if(forceAll === true || (q.length >= this.minChars)){
47301 if(this.lastQuery != q || this.alwaysQuery){
47302 this.lastQuery = q;
47303 if(this.mode == 'local'){
47304 this.selectedIndex = -1;
47306 this.store.clearFilter();
47308 this.store.filter(this.displayField, q);
47312 this.store.baseParams[this.queryParam] = q;
47314 params: this.getParams(q)
47319 this.selectedIndex = -1;
47326 getParams : function(q){
47328 //p[this.queryParam] = q;
47331 p.limit = this.pageSize;
47337 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
47339 collapse : function(){
47344 collapseIf : function(e){
47349 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
47351 expand : function(){
47359 * @cfg {Boolean} grow
47363 * @cfg {Number} growMin
47367 * @cfg {Number} growMax
47375 setWidth : function()
47379 getResizeEl : function(){
47382 });//<script type="text/javasscript">
47386 * @class Roo.DDView
47387 * A DnD enabled version of Roo.View.
47388 * @param {Element/String} container The Element in which to create the View.
47389 * @param {String} tpl The template string used to create the markup for each element of the View
47390 * @param {Object} config The configuration properties. These include all the config options of
47391 * {@link Roo.View} plus some specific to this class.<br>
47393 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
47394 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
47396 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
47397 .x-view-drag-insert-above {
47398 border-top:1px dotted #3366cc;
47400 .x-view-drag-insert-below {
47401 border-bottom:1px dotted #3366cc;
47407 Roo.DDView = function(container, tpl, config) {
47408 Roo.DDView.superclass.constructor.apply(this, arguments);
47409 this.getEl().setStyle("outline", "0px none");
47410 this.getEl().unselectable();
47411 if (this.dragGroup) {
47412 this.setDraggable(this.dragGroup.split(","));
47414 if (this.dropGroup) {
47415 this.setDroppable(this.dropGroup.split(","));
47417 if (this.deletable) {
47418 this.setDeletable();
47420 this.isDirtyFlag = false;
47426 Roo.extend(Roo.DDView, Roo.View, {
47427 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
47428 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
47429 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
47430 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
47434 reset: Roo.emptyFn,
47436 clearInvalid: Roo.form.Field.prototype.clearInvalid,
47438 validate: function() {
47442 destroy: function() {
47443 this.purgeListeners();
47444 this.getEl.removeAllListeners();
47445 this.getEl().remove();
47446 if (this.dragZone) {
47447 if (this.dragZone.destroy) {
47448 this.dragZone.destroy();
47451 if (this.dropZone) {
47452 if (this.dropZone.destroy) {
47453 this.dropZone.destroy();
47458 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
47459 getName: function() {
47463 /** Loads the View from a JSON string representing the Records to put into the Store. */
47464 setValue: function(v) {
47466 throw "DDView.setValue(). DDView must be constructed with a valid Store";
47469 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
47470 this.store.proxy = new Roo.data.MemoryProxy(data);
47474 /** @return {String} a parenthesised list of the ids of the Records in the View. */
47475 getValue: function() {
47477 this.store.each(function(rec) {
47478 result += rec.id + ',';
47480 return result.substr(0, result.length - 1) + ')';
47483 getIds: function() {
47484 var i = 0, result = new Array(this.store.getCount());
47485 this.store.each(function(rec) {
47486 result[i++] = rec.id;
47491 isDirty: function() {
47492 return this.isDirtyFlag;
47496 * Part of the Roo.dd.DropZone interface. If no target node is found, the
47497 * whole Element becomes the target, and this causes the drop gesture to append.
47499 getTargetFromEvent : function(e) {
47500 var target = e.getTarget();
47501 while ((target !== null) && (target.parentNode != this.el.dom)) {
47502 target = target.parentNode;
47505 target = this.el.dom.lastChild || this.el.dom;
47511 * Create the drag data which consists of an object which has the property "ddel" as
47512 * the drag proxy element.
47514 getDragData : function(e) {
47515 var target = this.findItemFromChild(e.getTarget());
47517 this.handleSelection(e);
47518 var selNodes = this.getSelectedNodes();
47521 copy: this.copy || (this.allowCopy && e.ctrlKey),
47525 var selectedIndices = this.getSelectedIndexes();
47526 for (var i = 0; i < selectedIndices.length; i++) {
47527 dragData.records.push(this.store.getAt(selectedIndices[i]));
47529 if (selNodes.length == 1) {
47530 dragData.ddel = target.cloneNode(true); // the div element
47532 var div = document.createElement('div'); // create the multi element drag "ghost"
47533 div.className = 'multi-proxy';
47534 for (var i = 0, len = selNodes.length; i < len; i++) {
47535 div.appendChild(selNodes[i].cloneNode(true));
47537 dragData.ddel = div;
47539 //console.log(dragData)
47540 //console.log(dragData.ddel.innerHTML)
47543 //console.log('nodragData')
47547 /** Specify to which ddGroup items in this DDView may be dragged. */
47548 setDraggable: function(ddGroup) {
47549 if (ddGroup instanceof Array) {
47550 Roo.each(ddGroup, this.setDraggable, this);
47553 if (this.dragZone) {
47554 this.dragZone.addToGroup(ddGroup);
47556 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
47557 containerScroll: true,
47561 // Draggability implies selection. DragZone's mousedown selects the element.
47562 if (!this.multiSelect) { this.singleSelect = true; }
47564 // Wire the DragZone's handlers up to methods in *this*
47565 this.dragZone.getDragData = this.getDragData.createDelegate(this);
47569 /** Specify from which ddGroup this DDView accepts drops. */
47570 setDroppable: function(ddGroup) {
47571 if (ddGroup instanceof Array) {
47572 Roo.each(ddGroup, this.setDroppable, this);
47575 if (this.dropZone) {
47576 this.dropZone.addToGroup(ddGroup);
47578 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
47579 containerScroll: true,
47583 // Wire the DropZone's handlers up to methods in *this*
47584 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
47585 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
47586 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
47587 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
47588 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
47592 /** Decide whether to drop above or below a View node. */
47593 getDropPoint : function(e, n, dd){
47594 if (n == this.el.dom) { return "above"; }
47595 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
47596 var c = t + (b - t) / 2;
47597 var y = Roo.lib.Event.getPageY(e);
47605 onNodeEnter : function(n, dd, e, data){
47609 onNodeOver : function(n, dd, e, data){
47610 var pt = this.getDropPoint(e, n, dd);
47611 // set the insert point style on the target node
47612 var dragElClass = this.dropNotAllowed;
47615 if (pt == "above"){
47616 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
47617 targetElClass = "x-view-drag-insert-above";
47619 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
47620 targetElClass = "x-view-drag-insert-below";
47622 if (this.lastInsertClass != targetElClass){
47623 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
47624 this.lastInsertClass = targetElClass;
47627 return dragElClass;
47630 onNodeOut : function(n, dd, e, data){
47631 this.removeDropIndicators(n);
47634 onNodeDrop : function(n, dd, e, data){
47635 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
47638 var pt = this.getDropPoint(e, n, dd);
47639 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
47640 if (pt == "below") { insertAt++; }
47641 for (var i = 0; i < data.records.length; i++) {
47642 var r = data.records[i];
47643 var dup = this.store.getById(r.id);
47644 if (dup && (dd != this.dragZone)) {
47645 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
47648 this.store.insert(insertAt++, r.copy());
47650 data.source.isDirtyFlag = true;
47652 this.store.insert(insertAt++, r);
47654 this.isDirtyFlag = true;
47657 this.dragZone.cachedTarget = null;
47661 removeDropIndicators : function(n){
47663 Roo.fly(n).removeClass([
47664 "x-view-drag-insert-above",
47665 "x-view-drag-insert-below"]);
47666 this.lastInsertClass = "_noclass";
47671 * Utility method. Add a delete option to the DDView's context menu.
47672 * @param {String} imageUrl The URL of the "delete" icon image.
47674 setDeletable: function(imageUrl) {
47675 if (!this.singleSelect && !this.multiSelect) {
47676 this.singleSelect = true;
47678 var c = this.getContextMenu();
47679 this.contextMenu.on("itemclick", function(item) {
47682 this.remove(this.getSelectedIndexes());
47686 this.contextMenu.add({
47693 /** Return the context menu for this DDView. */
47694 getContextMenu: function() {
47695 if (!this.contextMenu) {
47696 // Create the View's context menu
47697 this.contextMenu = new Roo.menu.Menu({
47698 id: this.id + "-contextmenu"
47700 this.el.on("contextmenu", this.showContextMenu, this);
47702 return this.contextMenu;
47705 disableContextMenu: function() {
47706 if (this.contextMenu) {
47707 this.el.un("contextmenu", this.showContextMenu, this);
47711 showContextMenu: function(e, item) {
47712 item = this.findItemFromChild(e.getTarget());
47715 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
47716 this.contextMenu.showAt(e.getXY());
47721 * Remove {@link Roo.data.Record}s at the specified indices.
47722 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
47724 remove: function(selectedIndices) {
47725 selectedIndices = [].concat(selectedIndices);
47726 for (var i = 0; i < selectedIndices.length; i++) {
47727 var rec = this.store.getAt(selectedIndices[i]);
47728 this.store.remove(rec);
47733 * Double click fires the event, but also, if this is draggable, and there is only one other
47734 * related DropZone, it transfers the selected node.
47736 onDblClick : function(e){
47737 var item = this.findItemFromChild(e.getTarget());
47739 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
47742 if (this.dragGroup) {
47743 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
47744 while (targets.indexOf(this.dropZone) > -1) {
47745 targets.remove(this.dropZone);
47747 if (targets.length == 1) {
47748 this.dragZone.cachedTarget = null;
47749 var el = Roo.get(targets[0].getEl());
47750 var box = el.getBox(true);
47751 targets[0].onNodeDrop(el.dom, {
47753 xy: [box.x, box.y + box.height - 1]
47754 }, null, this.getDragData(e));
47760 handleSelection: function(e) {
47761 this.dragZone.cachedTarget = null;
47762 var item = this.findItemFromChild(e.getTarget());
47764 this.clearSelections(true);
47767 if (item && (this.multiSelect || this.singleSelect)){
47768 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
47769 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
47770 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
47771 this.unselect(item);
47773 this.select(item, this.multiSelect && e.ctrlKey);
47774 this.lastSelection = item;
47779 onItemClick : function(item, index, e){
47780 if(this.fireEvent("beforeclick", this, index, item, e) === false){
47786 unselect : function(nodeInfo, suppressEvent){
47787 var node = this.getNode(nodeInfo);
47788 if(node && this.isSelected(node)){
47789 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
47790 Roo.fly(node).removeClass(this.selectedClass);
47791 this.selections.remove(node);
47792 if(!suppressEvent){
47793 this.fireEvent("selectionchange", this, this.selections);
47801 * Ext JS Library 1.1.1
47802 * Copyright(c) 2006-2007, Ext JS, LLC.
47804 * Originally Released Under LGPL - original licence link has changed is not relivant.
47807 * <script type="text/javascript">
47811 * @class Roo.LayoutManager
47812 * @extends Roo.util.Observable
47813 * Base class for layout managers.
47815 Roo.LayoutManager = function(container, config){
47816 Roo.LayoutManager.superclass.constructor.call(this);
47817 this.el = Roo.get(container);
47818 // ie scrollbar fix
47819 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
47820 document.body.scroll = "no";
47821 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
47822 this.el.position('relative');
47824 this.id = this.el.id;
47825 this.el.addClass("x-layout-container");
47826 /** false to disable window resize monitoring @type Boolean */
47827 this.monitorWindowResize = true;
47832 * Fires when a layout is performed.
47833 * @param {Roo.LayoutManager} this
47837 * @event regionresized
47838 * Fires when the user resizes a region.
47839 * @param {Roo.LayoutRegion} region The resized region
47840 * @param {Number} newSize The new size (width for east/west, height for north/south)
47842 "regionresized" : true,
47844 * @event regioncollapsed
47845 * Fires when a region is collapsed.
47846 * @param {Roo.LayoutRegion} region The collapsed region
47848 "regioncollapsed" : true,
47850 * @event regionexpanded
47851 * Fires when a region is expanded.
47852 * @param {Roo.LayoutRegion} region The expanded region
47854 "regionexpanded" : true
47856 this.updating = false;
47857 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
47860 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
47862 * Returns true if this layout is currently being updated
47863 * @return {Boolean}
47865 isUpdating : function(){
47866 return this.updating;
47870 * Suspend the LayoutManager from doing auto-layouts while
47871 * making multiple add or remove calls
47873 beginUpdate : function(){
47874 this.updating = true;
47878 * Restore auto-layouts and optionally disable the manager from performing a layout
47879 * @param {Boolean} noLayout true to disable a layout update
47881 endUpdate : function(noLayout){
47882 this.updating = false;
47888 layout: function(){
47892 onRegionResized : function(region, newSize){
47893 this.fireEvent("regionresized", region, newSize);
47897 onRegionCollapsed : function(region){
47898 this.fireEvent("regioncollapsed", region);
47901 onRegionExpanded : function(region){
47902 this.fireEvent("regionexpanded", region);
47906 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
47907 * performs box-model adjustments.
47908 * @return {Object} The size as an object {width: (the width), height: (the height)}
47910 getViewSize : function(){
47912 if(this.el.dom != document.body){
47913 size = this.el.getSize();
47915 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
47917 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
47918 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
47923 * Returns the Element this layout is bound to.
47924 * @return {Roo.Element}
47926 getEl : function(){
47931 * Returns the specified region.
47932 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
47933 * @return {Roo.LayoutRegion}
47935 getRegion : function(target){
47936 return this.regions[target.toLowerCase()];
47939 onWindowResize : function(){
47940 if(this.monitorWindowResize){
47946 * Ext JS Library 1.1.1
47947 * Copyright(c) 2006-2007, Ext JS, LLC.
47949 * Originally Released Under LGPL - original licence link has changed is not relivant.
47952 * <script type="text/javascript">
47955 * @class Roo.BorderLayout
47956 * @extends Roo.LayoutManager
47957 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
47958 * please see: <br><br>
47959 * <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>
47960 * <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>
47963 var layout = new Roo.BorderLayout(document.body, {
47997 preferredTabWidth: 150
48002 var CP = Roo.ContentPanel;
48004 layout.beginUpdate();
48005 layout.add("north", new CP("north", "North"));
48006 layout.add("south", new CP("south", {title: "South", closable: true}));
48007 layout.add("west", new CP("west", {title: "West"}));
48008 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
48009 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
48010 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
48011 layout.getRegion("center").showPanel("center1");
48012 layout.endUpdate();
48015 <b>The container the layout is rendered into can be either the body element or any other element.
48016 If it is not the body element, the container needs to either be an absolute positioned element,
48017 or you will need to add "position:relative" to the css of the container. You will also need to specify
48018 the container size if it is not the body element.</b>
48021 * Create a new BorderLayout
48022 * @param {String/HTMLElement/Element} container The container this layout is bound to
48023 * @param {Object} config Configuration options
48025 Roo.BorderLayout = function(container, config){
48026 config = config || {};
48027 Roo.BorderLayout.superclass.constructor.call(this, container, config);
48028 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
48029 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
48030 var target = this.factory.validRegions[i];
48031 if(config[target]){
48032 this.addRegion(target, config[target]);
48037 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
48039 * Creates and adds a new region if it doesn't already exist.
48040 * @param {String} target The target region key (north, south, east, west or center).
48041 * @param {Object} config The regions config object
48042 * @return {BorderLayoutRegion} The new region
48044 addRegion : function(target, config){
48045 if(!this.regions[target]){
48046 var r = this.factory.create(target, this, config);
48047 this.bindRegion(target, r);
48049 return this.regions[target];
48053 bindRegion : function(name, r){
48054 this.regions[name] = r;
48055 r.on("visibilitychange", this.layout, this);
48056 r.on("paneladded", this.layout, this);
48057 r.on("panelremoved", this.layout, this);
48058 r.on("invalidated", this.layout, this);
48059 r.on("resized", this.onRegionResized, this);
48060 r.on("collapsed", this.onRegionCollapsed, this);
48061 r.on("expanded", this.onRegionExpanded, this);
48065 * Performs a layout update.
48067 layout : function(){
48068 if(this.updating) return;
48069 var size = this.getViewSize();
48070 var w = size.width;
48071 var h = size.height;
48076 //var x = 0, y = 0;
48078 var rs = this.regions;
48079 var north = rs["north"];
48080 var south = rs["south"];
48081 var west = rs["west"];
48082 var east = rs["east"];
48083 var center = rs["center"];
48084 //if(this.hideOnLayout){ // not supported anymore
48085 //c.el.setStyle("display", "none");
48087 if(north && north.isVisible()){
48088 var b = north.getBox();
48089 var m = north.getMargins();
48090 b.width = w - (m.left+m.right);
48093 centerY = b.height + b.y + m.bottom;
48094 centerH -= centerY;
48095 north.updateBox(this.safeBox(b));
48097 if(south && south.isVisible()){
48098 var b = south.getBox();
48099 var m = south.getMargins();
48100 b.width = w - (m.left+m.right);
48102 var totalHeight = (b.height + m.top + m.bottom);
48103 b.y = h - totalHeight + m.top;
48104 centerH -= totalHeight;
48105 south.updateBox(this.safeBox(b));
48107 if(west && west.isVisible()){
48108 var b = west.getBox();
48109 var m = west.getMargins();
48110 b.height = centerH - (m.top+m.bottom);
48112 b.y = centerY + m.top;
48113 var totalWidth = (b.width + m.left + m.right);
48114 centerX += totalWidth;
48115 centerW -= totalWidth;
48116 west.updateBox(this.safeBox(b));
48118 if(east && east.isVisible()){
48119 var b = east.getBox();
48120 var m = east.getMargins();
48121 b.height = centerH - (m.top+m.bottom);
48122 var totalWidth = (b.width + m.left + m.right);
48123 b.x = w - totalWidth + m.left;
48124 b.y = centerY + m.top;
48125 centerW -= totalWidth;
48126 east.updateBox(this.safeBox(b));
48129 var m = center.getMargins();
48131 x: centerX + m.left,
48132 y: centerY + m.top,
48133 width: centerW - (m.left+m.right),
48134 height: centerH - (m.top+m.bottom)
48136 //if(this.hideOnLayout){
48137 //center.el.setStyle("display", "block");
48139 center.updateBox(this.safeBox(centerBox));
48142 this.fireEvent("layout", this);
48146 safeBox : function(box){
48147 box.width = Math.max(0, box.width);
48148 box.height = Math.max(0, box.height);
48153 * Adds a ContentPanel (or subclass) to this layout.
48154 * @param {String} target The target region key (north, south, east, west or center).
48155 * @param {Roo.ContentPanel} panel The panel to add
48156 * @return {Roo.ContentPanel} The added panel
48158 add : function(target, panel){
48160 target = target.toLowerCase();
48161 return this.regions[target].add(panel);
48165 * Remove a ContentPanel (or subclass) to this layout.
48166 * @param {String} target The target region key (north, south, east, west or center).
48167 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
48168 * @return {Roo.ContentPanel} The removed panel
48170 remove : function(target, panel){
48171 target = target.toLowerCase();
48172 return this.regions[target].remove(panel);
48176 * Searches all regions for a panel with the specified id
48177 * @param {String} panelId
48178 * @return {Roo.ContentPanel} The panel or null if it wasn't found
48180 findPanel : function(panelId){
48181 var rs = this.regions;
48182 for(var target in rs){
48183 if(typeof rs[target] != "function"){
48184 var p = rs[target].getPanel(panelId);
48194 * Searches all regions for a panel with the specified id and activates (shows) it.
48195 * @param {String/ContentPanel} panelId The panels id or the panel itself
48196 * @return {Roo.ContentPanel} The shown panel or null
48198 showPanel : function(panelId) {
48199 var rs = this.regions;
48200 for(var target in rs){
48201 var r = rs[target];
48202 if(typeof r != "function"){
48203 if(r.hasPanel(panelId)){
48204 return r.showPanel(panelId);
48212 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
48213 * @param {Roo.state.Provider} provider (optional) An alternate state provider
48215 restoreState : function(provider){
48217 provider = Roo.state.Manager;
48219 var sm = new Roo.LayoutStateManager();
48220 sm.init(this, provider);
48224 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
48225 * object should contain properties for each region to add ContentPanels to, and each property's value should be
48226 * a valid ContentPanel config object. Example:
48228 // Create the main layout
48229 var layout = new Roo.BorderLayout('main-ct', {
48240 // Create and add multiple ContentPanels at once via configs
48243 id: 'source-files',
48245 title:'Ext Source Files',
48258 * @param {Object} regions An object containing ContentPanel configs by region name
48260 batchAdd : function(regions){
48261 this.beginUpdate();
48262 for(var rname in regions){
48263 var lr = this.regions[rname];
48265 this.addTypedPanels(lr, regions[rname]);
48272 addTypedPanels : function(lr, ps){
48273 if(typeof ps == 'string'){
48274 lr.add(new Roo.ContentPanel(ps));
48276 else if(ps instanceof Array){
48277 for(var i =0, len = ps.length; i < len; i++){
48278 this.addTypedPanels(lr, ps[i]);
48281 else if(!ps.events){ // raw config?
48283 delete ps.el; // prevent conflict
48284 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
48286 else { // panel object assumed!
48291 * Adds a xtype elements to the layout.
48295 xtype : 'ContentPanel',
48302 xtype : 'NestedLayoutPanel',
48308 items : [ ... list of content panels or nested layout panels.. ]
48312 * @param {Object} cfg Xtype definition of item to add.
48314 addxtype : function(cfg)
48316 // basically accepts a pannel...
48317 // can accept a layout region..!?!?
48318 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
48320 if (!cfg.xtype.match(/Panel$/)) {
48325 if (typeof(cfg.region) == 'undefined') {
48326 Roo.log("Failed to add Panel, region was not set");
48330 var region = cfg.region;
48336 xitems = cfg.items;
48343 case 'ContentPanel': // ContentPanel (el, cfg)
48344 case 'ScrollPanel': // ContentPanel (el, cfg)
48346 if(cfg.autoCreate) {
48347 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48349 var el = this.el.createChild();
48350 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
48353 this.add(region, ret);
48357 case 'TreePanel': // our new panel!
48358 cfg.el = this.el.createChild();
48359 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48360 this.add(region, ret);
48363 case 'NestedLayoutPanel':
48364 // create a new Layout (which is a Border Layout...
48365 var el = this.el.createChild();
48366 var clayout = cfg.layout;
48368 clayout.items = clayout.items || [];
48369 // replace this exitems with the clayout ones..
48370 xitems = clayout.items;
48373 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
48374 cfg.background = false;
48376 var layout = new Roo.BorderLayout(el, clayout);
48378 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
48379 //console.log('adding nested layout panel ' + cfg.toSource());
48380 this.add(region, ret);
48381 nb = {}; /// find first...
48386 // needs grid and region
48388 //var el = this.getRegion(region).el.createChild();
48389 var el = this.el.createChild();
48390 // create the grid first...
48392 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
48394 if (region == 'center' && this.active ) {
48395 cfg.background = false;
48397 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
48399 this.add(region, ret);
48400 if (cfg.background) {
48401 ret.on('activate', function(gp) {
48402 if (!gp.grid.rendered) {
48417 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
48419 // GridPanel (grid, cfg)
48422 this.beginUpdate();
48426 Roo.each(xitems, function(i) {
48427 region = nb && i.region ? i.region : false;
48429 var add = ret.addxtype(i);
48432 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
48433 if (!i.background) {
48434 abn[region] = nb[region] ;
48441 // make the last non-background panel active..
48442 //if (nb) { Roo.log(abn); }
48445 for(var r in abn) {
48446 region = this.getRegion(r);
48448 // tried using nb[r], but it does not work..
48450 region.showPanel(abn[r]);
48461 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
48462 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
48463 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
48464 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
48467 var CP = Roo.ContentPanel;
48469 var layout = Roo.BorderLayout.create({
48473 panels: [new CP("north", "North")]
48482 panels: [new CP("west", {title: "West"})]
48491 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
48500 panels: [new CP("south", {title: "South", closable: true})]
48507 preferredTabWidth: 150,
48509 new CP("center1", {title: "Close Me", closable: true}),
48510 new CP("center2", {title: "Center Panel", closable: false})
48515 layout.getRegion("center").showPanel("center1");
48520 Roo.BorderLayout.create = function(config, targetEl){
48521 var layout = new Roo.BorderLayout(targetEl || document.body, config);
48522 layout.beginUpdate();
48523 var regions = Roo.BorderLayout.RegionFactory.validRegions;
48524 for(var j = 0, jlen = regions.length; j < jlen; j++){
48525 var lr = regions[j];
48526 if(layout.regions[lr] && config[lr].panels){
48527 var r = layout.regions[lr];
48528 var ps = config[lr].panels;
48529 layout.addTypedPanels(r, ps);
48532 layout.endUpdate();
48537 Roo.BorderLayout.RegionFactory = {
48539 validRegions : ["north","south","east","west","center"],
48542 create : function(target, mgr, config){
48543 target = target.toLowerCase();
48544 if(config.lightweight || config.basic){
48545 return new Roo.BasicLayoutRegion(mgr, config, target);
48549 return new Roo.NorthLayoutRegion(mgr, config);
48551 return new Roo.SouthLayoutRegion(mgr, config);
48553 return new Roo.EastLayoutRegion(mgr, config);
48555 return new Roo.WestLayoutRegion(mgr, config);
48557 return new Roo.CenterLayoutRegion(mgr, config);
48559 throw 'Layout region "'+target+'" not supported.';
48563 * Ext JS Library 1.1.1
48564 * Copyright(c) 2006-2007, Ext JS, LLC.
48566 * Originally Released Under LGPL - original licence link has changed is not relivant.
48569 * <script type="text/javascript">
48573 * @class Roo.BasicLayoutRegion
48574 * @extends Roo.util.Observable
48575 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
48576 * and does not have a titlebar, tabs or any other features. All it does is size and position
48577 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
48579 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
48581 this.position = pos;
48584 * @scope Roo.BasicLayoutRegion
48588 * @event beforeremove
48589 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
48590 * @param {Roo.LayoutRegion} this
48591 * @param {Roo.ContentPanel} panel The panel
48592 * @param {Object} e The cancel event object
48594 "beforeremove" : true,
48596 * @event invalidated
48597 * Fires when the layout for this region is changed.
48598 * @param {Roo.LayoutRegion} this
48600 "invalidated" : true,
48602 * @event visibilitychange
48603 * Fires when this region is shown or hidden
48604 * @param {Roo.LayoutRegion} this
48605 * @param {Boolean} visibility true or false
48607 "visibilitychange" : true,
48609 * @event paneladded
48610 * Fires when a panel is added.
48611 * @param {Roo.LayoutRegion} this
48612 * @param {Roo.ContentPanel} panel The panel
48614 "paneladded" : true,
48616 * @event panelremoved
48617 * Fires when a panel is removed.
48618 * @param {Roo.LayoutRegion} this
48619 * @param {Roo.ContentPanel} panel The panel
48621 "panelremoved" : true,
48624 * Fires when this region is collapsed.
48625 * @param {Roo.LayoutRegion} this
48627 "collapsed" : true,
48630 * Fires when this region is expanded.
48631 * @param {Roo.LayoutRegion} this
48636 * Fires when this region is slid into view.
48637 * @param {Roo.LayoutRegion} this
48639 "slideshow" : true,
48642 * Fires when this region slides out of view.
48643 * @param {Roo.LayoutRegion} this
48645 "slidehide" : true,
48647 * @event panelactivated
48648 * Fires when a panel is activated.
48649 * @param {Roo.LayoutRegion} this
48650 * @param {Roo.ContentPanel} panel The activated panel
48652 "panelactivated" : true,
48655 * Fires when the user resizes this region.
48656 * @param {Roo.LayoutRegion} this
48657 * @param {Number} newSize The new size (width for east/west, height for north/south)
48661 /** A collection of panels in this region. @type Roo.util.MixedCollection */
48662 this.panels = new Roo.util.MixedCollection();
48663 this.panels.getKey = this.getPanelId.createDelegate(this);
48665 this.activePanel = null;
48666 // ensure listeners are added...
48668 if (config.listeners || config.events) {
48669 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
48670 listeners : config.listeners || {},
48671 events : config.events || {}
48675 if(skipConfig !== true){
48676 this.applyConfig(config);
48680 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
48681 getPanelId : function(p){
48685 applyConfig : function(config){
48686 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
48687 this.config = config;
48692 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
48693 * the width, for horizontal (north, south) the height.
48694 * @param {Number} newSize The new width or height
48696 resizeTo : function(newSize){
48697 var el = this.el ? this.el :
48698 (this.activePanel ? this.activePanel.getEl() : null);
48700 switch(this.position){
48703 el.setWidth(newSize);
48704 this.fireEvent("resized", this, newSize);
48708 el.setHeight(newSize);
48709 this.fireEvent("resized", this, newSize);
48715 getBox : function(){
48716 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
48719 getMargins : function(){
48720 return this.margins;
48723 updateBox : function(box){
48725 var el = this.activePanel.getEl();
48726 el.dom.style.left = box.x + "px";
48727 el.dom.style.top = box.y + "px";
48728 this.activePanel.setSize(box.width, box.height);
48732 * Returns the container element for this region.
48733 * @return {Roo.Element}
48735 getEl : function(){
48736 return this.activePanel;
48740 * Returns true if this region is currently visible.
48741 * @return {Boolean}
48743 isVisible : function(){
48744 return this.activePanel ? true : false;
48747 setActivePanel : function(panel){
48748 panel = this.getPanel(panel);
48749 if(this.activePanel && this.activePanel != panel){
48750 this.activePanel.setActiveState(false);
48751 this.activePanel.getEl().setLeftTop(-10000,-10000);
48753 this.activePanel = panel;
48754 panel.setActiveState(true);
48756 panel.setSize(this.box.width, this.box.height);
48758 this.fireEvent("panelactivated", this, panel);
48759 this.fireEvent("invalidated");
48763 * Show the specified panel.
48764 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
48765 * @return {Roo.ContentPanel} The shown panel or null
48767 showPanel : function(panel){
48768 if(panel = this.getPanel(panel)){
48769 this.setActivePanel(panel);
48775 * Get the active panel for this region.
48776 * @return {Roo.ContentPanel} The active panel or null
48778 getActivePanel : function(){
48779 return this.activePanel;
48783 * Add the passed ContentPanel(s)
48784 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
48785 * @return {Roo.ContentPanel} The panel added (if only one was added)
48787 add : function(panel){
48788 if(arguments.length > 1){
48789 for(var i = 0, len = arguments.length; i < len; i++) {
48790 this.add(arguments[i]);
48794 if(this.hasPanel(panel)){
48795 this.showPanel(panel);
48798 var el = panel.getEl();
48799 if(el.dom.parentNode != this.mgr.el.dom){
48800 this.mgr.el.dom.appendChild(el.dom);
48802 if(panel.setRegion){
48803 panel.setRegion(this);
48805 this.panels.add(panel);
48806 el.setStyle("position", "absolute");
48807 if(!panel.background){
48808 this.setActivePanel(panel);
48809 if(this.config.initialSize && this.panels.getCount()==1){
48810 this.resizeTo(this.config.initialSize);
48813 this.fireEvent("paneladded", this, panel);
48818 * Returns true if the panel is in this region.
48819 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48820 * @return {Boolean}
48822 hasPanel : function(panel){
48823 if(typeof panel == "object"){ // must be panel obj
48824 panel = panel.getId();
48826 return this.getPanel(panel) ? true : false;
48830 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
48831 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48832 * @param {Boolean} preservePanel Overrides the config preservePanel option
48833 * @return {Roo.ContentPanel} The panel that was removed
48835 remove : function(panel, preservePanel){
48836 panel = this.getPanel(panel);
48841 this.fireEvent("beforeremove", this, panel, e);
48842 if(e.cancel === true){
48845 var panelId = panel.getId();
48846 this.panels.removeKey(panelId);
48851 * Returns the panel specified or null if it's not in this region.
48852 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48853 * @return {Roo.ContentPanel}
48855 getPanel : function(id){
48856 if(typeof id == "object"){ // must be panel obj
48859 return this.panels.get(id);
48863 * Returns this regions position (north/south/east/west/center).
48866 getPosition: function(){
48867 return this.position;
48871 * Ext JS Library 1.1.1
48872 * Copyright(c) 2006-2007, Ext JS, LLC.
48874 * Originally Released Under LGPL - original licence link has changed is not relivant.
48877 * <script type="text/javascript">
48881 * @class Roo.LayoutRegion
48882 * @extends Roo.BasicLayoutRegion
48883 * This class represents a region in a layout manager.
48884 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
48885 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
48886 * @cfg {Boolean} floatable False to disable floating (defaults to true)
48887 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
48888 * @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})
48889 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
48890 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
48891 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
48892 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
48893 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
48894 * @cfg {String} title The title for the region (overrides panel titles)
48895 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
48896 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
48897 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
48898 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
48899 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
48900 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
48901 * the space available, similar to FireFox 1.5 tabs (defaults to false)
48902 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
48903 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
48904 * @cfg {Boolean} showPin True to show a pin button
48905 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
48906 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
48907 * @cfg {Boolean} disableTabTips True to disable tab tooltips
48908 * @cfg {Number} width For East/West panels
48909 * @cfg {Number} height For North/South panels
48910 * @cfg {Boolean} split To show the splitter
48911 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
48913 Roo.LayoutRegion = function(mgr, config, pos){
48914 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
48915 var dh = Roo.DomHelper;
48916 /** This region's container element
48917 * @type Roo.Element */
48918 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
48919 /** This region's title element
48920 * @type Roo.Element */
48922 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
48923 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
48924 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
48926 this.titleEl.enableDisplayMode();
48927 /** This region's title text element
48928 * @type HTMLElement */
48929 this.titleTextEl = this.titleEl.dom.firstChild;
48930 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
48931 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
48932 this.closeBtn.enableDisplayMode();
48933 this.closeBtn.on("click", this.closeClicked, this);
48934 this.closeBtn.hide();
48936 this.createBody(config);
48937 this.visible = true;
48938 this.collapsed = false;
48940 if(config.hideWhenEmpty){
48942 this.on("paneladded", this.validateVisibility, this);
48943 this.on("panelremoved", this.validateVisibility, this);
48945 this.applyConfig(config);
48948 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
48950 createBody : function(){
48951 /** This region's body element
48952 * @type Roo.Element */
48953 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
48956 applyConfig : function(c){
48957 if(c.collapsible && this.position != "center" && !this.collapsedEl){
48958 var dh = Roo.DomHelper;
48959 if(c.titlebar !== false){
48960 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
48961 this.collapseBtn.on("click", this.collapse, this);
48962 this.collapseBtn.enableDisplayMode();
48964 if(c.showPin === true || this.showPin){
48965 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
48966 this.stickBtn.enableDisplayMode();
48967 this.stickBtn.on("click", this.expand, this);
48968 this.stickBtn.hide();
48971 /** This region's collapsed element
48972 * @type Roo.Element */
48973 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
48974 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
48976 if(c.floatable !== false){
48977 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
48978 this.collapsedEl.on("click", this.collapseClick, this);
48981 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
48982 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
48983 id: "message", unselectable: "on", style:{"float":"left"}});
48984 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
48986 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
48987 this.expandBtn.on("click", this.expand, this);
48989 if(this.collapseBtn){
48990 this.collapseBtn.setVisible(c.collapsible == true);
48992 this.cmargins = c.cmargins || this.cmargins ||
48993 (this.position == "west" || this.position == "east" ?
48994 {top: 0, left: 2, right:2, bottom: 0} :
48995 {top: 2, left: 0, right:0, bottom: 2});
48996 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
48997 this.bottomTabs = c.tabPosition != "top";
48998 this.autoScroll = c.autoScroll || false;
48999 if(this.autoScroll){
49000 this.bodyEl.setStyle("overflow", "auto");
49002 this.bodyEl.setStyle("overflow", "hidden");
49004 //if(c.titlebar !== false){
49005 if((!c.titlebar && !c.title) || c.titlebar === false){
49006 this.titleEl.hide();
49008 this.titleEl.show();
49010 this.titleTextEl.innerHTML = c.title;
49014 this.duration = c.duration || .30;
49015 this.slideDuration = c.slideDuration || .45;
49018 this.collapse(true);
49025 * Returns true if this region is currently visible.
49026 * @return {Boolean}
49028 isVisible : function(){
49029 return this.visible;
49033 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
49034 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
49036 setCollapsedTitle : function(title){
49037 title = title || " ";
49038 if(this.collapsedTitleTextEl){
49039 this.collapsedTitleTextEl.innerHTML = title;
49043 getBox : function(){
49045 if(!this.collapsed){
49046 b = this.el.getBox(false, true);
49048 b = this.collapsedEl.getBox(false, true);
49053 getMargins : function(){
49054 return this.collapsed ? this.cmargins : this.margins;
49057 highlight : function(){
49058 this.el.addClass("x-layout-panel-dragover");
49061 unhighlight : function(){
49062 this.el.removeClass("x-layout-panel-dragover");
49065 updateBox : function(box){
49067 if(!this.collapsed){
49068 this.el.dom.style.left = box.x + "px";
49069 this.el.dom.style.top = box.y + "px";
49070 this.updateBody(box.width, box.height);
49072 this.collapsedEl.dom.style.left = box.x + "px";
49073 this.collapsedEl.dom.style.top = box.y + "px";
49074 this.collapsedEl.setSize(box.width, box.height);
49077 this.tabs.autoSizeTabs();
49081 updateBody : function(w, h){
49083 this.el.setWidth(w);
49084 w -= this.el.getBorderWidth("rl");
49085 if(this.config.adjustments){
49086 w += this.config.adjustments[0];
49090 this.el.setHeight(h);
49091 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
49092 h -= this.el.getBorderWidth("tb");
49093 if(this.config.adjustments){
49094 h += this.config.adjustments[1];
49096 this.bodyEl.setHeight(h);
49098 h = this.tabs.syncHeight(h);
49101 if(this.panelSize){
49102 w = w !== null ? w : this.panelSize.width;
49103 h = h !== null ? h : this.panelSize.height;
49105 if(this.activePanel){
49106 var el = this.activePanel.getEl();
49107 w = w !== null ? w : el.getWidth();
49108 h = h !== null ? h : el.getHeight();
49109 this.panelSize = {width: w, height: h};
49110 this.activePanel.setSize(w, h);
49112 if(Roo.isIE && this.tabs){
49113 this.tabs.el.repaint();
49118 * Returns the container element for this region.
49119 * @return {Roo.Element}
49121 getEl : function(){
49126 * Hides this region.
49129 if(!this.collapsed){
49130 this.el.dom.style.left = "-2000px";
49133 this.collapsedEl.dom.style.left = "-2000px";
49134 this.collapsedEl.hide();
49136 this.visible = false;
49137 this.fireEvent("visibilitychange", this, false);
49141 * Shows this region if it was previously hidden.
49144 if(!this.collapsed){
49147 this.collapsedEl.show();
49149 this.visible = true;
49150 this.fireEvent("visibilitychange", this, true);
49153 closeClicked : function(){
49154 if(this.activePanel){
49155 this.remove(this.activePanel);
49159 collapseClick : function(e){
49161 e.stopPropagation();
49164 e.stopPropagation();
49170 * Collapses this region.
49171 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
49173 collapse : function(skipAnim){
49174 if(this.collapsed) return;
49175 this.collapsed = true;
49177 this.split.el.hide();
49179 if(this.config.animate && skipAnim !== true){
49180 this.fireEvent("invalidated", this);
49181 this.animateCollapse();
49183 this.el.setLocation(-20000,-20000);
49185 this.collapsedEl.show();
49186 this.fireEvent("collapsed", this);
49187 this.fireEvent("invalidated", this);
49191 animateCollapse : function(){
49196 * Expands this region if it was previously collapsed.
49197 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
49198 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
49200 expand : function(e, skipAnim){
49201 if(e) e.stopPropagation();
49202 if(!this.collapsed || this.el.hasActiveFx()) return;
49204 this.afterSlideIn();
49207 this.collapsed = false;
49208 if(this.config.animate && skipAnim !== true){
49209 this.animateExpand();
49213 this.split.el.show();
49215 this.collapsedEl.setLocation(-2000,-2000);
49216 this.collapsedEl.hide();
49217 this.fireEvent("invalidated", this);
49218 this.fireEvent("expanded", this);
49222 animateExpand : function(){
49226 initTabs : function()
49228 this.bodyEl.setStyle("overflow", "hidden");
49229 var ts = new Roo.TabPanel(
49232 tabPosition: this.bottomTabs ? 'bottom' : 'top',
49233 disableTooltips: this.config.disableTabTips,
49234 toolbar : this.config.toolbar
49237 if(this.config.hideTabs){
49238 ts.stripWrap.setDisplayed(false);
49241 ts.resizeTabs = this.config.resizeTabs === true;
49242 ts.minTabWidth = this.config.minTabWidth || 40;
49243 ts.maxTabWidth = this.config.maxTabWidth || 250;
49244 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
49245 ts.monitorResize = false;
49246 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49247 ts.bodyEl.addClass('x-layout-tabs-body');
49248 this.panels.each(this.initPanelAsTab, this);
49251 initPanelAsTab : function(panel){
49252 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
49253 this.config.closeOnTab && panel.isClosable());
49254 if(panel.tabTip !== undefined){
49255 ti.setTooltip(panel.tabTip);
49257 ti.on("activate", function(){
49258 this.setActivePanel(panel);
49260 if(this.config.closeOnTab){
49261 ti.on("beforeclose", function(t, e){
49263 this.remove(panel);
49269 updatePanelTitle : function(panel, title){
49270 if(this.activePanel == panel){
49271 this.updateTitle(title);
49274 var ti = this.tabs.getTab(panel.getEl().id);
49276 if(panel.tabTip !== undefined){
49277 ti.setTooltip(panel.tabTip);
49282 updateTitle : function(title){
49283 if(this.titleTextEl && !this.config.title){
49284 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
49288 setActivePanel : function(panel){
49289 panel = this.getPanel(panel);
49290 if(this.activePanel && this.activePanel != panel){
49291 this.activePanel.setActiveState(false);
49293 this.activePanel = panel;
49294 panel.setActiveState(true);
49295 if(this.panelSize){
49296 panel.setSize(this.panelSize.width, this.panelSize.height);
49299 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
49301 this.updateTitle(panel.getTitle());
49303 this.fireEvent("invalidated", this);
49305 this.fireEvent("panelactivated", this, panel);
49309 * Shows the specified panel.
49310 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
49311 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
49313 showPanel : function(panel){
49314 if(panel = this.getPanel(panel)){
49316 var tab = this.tabs.getTab(panel.getEl().id);
49317 if(tab.isHidden()){
49318 this.tabs.unhideTab(tab.id);
49322 this.setActivePanel(panel);
49329 * Get the active panel for this region.
49330 * @return {Roo.ContentPanel} The active panel or null
49332 getActivePanel : function(){
49333 return this.activePanel;
49336 validateVisibility : function(){
49337 if(this.panels.getCount() < 1){
49338 this.updateTitle(" ");
49339 this.closeBtn.hide();
49342 if(!this.isVisible()){
49349 * Adds the passed ContentPanel(s) to this region.
49350 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49351 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
49353 add : function(panel){
49354 if(arguments.length > 1){
49355 for(var i = 0, len = arguments.length; i < len; i++) {
49356 this.add(arguments[i]);
49360 if(this.hasPanel(panel)){
49361 this.showPanel(panel);
49364 panel.setRegion(this);
49365 this.panels.add(panel);
49366 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
49367 this.bodyEl.dom.appendChild(panel.getEl().dom);
49368 if(panel.background !== true){
49369 this.setActivePanel(panel);
49371 this.fireEvent("paneladded", this, panel);
49377 this.initPanelAsTab(panel);
49379 if(panel.background !== true){
49380 this.tabs.activate(panel.getEl().id);
49382 this.fireEvent("paneladded", this, panel);
49387 * Hides the tab for the specified panel.
49388 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49390 hidePanel : function(panel){
49391 if(this.tabs && (panel = this.getPanel(panel))){
49392 this.tabs.hideTab(panel.getEl().id);
49397 * Unhides the tab for a previously hidden panel.
49398 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49400 unhidePanel : function(panel){
49401 if(this.tabs && (panel = this.getPanel(panel))){
49402 this.tabs.unhideTab(panel.getEl().id);
49406 clearPanels : function(){
49407 while(this.panels.getCount() > 0){
49408 this.remove(this.panels.first());
49413 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49414 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49415 * @param {Boolean} preservePanel Overrides the config preservePanel option
49416 * @return {Roo.ContentPanel} The panel that was removed
49418 remove : function(panel, preservePanel){
49419 panel = this.getPanel(panel);
49424 this.fireEvent("beforeremove", this, panel, e);
49425 if(e.cancel === true){
49428 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
49429 var panelId = panel.getId();
49430 this.panels.removeKey(panelId);
49432 document.body.appendChild(panel.getEl().dom);
49435 this.tabs.removeTab(panel.getEl().id);
49436 }else if (!preservePanel){
49437 this.bodyEl.dom.removeChild(panel.getEl().dom);
49439 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
49440 var p = this.panels.first();
49441 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
49442 tempEl.appendChild(p.getEl().dom);
49443 this.bodyEl.update("");
49444 this.bodyEl.dom.appendChild(p.getEl().dom);
49446 this.updateTitle(p.getTitle());
49448 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49449 this.setActivePanel(p);
49451 panel.setRegion(null);
49452 if(this.activePanel == panel){
49453 this.activePanel = null;
49455 if(this.config.autoDestroy !== false && preservePanel !== true){
49456 try{panel.destroy();}catch(e){}
49458 this.fireEvent("panelremoved", this, panel);
49463 * Returns the TabPanel component used by this region
49464 * @return {Roo.TabPanel}
49466 getTabs : function(){
49470 createTool : function(parentEl, className){
49471 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
49472 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
49473 btn.addClassOnOver("x-layout-tools-button-over");
49478 * Ext JS Library 1.1.1
49479 * Copyright(c) 2006-2007, Ext JS, LLC.
49481 * Originally Released Under LGPL - original licence link has changed is not relivant.
49484 * <script type="text/javascript">
49490 * @class Roo.SplitLayoutRegion
49491 * @extends Roo.LayoutRegion
49492 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
49494 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
49495 this.cursor = cursor;
49496 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
49499 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
49500 splitTip : "Drag to resize.",
49501 collapsibleSplitTip : "Drag to resize. Double click to hide.",
49502 useSplitTips : false,
49504 applyConfig : function(config){
49505 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
49508 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
49509 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
49510 /** The SplitBar for this region
49511 * @type Roo.SplitBar */
49512 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
49513 this.split.on("moved", this.onSplitMove, this);
49514 this.split.useShim = config.useShim === true;
49515 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
49516 if(this.useSplitTips){
49517 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
49519 if(config.collapsible){
49520 this.split.el.on("dblclick", this.collapse, this);
49523 if(typeof config.minSize != "undefined"){
49524 this.split.minSize = config.minSize;
49526 if(typeof config.maxSize != "undefined"){
49527 this.split.maxSize = config.maxSize;
49529 if(config.hideWhenEmpty || config.hidden || config.collapsed){
49530 this.hideSplitter();
49535 getHMaxSize : function(){
49536 var cmax = this.config.maxSize || 10000;
49537 var center = this.mgr.getRegion("center");
49538 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
49541 getVMaxSize : function(){
49542 var cmax = this.config.maxSize || 10000;
49543 var center = this.mgr.getRegion("center");
49544 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
49547 onSplitMove : function(split, newSize){
49548 this.fireEvent("resized", this, newSize);
49552 * Returns the {@link Roo.SplitBar} for this region.
49553 * @return {Roo.SplitBar}
49555 getSplitBar : function(){
49560 this.hideSplitter();
49561 Roo.SplitLayoutRegion.superclass.hide.call(this);
49564 hideSplitter : function(){
49566 this.split.el.setLocation(-2000,-2000);
49567 this.split.el.hide();
49573 this.split.el.show();
49575 Roo.SplitLayoutRegion.superclass.show.call(this);
49578 beforeSlide: function(){
49579 if(Roo.isGecko){// firefox overflow auto bug workaround
49580 this.bodyEl.clip();
49581 if(this.tabs) this.tabs.bodyEl.clip();
49582 if(this.activePanel){
49583 this.activePanel.getEl().clip();
49585 if(this.activePanel.beforeSlide){
49586 this.activePanel.beforeSlide();
49592 afterSlide : function(){
49593 if(Roo.isGecko){// firefox overflow auto bug workaround
49594 this.bodyEl.unclip();
49595 if(this.tabs) this.tabs.bodyEl.unclip();
49596 if(this.activePanel){
49597 this.activePanel.getEl().unclip();
49598 if(this.activePanel.afterSlide){
49599 this.activePanel.afterSlide();
49605 initAutoHide : function(){
49606 if(this.autoHide !== false){
49607 if(!this.autoHideHd){
49608 var st = new Roo.util.DelayedTask(this.slideIn, this);
49609 this.autoHideHd = {
49610 "mouseout": function(e){
49611 if(!e.within(this.el, true)){
49615 "mouseover" : function(e){
49621 this.el.on(this.autoHideHd);
49625 clearAutoHide : function(){
49626 if(this.autoHide !== false){
49627 this.el.un("mouseout", this.autoHideHd.mouseout);
49628 this.el.un("mouseover", this.autoHideHd.mouseover);
49632 clearMonitor : function(){
49633 Roo.get(document).un("click", this.slideInIf, this);
49636 // these names are backwards but not changed for compat
49637 slideOut : function(){
49638 if(this.isSlid || this.el.hasActiveFx()){
49641 this.isSlid = true;
49642 if(this.collapseBtn){
49643 this.collapseBtn.hide();
49645 this.closeBtnState = this.closeBtn.getStyle('display');
49646 this.closeBtn.hide();
49648 this.stickBtn.show();
49651 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
49652 this.beforeSlide();
49653 this.el.setStyle("z-index", 10001);
49654 this.el.slideIn(this.getSlideAnchor(), {
49655 callback: function(){
49657 this.initAutoHide();
49658 Roo.get(document).on("click", this.slideInIf, this);
49659 this.fireEvent("slideshow", this);
49666 afterSlideIn : function(){
49667 this.clearAutoHide();
49668 this.isSlid = false;
49669 this.clearMonitor();
49670 this.el.setStyle("z-index", "");
49671 if(this.collapseBtn){
49672 this.collapseBtn.show();
49674 this.closeBtn.setStyle('display', this.closeBtnState);
49676 this.stickBtn.hide();
49678 this.fireEvent("slidehide", this);
49681 slideIn : function(cb){
49682 if(!this.isSlid || this.el.hasActiveFx()){
49686 this.isSlid = false;
49687 this.beforeSlide();
49688 this.el.slideOut(this.getSlideAnchor(), {
49689 callback: function(){
49690 this.el.setLeftTop(-10000, -10000);
49692 this.afterSlideIn();
49700 slideInIf : function(e){
49701 if(!e.within(this.el)){
49706 animateCollapse : function(){
49707 this.beforeSlide();
49708 this.el.setStyle("z-index", 20000);
49709 var anchor = this.getSlideAnchor();
49710 this.el.slideOut(anchor, {
49711 callback : function(){
49712 this.el.setStyle("z-index", "");
49713 this.collapsedEl.slideIn(anchor, {duration:.3});
49715 this.el.setLocation(-10000,-10000);
49717 this.fireEvent("collapsed", this);
49724 animateExpand : function(){
49725 this.beforeSlide();
49726 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
49727 this.el.setStyle("z-index", 20000);
49728 this.collapsedEl.hide({
49731 this.el.slideIn(this.getSlideAnchor(), {
49732 callback : function(){
49733 this.el.setStyle("z-index", "");
49736 this.split.el.show();
49738 this.fireEvent("invalidated", this);
49739 this.fireEvent("expanded", this);
49767 getAnchor : function(){
49768 return this.anchors[this.position];
49771 getCollapseAnchor : function(){
49772 return this.canchors[this.position];
49775 getSlideAnchor : function(){
49776 return this.sanchors[this.position];
49779 getAlignAdj : function(){
49780 var cm = this.cmargins;
49781 switch(this.position){
49797 getExpandAdj : function(){
49798 var c = this.collapsedEl, cm = this.cmargins;
49799 switch(this.position){
49801 return [-(cm.right+c.getWidth()+cm.left), 0];
49804 return [cm.right+c.getWidth()+cm.left, 0];
49807 return [0, -(cm.top+cm.bottom+c.getHeight())];
49810 return [0, cm.top+cm.bottom+c.getHeight()];
49816 * Ext JS Library 1.1.1
49817 * Copyright(c) 2006-2007, Ext JS, LLC.
49819 * Originally Released Under LGPL - original licence link has changed is not relivant.
49822 * <script type="text/javascript">
49825 * These classes are private internal classes
49827 Roo.CenterLayoutRegion = function(mgr, config){
49828 Roo.LayoutRegion.call(this, mgr, config, "center");
49829 this.visible = true;
49830 this.minWidth = config.minWidth || 20;
49831 this.minHeight = config.minHeight || 20;
49834 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
49836 // center panel can't be hidden
49840 // center panel can't be hidden
49843 getMinWidth: function(){
49844 return this.minWidth;
49847 getMinHeight: function(){
49848 return this.minHeight;
49853 Roo.NorthLayoutRegion = function(mgr, config){
49854 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
49856 this.split.placement = Roo.SplitBar.TOP;
49857 this.split.orientation = Roo.SplitBar.VERTICAL;
49858 this.split.el.addClass("x-layout-split-v");
49860 var size = config.initialSize || config.height;
49861 if(typeof size != "undefined"){
49862 this.el.setHeight(size);
49865 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
49866 orientation: Roo.SplitBar.VERTICAL,
49867 getBox : function(){
49868 if(this.collapsed){
49869 return this.collapsedEl.getBox();
49871 var box = this.el.getBox();
49873 box.height += this.split.el.getHeight();
49878 updateBox : function(box){
49879 if(this.split && !this.collapsed){
49880 box.height -= this.split.el.getHeight();
49881 this.split.el.setLeft(box.x);
49882 this.split.el.setTop(box.y+box.height);
49883 this.split.el.setWidth(box.width);
49885 if(this.collapsed){
49886 this.updateBody(box.width, null);
49888 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49892 Roo.SouthLayoutRegion = function(mgr, config){
49893 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
49895 this.split.placement = Roo.SplitBar.BOTTOM;
49896 this.split.orientation = Roo.SplitBar.VERTICAL;
49897 this.split.el.addClass("x-layout-split-v");
49899 var size = config.initialSize || config.height;
49900 if(typeof size != "undefined"){
49901 this.el.setHeight(size);
49904 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
49905 orientation: Roo.SplitBar.VERTICAL,
49906 getBox : function(){
49907 if(this.collapsed){
49908 return this.collapsedEl.getBox();
49910 var box = this.el.getBox();
49912 var sh = this.split.el.getHeight();
49919 updateBox : function(box){
49920 if(this.split && !this.collapsed){
49921 var sh = this.split.el.getHeight();
49924 this.split.el.setLeft(box.x);
49925 this.split.el.setTop(box.y-sh);
49926 this.split.el.setWidth(box.width);
49928 if(this.collapsed){
49929 this.updateBody(box.width, null);
49931 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49935 Roo.EastLayoutRegion = function(mgr, config){
49936 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
49938 this.split.placement = Roo.SplitBar.RIGHT;
49939 this.split.orientation = Roo.SplitBar.HORIZONTAL;
49940 this.split.el.addClass("x-layout-split-h");
49942 var size = config.initialSize || config.width;
49943 if(typeof size != "undefined"){
49944 this.el.setWidth(size);
49947 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
49948 orientation: Roo.SplitBar.HORIZONTAL,
49949 getBox : function(){
49950 if(this.collapsed){
49951 return this.collapsedEl.getBox();
49953 var box = this.el.getBox();
49955 var sw = this.split.el.getWidth();
49962 updateBox : function(box){
49963 if(this.split && !this.collapsed){
49964 var sw = this.split.el.getWidth();
49966 this.split.el.setLeft(box.x);
49967 this.split.el.setTop(box.y);
49968 this.split.el.setHeight(box.height);
49971 if(this.collapsed){
49972 this.updateBody(null, box.height);
49974 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49978 Roo.WestLayoutRegion = function(mgr, config){
49979 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
49981 this.split.placement = Roo.SplitBar.LEFT;
49982 this.split.orientation = Roo.SplitBar.HORIZONTAL;
49983 this.split.el.addClass("x-layout-split-h");
49985 var size = config.initialSize || config.width;
49986 if(typeof size != "undefined"){
49987 this.el.setWidth(size);
49990 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
49991 orientation: Roo.SplitBar.HORIZONTAL,
49992 getBox : function(){
49993 if(this.collapsed){
49994 return this.collapsedEl.getBox();
49996 var box = this.el.getBox();
49998 box.width += this.split.el.getWidth();
50003 updateBox : function(box){
50004 if(this.split && !this.collapsed){
50005 var sw = this.split.el.getWidth();
50007 this.split.el.setLeft(box.x+box.width);
50008 this.split.el.setTop(box.y);
50009 this.split.el.setHeight(box.height);
50011 if(this.collapsed){
50012 this.updateBody(null, box.height);
50014 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50019 * Ext JS Library 1.1.1
50020 * Copyright(c) 2006-2007, Ext JS, LLC.
50022 * Originally Released Under LGPL - original licence link has changed is not relivant.
50025 * <script type="text/javascript">
50030 * Private internal class for reading and applying state
50032 Roo.LayoutStateManager = function(layout){
50033 // default empty state
50042 Roo.LayoutStateManager.prototype = {
50043 init : function(layout, provider){
50044 this.provider = provider;
50045 var state = provider.get(layout.id+"-layout-state");
50047 var wasUpdating = layout.isUpdating();
50049 layout.beginUpdate();
50051 for(var key in state){
50052 if(typeof state[key] != "function"){
50053 var rstate = state[key];
50054 var r = layout.getRegion(key);
50057 r.resizeTo(rstate.size);
50059 if(rstate.collapsed == true){
50062 r.expand(null, true);
50068 layout.endUpdate();
50070 this.state = state;
50072 this.layout = layout;
50073 layout.on("regionresized", this.onRegionResized, this);
50074 layout.on("regioncollapsed", this.onRegionCollapsed, this);
50075 layout.on("regionexpanded", this.onRegionExpanded, this);
50078 storeState : function(){
50079 this.provider.set(this.layout.id+"-layout-state", this.state);
50082 onRegionResized : function(region, newSize){
50083 this.state[region.getPosition()].size = newSize;
50087 onRegionCollapsed : function(region){
50088 this.state[region.getPosition()].collapsed = true;
50092 onRegionExpanded : function(region){
50093 this.state[region.getPosition()].collapsed = false;
50098 * Ext JS Library 1.1.1
50099 * Copyright(c) 2006-2007, Ext JS, LLC.
50101 * Originally Released Under LGPL - original licence link has changed is not relivant.
50104 * <script type="text/javascript">
50107 * @class Roo.ContentPanel
50108 * @extends Roo.util.Observable
50109 * A basic ContentPanel element.
50110 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
50111 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
50112 * @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
50113 * @cfg {Boolean} closable True if the panel can be closed/removed
50114 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
50115 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
50116 * @cfg {Toolbar} toolbar A toolbar for this panel
50117 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
50118 * @cfg {String} title The title for this panel
50119 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
50120 * @cfg {String} url Calls {@link #setUrl} with this value
50121 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
50122 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
50123 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
50124 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
50127 * Create a new ContentPanel.
50128 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
50129 * @param {String/Object} config A string to set only the title or a config object
50130 * @param {String} content (optional) Set the HTML content for this panel
50131 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
50133 Roo.ContentPanel = function(el, config, content){
50137 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
50141 if (config && config.parentLayout) {
50142 el = config.parentLayout.el.createChild();
50145 if(el.autoCreate){ // xtype is available if this is called from factory
50149 this.el = Roo.get(el);
50150 if(!this.el && config && config.autoCreate){
50151 if(typeof config.autoCreate == "object"){
50152 if(!config.autoCreate.id){
50153 config.autoCreate.id = config.id||el;
50155 this.el = Roo.DomHelper.append(document.body,
50156 config.autoCreate, true);
50158 this.el = Roo.DomHelper.append(document.body,
50159 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
50162 this.closable = false;
50163 this.loaded = false;
50164 this.active = false;
50165 if(typeof config == "string"){
50166 this.title = config;
50168 Roo.apply(this, config);
50171 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
50172 this.wrapEl = this.el.wrap();
50173 this.toolbar.container = this.el.insertSibling(false, 'before');
50174 this.toolbar = new Roo.Toolbar(this.toolbar);
50177 // xtype created footer. - not sure if will work as we normally have to render first..
50178 if (this.footer && !this.footer.el && this.footer.xtype) {
50179 if (!this.wrapEl) {
50180 this.wrapEl = this.el.wrap();
50183 this.footer.container = this.wrapEl.createChild();
50185 this.footer = Roo.factory(this.footer, Roo);
50190 this.resizeEl = Roo.get(this.resizeEl, true);
50192 this.resizeEl = this.el;
50194 // handle view.xtype
50202 * Fires when this panel is activated.
50203 * @param {Roo.ContentPanel} this
50207 * @event deactivate
50208 * Fires when this panel is activated.
50209 * @param {Roo.ContentPanel} this
50211 "deactivate" : true,
50215 * Fires when this panel is resized if fitToFrame is true.
50216 * @param {Roo.ContentPanel} this
50217 * @param {Number} width The width after any component adjustments
50218 * @param {Number} height The height after any component adjustments
50224 * Fires when this tab is created
50225 * @param {Roo.ContentPanel} this
50236 if(this.autoScroll){
50237 this.resizeEl.setStyle("overflow", "auto");
50239 // fix randome scrolling
50240 this.el.on('scroll', function() {
50241 Roo.log('fix random scolling');
50242 this.scrollTo('top',0);
50245 content = content || this.content;
50247 this.setContent(content);
50249 if(config && config.url){
50250 this.setUrl(this.url, this.params, this.loadOnce);
50255 Roo.ContentPanel.superclass.constructor.call(this);
50257 if (this.view && typeof(this.view.xtype) != 'undefined') {
50258 this.view.el = this.el.appendChild(document.createElement("div"));
50259 this.view = Roo.factory(this.view);
50260 this.view.render && this.view.render(false, '');
50264 this.fireEvent('render', this);
50267 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
50269 setRegion : function(region){
50270 this.region = region;
50272 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
50274 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
50279 * Returns the toolbar for this Panel if one was configured.
50280 * @return {Roo.Toolbar}
50282 getToolbar : function(){
50283 return this.toolbar;
50286 setActiveState : function(active){
50287 this.active = active;
50289 this.fireEvent("deactivate", this);
50291 this.fireEvent("activate", this);
50295 * Updates this panel's element
50296 * @param {String} content The new content
50297 * @param {Boolean} loadScripts (optional) true to look for and process scripts
50299 setContent : function(content, loadScripts){
50300 this.el.update(content, loadScripts);
50303 ignoreResize : function(w, h){
50304 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
50307 this.lastSize = {width: w, height: h};
50312 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
50313 * @return {Roo.UpdateManager} The UpdateManager
50315 getUpdateManager : function(){
50316 return this.el.getUpdateManager();
50319 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
50320 * @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:
50323 url: "your-url.php",
50324 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
50325 callback: yourFunction,
50326 scope: yourObject, //(optional scope)
50329 text: "Loading...",
50334 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
50335 * 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.
50336 * @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}
50337 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
50338 * @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.
50339 * @return {Roo.ContentPanel} this
50342 var um = this.el.getUpdateManager();
50343 um.update.apply(um, arguments);
50349 * 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.
50350 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
50351 * @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)
50352 * @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)
50353 * @return {Roo.UpdateManager} The UpdateManager
50355 setUrl : function(url, params, loadOnce){
50356 if(this.refreshDelegate){
50357 this.removeListener("activate", this.refreshDelegate);
50359 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
50360 this.on("activate", this.refreshDelegate);
50361 return this.el.getUpdateManager();
50364 _handleRefresh : function(url, params, loadOnce){
50365 if(!loadOnce || !this.loaded){
50366 var updater = this.el.getUpdateManager();
50367 updater.update(url, params, this._setLoaded.createDelegate(this));
50371 _setLoaded : function(){
50372 this.loaded = true;
50376 * Returns this panel's id
50379 getId : function(){
50384 * Returns this panel's element - used by regiosn to add.
50385 * @return {Roo.Element}
50387 getEl : function(){
50388 return this.wrapEl || this.el;
50391 adjustForComponents : function(width, height)
50393 //Roo.log('adjustForComponents ');
50394 if(this.resizeEl != this.el){
50395 width -= this.el.getFrameWidth('lr');
50396 height -= this.el.getFrameWidth('tb');
50399 var te = this.toolbar.getEl();
50400 height -= te.getHeight();
50401 te.setWidth(width);
50404 var te = this.footer.getEl();
50405 Roo.log("footer:" + te.getHeight());
50407 height -= te.getHeight();
50408 te.setWidth(width);
50412 if(this.adjustments){
50413 width += this.adjustments[0];
50414 height += this.adjustments[1];
50416 return {"width": width, "height": height};
50419 setSize : function(width, height){
50420 if(this.fitToFrame && !this.ignoreResize(width, height)){
50421 if(this.fitContainer && this.resizeEl != this.el){
50422 this.el.setSize(width, height);
50424 var size = this.adjustForComponents(width, height);
50425 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
50426 this.fireEvent('resize', this, size.width, size.height);
50431 * Returns this panel's title
50434 getTitle : function(){
50439 * Set this panel's title
50440 * @param {String} title
50442 setTitle : function(title){
50443 this.title = title;
50445 this.region.updatePanelTitle(this, title);
50450 * Returns true is this panel was configured to be closable
50451 * @return {Boolean}
50453 isClosable : function(){
50454 return this.closable;
50457 beforeSlide : function(){
50459 this.resizeEl.clip();
50462 afterSlide : function(){
50464 this.resizeEl.unclip();
50468 * Force a content refresh from the URL specified in the {@link #setUrl} method.
50469 * Will fail silently if the {@link #setUrl} method has not been called.
50470 * This does not activate the panel, just updates its content.
50472 refresh : function(){
50473 if(this.refreshDelegate){
50474 this.loaded = false;
50475 this.refreshDelegate();
50480 * Destroys this panel
50482 destroy : function(){
50483 this.el.removeAllListeners();
50484 var tempEl = document.createElement("span");
50485 tempEl.appendChild(this.el.dom);
50486 tempEl.innerHTML = "";
50492 * form - if the content panel contains a form - this is a reference to it.
50493 * @type {Roo.form.Form}
50497 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
50498 * This contains a reference to it.
50504 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
50514 * @param {Object} cfg Xtype definition of item to add.
50517 addxtype : function(cfg) {
50519 if (cfg.xtype.match(/^Form$/)) {
50522 //if (this.footer) {
50523 // el = this.footer.container.insertSibling(false, 'before');
50525 el = this.el.createChild();
50528 this.form = new Roo.form.Form(cfg);
50531 if ( this.form.allItems.length) this.form.render(el.dom);
50534 // should only have one of theses..
50535 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
50536 // views.. should not be just added - used named prop 'view''
50538 cfg.el = this.el.appendChild(document.createElement("div"));
50541 var ret = new Roo.factory(cfg);
50543 ret.render && ret.render(false, ''); // render blank..
50552 * @class Roo.GridPanel
50553 * @extends Roo.ContentPanel
50555 * Create a new GridPanel.
50556 * @param {Roo.grid.Grid} grid The grid for this panel
50557 * @param {String/Object} config A string to set only the panel's title, or a config object
50559 Roo.GridPanel = function(grid, config){
50562 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
50563 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
50565 this.wrapper.dom.appendChild(grid.getGridEl().dom);
50567 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
50570 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
50572 // xtype created footer. - not sure if will work as we normally have to render first..
50573 if (this.footer && !this.footer.el && this.footer.xtype) {
50575 this.footer.container = this.grid.getView().getFooterPanel(true);
50576 this.footer.dataSource = this.grid.dataSource;
50577 this.footer = Roo.factory(this.footer, Roo);
50581 grid.monitorWindowResize = false; // turn off autosizing
50582 grid.autoHeight = false;
50583 grid.autoWidth = false;
50585 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
50588 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
50589 getId : function(){
50590 return this.grid.id;
50594 * Returns the grid for this panel
50595 * @return {Roo.grid.Grid}
50597 getGrid : function(){
50601 setSize : function(width, height){
50602 if(!this.ignoreResize(width, height)){
50603 var grid = this.grid;
50604 var size = this.adjustForComponents(width, height);
50605 grid.getGridEl().setSize(size.width, size.height);
50610 beforeSlide : function(){
50611 this.grid.getView().scroller.clip();
50614 afterSlide : function(){
50615 this.grid.getView().scroller.unclip();
50618 destroy : function(){
50619 this.grid.destroy();
50621 Roo.GridPanel.superclass.destroy.call(this);
50627 * @class Roo.NestedLayoutPanel
50628 * @extends Roo.ContentPanel
50630 * Create a new NestedLayoutPanel.
50633 * @param {Roo.BorderLayout} layout The layout for this panel
50634 * @param {String/Object} config A string to set only the title or a config object
50636 Roo.NestedLayoutPanel = function(layout, config)
50638 // construct with only one argument..
50639 /* FIXME - implement nicer consturctors
50640 if (layout.layout) {
50642 layout = config.layout;
50643 delete config.layout;
50645 if (layout.xtype && !layout.getEl) {
50646 // then layout needs constructing..
50647 layout = Roo.factory(layout, Roo);
50652 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
50654 layout.monitorWindowResize = false; // turn off autosizing
50655 this.layout = layout;
50656 this.layout.getEl().addClass("x-layout-nested-layout");
50663 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
50665 setSize : function(width, height){
50666 if(!this.ignoreResize(width, height)){
50667 var size = this.adjustForComponents(width, height);
50668 var el = this.layout.getEl();
50669 el.setSize(size.width, size.height);
50670 var touch = el.dom.offsetWidth;
50671 this.layout.layout();
50672 // ie requires a double layout on the first pass
50673 if(Roo.isIE && !this.initialized){
50674 this.initialized = true;
50675 this.layout.layout();
50680 // activate all subpanels if not currently active..
50682 setActiveState : function(active){
50683 this.active = active;
50685 this.fireEvent("deactivate", this);
50689 this.fireEvent("activate", this);
50690 // not sure if this should happen before or after..
50691 if (!this.layout) {
50692 return; // should not happen..
50695 for (var r in this.layout.regions) {
50696 reg = this.layout.getRegion(r);
50697 if (reg.getActivePanel()) {
50698 //reg.showPanel(reg.getActivePanel()); // force it to activate..
50699 reg.setActivePanel(reg.getActivePanel());
50702 if (!reg.panels.length) {
50705 reg.showPanel(reg.getPanel(0));
50714 * Returns the nested BorderLayout for this panel
50715 * @return {Roo.BorderLayout}
50717 getLayout : function(){
50718 return this.layout;
50722 * Adds a xtype elements to the layout of the nested panel
50726 xtype : 'ContentPanel',
50733 xtype : 'NestedLayoutPanel',
50739 items : [ ... list of content panels or nested layout panels.. ]
50743 * @param {Object} cfg Xtype definition of item to add.
50745 addxtype : function(cfg) {
50746 return this.layout.addxtype(cfg);
50751 Roo.ScrollPanel = function(el, config, content){
50752 config = config || {};
50753 config.fitToFrame = true;
50754 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
50756 this.el.dom.style.overflow = "hidden";
50757 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
50758 this.el.removeClass("x-layout-inactive-content");
50759 this.el.on("mousewheel", this.onWheel, this);
50761 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
50762 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
50763 up.unselectable(); down.unselectable();
50764 up.on("click", this.scrollUp, this);
50765 down.on("click", this.scrollDown, this);
50766 up.addClassOnOver("x-scroller-btn-over");
50767 down.addClassOnOver("x-scroller-btn-over");
50768 up.addClassOnClick("x-scroller-btn-click");
50769 down.addClassOnClick("x-scroller-btn-click");
50770 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
50772 this.resizeEl = this.el;
50773 this.el = wrap; this.up = up; this.down = down;
50776 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
50778 wheelIncrement : 5,
50779 scrollUp : function(){
50780 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
50783 scrollDown : function(){
50784 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
50787 afterScroll : function(){
50788 var el = this.resizeEl;
50789 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
50790 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
50791 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
50794 setSize : function(){
50795 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
50796 this.afterScroll();
50799 onWheel : function(e){
50800 var d = e.getWheelDelta();
50801 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
50802 this.afterScroll();
50806 setContent : function(content, loadScripts){
50807 this.resizeEl.update(content, loadScripts);
50821 * @class Roo.TreePanel
50822 * @extends Roo.ContentPanel
50824 * Create a new TreePanel. - defaults to fit/scoll contents.
50825 * @param {String/Object} config A string to set only the panel's title, or a config object
50826 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
50828 Roo.TreePanel = function(config){
50829 var el = config.el;
50830 var tree = config.tree;
50831 delete config.tree;
50832 delete config.el; // hopefull!
50834 // wrapper for IE7 strict & safari scroll issue
50836 var treeEl = el.createChild();
50837 config.resizeEl = treeEl;
50841 Roo.TreePanel.superclass.constructor.call(this, el, config);
50844 this.tree = new Roo.tree.TreePanel(treeEl , tree);
50845 //console.log(tree);
50846 this.on('activate', function()
50848 if (this.tree.rendered) {
50851 //console.log('render tree');
50852 this.tree.render();
50854 // this should not be needed.. - it's actually the 'el' that resizes?
50855 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
50857 //this.on('resize', function (cp, w, h) {
50858 // this.tree.innerCt.setWidth(w);
50859 // this.tree.innerCt.setHeight(h);
50860 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
50867 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
50884 * Ext JS Library 1.1.1
50885 * Copyright(c) 2006-2007, Ext JS, LLC.
50887 * Originally Released Under LGPL - original licence link has changed is not relivant.
50890 * <script type="text/javascript">
50895 * @class Roo.ReaderLayout
50896 * @extends Roo.BorderLayout
50897 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
50898 * center region containing two nested regions (a top one for a list view and one for item preview below),
50899 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
50900 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
50901 * expedites the setup of the overall layout and regions for this common application style.
50904 var reader = new Roo.ReaderLayout();
50905 var CP = Roo.ContentPanel; // shortcut for adding
50907 reader.beginUpdate();
50908 reader.add("north", new CP("north", "North"));
50909 reader.add("west", new CP("west", {title: "West"}));
50910 reader.add("east", new CP("east", {title: "East"}));
50912 reader.regions.listView.add(new CP("listView", "List"));
50913 reader.regions.preview.add(new CP("preview", "Preview"));
50914 reader.endUpdate();
50917 * Create a new ReaderLayout
50918 * @param {Object} config Configuration options
50919 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
50920 * document.body if omitted)
50922 Roo.ReaderLayout = function(config, renderTo){
50923 var c = config || {size:{}};
50924 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
50925 north: c.north !== false ? Roo.apply({
50929 }, c.north) : false,
50930 west: c.west !== false ? Roo.apply({
50938 margins:{left:5,right:0,bottom:5,top:5},
50939 cmargins:{left:5,right:5,bottom:5,top:5}
50940 }, c.west) : false,
50941 east: c.east !== false ? Roo.apply({
50949 margins:{left:0,right:5,bottom:5,top:5},
50950 cmargins:{left:5,right:5,bottom:5,top:5}
50951 }, c.east) : false,
50952 center: Roo.apply({
50953 tabPosition: 'top',
50957 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
50961 this.el.addClass('x-reader');
50963 this.beginUpdate();
50965 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
50966 south: c.preview !== false ? Roo.apply({
50973 cmargins:{top:5,left:0, right:0, bottom:0}
50974 }, c.preview) : false,
50975 center: Roo.apply({
50981 this.add('center', new Roo.NestedLayoutPanel(inner,
50982 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
50986 this.regions.preview = inner.getRegion('south');
50987 this.regions.listView = inner.getRegion('center');
50990 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
50992 * Ext JS Library 1.1.1
50993 * Copyright(c) 2006-2007, Ext JS, LLC.
50995 * Originally Released Under LGPL - original licence link has changed is not relivant.
50998 * <script type="text/javascript">
51002 * @class Roo.grid.Grid
51003 * @extends Roo.util.Observable
51004 * This class represents the primary interface of a component based grid control.
51005 * <br><br>Usage:<pre><code>
51006 var grid = new Roo.grid.Grid("my-container-id", {
51009 selModel: mySelectionModel,
51010 autoSizeColumns: true,
51011 monitorWindowResize: false,
51012 trackMouseOver: true
51017 * <b>Common Problems:</b><br/>
51018 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
51019 * element will correct this<br/>
51020 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
51021 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
51022 * are unpredictable.<br/>
51023 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
51024 * grid to calculate dimensions/offsets.<br/>
51026 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51027 * The container MUST have some type of size defined for the grid to fill. The container will be
51028 * automatically set to position relative if it isn't already.
51029 * @param {Object} config A config object that sets properties on this grid.
51031 Roo.grid.Grid = function(container, config){
51032 // initialize the container
51033 this.container = Roo.get(container);
51034 this.container.update("");
51035 this.container.setStyle("overflow", "hidden");
51036 this.container.addClass('x-grid-container');
51038 this.id = this.container.id;
51040 Roo.apply(this, config);
51041 // check and correct shorthanded configs
51043 this.dataSource = this.ds;
51047 this.colModel = this.cm;
51051 this.selModel = this.sm;
51055 if (this.selModel) {
51056 this.selModel = Roo.factory(this.selModel, Roo.grid);
51057 this.sm = this.selModel;
51058 this.sm.xmodule = this.xmodule || false;
51060 if (typeof(this.colModel.config) == 'undefined') {
51061 this.colModel = new Roo.grid.ColumnModel(this.colModel);
51062 this.cm = this.colModel;
51063 this.cm.xmodule = this.xmodule || false;
51065 if (this.dataSource) {
51066 this.dataSource= Roo.factory(this.dataSource, Roo.data);
51067 this.ds = this.dataSource;
51068 this.ds.xmodule = this.xmodule || false;
51075 this.container.setWidth(this.width);
51079 this.container.setHeight(this.height);
51086 * The raw click event for the entire grid.
51087 * @param {Roo.EventObject} e
51092 * The raw dblclick event for the entire grid.
51093 * @param {Roo.EventObject} e
51097 * @event contextmenu
51098 * The raw contextmenu event for the entire grid.
51099 * @param {Roo.EventObject} e
51101 "contextmenu" : true,
51104 * The raw mousedown event for the entire grid.
51105 * @param {Roo.EventObject} e
51107 "mousedown" : true,
51110 * The raw mouseup event for the entire grid.
51111 * @param {Roo.EventObject} e
51116 * The raw mouseover event for the entire grid.
51117 * @param {Roo.EventObject} e
51119 "mouseover" : true,
51122 * The raw mouseout event for the entire grid.
51123 * @param {Roo.EventObject} e
51128 * The raw keypress event for the entire grid.
51129 * @param {Roo.EventObject} e
51134 * The raw keydown event for the entire grid.
51135 * @param {Roo.EventObject} e
51143 * Fires when a cell is clicked
51144 * @param {Grid} this
51145 * @param {Number} rowIndex
51146 * @param {Number} columnIndex
51147 * @param {Roo.EventObject} e
51149 "cellclick" : true,
51151 * @event celldblclick
51152 * Fires when a cell is double clicked
51153 * @param {Grid} this
51154 * @param {Number} rowIndex
51155 * @param {Number} columnIndex
51156 * @param {Roo.EventObject} e
51158 "celldblclick" : true,
51161 * Fires when a row is clicked
51162 * @param {Grid} this
51163 * @param {Number} rowIndex
51164 * @param {Roo.EventObject} e
51168 * @event rowdblclick
51169 * Fires when a row is double clicked
51170 * @param {Grid} this
51171 * @param {Number} rowIndex
51172 * @param {Roo.EventObject} e
51174 "rowdblclick" : true,
51176 * @event headerclick
51177 * Fires when a header is clicked
51178 * @param {Grid} this
51179 * @param {Number} columnIndex
51180 * @param {Roo.EventObject} e
51182 "headerclick" : true,
51184 * @event headerdblclick
51185 * Fires when a header cell is double clicked
51186 * @param {Grid} this
51187 * @param {Number} columnIndex
51188 * @param {Roo.EventObject} e
51190 "headerdblclick" : true,
51192 * @event rowcontextmenu
51193 * Fires when a row is right clicked
51194 * @param {Grid} this
51195 * @param {Number} rowIndex
51196 * @param {Roo.EventObject} e
51198 "rowcontextmenu" : true,
51200 * @event cellcontextmenu
51201 * Fires when a cell is right clicked
51202 * @param {Grid} this
51203 * @param {Number} rowIndex
51204 * @param {Number} cellIndex
51205 * @param {Roo.EventObject} e
51207 "cellcontextmenu" : true,
51209 * @event headercontextmenu
51210 * Fires when a header is right clicked
51211 * @param {Grid} this
51212 * @param {Number} columnIndex
51213 * @param {Roo.EventObject} e
51215 "headercontextmenu" : true,
51217 * @event bodyscroll
51218 * Fires when the body element is scrolled
51219 * @param {Number} scrollLeft
51220 * @param {Number} scrollTop
51222 "bodyscroll" : true,
51224 * @event columnresize
51225 * Fires when the user resizes a column
51226 * @param {Number} columnIndex
51227 * @param {Number} newSize
51229 "columnresize" : true,
51231 * @event columnmove
51232 * Fires when the user moves a column
51233 * @param {Number} oldIndex
51234 * @param {Number} newIndex
51236 "columnmove" : true,
51239 * Fires when row(s) start being dragged
51240 * @param {Grid} this
51241 * @param {Roo.GridDD} dd The drag drop object
51242 * @param {event} e The raw browser event
51244 "startdrag" : true,
51247 * Fires when a drag operation is complete
51248 * @param {Grid} this
51249 * @param {Roo.GridDD} dd The drag drop object
51250 * @param {event} e The raw browser event
51255 * Fires when dragged row(s) are dropped on a valid DD target
51256 * @param {Grid} this
51257 * @param {Roo.GridDD} dd The drag drop object
51258 * @param {String} targetId The target drag drop object
51259 * @param {event} e The raw browser event
51264 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
51265 * @param {Grid} this
51266 * @param {Roo.GridDD} dd The drag drop object
51267 * @param {String} targetId The target drag drop object
51268 * @param {event} e The raw browser event
51273 * Fires when the dragged row(s) first cross another DD target while being dragged
51274 * @param {Grid} this
51275 * @param {Roo.GridDD} dd The drag drop object
51276 * @param {String} targetId The target drag drop object
51277 * @param {event} e The raw browser event
51279 "dragenter" : true,
51282 * Fires when the dragged row(s) leave another DD target while being dragged
51283 * @param {Grid} this
51284 * @param {Roo.GridDD} dd The drag drop object
51285 * @param {String} targetId The target drag drop object
51286 * @param {event} e The raw browser event
51291 * Fires when a row is rendered, so you can change add a style to it.
51292 * @param {GridView} gridview The grid view
51293 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
51299 * Fires when the grid is rendered
51300 * @param {Grid} grid
51305 Roo.grid.Grid.superclass.constructor.call(this);
51307 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
51310 * @cfg {String} ddGroup - drag drop group.
51314 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
51316 minColumnWidth : 25,
51319 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
51320 * <b>on initial render.</b> It is more efficient to explicitly size the columns
51321 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
51323 autoSizeColumns : false,
51326 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
51328 autoSizeHeaders : true,
51331 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
51333 monitorWindowResize : true,
51336 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
51337 * rows measured to get a columns size. Default is 0 (all rows).
51339 maxRowsToMeasure : 0,
51342 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
51344 trackMouseOver : true,
51347 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
51351 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
51353 enableDragDrop : false,
51356 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
51358 enableColumnMove : true,
51361 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
51363 enableColumnHide : true,
51366 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
51368 enableRowHeightSync : false,
51371 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
51376 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
51378 autoHeight : false,
51381 * @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.
51383 autoExpandColumn : false,
51386 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
51389 autoExpandMin : 50,
51392 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
51394 autoExpandMax : 1000,
51397 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
51402 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
51406 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
51416 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
51417 * of a fixed width. Default is false.
51420 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
51423 * Called once after all setup has been completed and the grid is ready to be rendered.
51424 * @return {Roo.grid.Grid} this
51426 render : function()
51428 var c = this.container;
51429 // try to detect autoHeight/width mode
51430 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
51431 this.autoHeight = true;
51433 var view = this.getView();
51436 c.on("click", this.onClick, this);
51437 c.on("dblclick", this.onDblClick, this);
51438 c.on("contextmenu", this.onContextMenu, this);
51439 c.on("keydown", this.onKeyDown, this);
51441 c.on("touchstart", this.onTouchStart, this);
51444 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
51446 this.getSelectionModel().init(this);
51451 this.loadMask = new Roo.LoadMask(this.container,
51452 Roo.apply({store:this.dataSource}, this.loadMask));
51456 if (this.toolbar && this.toolbar.xtype) {
51457 this.toolbar.container = this.getView().getHeaderPanel(true);
51458 this.toolbar = new Roo.Toolbar(this.toolbar);
51460 if (this.footer && this.footer.xtype) {
51461 this.footer.dataSource = this.getDataSource();
51462 this.footer.container = this.getView().getFooterPanel(true);
51463 this.footer = Roo.factory(this.footer, Roo);
51465 if (this.dropTarget && this.dropTarget.xtype) {
51466 delete this.dropTarget.xtype;
51467 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
51471 this.rendered = true;
51472 this.fireEvent('render', this);
51477 * Reconfigures the grid to use a different Store and Column Model.
51478 * The View will be bound to the new objects and refreshed.
51479 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
51480 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
51482 reconfigure : function(dataSource, colModel){
51484 this.loadMask.destroy();
51485 this.loadMask = new Roo.LoadMask(this.container,
51486 Roo.apply({store:dataSource}, this.loadMask));
51488 this.view.bind(dataSource, colModel);
51489 this.dataSource = dataSource;
51490 this.colModel = colModel;
51491 this.view.refresh(true);
51495 onKeyDown : function(e){
51496 this.fireEvent("keydown", e);
51500 * Destroy this grid.
51501 * @param {Boolean} removeEl True to remove the element
51503 destroy : function(removeEl, keepListeners){
51505 this.loadMask.destroy();
51507 var c = this.container;
51508 c.removeAllListeners();
51509 this.view.destroy();
51510 this.colModel.purgeListeners();
51511 if(!keepListeners){
51512 this.purgeListeners();
51515 if(removeEl === true){
51521 processEvent : function(name, e){
51522 // does this fire select???
51523 Roo.log('grid:processEvent ' + name);
51525 if (name != 'touchstart' ) {
51526 this.fireEvent(name, e);
51529 var t = e.getTarget();
51531 var header = v.findHeaderIndex(t);
51532 if(header !== false){
51533 this.fireEvent("header" + (name == 'touchstart' ? 'click' : name), this, header, e);
51535 var row = v.findRowIndex(t);
51536 var cell = v.findCellIndex(t);
51537 if (name == 'touchstart') {
51538 // first touch is always a click.
51539 // hopefull this happens after selection is updated.?
51542 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
51543 var cs = this.selModel.getSelectedCell();
51544 if (row == cs[0] && cell == cs[1]){
51548 if (typeof(this.selModel.getSelections) != 'undefined') {
51549 var cs = this.selModel.getSelections();
51550 var ds = this.dataSource;
51551 if (cs.length == 1 && ds.getAt(row) == cs[0]){
51562 this.fireEvent("row" + name, this, row, e);
51563 if(cell !== false){
51564 this.fireEvent("cell" + name, this, row, cell, e);
51571 onClick : function(e){
51572 this.processEvent("click", e);
51575 onTouchStart : function(e){
51576 this.processEvent("touchstart", e);
51580 onContextMenu : function(e, t){
51581 this.processEvent("contextmenu", e);
51585 onDblClick : function(e){
51586 this.processEvent("dblclick", e);
51590 walkCells : function(row, col, step, fn, scope){
51591 var cm = this.colModel, clen = cm.getColumnCount();
51592 var ds = this.dataSource, rlen = ds.getCount(), first = true;
51604 if(fn.call(scope || this, row, col, cm) === true){
51622 if(fn.call(scope || this, row, col, cm) === true){
51634 getSelections : function(){
51635 return this.selModel.getSelections();
51639 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
51640 * but if manual update is required this method will initiate it.
51642 autoSize : function(){
51644 this.view.layout();
51645 if(this.view.adjustForScroll){
51646 this.view.adjustForScroll();
51652 * Returns the grid's underlying element.
51653 * @return {Element} The element
51655 getGridEl : function(){
51656 return this.container;
51659 // private for compatibility, overridden by editor grid
51660 stopEditing : function(){},
51663 * Returns the grid's SelectionModel.
51664 * @return {SelectionModel}
51666 getSelectionModel : function(){
51667 if(!this.selModel){
51668 this.selModel = new Roo.grid.RowSelectionModel();
51670 return this.selModel;
51674 * Returns the grid's DataSource.
51675 * @return {DataSource}
51677 getDataSource : function(){
51678 return this.dataSource;
51682 * Returns the grid's ColumnModel.
51683 * @return {ColumnModel}
51685 getColumnModel : function(){
51686 return this.colModel;
51690 * Returns the grid's GridView object.
51691 * @return {GridView}
51693 getView : function(){
51695 this.view = new Roo.grid.GridView(this.viewConfig);
51700 * Called to get grid's drag proxy text, by default returns this.ddText.
51703 getDragDropText : function(){
51704 var count = this.selModel.getCount();
51705 return String.format(this.ddText, count, count == 1 ? '' : 's');
51709 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
51710 * %0 is replaced with the number of selected rows.
51713 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
51715 * Ext JS Library 1.1.1
51716 * Copyright(c) 2006-2007, Ext JS, LLC.
51718 * Originally Released Under LGPL - original licence link has changed is not relivant.
51721 * <script type="text/javascript">
51724 Roo.grid.AbstractGridView = function(){
51728 "beforerowremoved" : true,
51729 "beforerowsinserted" : true,
51730 "beforerefresh" : true,
51731 "rowremoved" : true,
51732 "rowsinserted" : true,
51733 "rowupdated" : true,
51736 Roo.grid.AbstractGridView.superclass.constructor.call(this);
51739 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
51740 rowClass : "x-grid-row",
51741 cellClass : "x-grid-cell",
51742 tdClass : "x-grid-td",
51743 hdClass : "x-grid-hd",
51744 splitClass : "x-grid-hd-split",
51746 init: function(grid){
51748 var cid = this.grid.getGridEl().id;
51749 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
51750 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
51751 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
51752 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
51755 getColumnRenderers : function(){
51756 var renderers = [];
51757 var cm = this.grid.colModel;
51758 var colCount = cm.getColumnCount();
51759 for(var i = 0; i < colCount; i++){
51760 renderers[i] = cm.getRenderer(i);
51765 getColumnIds : function(){
51767 var cm = this.grid.colModel;
51768 var colCount = cm.getColumnCount();
51769 for(var i = 0; i < colCount; i++){
51770 ids[i] = cm.getColumnId(i);
51775 getDataIndexes : function(){
51776 if(!this.indexMap){
51777 this.indexMap = this.buildIndexMap();
51779 return this.indexMap.colToData;
51782 getColumnIndexByDataIndex : function(dataIndex){
51783 if(!this.indexMap){
51784 this.indexMap = this.buildIndexMap();
51786 return this.indexMap.dataToCol[dataIndex];
51790 * Set a css style for a column dynamically.
51791 * @param {Number} colIndex The index of the column
51792 * @param {String} name The css property name
51793 * @param {String} value The css value
51795 setCSSStyle : function(colIndex, name, value){
51796 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
51797 Roo.util.CSS.updateRule(selector, name, value);
51800 generateRules : function(cm){
51801 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
51802 Roo.util.CSS.removeStyleSheet(rulesId);
51803 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51804 var cid = cm.getColumnId(i);
51805 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
51806 this.tdSelector, cid, " {\n}\n",
51807 this.hdSelector, cid, " {\n}\n",
51808 this.splitSelector, cid, " {\n}\n");
51810 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
51814 * Ext JS Library 1.1.1
51815 * Copyright(c) 2006-2007, Ext JS, LLC.
51817 * Originally Released Under LGPL - original licence link has changed is not relivant.
51820 * <script type="text/javascript">
51824 // This is a support class used internally by the Grid components
51825 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
51827 this.view = grid.getView();
51828 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
51829 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
51831 this.setHandleElId(Roo.id(hd));
51832 this.setOuterHandleElId(Roo.id(hd2));
51834 this.scroll = false;
51836 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
51838 getDragData : function(e){
51839 var t = Roo.lib.Event.getTarget(e);
51840 var h = this.view.findHeaderCell(t);
51842 return {ddel: h.firstChild, header:h};
51847 onInitDrag : function(e){
51848 this.view.headersDisabled = true;
51849 var clone = this.dragData.ddel.cloneNode(true);
51850 clone.id = Roo.id();
51851 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
51852 this.proxy.update(clone);
51856 afterValidDrop : function(){
51858 setTimeout(function(){
51859 v.headersDisabled = false;
51863 afterInvalidDrop : function(){
51865 setTimeout(function(){
51866 v.headersDisabled = false;
51872 * Ext JS Library 1.1.1
51873 * Copyright(c) 2006-2007, Ext JS, LLC.
51875 * Originally Released Under LGPL - original licence link has changed is not relivant.
51878 * <script type="text/javascript">
51881 // This is a support class used internally by the Grid components
51882 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
51884 this.view = grid.getView();
51885 // split the proxies so they don't interfere with mouse events
51886 this.proxyTop = Roo.DomHelper.append(document.body, {
51887 cls:"col-move-top", html:" "
51889 this.proxyBottom = Roo.DomHelper.append(document.body, {
51890 cls:"col-move-bottom", html:" "
51892 this.proxyTop.hide = this.proxyBottom.hide = function(){
51893 this.setLeftTop(-100,-100);
51894 this.setStyle("visibility", "hidden");
51896 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
51897 // temporarily disabled
51898 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
51899 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
51901 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
51902 proxyOffsets : [-4, -9],
51903 fly: Roo.Element.fly,
51905 getTargetFromEvent : function(e){
51906 var t = Roo.lib.Event.getTarget(e);
51907 var cindex = this.view.findCellIndex(t);
51908 if(cindex !== false){
51909 return this.view.getHeaderCell(cindex);
51914 nextVisible : function(h){
51915 var v = this.view, cm = this.grid.colModel;
51918 if(!cm.isHidden(v.getCellIndex(h))){
51926 prevVisible : function(h){
51927 var v = this.view, cm = this.grid.colModel;
51930 if(!cm.isHidden(v.getCellIndex(h))){
51938 positionIndicator : function(h, n, e){
51939 var x = Roo.lib.Event.getPageX(e);
51940 var r = Roo.lib.Dom.getRegion(n.firstChild);
51941 var px, pt, py = r.top + this.proxyOffsets[1];
51942 if((r.right - x) <= (r.right-r.left)/2){
51943 px = r.right+this.view.borderWidth;
51949 var oldIndex = this.view.getCellIndex(h);
51950 var newIndex = this.view.getCellIndex(n);
51952 if(this.grid.colModel.isFixed(newIndex)){
51956 var locked = this.grid.colModel.isLocked(newIndex);
51961 if(oldIndex < newIndex){
51964 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
51967 px += this.proxyOffsets[0];
51968 this.proxyTop.setLeftTop(px, py);
51969 this.proxyTop.show();
51970 if(!this.bottomOffset){
51971 this.bottomOffset = this.view.mainHd.getHeight();
51973 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
51974 this.proxyBottom.show();
51978 onNodeEnter : function(n, dd, e, data){
51979 if(data.header != n){
51980 this.positionIndicator(data.header, n, e);
51984 onNodeOver : function(n, dd, e, data){
51985 var result = false;
51986 if(data.header != n){
51987 result = this.positionIndicator(data.header, n, e);
51990 this.proxyTop.hide();
51991 this.proxyBottom.hide();
51993 return result ? this.dropAllowed : this.dropNotAllowed;
51996 onNodeOut : function(n, dd, e, data){
51997 this.proxyTop.hide();
51998 this.proxyBottom.hide();
52001 onNodeDrop : function(n, dd, e, data){
52002 var h = data.header;
52004 var cm = this.grid.colModel;
52005 var x = Roo.lib.Event.getPageX(e);
52006 var r = Roo.lib.Dom.getRegion(n.firstChild);
52007 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
52008 var oldIndex = this.view.getCellIndex(h);
52009 var newIndex = this.view.getCellIndex(n);
52010 var locked = cm.isLocked(newIndex);
52014 if(oldIndex < newIndex){
52017 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
52020 cm.setLocked(oldIndex, locked, true);
52021 cm.moveColumn(oldIndex, newIndex);
52022 this.grid.fireEvent("columnmove", oldIndex, newIndex);
52030 * Ext JS Library 1.1.1
52031 * Copyright(c) 2006-2007, Ext JS, LLC.
52033 * Originally Released Under LGPL - original licence link has changed is not relivant.
52036 * <script type="text/javascript">
52040 * @class Roo.grid.GridView
52041 * @extends Roo.util.Observable
52044 * @param {Object} config
52046 Roo.grid.GridView = function(config){
52047 Roo.grid.GridView.superclass.constructor.call(this);
52050 Roo.apply(this, config);
52053 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
52055 unselectable : 'unselectable="on"',
52056 unselectableCls : 'x-unselectable',
52059 rowClass : "x-grid-row",
52061 cellClass : "x-grid-col",
52063 tdClass : "x-grid-td",
52065 hdClass : "x-grid-hd",
52067 splitClass : "x-grid-split",
52069 sortClasses : ["sort-asc", "sort-desc"],
52071 enableMoveAnim : false,
52075 dh : Roo.DomHelper,
52077 fly : Roo.Element.fly,
52079 css : Roo.util.CSS,
52085 scrollIncrement : 22,
52087 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
52089 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
52091 bind : function(ds, cm){
52093 this.ds.un("load", this.onLoad, this);
52094 this.ds.un("datachanged", this.onDataChange, this);
52095 this.ds.un("add", this.onAdd, this);
52096 this.ds.un("remove", this.onRemove, this);
52097 this.ds.un("update", this.onUpdate, this);
52098 this.ds.un("clear", this.onClear, this);
52101 ds.on("load", this.onLoad, this);
52102 ds.on("datachanged", this.onDataChange, this);
52103 ds.on("add", this.onAdd, this);
52104 ds.on("remove", this.onRemove, this);
52105 ds.on("update", this.onUpdate, this);
52106 ds.on("clear", this.onClear, this);
52111 this.cm.un("widthchange", this.onColWidthChange, this);
52112 this.cm.un("headerchange", this.onHeaderChange, this);
52113 this.cm.un("hiddenchange", this.onHiddenChange, this);
52114 this.cm.un("columnmoved", this.onColumnMove, this);
52115 this.cm.un("columnlockchange", this.onColumnLock, this);
52118 this.generateRules(cm);
52119 cm.on("widthchange", this.onColWidthChange, this);
52120 cm.on("headerchange", this.onHeaderChange, this);
52121 cm.on("hiddenchange", this.onHiddenChange, this);
52122 cm.on("columnmoved", this.onColumnMove, this);
52123 cm.on("columnlockchange", this.onColumnLock, this);
52128 init: function(grid){
52129 Roo.grid.GridView.superclass.init.call(this, grid);
52131 this.bind(grid.dataSource, grid.colModel);
52133 grid.on("headerclick", this.handleHeaderClick, this);
52135 if(grid.trackMouseOver){
52136 grid.on("mouseover", this.onRowOver, this);
52137 grid.on("mouseout", this.onRowOut, this);
52139 grid.cancelTextSelection = function(){};
52140 this.gridId = grid.id;
52142 var tpls = this.templates || {};
52145 tpls.master = new Roo.Template(
52146 '<div class="x-grid" hidefocus="true">',
52147 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
52148 '<div class="x-grid-topbar"></div>',
52149 '<div class="x-grid-scroller"><div></div></div>',
52150 '<div class="x-grid-locked">',
52151 '<div class="x-grid-header">{lockedHeader}</div>',
52152 '<div class="x-grid-body">{lockedBody}</div>',
52154 '<div class="x-grid-viewport">',
52155 '<div class="x-grid-header">{header}</div>',
52156 '<div class="x-grid-body">{body}</div>',
52158 '<div class="x-grid-bottombar"></div>',
52160 '<div class="x-grid-resize-proxy"> </div>',
52163 tpls.master.disableformats = true;
52167 tpls.header = new Roo.Template(
52168 '<table border="0" cellspacing="0" cellpadding="0">',
52169 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
52172 tpls.header.disableformats = true;
52174 tpls.header.compile();
52177 tpls.hcell = new Roo.Template(
52178 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
52179 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
52182 tpls.hcell.disableFormats = true;
52184 tpls.hcell.compile();
52187 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
52188 this.unselectableCls + '" ' + this.unselectable +'> </div>');
52189 tpls.hsplit.disableFormats = true;
52191 tpls.hsplit.compile();
52194 tpls.body = new Roo.Template(
52195 '<table border="0" cellspacing="0" cellpadding="0">',
52196 "<tbody>{rows}</tbody>",
52199 tpls.body.disableFormats = true;
52201 tpls.body.compile();
52204 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
52205 tpls.row.disableFormats = true;
52207 tpls.row.compile();
52210 tpls.cell = new Roo.Template(
52211 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
52212 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
52213 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
52216 tpls.cell.disableFormats = true;
52218 tpls.cell.compile();
52220 this.templates = tpls;
52223 // remap these for backwards compat
52224 onColWidthChange : function(){
52225 this.updateColumns.apply(this, arguments);
52227 onHeaderChange : function(){
52228 this.updateHeaders.apply(this, arguments);
52230 onHiddenChange : function(){
52231 this.handleHiddenChange.apply(this, arguments);
52233 onColumnMove : function(){
52234 this.handleColumnMove.apply(this, arguments);
52236 onColumnLock : function(){
52237 this.handleLockChange.apply(this, arguments);
52240 onDataChange : function(){
52242 this.updateHeaderSortState();
52245 onClear : function(){
52249 onUpdate : function(ds, record){
52250 this.refreshRow(record);
52253 refreshRow : function(record){
52254 var ds = this.ds, index;
52255 if(typeof record == 'number'){
52257 record = ds.getAt(index);
52259 index = ds.indexOf(record);
52261 this.insertRows(ds, index, index, true);
52262 this.onRemove(ds, record, index+1, true);
52263 this.syncRowHeights(index, index);
52265 this.fireEvent("rowupdated", this, index, record);
52268 onAdd : function(ds, records, index){
52269 this.insertRows(ds, index, index + (records.length-1));
52272 onRemove : function(ds, record, index, isUpdate){
52273 if(isUpdate !== true){
52274 this.fireEvent("beforerowremoved", this, index, record);
52276 var bt = this.getBodyTable(), lt = this.getLockedTable();
52277 if(bt.rows[index]){
52278 bt.firstChild.removeChild(bt.rows[index]);
52280 if(lt.rows[index]){
52281 lt.firstChild.removeChild(lt.rows[index]);
52283 if(isUpdate !== true){
52284 this.stripeRows(index);
52285 this.syncRowHeights(index, index);
52287 this.fireEvent("rowremoved", this, index, record);
52291 onLoad : function(){
52292 this.scrollToTop();
52296 * Scrolls the grid to the top
52298 scrollToTop : function(){
52300 this.scroller.dom.scrollTop = 0;
52306 * Gets a panel in the header of the grid that can be used for toolbars etc.
52307 * After modifying the contents of this panel a call to grid.autoSize() may be
52308 * required to register any changes in size.
52309 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
52310 * @return Roo.Element
52312 getHeaderPanel : function(doShow){
52314 this.headerPanel.show();
52316 return this.headerPanel;
52320 * Gets a panel in the footer of the grid that can be used for toolbars etc.
52321 * After modifying the contents of this panel a call to grid.autoSize() may be
52322 * required to register any changes in size.
52323 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
52324 * @return Roo.Element
52326 getFooterPanel : function(doShow){
52328 this.footerPanel.show();
52330 return this.footerPanel;
52333 initElements : function(){
52334 var E = Roo.Element;
52335 var el = this.grid.getGridEl().dom.firstChild;
52336 var cs = el.childNodes;
52338 this.el = new E(el);
52340 this.focusEl = new E(el.firstChild);
52341 this.focusEl.swallowEvent("click", true);
52343 this.headerPanel = new E(cs[1]);
52344 this.headerPanel.enableDisplayMode("block");
52346 this.scroller = new E(cs[2]);
52347 this.scrollSizer = new E(this.scroller.dom.firstChild);
52349 this.lockedWrap = new E(cs[3]);
52350 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
52351 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
52353 this.mainWrap = new E(cs[4]);
52354 this.mainHd = new E(this.mainWrap.dom.firstChild);
52355 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
52357 this.footerPanel = new E(cs[5]);
52358 this.footerPanel.enableDisplayMode("block");
52360 this.resizeProxy = new E(cs[6]);
52362 this.headerSelector = String.format(
52363 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
52364 this.lockedHd.id, this.mainHd.id
52367 this.splitterSelector = String.format(
52368 '#{0} div.x-grid-split, #{1} div.x-grid-split',
52369 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
52372 idToCssName : function(s)
52374 return s.replace(/[^a-z0-9]+/ig, '-');
52377 getHeaderCell : function(index){
52378 return Roo.DomQuery.select(this.headerSelector)[index];
52381 getHeaderCellMeasure : function(index){
52382 return this.getHeaderCell(index).firstChild;
52385 getHeaderCellText : function(index){
52386 return this.getHeaderCell(index).firstChild.firstChild;
52389 getLockedTable : function(){
52390 return this.lockedBody.dom.firstChild;
52393 getBodyTable : function(){
52394 return this.mainBody.dom.firstChild;
52397 getLockedRow : function(index){
52398 return this.getLockedTable().rows[index];
52401 getRow : function(index){
52402 return this.getBodyTable().rows[index];
52405 getRowComposite : function(index){
52407 this.rowEl = new Roo.CompositeElementLite();
52409 var els = [], lrow, mrow;
52410 if(lrow = this.getLockedRow(index)){
52413 if(mrow = this.getRow(index)){
52416 this.rowEl.elements = els;
52420 * Gets the 'td' of the cell
52422 * @param {Integer} rowIndex row to select
52423 * @param {Integer} colIndex column to select
52427 getCell : function(rowIndex, colIndex){
52428 var locked = this.cm.getLockedCount();
52430 if(colIndex < locked){
52431 source = this.lockedBody.dom.firstChild;
52433 source = this.mainBody.dom.firstChild;
52434 colIndex -= locked;
52436 return source.rows[rowIndex].childNodes[colIndex];
52439 getCellText : function(rowIndex, colIndex){
52440 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
52443 getCellBox : function(cell){
52444 var b = this.fly(cell).getBox();
52445 if(Roo.isOpera){ // opera fails to report the Y
52446 b.y = cell.offsetTop + this.mainBody.getY();
52451 getCellIndex : function(cell){
52452 var id = String(cell.className).match(this.cellRE);
52454 return parseInt(id[1], 10);
52459 findHeaderIndex : function(n){
52460 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
52461 return r ? this.getCellIndex(r) : false;
52464 findHeaderCell : function(n){
52465 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
52466 return r ? r : false;
52469 findRowIndex : function(n){
52473 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
52474 return r ? r.rowIndex : false;
52477 findCellIndex : function(node){
52478 var stop = this.el.dom;
52479 while(node && node != stop){
52480 if(this.findRE.test(node.className)){
52481 return this.getCellIndex(node);
52483 node = node.parentNode;
52488 getColumnId : function(index){
52489 return this.cm.getColumnId(index);
52492 getSplitters : function()
52494 if(this.splitterSelector){
52495 return Roo.DomQuery.select(this.splitterSelector);
52501 getSplitter : function(index){
52502 return this.getSplitters()[index];
52505 onRowOver : function(e, t){
52507 if((row = this.findRowIndex(t)) !== false){
52508 this.getRowComposite(row).addClass("x-grid-row-over");
52512 onRowOut : function(e, t){
52514 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
52515 this.getRowComposite(row).removeClass("x-grid-row-over");
52519 renderHeaders : function(){
52521 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
52522 var cb = [], lb = [], sb = [], lsb = [], p = {};
52523 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52524 p.cellId = "x-grid-hd-0-" + i;
52525 p.splitId = "x-grid-csplit-0-" + i;
52526 p.id = cm.getColumnId(i);
52527 p.title = cm.getColumnTooltip(i) || "";
52528 p.value = cm.getColumnHeader(i) || "";
52529 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
52530 if(!cm.isLocked(i)){
52531 cb[cb.length] = ct.apply(p);
52532 sb[sb.length] = st.apply(p);
52534 lb[lb.length] = ct.apply(p);
52535 lsb[lsb.length] = st.apply(p);
52538 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
52539 ht.apply({cells: cb.join(""), splits:sb.join("")})];
52542 updateHeaders : function(){
52543 var html = this.renderHeaders();
52544 this.lockedHd.update(html[0]);
52545 this.mainHd.update(html[1]);
52549 * Focuses the specified row.
52550 * @param {Number} row The row index
52552 focusRow : function(row)
52554 //Roo.log('GridView.focusRow');
52555 var x = this.scroller.dom.scrollLeft;
52556 this.focusCell(row, 0, false);
52557 this.scroller.dom.scrollLeft = x;
52561 * Focuses the specified cell.
52562 * @param {Number} row The row index
52563 * @param {Number} col The column index
52564 * @param {Boolean} hscroll false to disable horizontal scrolling
52566 focusCell : function(row, col, hscroll)
52568 //Roo.log('GridView.focusCell');
52569 var el = this.ensureVisible(row, col, hscroll);
52570 this.focusEl.alignTo(el, "tl-tl");
52572 this.focusEl.focus();
52574 this.focusEl.focus.defer(1, this.focusEl);
52579 * Scrolls the specified cell into view
52580 * @param {Number} row The row index
52581 * @param {Number} col The column index
52582 * @param {Boolean} hscroll false to disable horizontal scrolling
52584 ensureVisible : function(row, col, hscroll)
52586 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
52587 //return null; //disable for testing.
52588 if(typeof row != "number"){
52589 row = row.rowIndex;
52591 if(row < 0 && row >= this.ds.getCount()){
52594 col = (col !== undefined ? col : 0);
52595 var cm = this.grid.colModel;
52596 while(cm.isHidden(col)){
52600 var el = this.getCell(row, col);
52604 var c = this.scroller.dom;
52606 var ctop = parseInt(el.offsetTop, 10);
52607 var cleft = parseInt(el.offsetLeft, 10);
52608 var cbot = ctop + el.offsetHeight;
52609 var cright = cleft + el.offsetWidth;
52611 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
52612 var stop = parseInt(c.scrollTop, 10);
52613 var sleft = parseInt(c.scrollLeft, 10);
52614 var sbot = stop + ch;
52615 var sright = sleft + c.clientWidth;
52617 Roo.log('GridView.ensureVisible:' +
52619 ' c.clientHeight:' + c.clientHeight +
52620 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
52628 c.scrollTop = ctop;
52629 //Roo.log("set scrolltop to ctop DISABLE?");
52630 }else if(cbot > sbot){
52631 //Roo.log("set scrolltop to cbot-ch");
52632 c.scrollTop = cbot-ch;
52635 if(hscroll !== false){
52637 c.scrollLeft = cleft;
52638 }else if(cright > sright){
52639 c.scrollLeft = cright-c.clientWidth;
52646 updateColumns : function(){
52647 this.grid.stopEditing();
52648 var cm = this.grid.colModel, colIds = this.getColumnIds();
52649 //var totalWidth = cm.getTotalWidth();
52651 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52652 //if(cm.isHidden(i)) continue;
52653 var w = cm.getColumnWidth(i);
52654 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
52655 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
52657 this.updateSplitters();
52660 generateRules : function(cm){
52661 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
52662 Roo.util.CSS.removeStyleSheet(rulesId);
52663 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52664 var cid = cm.getColumnId(i);
52666 if(cm.config[i].align){
52667 align = 'text-align:'+cm.config[i].align+';';
52670 if(cm.isHidden(i)){
52671 hidden = 'display:none;';
52673 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
52675 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
52676 this.hdSelector, cid, " {\n", align, width, "}\n",
52677 this.tdSelector, cid, " {\n",hidden,"\n}\n",
52678 this.splitSelector, cid, " {\n", hidden , "\n}\n");
52680 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52683 updateSplitters : function(){
52684 var cm = this.cm, s = this.getSplitters();
52685 if(s){ // splitters not created yet
52686 var pos = 0, locked = true;
52687 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52688 if(cm.isHidden(i)) continue;
52689 var w = cm.getColumnWidth(i); // make sure it's a number
52690 if(!cm.isLocked(i) && locked){
52695 s[i].style.left = (pos-this.splitOffset) + "px";
52700 handleHiddenChange : function(colModel, colIndex, hidden){
52702 this.hideColumn(colIndex);
52704 this.unhideColumn(colIndex);
52708 hideColumn : function(colIndex){
52709 var cid = this.getColumnId(colIndex);
52710 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
52711 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
52713 this.updateHeaders();
52715 this.updateSplitters();
52719 unhideColumn : function(colIndex){
52720 var cid = this.getColumnId(colIndex);
52721 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
52722 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
52725 this.updateHeaders();
52727 this.updateSplitters();
52731 insertRows : function(dm, firstRow, lastRow, isUpdate){
52732 if(firstRow == 0 && lastRow == dm.getCount()-1){
52736 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
52738 var s = this.getScrollState();
52739 var markup = this.renderRows(firstRow, lastRow);
52740 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
52741 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
52742 this.restoreScroll(s);
52744 this.fireEvent("rowsinserted", this, firstRow, lastRow);
52745 this.syncRowHeights(firstRow, lastRow);
52746 this.stripeRows(firstRow);
52752 bufferRows : function(markup, target, index){
52753 var before = null, trows = target.rows, tbody = target.tBodies[0];
52754 if(index < trows.length){
52755 before = trows[index];
52757 var b = document.createElement("div");
52758 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
52759 var rows = b.firstChild.rows;
52760 for(var i = 0, len = rows.length; i < len; i++){
52762 tbody.insertBefore(rows[0], before);
52764 tbody.appendChild(rows[0]);
52771 deleteRows : function(dm, firstRow, lastRow){
52772 if(dm.getRowCount()<1){
52773 this.fireEvent("beforerefresh", this);
52774 this.mainBody.update("");
52775 this.lockedBody.update("");
52776 this.fireEvent("refresh", this);
52778 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
52779 var bt = this.getBodyTable();
52780 var tbody = bt.firstChild;
52781 var rows = bt.rows;
52782 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
52783 tbody.removeChild(rows[firstRow]);
52785 this.stripeRows(firstRow);
52786 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
52790 updateRows : function(dataSource, firstRow, lastRow){
52791 var s = this.getScrollState();
52793 this.restoreScroll(s);
52796 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
52800 this.updateHeaderSortState();
52803 getScrollState : function(){
52805 var sb = this.scroller.dom;
52806 return {left: sb.scrollLeft, top: sb.scrollTop};
52809 stripeRows : function(startRow){
52810 if(!this.grid.stripeRows || this.ds.getCount() < 1){
52813 startRow = startRow || 0;
52814 var rows = this.getBodyTable().rows;
52815 var lrows = this.getLockedTable().rows;
52816 var cls = ' x-grid-row-alt ';
52817 for(var i = startRow, len = rows.length; i < len; i++){
52818 var row = rows[i], lrow = lrows[i];
52819 var isAlt = ((i+1) % 2 == 0);
52820 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
52821 if(isAlt == hasAlt){
52825 row.className += " x-grid-row-alt";
52827 row.className = row.className.replace("x-grid-row-alt", "");
52830 lrow.className = row.className;
52835 restoreScroll : function(state){
52836 //Roo.log('GridView.restoreScroll');
52837 var sb = this.scroller.dom;
52838 sb.scrollLeft = state.left;
52839 sb.scrollTop = state.top;
52843 syncScroll : function(){
52844 //Roo.log('GridView.syncScroll');
52845 var sb = this.scroller.dom;
52846 var sh = this.mainHd.dom;
52847 var bs = this.mainBody.dom;
52848 var lv = this.lockedBody.dom;
52849 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
52850 lv.scrollTop = bs.scrollTop = sb.scrollTop;
52853 handleScroll : function(e){
52855 var sb = this.scroller.dom;
52856 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
52860 handleWheel : function(e){
52861 var d = e.getWheelDelta();
52862 this.scroller.dom.scrollTop -= d*22;
52863 // set this here to prevent jumpy scrolling on large tables
52864 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
52868 renderRows : function(startRow, endRow){
52869 // pull in all the crap needed to render rows
52870 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
52871 var colCount = cm.getColumnCount();
52873 if(ds.getCount() < 1){
52877 // build a map for all the columns
52879 for(var i = 0; i < colCount; i++){
52880 var name = cm.getDataIndex(i);
52882 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
52883 renderer : cm.getRenderer(i),
52884 id : cm.getColumnId(i),
52885 locked : cm.isLocked(i)
52889 startRow = startRow || 0;
52890 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
52892 // records to render
52893 var rs = ds.getRange(startRow, endRow);
52895 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
52898 // As much as I hate to duplicate code, this was branched because FireFox really hates
52899 // [].join("") on strings. The performance difference was substantial enough to
52900 // branch this function
52901 doRender : Roo.isGecko ?
52902 function(cs, rs, ds, startRow, colCount, stripe){
52903 var ts = this.templates, ct = ts.cell, rt = ts.row;
52905 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
52907 var hasListener = this.grid.hasListener('rowclass');
52909 for(var j = 0, len = rs.length; j < len; j++){
52910 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
52911 for(var i = 0; i < colCount; i++){
52913 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
52915 p.css = p.attr = "";
52916 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
52917 if(p.value == undefined || p.value === "") p.value = " ";
52918 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
52919 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
52921 var markup = ct.apply(p);
52929 if(stripe && ((rowIndex+1) % 2 == 0)){
52930 alt.push("x-grid-row-alt")
52933 alt.push( " x-grid-dirty-row");
52936 if(this.getRowClass){
52937 alt.push(this.getRowClass(r, rowIndex));
52943 rowIndex : rowIndex,
52946 this.grid.fireEvent('rowclass', this, rowcfg);
52947 alt.push(rowcfg.rowClass);
52949 rp.alt = alt.join(" ");
52950 lbuf+= rt.apply(rp);
52952 buf+= rt.apply(rp);
52954 return [lbuf, buf];
52956 function(cs, rs, ds, startRow, colCount, stripe){
52957 var ts = this.templates, ct = ts.cell, rt = ts.row;
52959 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
52960 var hasListener = this.grid.hasListener('rowclass');
52963 for(var j = 0, len = rs.length; j < len; j++){
52964 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
52965 for(var i = 0; i < colCount; i++){
52967 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
52969 p.css = p.attr = "";
52970 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
52971 if(p.value == undefined || p.value === "") p.value = " ";
52972 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
52973 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
52976 var markup = ct.apply(p);
52978 cb[cb.length] = markup;
52980 lcb[lcb.length] = markup;
52984 if(stripe && ((rowIndex+1) % 2 == 0)){
52985 alt.push( "x-grid-row-alt");
52988 alt.push(" x-grid-dirty-row");
52991 if(this.getRowClass){
52992 alt.push( this.getRowClass(r, rowIndex));
52998 rowIndex : rowIndex,
53001 this.grid.fireEvent('rowclass', this, rowcfg);
53002 alt.push(rowcfg.rowClass);
53004 rp.alt = alt.join(" ");
53005 rp.cells = lcb.join("");
53006 lbuf[lbuf.length] = rt.apply(rp);
53007 rp.cells = cb.join("");
53008 buf[buf.length] = rt.apply(rp);
53010 return [lbuf.join(""), buf.join("")];
53013 renderBody : function(){
53014 var markup = this.renderRows();
53015 var bt = this.templates.body;
53016 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
53020 * Refreshes the grid
53021 * @param {Boolean} headersToo
53023 refresh : function(headersToo){
53024 this.fireEvent("beforerefresh", this);
53025 this.grid.stopEditing();
53026 var result = this.renderBody();
53027 this.lockedBody.update(result[0]);
53028 this.mainBody.update(result[1]);
53029 if(headersToo === true){
53030 this.updateHeaders();
53031 this.updateColumns();
53032 this.updateSplitters();
53033 this.updateHeaderSortState();
53035 this.syncRowHeights();
53037 this.fireEvent("refresh", this);
53040 handleColumnMove : function(cm, oldIndex, newIndex){
53041 this.indexMap = null;
53042 var s = this.getScrollState();
53043 this.refresh(true);
53044 this.restoreScroll(s);
53045 this.afterMove(newIndex);
53048 afterMove : function(colIndex){
53049 if(this.enableMoveAnim && Roo.enableFx){
53050 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
53052 // if multisort - fix sortOrder, and reload..
53053 if (this.grid.dataSource.multiSort) {
53054 // the we can call sort again..
53055 var dm = this.grid.dataSource;
53056 var cm = this.grid.colModel;
53058 for(var i = 0; i < cm.config.length; i++ ) {
53060 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
53061 continue; // dont' bother, it's not in sort list or being set.
53064 so.push(cm.config[i].dataIndex);
53067 dm.load(dm.lastOptions);
53074 updateCell : function(dm, rowIndex, dataIndex){
53075 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
53076 if(typeof colIndex == "undefined"){ // not present in grid
53079 var cm = this.grid.colModel;
53080 var cell = this.getCell(rowIndex, colIndex);
53081 var cellText = this.getCellText(rowIndex, colIndex);
53084 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
53085 id : cm.getColumnId(colIndex),
53086 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
53088 var renderer = cm.getRenderer(colIndex);
53089 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
53090 if(typeof val == "undefined" || val === "") val = " ";
53091 cellText.innerHTML = val;
53092 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
53093 this.syncRowHeights(rowIndex, rowIndex);
53096 calcColumnWidth : function(colIndex, maxRowsToMeasure){
53098 if(this.grid.autoSizeHeaders){
53099 var h = this.getHeaderCellMeasure(colIndex);
53100 maxWidth = Math.max(maxWidth, h.scrollWidth);
53103 if(this.cm.isLocked(colIndex)){
53104 tb = this.getLockedTable();
53107 tb = this.getBodyTable();
53108 index = colIndex - this.cm.getLockedCount();
53111 var rows = tb.rows;
53112 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
53113 for(var i = 0; i < stopIndex; i++){
53114 var cell = rows[i].childNodes[index].firstChild;
53115 maxWidth = Math.max(maxWidth, cell.scrollWidth);
53118 return maxWidth + /*margin for error in IE*/ 5;
53121 * Autofit a column to its content.
53122 * @param {Number} colIndex
53123 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
53125 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
53126 if(this.cm.isHidden(colIndex)){
53127 return; // can't calc a hidden column
53130 var cid = this.cm.getColumnId(colIndex);
53131 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
53132 if(this.grid.autoSizeHeaders){
53133 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
53136 var newWidth = this.calcColumnWidth(colIndex);
53137 this.cm.setColumnWidth(colIndex,
53138 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
53139 if(!suppressEvent){
53140 this.grid.fireEvent("columnresize", colIndex, newWidth);
53145 * Autofits all columns to their content and then expands to fit any extra space in the grid
53147 autoSizeColumns : function(){
53148 var cm = this.grid.colModel;
53149 var colCount = cm.getColumnCount();
53150 for(var i = 0; i < colCount; i++){
53151 this.autoSizeColumn(i, true, true);
53153 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
53156 this.updateColumns();
53162 * Autofits all columns to the grid's width proportionate with their current size
53163 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
53165 fitColumns : function(reserveScrollSpace){
53166 var cm = this.grid.colModel;
53167 var colCount = cm.getColumnCount();
53171 for (i = 0; i < colCount; i++){
53172 if(!cm.isHidden(i) && !cm.isFixed(i)){
53173 w = cm.getColumnWidth(i);
53179 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
53180 if(reserveScrollSpace){
53183 var frac = (avail - cm.getTotalWidth())/width;
53184 while (cols.length){
53187 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
53189 this.updateColumns();
53193 onRowSelect : function(rowIndex){
53194 var row = this.getRowComposite(rowIndex);
53195 row.addClass("x-grid-row-selected");
53198 onRowDeselect : function(rowIndex){
53199 var row = this.getRowComposite(rowIndex);
53200 row.removeClass("x-grid-row-selected");
53203 onCellSelect : function(row, col){
53204 var cell = this.getCell(row, col);
53206 Roo.fly(cell).addClass("x-grid-cell-selected");
53210 onCellDeselect : function(row, col){
53211 var cell = this.getCell(row, col);
53213 Roo.fly(cell).removeClass("x-grid-cell-selected");
53217 updateHeaderSortState : function(){
53219 // sort state can be single { field: xxx, direction : yyy}
53220 // or { xxx=>ASC , yyy : DESC ..... }
53223 if (!this.ds.multiSort) {
53224 var state = this.ds.getSortState();
53228 mstate[state.field] = state.direction;
53229 // FIXME... - this is not used here.. but might be elsewhere..
53230 this.sortState = state;
53233 mstate = this.ds.sortToggle;
53235 //remove existing sort classes..
53237 var sc = this.sortClasses;
53238 var hds = this.el.select(this.headerSelector).removeClass(sc);
53240 for(var f in mstate) {
53242 var sortColumn = this.cm.findColumnIndex(f);
53244 if(sortColumn != -1){
53245 var sortDir = mstate[f];
53246 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
53255 handleHeaderClick : function(g, index){
53256 if(this.headersDisabled){
53259 var dm = g.dataSource, cm = g.colModel;
53260 if(!cm.isSortable(index)){
53265 if (dm.multiSort) {
53266 // update the sortOrder
53268 for(var i = 0; i < cm.config.length; i++ ) {
53270 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
53271 continue; // dont' bother, it's not in sort list or being set.
53274 so.push(cm.config[i].dataIndex);
53280 dm.sort(cm.getDataIndex(index));
53284 destroy : function(){
53286 this.colMenu.removeAll();
53287 Roo.menu.MenuMgr.unregister(this.colMenu);
53288 this.colMenu.getEl().remove();
53289 delete this.colMenu;
53292 this.hmenu.removeAll();
53293 Roo.menu.MenuMgr.unregister(this.hmenu);
53294 this.hmenu.getEl().remove();
53297 if(this.grid.enableColumnMove){
53298 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53300 for(var dd in dds){
53301 if(!dds[dd].config.isTarget && dds[dd].dragElId){
53302 var elid = dds[dd].dragElId;
53304 Roo.get(elid).remove();
53305 } else if(dds[dd].config.isTarget){
53306 dds[dd].proxyTop.remove();
53307 dds[dd].proxyBottom.remove();
53310 if(Roo.dd.DDM.locationCache[dd]){
53311 delete Roo.dd.DDM.locationCache[dd];
53314 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53317 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
53318 this.bind(null, null);
53319 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
53322 handleLockChange : function(){
53323 this.refresh(true);
53326 onDenyColumnLock : function(){
53330 onDenyColumnHide : function(){
53334 handleHdMenuClick : function(item){
53335 var index = this.hdCtxIndex;
53336 var cm = this.cm, ds = this.ds;
53339 ds.sort(cm.getDataIndex(index), "ASC");
53342 ds.sort(cm.getDataIndex(index), "DESC");
53345 var lc = cm.getLockedCount();
53346 if(cm.getColumnCount(true) <= lc+1){
53347 this.onDenyColumnLock();
53351 cm.setLocked(index, true, true);
53352 cm.moveColumn(index, lc);
53353 this.grid.fireEvent("columnmove", index, lc);
53355 cm.setLocked(index, true);
53359 var lc = cm.getLockedCount();
53360 if((lc-1) != index){
53361 cm.setLocked(index, false, true);
53362 cm.moveColumn(index, lc-1);
53363 this.grid.fireEvent("columnmove", index, lc-1);
53365 cm.setLocked(index, false);
53369 index = cm.getIndexById(item.id.substr(4));
53371 if(item.checked && cm.getColumnCount(true) <= 1){
53372 this.onDenyColumnHide();
53375 cm.setHidden(index, item.checked);
53381 beforeColMenuShow : function(){
53382 var cm = this.cm, colCount = cm.getColumnCount();
53383 this.colMenu.removeAll();
53384 for(var i = 0; i < colCount; i++){
53385 this.colMenu.add(new Roo.menu.CheckItem({
53386 id: "col-"+cm.getColumnId(i),
53387 text: cm.getColumnHeader(i),
53388 checked: !cm.isHidden(i),
53394 handleHdCtx : function(g, index, e){
53396 var hd = this.getHeaderCell(index);
53397 this.hdCtxIndex = index;
53398 var ms = this.hmenu.items, cm = this.cm;
53399 ms.get("asc").setDisabled(!cm.isSortable(index));
53400 ms.get("desc").setDisabled(!cm.isSortable(index));
53401 if(this.grid.enableColLock !== false){
53402 ms.get("lock").setDisabled(cm.isLocked(index));
53403 ms.get("unlock").setDisabled(!cm.isLocked(index));
53405 this.hmenu.show(hd, "tl-bl");
53408 handleHdOver : function(e){
53409 var hd = this.findHeaderCell(e.getTarget());
53410 if(hd && !this.headersDisabled){
53411 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
53412 this.fly(hd).addClass("x-grid-hd-over");
53417 handleHdOut : function(e){
53418 var hd = this.findHeaderCell(e.getTarget());
53420 this.fly(hd).removeClass("x-grid-hd-over");
53424 handleSplitDblClick : function(e, t){
53425 var i = this.getCellIndex(t);
53426 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
53427 this.autoSizeColumn(i, true);
53432 render : function(){
53435 var colCount = cm.getColumnCount();
53437 if(this.grid.monitorWindowResize === true){
53438 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
53440 var header = this.renderHeaders();
53441 var body = this.templates.body.apply({rows:""});
53442 var html = this.templates.master.apply({
53445 lockedHeader: header[0],
53449 //this.updateColumns();
53451 this.grid.getGridEl().dom.innerHTML = html;
53453 this.initElements();
53455 // a kludge to fix the random scolling effect in webkit
53456 this.el.on("scroll", function() {
53457 this.el.dom.scrollTop=0; // hopefully not recursive..
53460 this.scroller.on("scroll", this.handleScroll, this);
53461 this.lockedBody.on("mousewheel", this.handleWheel, this);
53462 this.mainBody.on("mousewheel", this.handleWheel, this);
53464 this.mainHd.on("mouseover", this.handleHdOver, this);
53465 this.mainHd.on("mouseout", this.handleHdOut, this);
53466 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
53467 {delegate: "."+this.splitClass});
53469 this.lockedHd.on("mouseover", this.handleHdOver, this);
53470 this.lockedHd.on("mouseout", this.handleHdOut, this);
53471 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
53472 {delegate: "."+this.splitClass});
53474 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
53475 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53478 this.updateSplitters();
53480 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
53481 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53482 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53485 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
53486 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
53488 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
53489 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
53491 if(this.grid.enableColLock !== false){
53492 this.hmenu.add('-',
53493 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
53494 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
53497 if(this.grid.enableColumnHide !== false){
53499 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
53500 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
53501 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
53503 this.hmenu.add('-',
53504 {id:"columns", text: this.columnsText, menu: this.colMenu}
53507 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
53509 this.grid.on("headercontextmenu", this.handleHdCtx, this);
53512 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
53513 this.dd = new Roo.grid.GridDragZone(this.grid, {
53514 ddGroup : this.grid.ddGroup || 'GridDD'
53520 for(var i = 0; i < colCount; i++){
53521 if(cm.isHidden(i)){
53522 this.hideColumn(i);
53524 if(cm.config[i].align){
53525 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
53526 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
53530 this.updateHeaderSortState();
53532 this.beforeInitialResize();
53535 // two part rendering gives faster view to the user
53536 this.renderPhase2.defer(1, this);
53539 renderPhase2 : function(){
53540 // render the rows now
53542 if(this.grid.autoSizeColumns){
53543 this.autoSizeColumns();
53547 beforeInitialResize : function(){
53551 onColumnSplitterMoved : function(i, w){
53552 this.userResized = true;
53553 var cm = this.grid.colModel;
53554 cm.setColumnWidth(i, w, true);
53555 var cid = cm.getColumnId(i);
53556 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
53557 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
53558 this.updateSplitters();
53560 this.grid.fireEvent("columnresize", i, w);
53563 syncRowHeights : function(startIndex, endIndex){
53564 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
53565 startIndex = startIndex || 0;
53566 var mrows = this.getBodyTable().rows;
53567 var lrows = this.getLockedTable().rows;
53568 var len = mrows.length-1;
53569 endIndex = Math.min(endIndex || len, len);
53570 for(var i = startIndex; i <= endIndex; i++){
53571 var m = mrows[i], l = lrows[i];
53572 var h = Math.max(m.offsetHeight, l.offsetHeight);
53573 m.style.height = l.style.height = h + "px";
53578 layout : function(initialRender, is2ndPass){
53580 var auto = g.autoHeight;
53581 var scrollOffset = 16;
53582 var c = g.getGridEl(), cm = this.cm,
53583 expandCol = g.autoExpandColumn,
53585 //c.beginMeasure();
53587 if(!c.dom.offsetWidth){ // display:none?
53589 this.lockedWrap.show();
53590 this.mainWrap.show();
53595 var hasLock = this.cm.isLocked(0);
53597 var tbh = this.headerPanel.getHeight();
53598 var bbh = this.footerPanel.getHeight();
53601 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
53602 var newHeight = ch + c.getBorderWidth("tb");
53604 newHeight = Math.min(g.maxHeight, newHeight);
53606 c.setHeight(newHeight);
53610 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
53613 var s = this.scroller;
53615 var csize = c.getSize(true);
53617 this.el.setSize(csize.width, csize.height);
53619 this.headerPanel.setWidth(csize.width);
53620 this.footerPanel.setWidth(csize.width);
53622 var hdHeight = this.mainHd.getHeight();
53623 var vw = csize.width;
53624 var vh = csize.height - (tbh + bbh);
53628 var bt = this.getBodyTable();
53629 var ltWidth = hasLock ?
53630 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
53632 var scrollHeight = bt.offsetHeight;
53633 var scrollWidth = ltWidth + bt.offsetWidth;
53634 var vscroll = false, hscroll = false;
53636 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
53638 var lw = this.lockedWrap, mw = this.mainWrap;
53639 var lb = this.lockedBody, mb = this.mainBody;
53641 setTimeout(function(){
53642 var t = s.dom.offsetTop;
53643 var w = s.dom.clientWidth,
53644 h = s.dom.clientHeight;
53647 lw.setSize(ltWidth, h);
53649 mw.setLeftTop(ltWidth, t);
53650 mw.setSize(w-ltWidth, h);
53652 lb.setHeight(h-hdHeight);
53653 mb.setHeight(h-hdHeight);
53655 if(is2ndPass !== true && !gv.userResized && expandCol){
53656 // high speed resize without full column calculation
53658 var ci = cm.getIndexById(expandCol);
53660 ci = cm.findColumnIndex(expandCol);
53662 ci = Math.max(0, ci); // make sure it's got at least the first col.
53663 var expandId = cm.getColumnId(ci);
53664 var tw = cm.getTotalWidth(false);
53665 var currentWidth = cm.getColumnWidth(ci);
53666 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
53667 if(currentWidth != cw){
53668 cm.setColumnWidth(ci, cw, true);
53669 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
53670 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
53671 gv.updateSplitters();
53672 gv.layout(false, true);
53684 onWindowResize : function(){
53685 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
53691 appendFooter : function(parentEl){
53695 sortAscText : "Sort Ascending",
53696 sortDescText : "Sort Descending",
53697 lockText : "Lock Column",
53698 unlockText : "Unlock Column",
53699 columnsText : "Columns"
53703 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
53704 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
53705 this.proxy.el.addClass('x-grid3-col-dd');
53708 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
53709 handleMouseDown : function(e){
53713 callHandleMouseDown : function(e){
53714 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
53719 * Ext JS Library 1.1.1
53720 * Copyright(c) 2006-2007, Ext JS, LLC.
53722 * Originally Released Under LGPL - original licence link has changed is not relivant.
53725 * <script type="text/javascript">
53729 // This is a support class used internally by the Grid components
53730 Roo.grid.SplitDragZone = function(grid, hd, hd2){
53732 this.view = grid.getView();
53733 this.proxy = this.view.resizeProxy;
53734 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
53735 "gridSplitters" + this.grid.getGridEl().id, {
53736 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
53738 this.setHandleElId(Roo.id(hd));
53739 this.setOuterHandleElId(Roo.id(hd2));
53740 this.scroll = false;
53742 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
53743 fly: Roo.Element.fly,
53745 b4StartDrag : function(x, y){
53746 this.view.headersDisabled = true;
53747 this.proxy.setHeight(this.view.mainWrap.getHeight());
53748 var w = this.cm.getColumnWidth(this.cellIndex);
53749 var minw = Math.max(w-this.grid.minColumnWidth, 0);
53750 this.resetConstraints();
53751 this.setXConstraint(minw, 1000);
53752 this.setYConstraint(0, 0);
53753 this.minX = x - minw;
53754 this.maxX = x + 1000;
53756 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
53760 handleMouseDown : function(e){
53761 ev = Roo.EventObject.setEvent(e);
53762 var t = this.fly(ev.getTarget());
53763 if(t.hasClass("x-grid-split")){
53764 this.cellIndex = this.view.getCellIndex(t.dom);
53765 this.split = t.dom;
53766 this.cm = this.grid.colModel;
53767 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
53768 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
53773 endDrag : function(e){
53774 this.view.headersDisabled = false;
53775 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
53776 var diff = endX - this.startPos;
53777 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
53780 autoOffset : function(){
53781 this.setDelta(0,0);
53785 * Ext JS Library 1.1.1
53786 * Copyright(c) 2006-2007, Ext JS, LLC.
53788 * Originally Released Under LGPL - original licence link has changed is not relivant.
53791 * <script type="text/javascript">
53795 // This is a support class used internally by the Grid components
53796 Roo.grid.GridDragZone = function(grid, config){
53797 this.view = grid.getView();
53798 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
53799 if(this.view.lockedBody){
53800 this.setHandleElId(Roo.id(this.view.mainBody.dom));
53801 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
53803 this.scroll = false;
53805 this.ddel = document.createElement('div');
53806 this.ddel.className = 'x-grid-dd-wrap';
53809 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
53810 ddGroup : "GridDD",
53812 getDragData : function(e){
53813 var t = Roo.lib.Event.getTarget(e);
53814 var rowIndex = this.view.findRowIndex(t);
53815 var sm = this.grid.selModel;
53817 //Roo.log(rowIndex);
53819 if (sm.getSelectedCell) {
53820 // cell selection..
53821 if (!sm.getSelectedCell()) {
53824 if (rowIndex != sm.getSelectedCell()[0]) {
53830 if(rowIndex !== false){
53835 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
53837 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
53840 if (e.hasModifier()){
53841 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
53844 Roo.log("getDragData");
53849 rowIndex: rowIndex,
53850 selections:sm.getSelections ? sm.getSelections() : (
53851 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
53858 onInitDrag : function(e){
53859 var data = this.dragData;
53860 this.ddel.innerHTML = this.grid.getDragDropText();
53861 this.proxy.update(this.ddel);
53862 // fire start drag?
53865 afterRepair : function(){
53866 this.dragging = false;
53869 getRepairXY : function(e, data){
53873 onEndDrag : function(data, e){
53877 onValidDrop : function(dd, e, id){
53882 beforeInvalidDrop : function(e, id){
53887 * Ext JS Library 1.1.1
53888 * Copyright(c) 2006-2007, Ext JS, LLC.
53890 * Originally Released Under LGPL - original licence link has changed is not relivant.
53893 * <script type="text/javascript">
53898 * @class Roo.grid.ColumnModel
53899 * @extends Roo.util.Observable
53900 * This is the default implementation of a ColumnModel used by the Grid. It defines
53901 * the columns in the grid.
53904 var colModel = new Roo.grid.ColumnModel([
53905 {header: "Ticker", width: 60, sortable: true, locked: true},
53906 {header: "Company Name", width: 150, sortable: true},
53907 {header: "Market Cap.", width: 100, sortable: true},
53908 {header: "$ Sales", width: 100, sortable: true, renderer: money},
53909 {header: "Employees", width: 100, sortable: true, resizable: false}
53914 * The config options listed for this class are options which may appear in each
53915 * individual column definition.
53916 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
53918 * @param {Object} config An Array of column config objects. See this class's
53919 * config objects for details.
53921 Roo.grid.ColumnModel = function(config){
53923 * The config passed into the constructor
53925 this.config = config;
53928 // if no id, create one
53929 // if the column does not have a dataIndex mapping,
53930 // map it to the order it is in the config
53931 for(var i = 0, len = config.length; i < len; i++){
53933 if(typeof c.dataIndex == "undefined"){
53936 if(typeof c.renderer == "string"){
53937 c.renderer = Roo.util.Format[c.renderer];
53939 if(typeof c.id == "undefined"){
53942 if(c.editor && c.editor.xtype){
53943 c.editor = Roo.factory(c.editor, Roo.grid);
53945 if(c.editor && c.editor.isFormField){
53946 c.editor = new Roo.grid.GridEditor(c.editor);
53948 this.lookup[c.id] = c;
53952 * The width of columns which have no width specified (defaults to 100)
53955 this.defaultWidth = 100;
53958 * Default sortable of columns which have no sortable specified (defaults to false)
53961 this.defaultSortable = false;
53965 * @event widthchange
53966 * Fires when the width of a column changes.
53967 * @param {ColumnModel} this
53968 * @param {Number} columnIndex The column index
53969 * @param {Number} newWidth The new width
53971 "widthchange": true,
53973 * @event headerchange
53974 * Fires when the text of a header changes.
53975 * @param {ColumnModel} this
53976 * @param {Number} columnIndex The column index
53977 * @param {Number} newText The new header text
53979 "headerchange": true,
53981 * @event hiddenchange
53982 * Fires when a column is hidden or "unhidden".
53983 * @param {ColumnModel} this
53984 * @param {Number} columnIndex The column index
53985 * @param {Boolean} hidden true if hidden, false otherwise
53987 "hiddenchange": true,
53989 * @event columnmoved
53990 * Fires when a column is moved.
53991 * @param {ColumnModel} this
53992 * @param {Number} oldIndex
53993 * @param {Number} newIndex
53995 "columnmoved" : true,
53997 * @event columlockchange
53998 * Fires when a column's locked state is changed
53999 * @param {ColumnModel} this
54000 * @param {Number} colIndex
54001 * @param {Boolean} locked true if locked
54003 "columnlockchange" : true
54005 Roo.grid.ColumnModel.superclass.constructor.call(this);
54007 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
54009 * @cfg {String} header The header text to display in the Grid view.
54012 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
54013 * {@link Roo.data.Record} definition from which to draw the column's value. If not
54014 * specified, the column's index is used as an index into the Record's data Array.
54017 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
54018 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
54021 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
54022 * Defaults to the value of the {@link #defaultSortable} property.
54023 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
54026 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
54029 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
54032 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
54035 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
54038 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
54039 * given the cell's data value. See {@link #setRenderer}. If not specified, the
54040 * default renderer uses the raw data value.
54043 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
54046 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
54050 * Returns the id of the column at the specified index.
54051 * @param {Number} index The column index
54052 * @return {String} the id
54054 getColumnId : function(index){
54055 return this.config[index].id;
54059 * Returns the column for a specified id.
54060 * @param {String} id The column id
54061 * @return {Object} the column
54063 getColumnById : function(id){
54064 return this.lookup[id];
54069 * Returns the column for a specified dataIndex.
54070 * @param {String} dataIndex The column dataIndex
54071 * @return {Object|Boolean} the column or false if not found
54073 getColumnByDataIndex: function(dataIndex){
54074 var index = this.findColumnIndex(dataIndex);
54075 return index > -1 ? this.config[index] : false;
54079 * Returns the index for a specified column id.
54080 * @param {String} id The column id
54081 * @return {Number} the index, or -1 if not found
54083 getIndexById : function(id){
54084 for(var i = 0, len = this.config.length; i < len; i++){
54085 if(this.config[i].id == id){
54093 * Returns the index for a specified column dataIndex.
54094 * @param {String} dataIndex The column dataIndex
54095 * @return {Number} the index, or -1 if not found
54098 findColumnIndex : function(dataIndex){
54099 for(var i = 0, len = this.config.length; i < len; i++){
54100 if(this.config[i].dataIndex == dataIndex){
54108 moveColumn : function(oldIndex, newIndex){
54109 var c = this.config[oldIndex];
54110 this.config.splice(oldIndex, 1);
54111 this.config.splice(newIndex, 0, c);
54112 this.dataMap = null;
54113 this.fireEvent("columnmoved", this, oldIndex, newIndex);
54116 isLocked : function(colIndex){
54117 return this.config[colIndex].locked === true;
54120 setLocked : function(colIndex, value, suppressEvent){
54121 if(this.isLocked(colIndex) == value){
54124 this.config[colIndex].locked = value;
54125 if(!suppressEvent){
54126 this.fireEvent("columnlockchange", this, colIndex, value);
54130 getTotalLockedWidth : function(){
54131 var totalWidth = 0;
54132 for(var i = 0; i < this.config.length; i++){
54133 if(this.isLocked(i) && !this.isHidden(i)){
54134 this.totalWidth += this.getColumnWidth(i);
54140 getLockedCount : function(){
54141 for(var i = 0, len = this.config.length; i < len; i++){
54142 if(!this.isLocked(i)){
54149 * Returns the number of columns.
54152 getColumnCount : function(visibleOnly){
54153 if(visibleOnly === true){
54155 for(var i = 0, len = this.config.length; i < len; i++){
54156 if(!this.isHidden(i)){
54162 return this.config.length;
54166 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
54167 * @param {Function} fn
54168 * @param {Object} scope (optional)
54169 * @return {Array} result
54171 getColumnsBy : function(fn, scope){
54173 for(var i = 0, len = this.config.length; i < len; i++){
54174 var c = this.config[i];
54175 if(fn.call(scope||this, c, i) === true){
54183 * Returns true if the specified column is sortable.
54184 * @param {Number} col The column index
54185 * @return {Boolean}
54187 isSortable : function(col){
54188 if(typeof this.config[col].sortable == "undefined"){
54189 return this.defaultSortable;
54191 return this.config[col].sortable;
54195 * Returns the rendering (formatting) function defined for the column.
54196 * @param {Number} col The column index.
54197 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
54199 getRenderer : function(col){
54200 if(!this.config[col].renderer){
54201 return Roo.grid.ColumnModel.defaultRenderer;
54203 return this.config[col].renderer;
54207 * Sets the rendering (formatting) function for a column.
54208 * @param {Number} col The column index
54209 * @param {Function} fn The function to use to process the cell's raw data
54210 * to return HTML markup for the grid view. The render function is called with
54211 * the following parameters:<ul>
54212 * <li>Data value.</li>
54213 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
54214 * <li>css A CSS style string to apply to the table cell.</li>
54215 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
54216 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
54217 * <li>Row index</li>
54218 * <li>Column index</li>
54219 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
54221 setRenderer : function(col, fn){
54222 this.config[col].renderer = fn;
54226 * Returns the width for the specified column.
54227 * @param {Number} col The column index
54230 getColumnWidth : function(col){
54231 return this.config[col].width * 1 || this.defaultWidth;
54235 * Sets the width for a column.
54236 * @param {Number} col The column index
54237 * @param {Number} width The new width
54239 setColumnWidth : function(col, width, suppressEvent){
54240 this.config[col].width = width;
54241 this.totalWidth = null;
54242 if(!suppressEvent){
54243 this.fireEvent("widthchange", this, col, width);
54248 * Returns the total width of all columns.
54249 * @param {Boolean} includeHidden True to include hidden column widths
54252 getTotalWidth : function(includeHidden){
54253 if(!this.totalWidth){
54254 this.totalWidth = 0;
54255 for(var i = 0, len = this.config.length; i < len; i++){
54256 if(includeHidden || !this.isHidden(i)){
54257 this.totalWidth += this.getColumnWidth(i);
54261 return this.totalWidth;
54265 * Returns the header for the specified column.
54266 * @param {Number} col The column index
54269 getColumnHeader : function(col){
54270 return this.config[col].header;
54274 * Sets the header for a column.
54275 * @param {Number} col The column index
54276 * @param {String} header The new header
54278 setColumnHeader : function(col, header){
54279 this.config[col].header = header;
54280 this.fireEvent("headerchange", this, col, header);
54284 * Returns the tooltip for the specified column.
54285 * @param {Number} col The column index
54288 getColumnTooltip : function(col){
54289 return this.config[col].tooltip;
54292 * Sets the tooltip for a column.
54293 * @param {Number} col The column index
54294 * @param {String} tooltip The new tooltip
54296 setColumnTooltip : function(col, tooltip){
54297 this.config[col].tooltip = tooltip;
54301 * Returns the dataIndex for the specified column.
54302 * @param {Number} col The column index
54305 getDataIndex : function(col){
54306 return this.config[col].dataIndex;
54310 * Sets the dataIndex for a column.
54311 * @param {Number} col The column index
54312 * @param {Number} dataIndex The new dataIndex
54314 setDataIndex : function(col, dataIndex){
54315 this.config[col].dataIndex = dataIndex;
54321 * Returns true if the cell is editable.
54322 * @param {Number} colIndex The column index
54323 * @param {Number} rowIndex The row index
54324 * @return {Boolean}
54326 isCellEditable : function(colIndex, rowIndex){
54327 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
54331 * Returns the editor defined for the cell/column.
54332 * return false or null to disable editing.
54333 * @param {Number} colIndex The column index
54334 * @param {Number} rowIndex The row index
54337 getCellEditor : function(colIndex, rowIndex){
54338 return this.config[colIndex].editor;
54342 * Sets if a column is editable.
54343 * @param {Number} col The column index
54344 * @param {Boolean} editable True if the column is editable
54346 setEditable : function(col, editable){
54347 this.config[col].editable = editable;
54352 * Returns true if the column is hidden.
54353 * @param {Number} colIndex The column index
54354 * @return {Boolean}
54356 isHidden : function(colIndex){
54357 return this.config[colIndex].hidden;
54362 * Returns true if the column width cannot be changed
54364 isFixed : function(colIndex){
54365 return this.config[colIndex].fixed;
54369 * Returns true if the column can be resized
54370 * @return {Boolean}
54372 isResizable : function(colIndex){
54373 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
54376 * Sets if a column is hidden.
54377 * @param {Number} colIndex The column index
54378 * @param {Boolean} hidden True if the column is hidden
54380 setHidden : function(colIndex, hidden){
54381 this.config[colIndex].hidden = hidden;
54382 this.totalWidth = null;
54383 this.fireEvent("hiddenchange", this, colIndex, hidden);
54387 * Sets the editor for a column.
54388 * @param {Number} col The column index
54389 * @param {Object} editor The editor object
54391 setEditor : function(col, editor){
54392 this.config[col].editor = editor;
54396 Roo.grid.ColumnModel.defaultRenderer = function(value){
54397 if(typeof value == "string" && value.length < 1){
54403 // Alias for backwards compatibility
54404 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
54407 * Ext JS Library 1.1.1
54408 * Copyright(c) 2006-2007, Ext JS, LLC.
54410 * Originally Released Under LGPL - original licence link has changed is not relivant.
54413 * <script type="text/javascript">
54417 * @class Roo.grid.AbstractSelectionModel
54418 * @extends Roo.util.Observable
54419 * Abstract base class for grid SelectionModels. It provides the interface that should be
54420 * implemented by descendant classes. This class should not be directly instantiated.
54423 Roo.grid.AbstractSelectionModel = function(){
54424 this.locked = false;
54425 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
54428 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
54429 /** @ignore Called by the grid automatically. Do not call directly. */
54430 init : function(grid){
54436 * Locks the selections.
54439 this.locked = true;
54443 * Unlocks the selections.
54445 unlock : function(){
54446 this.locked = false;
54450 * Returns true if the selections are locked.
54451 * @return {Boolean}
54453 isLocked : function(){
54454 return this.locked;
54458 * Ext JS Library 1.1.1
54459 * Copyright(c) 2006-2007, Ext JS, LLC.
54461 * Originally Released Under LGPL - original licence link has changed is not relivant.
54464 * <script type="text/javascript">
54467 * @extends Roo.grid.AbstractSelectionModel
54468 * @class Roo.grid.RowSelectionModel
54469 * The default SelectionModel used by {@link Roo.grid.Grid}.
54470 * It supports multiple selections and keyboard selection/navigation.
54472 * @param {Object} config
54474 Roo.grid.RowSelectionModel = function(config){
54475 Roo.apply(this, config);
54476 this.selections = new Roo.util.MixedCollection(false, function(o){
54481 this.lastActive = false;
54485 * @event selectionchange
54486 * Fires when the selection changes
54487 * @param {SelectionModel} this
54489 "selectionchange" : true,
54491 * @event afterselectionchange
54492 * Fires after the selection changes (eg. by key press or clicking)
54493 * @param {SelectionModel} this
54495 "afterselectionchange" : true,
54497 * @event beforerowselect
54498 * Fires when a row is selected being selected, return false to cancel.
54499 * @param {SelectionModel} this
54500 * @param {Number} rowIndex The selected index
54501 * @param {Boolean} keepExisting False if other selections will be cleared
54503 "beforerowselect" : true,
54506 * Fires when a row is selected.
54507 * @param {SelectionModel} this
54508 * @param {Number} rowIndex The selected index
54509 * @param {Roo.data.Record} r The record
54511 "rowselect" : true,
54513 * @event rowdeselect
54514 * Fires when a row is deselected.
54515 * @param {SelectionModel} this
54516 * @param {Number} rowIndex The selected index
54518 "rowdeselect" : true
54520 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
54521 this.locked = false;
54524 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
54526 * @cfg {Boolean} singleSelect
54527 * True to allow selection of only one row at a time (defaults to false)
54529 singleSelect : false,
54532 initEvents : function(){
54534 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
54535 this.grid.on("mousedown", this.handleMouseDown, this);
54536 }else{ // allow click to work like normal
54537 this.grid.on("rowclick", this.handleDragableRowClick, this);
54540 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
54541 "up" : function(e){
54543 this.selectPrevious(e.shiftKey);
54544 }else if(this.last !== false && this.lastActive !== false){
54545 var last = this.last;
54546 this.selectRange(this.last, this.lastActive-1);
54547 this.grid.getView().focusRow(this.lastActive);
54548 if(last !== false){
54552 this.selectFirstRow();
54554 this.fireEvent("afterselectionchange", this);
54556 "down" : function(e){
54558 this.selectNext(e.shiftKey);
54559 }else if(this.last !== false && this.lastActive !== false){
54560 var last = this.last;
54561 this.selectRange(this.last, this.lastActive+1);
54562 this.grid.getView().focusRow(this.lastActive);
54563 if(last !== false){
54567 this.selectFirstRow();
54569 this.fireEvent("afterselectionchange", this);
54574 var view = this.grid.view;
54575 view.on("refresh", this.onRefresh, this);
54576 view.on("rowupdated", this.onRowUpdated, this);
54577 view.on("rowremoved", this.onRemove, this);
54581 onRefresh : function(){
54582 var ds = this.grid.dataSource, i, v = this.grid.view;
54583 var s = this.selections;
54584 s.each(function(r){
54585 if((i = ds.indexOfId(r.id)) != -1){
54594 onRemove : function(v, index, r){
54595 this.selections.remove(r);
54599 onRowUpdated : function(v, index, r){
54600 if(this.isSelected(r)){
54601 v.onRowSelect(index);
54607 * @param {Array} records The records to select
54608 * @param {Boolean} keepExisting (optional) True to keep existing selections
54610 selectRecords : function(records, keepExisting){
54612 this.clearSelections();
54614 var ds = this.grid.dataSource;
54615 for(var i = 0, len = records.length; i < len; i++){
54616 this.selectRow(ds.indexOf(records[i]), true);
54621 * Gets the number of selected rows.
54624 getCount : function(){
54625 return this.selections.length;
54629 * Selects the first row in the grid.
54631 selectFirstRow : function(){
54636 * Select the last row.
54637 * @param {Boolean} keepExisting (optional) True to keep existing selections
54639 selectLastRow : function(keepExisting){
54640 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
54644 * Selects the row immediately following the last selected row.
54645 * @param {Boolean} keepExisting (optional) True to keep existing selections
54647 selectNext : function(keepExisting){
54648 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
54649 this.selectRow(this.last+1, keepExisting);
54650 this.grid.getView().focusRow(this.last);
54655 * Selects the row that precedes the last selected row.
54656 * @param {Boolean} keepExisting (optional) True to keep existing selections
54658 selectPrevious : function(keepExisting){
54660 this.selectRow(this.last-1, keepExisting);
54661 this.grid.getView().focusRow(this.last);
54666 * Returns the selected records
54667 * @return {Array} Array of selected records
54669 getSelections : function(){
54670 return [].concat(this.selections.items);
54674 * Returns the first selected record.
54677 getSelected : function(){
54678 return this.selections.itemAt(0);
54683 * Clears all selections.
54685 clearSelections : function(fast){
54686 if(this.locked) return;
54688 var ds = this.grid.dataSource;
54689 var s = this.selections;
54690 s.each(function(r){
54691 this.deselectRow(ds.indexOfId(r.id));
54695 this.selections.clear();
54702 * Selects all rows.
54704 selectAll : function(){
54705 if(this.locked) return;
54706 this.selections.clear();
54707 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
54708 this.selectRow(i, true);
54713 * Returns True if there is a selection.
54714 * @return {Boolean}
54716 hasSelection : function(){
54717 return this.selections.length > 0;
54721 * Returns True if the specified row is selected.
54722 * @param {Number/Record} record The record or index of the record to check
54723 * @return {Boolean}
54725 isSelected : function(index){
54726 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
54727 return (r && this.selections.key(r.id) ? true : false);
54731 * Returns True if the specified record id is selected.
54732 * @param {String} id The id of record to check
54733 * @return {Boolean}
54735 isIdSelected : function(id){
54736 return (this.selections.key(id) ? true : false);
54740 handleMouseDown : function(e, t){
54741 var view = this.grid.getView(), rowIndex;
54742 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
54745 if(e.shiftKey && this.last !== false){
54746 var last = this.last;
54747 this.selectRange(last, rowIndex, e.ctrlKey);
54748 this.last = last; // reset the last
54749 view.focusRow(rowIndex);
54751 var isSelected = this.isSelected(rowIndex);
54752 if(e.button !== 0 && isSelected){
54753 view.focusRow(rowIndex);
54754 }else if(e.ctrlKey && isSelected){
54755 this.deselectRow(rowIndex);
54756 }else if(!isSelected){
54757 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
54758 view.focusRow(rowIndex);
54761 this.fireEvent("afterselectionchange", this);
54764 handleDragableRowClick : function(grid, rowIndex, e)
54766 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
54767 this.selectRow(rowIndex, false);
54768 grid.view.focusRow(rowIndex);
54769 this.fireEvent("afterselectionchange", this);
54774 * Selects multiple rows.
54775 * @param {Array} rows Array of the indexes of the row to select
54776 * @param {Boolean} keepExisting (optional) True to keep existing selections
54778 selectRows : function(rows, keepExisting){
54780 this.clearSelections();
54782 for(var i = 0, len = rows.length; i < len; i++){
54783 this.selectRow(rows[i], true);
54788 * Selects a range of rows. All rows in between startRow and endRow are also selected.
54789 * @param {Number} startRow The index of the first row in the range
54790 * @param {Number} endRow The index of the last row in the range
54791 * @param {Boolean} keepExisting (optional) True to retain existing selections
54793 selectRange : function(startRow, endRow, keepExisting){
54794 if(this.locked) return;
54796 this.clearSelections();
54798 if(startRow <= endRow){
54799 for(var i = startRow; i <= endRow; i++){
54800 this.selectRow(i, true);
54803 for(var i = startRow; i >= endRow; i--){
54804 this.selectRow(i, true);
54810 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
54811 * @param {Number} startRow The index of the first row in the range
54812 * @param {Number} endRow The index of the last row in the range
54814 deselectRange : function(startRow, endRow, preventViewNotify){
54815 if(this.locked) return;
54816 for(var i = startRow; i <= endRow; i++){
54817 this.deselectRow(i, preventViewNotify);
54823 * @param {Number} row The index of the row to select
54824 * @param {Boolean} keepExisting (optional) True to keep existing selections
54826 selectRow : function(index, keepExisting, preventViewNotify){
54827 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
54828 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
54829 if(!keepExisting || this.singleSelect){
54830 this.clearSelections();
54832 var r = this.grid.dataSource.getAt(index);
54833 this.selections.add(r);
54834 this.last = this.lastActive = index;
54835 if(!preventViewNotify){
54836 this.grid.getView().onRowSelect(index);
54838 this.fireEvent("rowselect", this, index, r);
54839 this.fireEvent("selectionchange", this);
54845 * @param {Number} row The index of the row to deselect
54847 deselectRow : function(index, preventViewNotify){
54848 if(this.locked) return;
54849 if(this.last == index){
54852 if(this.lastActive == index){
54853 this.lastActive = false;
54855 var r = this.grid.dataSource.getAt(index);
54856 this.selections.remove(r);
54857 if(!preventViewNotify){
54858 this.grid.getView().onRowDeselect(index);
54860 this.fireEvent("rowdeselect", this, index);
54861 this.fireEvent("selectionchange", this);
54865 restoreLast : function(){
54867 this.last = this._last;
54872 acceptsNav : function(row, col, cm){
54873 return !cm.isHidden(col) && cm.isCellEditable(col, row);
54877 onEditorKey : function(field, e){
54878 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
54883 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
54885 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
54887 }else if(k == e.ENTER && !e.ctrlKey){
54891 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
54893 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
54895 }else if(k == e.ESC){
54899 g.startEditing(newCell[0], newCell[1]);
54904 * Ext JS Library 1.1.1
54905 * Copyright(c) 2006-2007, Ext JS, LLC.
54907 * Originally Released Under LGPL - original licence link has changed is not relivant.
54910 * <script type="text/javascript">
54913 * @class Roo.grid.CellSelectionModel
54914 * @extends Roo.grid.AbstractSelectionModel
54915 * This class provides the basic implementation for cell selection in a grid.
54917 * @param {Object} config The object containing the configuration of this model.
54918 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
54920 Roo.grid.CellSelectionModel = function(config){
54921 Roo.apply(this, config);
54923 this.selection = null;
54927 * @event beforerowselect
54928 * Fires before a cell is selected.
54929 * @param {SelectionModel} this
54930 * @param {Number} rowIndex The selected row index
54931 * @param {Number} colIndex The selected cell index
54933 "beforecellselect" : true,
54935 * @event cellselect
54936 * Fires when a cell is selected.
54937 * @param {SelectionModel} this
54938 * @param {Number} rowIndex The selected row index
54939 * @param {Number} colIndex The selected cell index
54941 "cellselect" : true,
54943 * @event selectionchange
54944 * Fires when the active selection changes.
54945 * @param {SelectionModel} this
54946 * @param {Object} selection null for no selection or an object (o) with two properties
54948 <li>o.record: the record object for the row the selection is in</li>
54949 <li>o.cell: An array of [rowIndex, columnIndex]</li>
54952 "selectionchange" : true,
54955 * Fires when the tab (or enter) was pressed on the last editable cell
54956 * You can use this to trigger add new row.
54957 * @param {SelectionModel} this
54961 * @event beforeeditnext
54962 * Fires before the next editable sell is made active
54963 * You can use this to skip to another cell or fire the tabend
54964 * if you set cell to false
54965 * @param {Object} eventdata object : { cell : [ row, col ] }
54967 "beforeeditnext" : true
54969 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
54972 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
54974 enter_is_tab: false,
54977 initEvents : function(){
54978 this.grid.on("mousedown", this.handleMouseDown, this);
54979 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
54980 var view = this.grid.view;
54981 view.on("refresh", this.onViewChange, this);
54982 view.on("rowupdated", this.onRowUpdated, this);
54983 view.on("beforerowremoved", this.clearSelections, this);
54984 view.on("beforerowsinserted", this.clearSelections, this);
54985 if(this.grid.isEditor){
54986 this.grid.on("beforeedit", this.beforeEdit, this);
54991 beforeEdit : function(e){
54992 this.select(e.row, e.column, false, true, e.record);
54996 onRowUpdated : function(v, index, r){
54997 if(this.selection && this.selection.record == r){
54998 v.onCellSelect(index, this.selection.cell[1]);
55003 onViewChange : function(){
55004 this.clearSelections(true);
55008 * Returns the currently selected cell,.
55009 * @return {Array} The selected cell (row, column) or null if none selected.
55011 getSelectedCell : function(){
55012 return this.selection ? this.selection.cell : null;
55016 * Clears all selections.
55017 * @param {Boolean} true to prevent the gridview from being notified about the change.
55019 clearSelections : function(preventNotify){
55020 var s = this.selection;
55022 if(preventNotify !== true){
55023 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
55025 this.selection = null;
55026 this.fireEvent("selectionchange", this, null);
55031 * Returns true if there is a selection.
55032 * @return {Boolean}
55034 hasSelection : function(){
55035 return this.selection ? true : false;
55039 handleMouseDown : function(e, t){
55040 var v = this.grid.getView();
55041 if(this.isLocked()){
55044 var row = v.findRowIndex(t);
55045 var cell = v.findCellIndex(t);
55046 if(row !== false && cell !== false){
55047 this.select(row, cell);
55053 * @param {Number} rowIndex
55054 * @param {Number} collIndex
55056 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
55057 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
55058 this.clearSelections();
55059 r = r || this.grid.dataSource.getAt(rowIndex);
55062 cell : [rowIndex, colIndex]
55064 if(!preventViewNotify){
55065 var v = this.grid.getView();
55066 v.onCellSelect(rowIndex, colIndex);
55067 if(preventFocus !== true){
55068 v.focusCell(rowIndex, colIndex);
55071 this.fireEvent("cellselect", this, rowIndex, colIndex);
55072 this.fireEvent("selectionchange", this, this.selection);
55077 isSelectable : function(rowIndex, colIndex, cm){
55078 return !cm.isHidden(colIndex);
55082 handleKeyDown : function(e){
55083 //Roo.log('Cell Sel Model handleKeyDown');
55084 if(!e.isNavKeyPress()){
55087 var g = this.grid, s = this.selection;
55090 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
55092 this.select(cell[0], cell[1]);
55097 var walk = function(row, col, step){
55098 return g.walkCells(row, col, step, sm.isSelectable, sm);
55100 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
55107 // handled by onEditorKey
55108 if (g.isEditor && g.editing) {
55112 newCell = walk(r, c-1, -1);
55114 newCell = walk(r, c+1, 1);
55119 newCell = walk(r+1, c, 1);
55123 newCell = walk(r-1, c, -1);
55127 newCell = walk(r, c+1, 1);
55131 newCell = walk(r, c-1, -1);
55136 if(g.isEditor && !g.editing){
55137 g.startEditing(r, c);
55146 this.select(newCell[0], newCell[1]);
55152 acceptsNav : function(row, col, cm){
55153 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55157 * @param {Number} field (not used) - as it's normally used as a listener
55158 * @param {Number} e - event - fake it by using
55160 * var e = Roo.EventObjectImpl.prototype;
55161 * e.keyCode = e.TAB
55165 onEditorKey : function(field, e){
55167 var k = e.getKey(),
55170 ed = g.activeEditor,
55172 ///Roo.log('onEditorKey' + k);
55175 if (this.enter_is_tab && k == e.ENTER) {
55181 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55183 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55189 } else if(k == e.ENTER && !e.ctrlKey){
55192 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55194 } else if(k == e.ESC){
55199 var ecall = { cell : newCell, forward : forward };
55200 this.fireEvent('beforeeditnext', ecall );
55201 newCell = ecall.cell;
55202 forward = ecall.forward;
55206 //Roo.log('next cell after edit');
55207 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
55208 } else if (forward) {
55209 // tabbed past last
55210 this.fireEvent.defer(100, this, ['tabend',this]);
55215 * Ext JS Library 1.1.1
55216 * Copyright(c) 2006-2007, Ext JS, LLC.
55218 * Originally Released Under LGPL - original licence link has changed is not relivant.
55221 * <script type="text/javascript">
55225 * @class Roo.grid.EditorGrid
55226 * @extends Roo.grid.Grid
55227 * Class for creating and editable grid.
55228 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55229 * The container MUST have some type of size defined for the grid to fill. The container will be
55230 * automatically set to position relative if it isn't already.
55231 * @param {Object} dataSource The data model to bind to
55232 * @param {Object} colModel The column model with info about this grid's columns
55234 Roo.grid.EditorGrid = function(container, config){
55235 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
55236 this.getGridEl().addClass("xedit-grid");
55238 if(!this.selModel){
55239 this.selModel = new Roo.grid.CellSelectionModel();
55242 this.activeEditor = null;
55246 * @event beforeedit
55247 * Fires before cell editing is triggered. The edit event object has the following properties <br />
55248 * <ul style="padding:5px;padding-left:16px;">
55249 * <li>grid - This grid</li>
55250 * <li>record - The record being edited</li>
55251 * <li>field - The field name being edited</li>
55252 * <li>value - The value for the field being edited.</li>
55253 * <li>row - The grid row index</li>
55254 * <li>column - The grid column index</li>
55255 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55257 * @param {Object} e An edit event (see above for description)
55259 "beforeedit" : true,
55262 * Fires after a cell is edited. <br />
55263 * <ul style="padding:5px;padding-left:16px;">
55264 * <li>grid - This grid</li>
55265 * <li>record - The record being edited</li>
55266 * <li>field - The field name being edited</li>
55267 * <li>value - The value being set</li>
55268 * <li>originalValue - The original value for the field, before the edit.</li>
55269 * <li>row - The grid row index</li>
55270 * <li>column - The grid column index</li>
55272 * @param {Object} e An edit event (see above for description)
55274 "afteredit" : true,
55276 * @event validateedit
55277 * Fires after a cell is edited, but before the value is set in the record.
55278 * You can use this to modify the value being set in the field, Return false
55279 * to cancel the change. The edit event object has the following properties <br />
55280 * <ul style="padding:5px;padding-left:16px;">
55281 * <li>editor - This editor</li>
55282 * <li>grid - This grid</li>
55283 * <li>record - The record being edited</li>
55284 * <li>field - The field name being edited</li>
55285 * <li>value - The value being set</li>
55286 * <li>originalValue - The original value for the field, before the edit.</li>
55287 * <li>row - The grid row index</li>
55288 * <li>column - The grid column index</li>
55289 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55291 * @param {Object} e An edit event (see above for description)
55293 "validateedit" : true
55295 this.on("bodyscroll", this.stopEditing, this);
55296 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
55299 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
55301 * @cfg {Number} clicksToEdit
55302 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
55309 trackMouseOver: false, // causes very odd FF errors
55311 onCellDblClick : function(g, row, col){
55312 this.startEditing(row, col);
55315 onEditComplete : function(ed, value, startValue){
55316 this.editing = false;
55317 this.activeEditor = null;
55318 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
55320 var field = this.colModel.getDataIndex(ed.col);
55325 originalValue: startValue,
55332 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
55335 if(String(value) !== String(startValue)){
55337 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
55338 r.set(field, e.value);
55339 // if we are dealing with a combo box..
55340 // then we also set the 'name' colum to be the displayField
55341 if (ed.field.displayField && ed.field.name) {
55342 r.set(ed.field.name, ed.field.el.dom.value);
55345 delete e.cancel; //?? why!!!
55346 this.fireEvent("afteredit", e);
55349 this.fireEvent("afteredit", e); // always fire it!
55351 this.view.focusCell(ed.row, ed.col);
55355 * Starts editing the specified for the specified row/column
55356 * @param {Number} rowIndex
55357 * @param {Number} colIndex
55359 startEditing : function(row, col){
55360 this.stopEditing();
55361 if(this.colModel.isCellEditable(col, row)){
55362 this.view.ensureVisible(row, col, true);
55364 var r = this.dataSource.getAt(row);
55365 var field = this.colModel.getDataIndex(col);
55366 var cell = Roo.get(this.view.getCell(row,col));
55371 value: r.data[field],
55376 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
55377 this.editing = true;
55378 var ed = this.colModel.getCellEditor(col, row);
55384 ed.render(ed.parentEl || document.body);
55390 (function(){ // complex but required for focus issues in safari, ie and opera
55394 ed.on("complete", this.onEditComplete, this, {single: true});
55395 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
55396 this.activeEditor = ed;
55397 var v = r.data[field];
55398 ed.startEdit(this.view.getCell(row, col), v);
55399 // combo's with 'displayField and name set
55400 if (ed.field.displayField && ed.field.name) {
55401 ed.field.el.dom.value = r.data[ed.field.name];
55405 }).defer(50, this);
55411 * Stops any active editing
55413 stopEditing : function(){
55414 if(this.activeEditor){
55415 this.activeEditor.completeEdit();
55417 this.activeEditor = null;
55421 * Called to get grid's drag proxy text, by default returns this.ddText.
55424 getDragDropText : function(){
55425 var count = this.selModel.getSelectedCell() ? 1 : 0;
55426 return String.format(this.ddText, count, count == 1 ? '' : 's');
55431 * Ext JS Library 1.1.1
55432 * Copyright(c) 2006-2007, Ext JS, LLC.
55434 * Originally Released Under LGPL - original licence link has changed is not relivant.
55437 * <script type="text/javascript">
55440 // private - not really -- you end up using it !
55441 // This is a support class used internally by the Grid components
55444 * @class Roo.grid.GridEditor
55445 * @extends Roo.Editor
55446 * Class for creating and editable grid elements.
55447 * @param {Object} config any settings (must include field)
55449 Roo.grid.GridEditor = function(field, config){
55450 if (!config && field.field) {
55452 field = Roo.factory(config.field, Roo.form);
55454 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
55455 field.monitorTab = false;
55458 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
55461 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
55464 alignment: "tl-tl",
55467 cls: "x-small-editor x-grid-editor",
55472 * Ext JS Library 1.1.1
55473 * Copyright(c) 2006-2007, Ext JS, LLC.
55475 * Originally Released Under LGPL - original licence link has changed is not relivant.
55478 * <script type="text/javascript">
55483 Roo.grid.PropertyRecord = Roo.data.Record.create([
55484 {name:'name',type:'string'}, 'value'
55488 Roo.grid.PropertyStore = function(grid, source){
55490 this.store = new Roo.data.Store({
55491 recordType : Roo.grid.PropertyRecord
55493 this.store.on('update', this.onUpdate, this);
55495 this.setSource(source);
55497 Roo.grid.PropertyStore.superclass.constructor.call(this);
55502 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
55503 setSource : function(o){
55505 this.store.removeAll();
55508 if(this.isEditableValue(o[k])){
55509 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
55512 this.store.loadRecords({records: data}, {}, true);
55515 onUpdate : function(ds, record, type){
55516 if(type == Roo.data.Record.EDIT){
55517 var v = record.data['value'];
55518 var oldValue = record.modified['value'];
55519 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
55520 this.source[record.id] = v;
55522 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
55529 getProperty : function(row){
55530 return this.store.getAt(row);
55533 isEditableValue: function(val){
55534 if(val && val instanceof Date){
55536 }else if(typeof val == 'object' || typeof val == 'function'){
55542 setValue : function(prop, value){
55543 this.source[prop] = value;
55544 this.store.getById(prop).set('value', value);
55547 getSource : function(){
55548 return this.source;
55552 Roo.grid.PropertyColumnModel = function(grid, store){
55555 g.PropertyColumnModel.superclass.constructor.call(this, [
55556 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
55557 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
55559 this.store = store;
55560 this.bselect = Roo.DomHelper.append(document.body, {
55561 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
55562 {tag: 'option', value: 'true', html: 'true'},
55563 {tag: 'option', value: 'false', html: 'false'}
55566 Roo.id(this.bselect);
55569 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
55570 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
55571 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
55572 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
55573 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
55575 this.renderCellDelegate = this.renderCell.createDelegate(this);
55576 this.renderPropDelegate = this.renderProp.createDelegate(this);
55579 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
55583 valueText : 'Value',
55585 dateFormat : 'm/j/Y',
55588 renderDate : function(dateVal){
55589 return dateVal.dateFormat(this.dateFormat);
55592 renderBool : function(bVal){
55593 return bVal ? 'true' : 'false';
55596 isCellEditable : function(colIndex, rowIndex){
55597 return colIndex == 1;
55600 getRenderer : function(col){
55602 this.renderCellDelegate : this.renderPropDelegate;
55605 renderProp : function(v){
55606 return this.getPropertyName(v);
55609 renderCell : function(val){
55611 if(val instanceof Date){
55612 rv = this.renderDate(val);
55613 }else if(typeof val == 'boolean'){
55614 rv = this.renderBool(val);
55616 return Roo.util.Format.htmlEncode(rv);
55619 getPropertyName : function(name){
55620 var pn = this.grid.propertyNames;
55621 return pn && pn[name] ? pn[name] : name;
55624 getCellEditor : function(colIndex, rowIndex){
55625 var p = this.store.getProperty(rowIndex);
55626 var n = p.data['name'], val = p.data['value'];
55628 if(typeof(this.grid.customEditors[n]) == 'string'){
55629 return this.editors[this.grid.customEditors[n]];
55631 if(typeof(this.grid.customEditors[n]) != 'undefined'){
55632 return this.grid.customEditors[n];
55634 if(val instanceof Date){
55635 return this.editors['date'];
55636 }else if(typeof val == 'number'){
55637 return this.editors['number'];
55638 }else if(typeof val == 'boolean'){
55639 return this.editors['boolean'];
55641 return this.editors['string'];
55647 * @class Roo.grid.PropertyGrid
55648 * @extends Roo.grid.EditorGrid
55649 * This class represents the interface of a component based property grid control.
55650 * <br><br>Usage:<pre><code>
55651 var grid = new Roo.grid.PropertyGrid("my-container-id", {
55659 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55660 * The container MUST have some type of size defined for the grid to fill. The container will be
55661 * automatically set to position relative if it isn't already.
55662 * @param {Object} config A config object that sets properties on this grid.
55664 Roo.grid.PropertyGrid = function(container, config){
55665 config = config || {};
55666 var store = new Roo.grid.PropertyStore(this);
55667 this.store = store;
55668 var cm = new Roo.grid.PropertyColumnModel(this, store);
55669 store.store.sort('name', 'ASC');
55670 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
55673 enableColLock:false,
55674 enableColumnMove:false,
55676 trackMouseOver: false,
55679 this.getGridEl().addClass('x-props-grid');
55680 this.lastEditRow = null;
55681 this.on('columnresize', this.onColumnResize, this);
55684 * @event beforepropertychange
55685 * Fires before a property changes (return false to stop?)
55686 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
55687 * @param {String} id Record Id
55688 * @param {String} newval New Value
55689 * @param {String} oldval Old Value
55691 "beforepropertychange": true,
55693 * @event propertychange
55694 * Fires after a property changes
55695 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
55696 * @param {String} id Record Id
55697 * @param {String} newval New Value
55698 * @param {String} oldval Old Value
55700 "propertychange": true
55702 this.customEditors = this.customEditors || {};
55704 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
55707 * @cfg {Object} customEditors map of colnames=> custom editors.
55708 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
55709 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
55710 * false disables editing of the field.
55714 * @cfg {Object} propertyNames map of property Names to their displayed value
55717 render : function(){
55718 Roo.grid.PropertyGrid.superclass.render.call(this);
55719 this.autoSize.defer(100, this);
55722 autoSize : function(){
55723 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
55725 this.view.fitColumns();
55729 onColumnResize : function(){
55730 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
55734 * Sets the data for the Grid
55735 * accepts a Key => Value object of all the elements avaiable.
55736 * @param {Object} data to appear in grid.
55738 setSource : function(source){
55739 this.store.setSource(source);
55743 * Gets all the data from the grid.
55744 * @return {Object} data data stored in grid
55746 getSource : function(){
55747 return this.store.getSource();
55751 * Ext JS Library 1.1.1
55752 * Copyright(c) 2006-2007, Ext JS, LLC.
55754 * Originally Released Under LGPL - original licence link has changed is not relivant.
55757 * <script type="text/javascript">
55761 * @class Roo.LoadMask
55762 * A simple utility class for generically masking elements while loading data. If the element being masked has
55763 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
55764 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
55765 * element's UpdateManager load indicator and will be destroyed after the initial load.
55767 * Create a new LoadMask
55768 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
55769 * @param {Object} config The config object
55771 Roo.LoadMask = function(el, config){
55772 this.el = Roo.get(el);
55773 Roo.apply(this, config);
55775 this.store.on('beforeload', this.onBeforeLoad, this);
55776 this.store.on('load', this.onLoad, this);
55777 this.store.on('loadexception', this.onLoadException, this);
55778 this.removeMask = false;
55780 var um = this.el.getUpdateManager();
55781 um.showLoadIndicator = false; // disable the default indicator
55782 um.on('beforeupdate', this.onBeforeLoad, this);
55783 um.on('update', this.onLoad, this);
55784 um.on('failure', this.onLoad, this);
55785 this.removeMask = true;
55789 Roo.LoadMask.prototype = {
55791 * @cfg {Boolean} removeMask
55792 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
55793 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
55796 * @cfg {String} msg
55797 * The text to display in a centered loading message box (defaults to 'Loading...')
55799 msg : 'Loading...',
55801 * @cfg {String} msgCls
55802 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
55804 msgCls : 'x-mask-loading',
55807 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
55813 * Disables the mask to prevent it from being displayed
55815 disable : function(){
55816 this.disabled = true;
55820 * Enables the mask so that it can be displayed
55822 enable : function(){
55823 this.disabled = false;
55826 onLoadException : function()
55828 Roo.log(arguments);
55830 if (typeof(arguments[3]) != 'undefined') {
55831 Roo.MessageBox.alert("Error loading",arguments[3]);
55835 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
55836 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
55845 this.el.unmask(this.removeMask);
55848 onLoad : function()
55850 this.el.unmask(this.removeMask);
55854 onBeforeLoad : function(){
55855 if(!this.disabled){
55856 this.el.mask(this.msg, this.msgCls);
55861 destroy : function(){
55863 this.store.un('beforeload', this.onBeforeLoad, this);
55864 this.store.un('load', this.onLoad, this);
55865 this.store.un('loadexception', this.onLoadException, this);
55867 var um = this.el.getUpdateManager();
55868 um.un('beforeupdate', this.onBeforeLoad, this);
55869 um.un('update', this.onLoad, this);
55870 um.un('failure', this.onLoad, this);
55875 * Ext JS Library 1.1.1
55876 * Copyright(c) 2006-2007, Ext JS, LLC.
55878 * Originally Released Under LGPL - original licence link has changed is not relivant.
55881 * <script type="text/javascript">
55886 * @class Roo.XTemplate
55887 * @extends Roo.Template
55888 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
55890 var t = new Roo.XTemplate(
55891 '<select name="{name}">',
55892 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
55896 // then append, applying the master template values
55899 * Supported features:
55904 {a_variable} - output encoded.
55905 {a_variable.format:("Y-m-d")} - call a method on the variable
55906 {a_variable:raw} - unencoded output
55907 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
55908 {a_variable:this.method_on_template(...)} - call a method on the template object.
55913 <tpl for="a_variable or condition.."></tpl>
55914 <tpl if="a_variable or condition"></tpl>
55915 <tpl exec="some javascript"></tpl>
55916 <tpl name="named_template"></tpl> (experimental)
55918 <tpl for="."></tpl> - just iterate the property..
55919 <tpl for=".."></tpl> - iterates with the parent (probably the template)
55923 Roo.XTemplate = function()
55925 Roo.XTemplate.superclass.constructor.apply(this, arguments);
55932 Roo.extend(Roo.XTemplate, Roo.Template, {
55935 * The various sub templates
55940 * basic tag replacing syntax
55943 * // you can fake an object call by doing this
55947 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
55950 * compile the template
55952 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
55955 compile: function()
55959 s = ['<tpl>', s, '</tpl>'].join('');
55961 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
55962 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
55963 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
55964 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
55965 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
55970 while(true == !!(m = s.match(re))){
55971 var forMatch = m[0].match(nameRe),
55972 ifMatch = m[0].match(ifRe),
55973 execMatch = m[0].match(execRe),
55974 namedMatch = m[0].match(namedRe),
55979 name = forMatch && forMatch[1] ? forMatch[1] : '';
55982 // if - puts fn into test..
55983 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
55985 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
55990 // exec - calls a function... returns empty if true is returned.
55991 exp = execMatch && execMatch[1] ? execMatch[1] : null;
55993 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
56001 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
56002 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
56003 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
56006 var uid = namedMatch ? namedMatch[1] : id;
56010 id: namedMatch ? namedMatch[1] : id,
56017 s = s.replace(m[0], '');
56019 s = s.replace(m[0], '{xtpl'+ id + '}');
56024 for(var i = tpls.length-1; i >= 0; --i){
56025 this.compileTpl(tpls[i]);
56026 this.tpls[tpls[i].id] = tpls[i];
56028 this.master = tpls[tpls.length-1];
56032 * same as applyTemplate, except it's done to one of the subTemplates
56033 * when using named templates, you can do:
56035 * var str = pl.applySubTemplate('your-name', values);
56038 * @param {Number} id of the template
56039 * @param {Object} values to apply to template
56040 * @param {Object} parent (normaly the instance of this object)
56042 applySubTemplate : function(id, values, parent)
56046 var t = this.tpls[id];
56050 if(t.test && !t.test.call(this, values, parent)){
56054 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
56055 Roo.log(e.toString());
56061 if(t.exec && t.exec.call(this, values, parent)){
56065 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
56066 Roo.log(e.toString());
56071 var vs = t.target ? t.target.call(this, values, parent) : values;
56072 parent = t.target ? values : parent;
56073 if(t.target && vs instanceof Array){
56075 for(var i = 0, len = vs.length; i < len; i++){
56076 buf[buf.length] = t.compiled.call(this, vs[i], parent);
56078 return buf.join('');
56080 return t.compiled.call(this, vs, parent);
56082 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
56083 Roo.log(e.toString());
56084 Roo.log(t.compiled);
56089 compileTpl : function(tpl)
56091 var fm = Roo.util.Format;
56092 var useF = this.disableFormats !== true;
56093 var sep = Roo.isGecko ? "+" : ",";
56094 var undef = function(str) {
56095 Roo.log("Property not found :" + str);
56099 var fn = function(m, name, format, args)
56101 //Roo.log(arguments);
56102 args = args ? args.replace(/\\'/g,"'") : args;
56103 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
56104 if (typeof(format) == 'undefined') {
56105 format= 'htmlEncode';
56107 if (format == 'raw' ) {
56111 if(name.substr(0, 4) == 'xtpl'){
56112 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
56115 // build an array of options to determine if value is undefined..
56117 // basically get 'xxxx.yyyy' then do
56118 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
56119 // (function () { Roo.log("Property not found"); return ''; })() :
56124 Roo.each(name.split('.'), function(st) {
56125 lookfor += (lookfor.length ? '.': '') + st;
56126 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
56129 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
56132 if(format && useF){
56134 args = args ? ',' + args : "";
56136 if(format.substr(0, 5) != "this."){
56137 format = "fm." + format + '(';
56139 format = 'this.call("'+ format.substr(5) + '", ';
56143 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
56147 // called with xxyx.yuu:(test,test)
56149 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
56151 // raw.. - :raw modifier..
56152 return "'"+ sep + udef_st + name + ")"+sep+"'";
56156 // branched to use + in gecko and [].join() in others
56158 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
56159 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
56162 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
56163 body.push(tpl.body.replace(/(\r\n|\n)/g,
56164 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
56165 body.push("'].join('');};};");
56166 body = body.join('');
56169 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
56171 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
56177 applyTemplate : function(values){
56178 return this.master.compiled.call(this, values, {});
56179 //var s = this.subs;
56182 apply : function(){
56183 return this.applyTemplate.apply(this, arguments);
56188 Roo.XTemplate.from = function(el){
56189 el = Roo.getDom(el);
56190 return new Roo.XTemplate(el.value || el.innerHTML);