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;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
212 sb = function(){sp.apply(this, arguments);};
214 var F = function(){}, sbp, spp = sp.prototype;
216 sbp = sb.prototype = new F();
220 if(spp.constructor == Object.prototype.constructor){
225 sb.override = function(o){
229 Roo.override(sb, overrides);
235 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
237 Roo.override(MyClass, {
238 newMethod1: function(){
241 newMethod2: function(foo){
246 * @param {Object} origclass The class to override
247 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
248 * containing one or more methods.
251 override : function(origclass, overrides){
253 var p = origclass.prototype;
254 for(var method in overrides){
255 p[method] = overrides[method];
260 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
266 * @param {String} namespace1
267 * @param {String} namespace2
268 * @param {String} etc
271 namespace : function(){
272 var a=arguments, o=null, i, j, d, rt;
273 for (i=0; i<a.length; ++i) {
277 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278 for (j=1; j<d.length; ++j) {
279 o[d[j]]=o[d[j]] || {};
285 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
290 * @param {String} classname
291 * @param {String} namespace (optional)
295 factory : function(c, ns)
297 // no xtype, no ns or c.xns - or forced off by c.xns
298 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
301 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302 if (c.constructor == ns[c.xtype]) {// already created...
306 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307 var ret = new ns[c.xtype](c);
311 c.xns = false; // prevent recursion..
315 * Logs to console if it can.
317 * @param {String|Object} string
322 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
329 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
333 urlEncode : function(o){
339 var ov = o[key], k = encodeURIComponent(key);
340 var type = typeof ov;
341 if(type == 'undefined'){
343 }else if(type != "function" && type != "object"){
344 buf.push(k, "=", encodeURIComponent(ov), "&");
345 }else if(ov instanceof Array){
347 for(var i = 0, len = ov.length; i < len; i++) {
348 buf.push(k, "=", encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
360 * 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]}.
361 * @param {String} string
362 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
363 * @return {Object} A literal with members
365 urlDecode : function(string, overwrite){
366 if(!string || !string.length){
370 var pairs = string.split('&');
371 var pair, name, value;
372 for(var i = 0, len = pairs.length; i < len; i++){
373 pair = pairs[i].split('=');
374 name = decodeURIComponent(pair[0]);
375 value = decodeURIComponent(pair[1]);
376 if(overwrite !== true){
377 if(typeof obj[name] == "undefined"){
379 }else if(typeof obj[name] == "string"){
380 obj[name] = [obj[name]];
381 obj[name].push(value);
383 obj[name].push(value);
393 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
394 * passed array is not really an array, your function is called once with it.
395 * The supplied function is called with (Object item, Number index, Array allItems).
396 * @param {Array/NodeList/Mixed} array
397 * @param {Function} fn
398 * @param {Object} scope
400 each : function(array, fn, scope){
401 if(typeof array.length == "undefined" || typeof array == "string"){
404 for(var i = 0, len = array.length; i < len; i++){
405 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
410 combine : function(){
411 var as = arguments, l = as.length, r = [];
412 for(var i = 0; i < l; i++){
414 if(a instanceof Array){
416 }else if(a.length !== undefined && !a.substr){
417 r = r.concat(Array.prototype.slice.call(a, 0));
426 * Escapes the passed string for use in a regular expression
427 * @param {String} str
430 escapeRe : function(s) {
431 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
435 callback : function(cb, scope, args, delay){
436 if(typeof cb == "function"){
438 cb.defer(delay, scope, args || []);
440 cb.apply(scope, args || []);
446 * Return the dom node for the passed string (id), dom node, or Roo.Element
447 * @param {String/HTMLElement/Roo.Element} el
448 * @return HTMLElement
450 getDom : function(el){
454 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
458 * Shorthand for {@link Roo.ComponentMgr#get}
460 * @return Roo.Component
462 getCmp : function(id){
463 return Roo.ComponentMgr.get(id);
466 num : function(v, defaultValue){
467 if(typeof v != 'number'){
473 destroy : function(){
474 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
478 as.removeAllListeners();
482 if(typeof as.purgeListeners == 'function'){
485 if(typeof as.destroy == 'function'){
492 // inpired by a similar function in mootools library
494 * Returns the type of object that is passed in. If the object passed in is null or undefined it
495 * return false otherwise it returns one of the following values:<ul>
496 * <li><b>string</b>: If the object passed is a string</li>
497 * <li><b>number</b>: If the object passed is a number</li>
498 * <li><b>boolean</b>: If the object passed is a boolean value</li>
499 * <li><b>function</b>: If the object passed is a function reference</li>
500 * <li><b>object</b>: If the object passed is an object</li>
501 * <li><b>array</b>: If the object passed is an array</li>
502 * <li><b>regexp</b>: If the object passed is a regular expression</li>
503 * <li><b>element</b>: If the object passed is a DOM Element</li>
504 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
505 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
506 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
507 * @param {Mixed} object
511 if(o === undefined || o === null){
518 if(t == 'object' && o.nodeName) {
520 case 1: return 'element';
521 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
524 if(t == 'object' || t == 'function') {
525 switch(o.constructor) {
526 case Array: return 'array';
527 case RegExp: return 'regexp';
529 if(typeof o.length == 'number' && typeof o.item == 'function') {
537 * Returns true if the passed value is null, undefined or an empty string (optional).
538 * @param {Mixed} value The value to test
539 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
542 isEmpty : function(v, allowBlank){
543 return v === null || v === undefined || (!allowBlank ? v === '' : false);
557 isBorderBox : isBorderBox,
559 isWindows : isWindows,
566 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
567 * you may want to set this to true.
570 useShims : ((isIE && !isIE7) || (isGecko && isMac))
576 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
577 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
580 * Ext JS Library 1.1.1
581 * Copyright(c) 2006-2007, Ext JS, LLC.
583 * Originally Released Under LGPL - original licence link has changed is not relivant.
586 * <script type="text/javascript">
590 // wrappedn so fnCleanup is not in global scope...
592 function fnCleanUp() {
593 var p = Function.prototype;
594 delete p.createSequence;
596 delete p.createDelegate;
597 delete p.createCallback;
598 delete p.createInterceptor;
600 window.detachEvent("onunload", fnCleanUp);
602 window.attachEvent("onunload", fnCleanUp);
609 * These functions are available on every Function object (any JavaScript function).
611 Roo.apply(Function.prototype, {
613 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
614 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
615 * Will create a function that is bound to those 2 args.
616 * @return {Function} The new function
618 createCallback : function(/*args...*/){
619 // make args available, in function below
620 var args = arguments;
623 return method.apply(window, args);
628 * Creates a delegate (callback) that sets the scope to obj.
629 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
630 * Will create a function that is automatically scoped to this.
631 * @param {Object} obj (optional) The object for which the scope is set
632 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
633 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
634 * if a number the args are inserted at the specified position
635 * @return {Function} The new function
637 createDelegate : function(obj, args, appendArgs){
640 var callArgs = args || arguments;
641 if(appendArgs === true){
642 callArgs = Array.prototype.slice.call(arguments, 0);
643 callArgs = callArgs.concat(args);
644 }else if(typeof appendArgs == "number"){
645 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
646 var applyArgs = [appendArgs, 0].concat(args); // create method call params
647 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
649 return method.apply(obj || window, callArgs);
654 * Calls this function after the number of millseconds specified.
655 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
656 * @param {Object} obj (optional) The object for which the scope is set
657 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
658 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
659 * if a number the args are inserted at the specified position
660 * @return {Number} The timeout id that can be used with clearTimeout
662 defer : function(millis, obj, args, appendArgs){
663 var fn = this.createDelegate(obj, args, appendArgs);
665 return setTimeout(fn, millis);
671 * Create a combined function call sequence of the original function + the passed function.
672 * The resulting function returns the results of the original function.
673 * The passed fcn is called with the parameters of the original function
674 * @param {Function} fcn The function to sequence
675 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
676 * @return {Function} The new function
678 createSequence : function(fcn, scope){
679 if(typeof fcn != "function"){
684 var retval = method.apply(this || window, arguments);
685 fcn.apply(scope || this || window, arguments);
691 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
692 * The resulting function returns the results of the original function.
693 * The passed fcn is called with the parameters of the original function.
695 * @param {Function} fcn The function to call before the original
696 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
697 * @return {Function} The new function
699 createInterceptor : function(fcn, scope){
700 if(typeof fcn != "function"){
707 if(fcn.apply(scope || this || window, arguments) === false){
710 return method.apply(this || window, arguments);
716 * Ext JS Library 1.1.1
717 * Copyright(c) 2006-2007, Ext JS, LLC.
719 * Originally Released Under LGPL - original licence link has changed is not relivant.
722 * <script type="text/javascript">
725 Roo.applyIf(String, {
730 * Escapes the passed string for ' and \
731 * @param {String} string The string to escape
732 * @return {String} The escaped string
735 escape : function(string) {
736 return string.replace(/('|\\)/g, "\\$1");
740 * Pads the left side of a string with a specified character. This is especially useful
741 * for normalizing number and date strings. Example usage:
743 var s = String.leftPad('123', 5, '0');
744 // s now contains the string: '00123'
746 * @param {String} string The original string
747 * @param {Number} size The total length of the output string
748 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
749 * @return {String} The padded string
752 leftPad : function (val, size, ch) {
753 var result = new String(val);
754 if(ch === null || ch === undefined || ch === '') {
757 while (result.length < size) {
758 result = ch + result;
764 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
765 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
767 var cls = 'my-class', text = 'Some text';
768 var s = String.format('<div class="{0}">{1}</div>', cls, text);
769 // s now contains the string: '<div class="my-class">Some text</div>'
771 * @param {String} string The tokenized string to be formatted
772 * @param {String} value1 The value to replace token {0}
773 * @param {String} value2 Etc...
774 * @return {String} The formatted string
777 format : function(format){
778 var args = Array.prototype.slice.call(arguments, 1);
779 return format.replace(/\{(\d+)\}/g, function(m, i){
780 return Roo.util.Format.htmlEncode(args[i]);
786 * Utility function that allows you to easily switch a string between two alternating values. The passed value
787 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
788 * they are already different, the first value passed in is returned. Note that this method returns the new value
789 * but does not change the current string.
791 // alternate sort directions
792 sort = sort.toggle('ASC', 'DESC');
794 // instead of conditional logic:
795 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
797 * @param {String} value The value to compare to the current string
798 * @param {String} other The new value to use if the string already equals the first value passed in
799 * @return {String} The new value
802 String.prototype.toggle = function(value, other){
803 return this == value ? other : value;
806 * Ext JS Library 1.1.1
807 * Copyright(c) 2006-2007, Ext JS, LLC.
809 * Originally Released Under LGPL - original licence link has changed is not relivant.
812 * <script type="text/javascript">
818 Roo.applyIf(Number.prototype, {
820 * Checks whether or not the current number is within a desired range. If the number is already within the
821 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
822 * exceeded. Note that this method returns the constrained value but does not change the current number.
823 * @param {Number} min The minimum number in the range
824 * @param {Number} max The maximum number in the range
825 * @return {Number} The constrained value if outside the range, otherwise the current value
827 constrain : function(min, max){
828 return Math.min(Math.max(this, min), max);
832 * Ext JS Library 1.1.1
833 * Copyright(c) 2006-2007, Ext JS, LLC.
835 * Originally Released Under LGPL - original licence link has changed is not relivant.
838 * <script type="text/javascript">
843 Roo.applyIf(Array.prototype, {
845 * Checks whether or not the specified object exists in the array.
846 * @param {Object} o The object to check for
847 * @return {Number} The index of o in the array (or -1 if it is not found)
849 indexOf : function(o){
850 for (var i = 0, len = this.length; i < len; i++){
851 if(this[i] == o) return i;
857 * Removes the specified object from the array. If the object is not found nothing happens.
858 * @param {Object} o The object to remove
860 remove : function(o){
861 var index = this.indexOf(o);
863 this.splice(index, 1);
867 * Map (JS 1.6 compatibility)
868 * @param {Function} function to call
872 var len = this.length >>> 0;
873 if (typeof fun != "function")
874 throw new TypeError();
876 var res = new Array(len);
877 var thisp = arguments[1];
878 for (var i = 0; i < len; i++)
881 res[i] = fun.call(thisp, this[i], i, this);
892 * Ext JS Library 1.1.1
893 * Copyright(c) 2006-2007, Ext JS, LLC.
895 * Originally Released Under LGPL - original licence link has changed is not relivant.
898 * <script type="text/javascript">
904 * The date parsing and format syntax is a subset of
905 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
906 * supported will provide results equivalent to their PHP versions.
908 * Following is the list of all currently supported formats:
911 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
913 Format Output Description
914 ------ ---------- --------------------------------------------------------------
915 d 10 Day of the month, 2 digits with leading zeros
916 D Wed A textual representation of a day, three letters
917 j 10 Day of the month without leading zeros
918 l Wednesday A full textual representation of the day of the week
919 S th English ordinal day of month suffix, 2 chars (use with j)
920 w 3 Numeric representation of the day of the week
921 z 9 The julian date, or day of the year (0-365)
922 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
923 F January A full textual representation of the month
924 m 01 Numeric representation of a month, with leading zeros
925 M Jan Month name abbreviation, three letters
926 n 1 Numeric representation of a month, without leading zeros
927 t 31 Number of days in the given month
928 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
929 Y 2007 A full numeric representation of a year, 4 digits
930 y 07 A two digit representation of a year
931 a pm Lowercase Ante meridiem and Post meridiem
932 A PM Uppercase Ante meridiem and Post meridiem
933 g 3 12-hour format of an hour without leading zeros
934 G 15 24-hour format of an hour without leading zeros
935 h 03 12-hour format of an hour with leading zeros
936 H 15 24-hour format of an hour with leading zeros
937 i 05 Minutes with leading zeros
938 s 01 Seconds, with leading zeros
939 O -0600 Difference to Greenwich time (GMT) in hours
940 T CST Timezone setting of the machine running the code
941 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
944 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
946 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
947 document.write(dt.format('Y-m-d')); //2007-01-10
948 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
949 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
952 * Here are some standard date/time patterns that you might find helpful. They
953 * are not part of the source of Date.js, but to use them you can simply copy this
954 * block of code into any script that is included after Date.js and they will also become
955 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
958 ISO8601Long:"Y-m-d H:i:s",
959 ISO8601Short:"Y-m-d",
961 LongDate: "l, F d, Y",
962 FullDateTime: "l, F d, Y g:i:s A",
966 SortableDateTime: "Y-m-d\\TH:i:s",
967 UniversalSortableDateTime: "Y-m-d H:i:sO",
975 document.write(dt.format(Date.patterns.ShortDate));
980 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
981 * They generate precompiled functions from date formats instead of parsing and
982 * processing the pattern every time you format a date. These functions are available
983 * on every Date object (any javascript function).
985 * The original article and download are here:
986 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
993 Returns the number of milliseconds between this date and date
994 @param {Date} date (optional) Defaults to now
995 @return {Number} The diff in milliseconds
996 @member Date getElapsed
998 Date.prototype.getElapsed = function(date) {
999 return Math.abs((date || new Date()).getTime()-this.getTime());
1001 // was in date file..
1005 Date.parseFunctions = {count:0};
1007 Date.parseRegexes = [];
1009 Date.formatFunctions = {count:0};
1012 Date.prototype.dateFormat = function(format) {
1013 if (Date.formatFunctions[format] == null) {
1014 Date.createNewFormat(format);
1016 var func = Date.formatFunctions[format];
1017 return this[func]();
1022 * Formats a date given the supplied format string
1023 * @param {String} format The format string
1024 * @return {String} The formatted date
1027 Date.prototype.format = Date.prototype.dateFormat;
1030 Date.createNewFormat = function(format) {
1031 var funcName = "format" + Date.formatFunctions.count++;
1032 Date.formatFunctions[format] = funcName;
1033 var code = "Date.prototype." + funcName + " = function(){return ";
1034 var special = false;
1036 for (var i = 0; i < format.length; ++i) {
1037 ch = format.charAt(i);
1038 if (!special && ch == "\\") {
1043 code += "'" + String.escape(ch) + "' + ";
1046 code += Date.getFormatCode(ch);
1049 /** eval:var:zzzzzzzzzzzzz */
1050 eval(code.substring(0, code.length - 3) + ";}");
1054 Date.getFormatCode = function(character) {
1055 switch (character) {
1057 return "String.leftPad(this.getDate(), 2, '0') + ";
1059 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1061 return "this.getDate() + ";
1063 return "Date.dayNames[this.getDay()] + ";
1065 return "this.getSuffix() + ";
1067 return "this.getDay() + ";
1069 return "this.getDayOfYear() + ";
1071 return "this.getWeekOfYear() + ";
1073 return "Date.monthNames[this.getMonth()] + ";
1075 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1077 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1079 return "(this.getMonth() + 1) + ";
1081 return "this.getDaysInMonth() + ";
1083 return "(this.isLeapYear() ? 1 : 0) + ";
1085 return "this.getFullYear() + ";
1087 return "('' + this.getFullYear()).substring(2, 4) + ";
1089 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1091 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1093 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1095 return "this.getHours() + ";
1097 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1099 return "String.leftPad(this.getHours(), 2, '0') + ";
1101 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1103 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1105 return "this.getGMTOffset() + ";
1107 return "this.getTimezone() + ";
1109 return "(this.getTimezoneOffset() * -60) + ";
1111 return "'" + String.escape(character) + "' + ";
1116 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1117 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1118 * the date format that is not specified will default to the current date value for that part. Time parts can also
1119 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1120 * string or the parse operation will fail.
1123 //dt = Fri May 25 2007 (current date)
1124 var dt = new Date();
1126 //dt = Thu May 25 2006 (today's month/day in 2006)
1127 dt = Date.parseDate("2006", "Y");
1129 //dt = Sun Jan 15 2006 (all date parts specified)
1130 dt = Date.parseDate("2006-1-15", "Y-m-d");
1132 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1133 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1135 * @param {String} input The unparsed date as a string
1136 * @param {String} format The format the date is in
1137 * @return {Date} The parsed date
1140 Date.parseDate = function(input, format) {
1141 if (Date.parseFunctions[format] == null) {
1142 Date.createParser(format);
1144 var func = Date.parseFunctions[format];
1145 return Date[func](input);
1150 Date.createParser = function(format) {
1151 var funcName = "parse" + Date.parseFunctions.count++;
1152 var regexNum = Date.parseRegexes.length;
1153 var currentGroup = 1;
1154 Date.parseFunctions[format] = funcName;
1156 var code = "Date." + funcName + " = function(input){\n"
1157 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1158 + "var d = new Date();\n"
1159 + "y = d.getFullYear();\n"
1160 + "m = d.getMonth();\n"
1161 + "d = d.getDate();\n"
1162 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1163 + "if (results && results.length > 0) {";
1166 var special = false;
1168 for (var i = 0; i < format.length; ++i) {
1169 ch = format.charAt(i);
1170 if (!special && ch == "\\") {
1175 regex += String.escape(ch);
1178 var obj = Date.formatCodeToRegex(ch, currentGroup);
1179 currentGroup += obj.g;
1181 if (obj.g && obj.c) {
1187 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1188 + "{v = new Date(y, m, d, h, i, s);}\n"
1189 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1190 + "{v = new Date(y, m, d, h, i);}\n"
1191 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1192 + "{v = new Date(y, m, d, h);}\n"
1193 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1194 + "{v = new Date(y, m, d);}\n"
1195 + "else if (y >= 0 && m >= 0)\n"
1196 + "{v = new Date(y, m);}\n"
1197 + "else if (y >= 0)\n"
1198 + "{v = new Date(y);}\n"
1199 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1200 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1201 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1204 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1205 /** eval:var:zzzzzzzzzzzzz */
1210 Date.formatCodeToRegex = function(character, currentGroup) {
1211 switch (character) {
1215 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1218 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1219 s:"(\\d{1,2})"}; // day of month without leading zeroes
1222 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1223 s:"(\\d{2})"}; // day of month with leading zeroes
1227 s:"(?:" + Date.dayNames.join("|") + ")"};
1231 s:"(?:st|nd|rd|th)"};
1246 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1247 s:"(" + Date.monthNames.join("|") + ")"};
1250 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1251 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1254 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1255 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1258 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1259 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1270 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1274 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1275 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1279 c:"if (results[" + currentGroup + "] == 'am') {\n"
1280 + "if (h == 12) { h = 0; }\n"
1281 + "} else { if (h < 12) { h += 12; }}",
1285 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1286 + "if (h == 12) { h = 0; }\n"
1287 + "} else { if (h < 12) { h += 12; }}",
1292 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1293 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1297 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1298 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1301 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1305 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1310 "o = results[", currentGroup, "];\n",
1311 "var sn = o.substring(0,1);\n", // get + / - sign
1312 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1313 "var mn = o.substring(3,5) % 60;\n", // get minutes
1314 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1315 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1321 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1324 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1325 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1326 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1330 s:String.escape(character)};
1335 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1336 * @return {String} The abbreviated timezone name (e.g. 'CST')
1338 Date.prototype.getTimezone = function() {
1339 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1343 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1344 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1346 Date.prototype.getGMTOffset = function() {
1347 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1348 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1349 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1353 * Get the numeric day number of the year, adjusted for leap year.
1354 * @return {Number} 0 through 364 (365 in leap years)
1356 Date.prototype.getDayOfYear = function() {
1358 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1359 for (var i = 0; i < this.getMonth(); ++i) {
1360 num += Date.daysInMonth[i];
1362 return num + this.getDate() - 1;
1366 * Get the string representation of the numeric week number of the year
1367 * (equivalent to the format specifier 'W').
1368 * @return {String} '00' through '52'
1370 Date.prototype.getWeekOfYear = function() {
1371 // Skip to Thursday of this week
1372 var now = this.getDayOfYear() + (4 - this.getDay());
1373 // Find the first Thursday of the year
1374 var jan1 = new Date(this.getFullYear(), 0, 1);
1375 var then = (7 - jan1.getDay() + 4);
1376 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1380 * Whether or not the current date is in a leap year.
1381 * @return {Boolean} True if the current date is in a leap year, else false
1383 Date.prototype.isLeapYear = function() {
1384 var year = this.getFullYear();
1385 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1389 * Get the first day of the current month, adjusted for leap year. The returned value
1390 * is the numeric day index within the week (0-6) which can be used in conjunction with
1391 * the {@link #monthNames} array to retrieve the textual day name.
1394 var dt = new Date('1/10/2007');
1395 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1397 * @return {Number} The day number (0-6)
1399 Date.prototype.getFirstDayOfMonth = function() {
1400 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1401 return (day < 0) ? (day + 7) : day;
1405 * Get the last day of the current month, adjusted for leap year. The returned value
1406 * is the numeric day index within the week (0-6) which can be used in conjunction with
1407 * the {@link #monthNames} array to retrieve the textual day name.
1410 var dt = new Date('1/10/2007');
1411 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1413 * @return {Number} The day number (0-6)
1415 Date.prototype.getLastDayOfMonth = function() {
1416 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1417 return (day < 0) ? (day + 7) : day;
1422 * Get the first date of this date's month
1425 Date.prototype.getFirstDateOfMonth = function() {
1426 return new Date(this.getFullYear(), this.getMonth(), 1);
1430 * Get the last date of this date's month
1433 Date.prototype.getLastDateOfMonth = function() {
1434 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1437 * Get the number of days in the current month, adjusted for leap year.
1438 * @return {Number} The number of days in the month
1440 Date.prototype.getDaysInMonth = function() {
1441 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1442 return Date.daysInMonth[this.getMonth()];
1446 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1447 * @return {String} 'st, 'nd', 'rd' or 'th'
1449 Date.prototype.getSuffix = function() {
1450 switch (this.getDate()) {
1467 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1470 * An array of textual month names.
1471 * Override these values for international dates, for example...
1472 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1491 * An array of textual day names.
1492 * Override these values for international dates, for example...
1493 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1509 Date.monthNumbers = {
1524 * Creates and returns a new Date instance with the exact same date value as the called instance.
1525 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1526 * variable will also be changed. When the intention is to create a new variable that will not
1527 * modify the original instance, you should create a clone.
1529 * Example of correctly cloning a date:
1532 var orig = new Date('10/1/2006');
1535 document.write(orig); //returns 'Thu Oct 05 2006'!
1538 var orig = new Date('10/1/2006');
1539 var copy = orig.clone();
1541 document.write(orig); //returns 'Thu Oct 01 2006'
1543 * @return {Date} The new Date instance
1545 Date.prototype.clone = function() {
1546 return new Date(this.getTime());
1550 * Clears any time information from this date
1551 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1552 @return {Date} this or the clone
1554 Date.prototype.clearTime = function(clone){
1556 return this.clone().clearTime();
1561 this.setMilliseconds(0);
1566 // safari setMonth is broken
1568 Date.brokenSetMonth = Date.prototype.setMonth;
1569 Date.prototype.setMonth = function(num){
1571 var n = Math.ceil(-num);
1572 var back_year = Math.ceil(n/12);
1573 var month = (n % 12) ? 12 - n % 12 : 0 ;
1574 this.setFullYear(this.getFullYear() - back_year);
1575 return Date.brokenSetMonth.call(this, month);
1577 return Date.brokenSetMonth.apply(this, arguments);
1582 /** Date interval constant
1586 /** Date interval constant
1590 /** Date interval constant
1594 /** Date interval constant
1598 /** Date interval constant
1602 /** Date interval constant
1606 /** Date interval constant
1612 * Provides a convenient method of performing basic date arithmetic. This method
1613 * does not modify the Date instance being called - it creates and returns
1614 * a new Date instance containing the resulting date value.
1619 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1620 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1622 //Negative values will subtract correctly:
1623 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1624 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1626 //You can even chain several calls together in one line!
1627 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1628 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1631 * @param {String} interval A valid date interval enum value
1632 * @param {Number} value The amount to add to the current date
1633 * @return {Date} The new Date instance
1635 Date.prototype.add = function(interval, value){
1636 var d = this.clone();
1637 if (!interval || value === 0) return d;
1638 switch(interval.toLowerCase()){
1640 d.setMilliseconds(this.getMilliseconds() + value);
1643 d.setSeconds(this.getSeconds() + value);
1646 d.setMinutes(this.getMinutes() + value);
1649 d.setHours(this.getHours() + value);
1652 d.setDate(this.getDate() + value);
1655 var day = this.getDate();
1657 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1660 d.setMonth(this.getMonth() + value);
1663 d.setFullYear(this.getFullYear() + value);
1669 * Ext JS Library 1.1.1
1670 * Copyright(c) 2006-2007, Ext JS, LLC.
1672 * Originally Released Under LGPL - original licence link has changed is not relivant.
1675 * <script type="text/javascript">
1679 getViewWidth : function(full) {
1680 return full ? this.getDocumentWidth() : this.getViewportWidth();
1683 getViewHeight : function(full) {
1684 return full ? this.getDocumentHeight() : this.getViewportHeight();
1687 getDocumentHeight: function() {
1688 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1689 return Math.max(scrollHeight, this.getViewportHeight());
1692 getDocumentWidth: function() {
1693 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1694 return Math.max(scrollWidth, this.getViewportWidth());
1697 getViewportHeight: function() {
1698 var height = self.innerHeight;
1699 var mode = document.compatMode;
1701 if ((mode || Roo.isIE) && !Roo.isOpera) {
1702 height = (mode == "CSS1Compat") ?
1703 document.documentElement.clientHeight :
1704 document.body.clientHeight;
1710 getViewportWidth: function() {
1711 var width = self.innerWidth;
1712 var mode = document.compatMode;
1714 if (mode || Roo.isIE) {
1715 width = (mode == "CSS1Compat") ?
1716 document.documentElement.clientWidth :
1717 document.body.clientWidth;
1722 isAncestor : function(p, c) {
1729 if (p.contains && !Roo.isSafari) {
1730 return p.contains(c);
1731 } else if (p.compareDocumentPosition) {
1732 return !!(p.compareDocumentPosition(c) & 16);
1734 var parent = c.parentNode;
1739 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1742 parent = parent.parentNode;
1748 getRegion : function(el) {
1749 return Roo.lib.Region.getRegion(el);
1752 getY : function(el) {
1753 return this.getXY(el)[1];
1756 getX : function(el) {
1757 return this.getXY(el)[0];
1760 getXY : function(el) {
1761 var p, pe, b, scroll, bd = document.body;
1762 el = Roo.getDom(el);
1763 var fly = Roo.lib.AnimBase.fly;
1764 if (el.getBoundingClientRect) {
1765 b = el.getBoundingClientRect();
1766 scroll = fly(document).getScroll();
1767 return [b.left + scroll.left, b.top + scroll.top];
1773 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1780 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1787 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1788 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1795 if (p != el && pe.getStyle('overflow') != 'visible') {
1803 if (Roo.isSafari && hasAbsolute) {
1808 if (Roo.isGecko && !hasAbsolute) {
1810 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1811 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1815 while (p && p != bd) {
1816 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1828 setXY : function(el, xy) {
1829 el = Roo.fly(el, '_setXY');
1831 var pts = el.translatePoints(xy);
1832 if (xy[0] !== false) {
1833 el.dom.style.left = pts.left + "px";
1835 if (xy[1] !== false) {
1836 el.dom.style.top = pts.top + "px";
1840 setX : function(el, x) {
1841 this.setXY(el, [x, false]);
1844 setY : function(el, y) {
1845 this.setXY(el, [false, y]);
1849 * Portions of this file are based on pieces of Yahoo User Interface Library
1850 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1851 * YUI licensed under the BSD License:
1852 * http://developer.yahoo.net/yui/license.txt
1853 * <script type="text/javascript">
1857 Roo.lib.Event = function() {
1858 var loadComplete = false;
1860 var unloadListeners = [];
1862 var onAvailStack = [];
1864 var lastError = null;
1877 startInterval: function() {
1878 if (!this._interval) {
1880 var callback = function() {
1881 self._tryPreloadAttach();
1883 this._interval = setInterval(callback, this.POLL_INTERVAL);
1888 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1889 onAvailStack.push({ id: p_id,
1892 override: p_override,
1893 checkReady: false });
1895 retryCount = this.POLL_RETRYS;
1896 this.startInterval();
1900 addListener: function(el, eventName, fn) {
1901 el = Roo.getDom(el);
1906 if ("unload" == eventName) {
1907 unloadListeners[unloadListeners.length] =
1908 [el, eventName, fn];
1912 var wrappedFn = function(e) {
1913 return fn(Roo.lib.Event.getEvent(e));
1916 var li = [el, eventName, fn, wrappedFn];
1918 var index = listeners.length;
1919 listeners[index] = li;
1921 this.doAdd(el, eventName, wrappedFn, false);
1927 removeListener: function(el, eventName, fn) {
1930 el = Roo.getDom(el);
1933 return this.purgeElement(el, false, eventName);
1937 if ("unload" == eventName) {
1939 for (i = 0,len = unloadListeners.length; i < len; i++) {
1940 var li = unloadListeners[i];
1943 li[1] == eventName &&
1945 unloadListeners.splice(i, 1);
1953 var cacheItem = null;
1956 var index = arguments[3];
1958 if ("undefined" == typeof index) {
1959 index = this._getCacheIndex(el, eventName, fn);
1963 cacheItem = listeners[index];
1966 if (!el || !cacheItem) {
1970 this.doRemove(el, eventName, cacheItem[this.WFN], false);
1972 delete listeners[index][this.WFN];
1973 delete listeners[index][this.FN];
1974 listeners.splice(index, 1);
1981 getTarget: function(ev, resolveTextNode) {
1982 ev = ev.browserEvent || ev;
1983 var t = ev.target || ev.srcElement;
1984 return this.resolveTextNode(t);
1988 resolveTextNode: function(node) {
1989 if (Roo.isSafari && node && 3 == node.nodeType) {
1990 return node.parentNode;
1997 getPageX: function(ev) {
1998 ev = ev.browserEvent || ev;
2000 if (!x && 0 !== x) {
2001 x = ev.clientX || 0;
2004 x += this.getScroll()[1];
2012 getPageY: function(ev) {
2013 ev = ev.browserEvent || ev;
2015 if (!y && 0 !== y) {
2016 y = ev.clientY || 0;
2019 y += this.getScroll()[0];
2028 getXY: function(ev) {
2029 ev = ev.browserEvent || ev;
2030 return [this.getPageX(ev), this.getPageY(ev)];
2034 getRelatedTarget: function(ev) {
2035 ev = ev.browserEvent || ev;
2036 var t = ev.relatedTarget;
2038 if (ev.type == "mouseout") {
2040 } else if (ev.type == "mouseover") {
2045 return this.resolveTextNode(t);
2049 getTime: function(ev) {
2050 ev = ev.browserEvent || ev;
2052 var t = new Date().getTime();
2056 this.lastError = ex;
2065 stopEvent: function(ev) {
2066 this.stopPropagation(ev);
2067 this.preventDefault(ev);
2071 stopPropagation: function(ev) {
2072 ev = ev.browserEvent || ev;
2073 if (ev.stopPropagation) {
2074 ev.stopPropagation();
2076 ev.cancelBubble = true;
2081 preventDefault: function(ev) {
2082 ev = ev.browserEvent || ev;
2083 if(ev.preventDefault) {
2084 ev.preventDefault();
2086 ev.returnValue = false;
2091 getEvent: function(e) {
2092 var ev = e || window.event;
2094 var c = this.getEvent.caller;
2096 ev = c.arguments[0];
2097 if (ev && Event == ev.constructor) {
2107 getCharCode: function(ev) {
2108 ev = ev.browserEvent || ev;
2109 return ev.charCode || ev.keyCode || 0;
2113 _getCacheIndex: function(el, eventName, fn) {
2114 for (var i = 0,len = listeners.length; i < len; ++i) {
2115 var li = listeners[i];
2117 li[this.FN] == fn &&
2118 li[this.EL] == el &&
2119 li[this.TYPE] == eventName) {
2131 getEl: function(id) {
2132 return document.getElementById(id);
2136 clearCache: function() {
2140 _load: function(e) {
2141 loadComplete = true;
2142 var EU = Roo.lib.Event;
2146 EU.doRemove(window, "load", EU._load);
2151 _tryPreloadAttach: function() {
2160 var tryAgain = !loadComplete;
2162 tryAgain = (retryCount > 0);
2167 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2168 var item = onAvailStack[i];
2170 var el = this.getEl(item.id);
2173 if (!item.checkReady ||
2176 (document && document.body)) {
2179 if (item.override) {
2180 if (item.override === true) {
2183 scope = item.override;
2186 item.fn.call(scope, item.obj);
2187 onAvailStack[i] = null;
2190 notAvail.push(item);
2195 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2199 this.startInterval();
2201 clearInterval(this._interval);
2202 this._interval = null;
2205 this.locked = false;
2212 purgeElement: function(el, recurse, eventName) {
2213 var elListeners = this.getListeners(el, eventName);
2215 for (var i = 0,len = elListeners.length; i < len; ++i) {
2216 var l = elListeners[i];
2217 this.removeListener(el, l.type, l.fn);
2221 if (recurse && el && el.childNodes) {
2222 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2223 this.purgeElement(el.childNodes[i], recurse, eventName);
2229 getListeners: function(el, eventName) {
2230 var results = [], searchLists;
2232 searchLists = [listeners, unloadListeners];
2233 } else if (eventName == "unload") {
2234 searchLists = [unloadListeners];
2236 searchLists = [listeners];
2239 for (var j = 0; j < searchLists.length; ++j) {
2240 var searchList = searchLists[j];
2241 if (searchList && searchList.length > 0) {
2242 for (var i = 0,len = searchList.length; i < len; ++i) {
2243 var l = searchList[i];
2244 if (l && l[this.EL] === el &&
2245 (!eventName || eventName === l[this.TYPE])) {
2250 adjust: l[this.ADJ_SCOPE],
2258 return (results.length) ? results : null;
2262 _unload: function(e) {
2264 var EU = Roo.lib.Event, i, j, l, len, index;
2266 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2267 l = unloadListeners[i];
2270 if (l[EU.ADJ_SCOPE]) {
2271 if (l[EU.ADJ_SCOPE] === true) {
2274 scope = l[EU.ADJ_SCOPE];
2277 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2278 unloadListeners[i] = null;
2284 unloadListeners = null;
2286 if (listeners && listeners.length > 0) {
2287 j = listeners.length;
2290 l = listeners[index];
2292 EU.removeListener(l[EU.EL], l[EU.TYPE],
2302 EU.doRemove(window, "unload", EU._unload);
2307 getScroll: function() {
2308 var dd = document.documentElement, db = document.body;
2309 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2310 return [dd.scrollTop, dd.scrollLeft];
2312 return [db.scrollTop, db.scrollLeft];
2319 doAdd: function () {
2320 if (window.addEventListener) {
2321 return function(el, eventName, fn, capture) {
2322 el.addEventListener(eventName, fn, (capture));
2324 } else if (window.attachEvent) {
2325 return function(el, eventName, fn, capture) {
2326 el.attachEvent("on" + eventName, fn);
2335 doRemove: function() {
2336 if (window.removeEventListener) {
2337 return function (el, eventName, fn, capture) {
2338 el.removeEventListener(eventName, fn, (capture));
2340 } else if (window.detachEvent) {
2341 return function (el, eventName, fn) {
2342 el.detachEvent("on" + eventName, fn);
2354 var E = Roo.lib.Event;
2355 E.on = E.addListener;
2356 E.un = E.removeListener;
2358 if (document && document.body) {
2361 E.doAdd(window, "load", E._load);
2363 E.doAdd(window, "unload", E._unload);
2364 E._tryPreloadAttach();
2368 * Portions of this file are based on pieces of Yahoo User Interface Library
2369 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2370 * YUI licensed under the BSD License:
2371 * http://developer.yahoo.net/yui/license.txt
2372 * <script type="text/javascript">
2379 request : function(method, uri, cb, data, options) {
2381 var hs = options.headers;
2384 if(hs.hasOwnProperty(h)){
2385 this.initHeader(h, hs[h], false);
2389 if(options.xmlData){
2390 this.initHeader('Content-Type', 'text/xml', false);
2392 data = options.xmlData;
2396 return this.asyncRequest(method, uri, cb, data);
2399 serializeForm : function(form) {
2400 if(typeof form == 'string') {
2401 form = (document.getElementById(form) || document.forms[form]);
2404 var el, name, val, disabled, data = '', hasSubmit = false;
2405 for (var i = 0; i < form.elements.length; i++) {
2406 el = form.elements[i];
2407 disabled = form.elements[i].disabled;
2408 name = form.elements[i].name;
2409 val = form.elements[i].value;
2411 if (!disabled && name){
2415 case 'select-multiple':
2416 for (var j = 0; j < el.options.length; j++) {
2417 if (el.options[j].selected) {
2419 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2422 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2430 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2443 if(hasSubmit == false) {
2444 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2449 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2454 data = data.substr(0, data.length - 1);
2462 useDefaultHeader:true,
2464 defaultPostHeader:'application/x-www-form-urlencoded',
2466 useDefaultXhrHeader:true,
2468 defaultXhrHeader:'XMLHttpRequest',
2470 hasDefaultHeaders:true,
2482 setProgId:function(id)
2484 this.activeX.unshift(id);
2487 setDefaultPostHeader:function(b)
2489 this.useDefaultHeader = b;
2492 setDefaultXhrHeader:function(b)
2494 this.useDefaultXhrHeader = b;
2497 setPollingInterval:function(i)
2499 if (typeof i == 'number' && isFinite(i)) {
2500 this.pollInterval = i;
2504 createXhrObject:function(transactionId)
2510 http = new XMLHttpRequest();
2512 obj = { conn:http, tId:transactionId };
2516 for (var i = 0; i < this.activeX.length; ++i) {
2520 http = new ActiveXObject(this.activeX[i]);
2522 obj = { conn:http, tId:transactionId };
2535 getConnectionObject:function()
2538 var tId = this.transactionId;
2542 o = this.createXhrObject(tId);
2544 this.transactionId++;
2555 asyncRequest:function(method, uri, callback, postData)
2557 var o = this.getConnectionObject();
2563 o.conn.open(method, uri, true);
2565 if (this.useDefaultXhrHeader) {
2566 if (!this.defaultHeaders['X-Requested-With']) {
2567 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2571 if(postData && this.useDefaultHeader){
2572 this.initHeader('Content-Type', this.defaultPostHeader);
2575 if (this.hasDefaultHeaders || this.hasHeaders) {
2579 this.handleReadyState(o, callback);
2580 o.conn.send(postData || null);
2586 handleReadyState:function(o, callback)
2590 if (callback && callback.timeout) {
2591 this.timeout[o.tId] = window.setTimeout(function() {
2592 oConn.abort(o, callback, true);
2593 }, callback.timeout);
2596 this.poll[o.tId] = window.setInterval(
2598 if (o.conn && o.conn.readyState == 4) {
2599 window.clearInterval(oConn.poll[o.tId]);
2600 delete oConn.poll[o.tId];
2602 if(callback && callback.timeout) {
2603 window.clearTimeout(oConn.timeout[o.tId]);
2604 delete oConn.timeout[o.tId];
2607 oConn.handleTransactionResponse(o, callback);
2610 , this.pollInterval);
2613 handleTransactionResponse:function(o, callback, isAbort)
2617 this.releaseObject(o);
2621 var httpStatus, responseObject;
2625 if (o.conn.status !== undefined && o.conn.status != 0) {
2626 httpStatus = o.conn.status;
2638 if (httpStatus >= 200 && httpStatus < 300) {
2639 responseObject = this.createResponseObject(o, callback.argument);
2640 if (callback.success) {
2641 if (!callback.scope) {
2642 callback.success(responseObject);
2647 callback.success.apply(callback.scope, [responseObject]);
2652 switch (httpStatus) {
2660 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2661 if (callback.failure) {
2662 if (!callback.scope) {
2663 callback.failure(responseObject);
2666 callback.failure.apply(callback.scope, [responseObject]);
2671 responseObject = this.createResponseObject(o, callback.argument);
2672 if (callback.failure) {
2673 if (!callback.scope) {
2674 callback.failure(responseObject);
2677 callback.failure.apply(callback.scope, [responseObject]);
2683 this.releaseObject(o);
2684 responseObject = null;
2687 createResponseObject:function(o, callbackArg)
2694 var headerStr = o.conn.getAllResponseHeaders();
2695 var header = headerStr.split('\n');
2696 for (var i = 0; i < header.length; i++) {
2697 var delimitPos = header[i].indexOf(':');
2698 if (delimitPos != -1) {
2699 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2707 obj.status = o.conn.status;
2708 obj.statusText = o.conn.statusText;
2709 obj.getResponseHeader = headerObj;
2710 obj.getAllResponseHeaders = headerStr;
2711 obj.responseText = o.conn.responseText;
2712 obj.responseXML = o.conn.responseXML;
2714 if (typeof callbackArg !== undefined) {
2715 obj.argument = callbackArg;
2721 createExceptionObject:function(tId, callbackArg, isAbort)
2724 var COMM_ERROR = 'communication failure';
2725 var ABORT_CODE = -1;
2726 var ABORT_ERROR = 'transaction aborted';
2732 obj.status = ABORT_CODE;
2733 obj.statusText = ABORT_ERROR;
2736 obj.status = COMM_CODE;
2737 obj.statusText = COMM_ERROR;
2741 obj.argument = callbackArg;
2747 initHeader:function(label, value, isDefault)
2749 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2751 if (headerObj[label] === undefined) {
2752 headerObj[label] = value;
2757 headerObj[label] = value + "," + headerObj[label];
2761 this.hasDefaultHeaders = true;
2764 this.hasHeaders = true;
2769 setHeader:function(o)
2771 if (this.hasDefaultHeaders) {
2772 for (var prop in this.defaultHeaders) {
2773 if (this.defaultHeaders.hasOwnProperty(prop)) {
2774 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2779 if (this.hasHeaders) {
2780 for (var prop in this.headers) {
2781 if (this.headers.hasOwnProperty(prop)) {
2782 o.conn.setRequestHeader(prop, this.headers[prop]);
2786 this.hasHeaders = false;
2790 resetDefaultHeaders:function() {
2791 delete this.defaultHeaders;
2792 this.defaultHeaders = {};
2793 this.hasDefaultHeaders = false;
2796 abort:function(o, callback, isTimeout)
2798 if(this.isCallInProgress(o)) {
2800 window.clearInterval(this.poll[o.tId]);
2801 delete this.poll[o.tId];
2803 delete this.timeout[o.tId];
2806 this.handleTransactionResponse(o, callback, true);
2816 isCallInProgress:function(o)
2819 return o.conn.readyState != 4 && o.conn.readyState != 0;
2828 releaseObject:function(o)
2837 'MSXML2.XMLHTTP.3.0',
2845 * Portions of this file are based on pieces of Yahoo User Interface Library
2846 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2847 * YUI licensed under the BSD License:
2848 * http://developer.yahoo.net/yui/license.txt
2849 * <script type="text/javascript">
2853 Roo.lib.Region = function(t, r, b, l) {
2863 Roo.lib.Region.prototype = {
2864 contains : function(region) {
2865 return ( region.left >= this.left &&
2866 region.right <= this.right &&
2867 region.top >= this.top &&
2868 region.bottom <= this.bottom );
2872 getArea : function() {
2873 return ( (this.bottom - this.top) * (this.right - this.left) );
2876 intersect : function(region) {
2877 var t = Math.max(this.top, region.top);
2878 var r = Math.min(this.right, region.right);
2879 var b = Math.min(this.bottom, region.bottom);
2880 var l = Math.max(this.left, region.left);
2882 if (b >= t && r >= l) {
2883 return new Roo.lib.Region(t, r, b, l);
2888 union : function(region) {
2889 var t = Math.min(this.top, region.top);
2890 var r = Math.max(this.right, region.right);
2891 var b = Math.max(this.bottom, region.bottom);
2892 var l = Math.min(this.left, region.left);
2894 return new Roo.lib.Region(t, r, b, l);
2897 adjust : function(t, l, b, r) {
2906 Roo.lib.Region.getRegion = function(el) {
2907 var p = Roo.lib.Dom.getXY(el);
2910 var r = p[0] + el.offsetWidth;
2911 var b = p[1] + el.offsetHeight;
2914 return new Roo.lib.Region(t, r, b, l);
2917 * Portions of this file are based on pieces of Yahoo User Interface Library
2918 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2919 * YUI licensed under the BSD License:
2920 * http://developer.yahoo.net/yui/license.txt
2921 * <script type="text/javascript">
2924 //@@dep Roo.lib.Region
2927 Roo.lib.Point = function(x, y) {
2928 if (x instanceof Array) {
2932 this.x = this.right = this.left = this[0] = x;
2933 this.y = this.top = this.bottom = this[1] = y;
2936 Roo.lib.Point.prototype = new Roo.lib.Region();
2938 * Portions of this file are based on pieces of Yahoo User Interface Library
2939 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2940 * YUI licensed under the BSD License:
2941 * http://developer.yahoo.net/yui/license.txt
2942 * <script type="text/javascript">
2949 scroll : function(el, args, duration, easing, cb, scope) {
2950 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2953 motion : function(el, args, duration, easing, cb, scope) {
2954 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2957 color : function(el, args, duration, easing, cb, scope) {
2958 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2961 run : function(el, args, duration, easing, cb, scope, type) {
2962 type = type || Roo.lib.AnimBase;
2963 if (typeof easing == "string") {
2964 easing = Roo.lib.Easing[easing];
2966 var anim = new type(el, args, duration, easing);
2967 anim.animateX(function() {
2968 Roo.callback(cb, scope);
2974 * Portions of this file are based on pieces of Yahoo User Interface Library
2975 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2976 * YUI licensed under the BSD License:
2977 * http://developer.yahoo.net/yui/license.txt
2978 * <script type="text/javascript">
2986 if (!libFlyweight) {
2987 libFlyweight = new Roo.Element.Flyweight();
2989 libFlyweight.dom = el;
2990 return libFlyweight;
2993 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
2997 Roo.lib.AnimBase = function(el, attributes, duration, method) {
2999 this.init(el, attributes, duration, method);
3003 Roo.lib.AnimBase.fly = fly;
3007 Roo.lib.AnimBase.prototype = {
3009 toString: function() {
3010 var el = this.getEl();
3011 var id = el.id || el.tagName;
3012 return ("Anim " + id);
3016 noNegatives: /width|height|opacity|padding/i,
3017 offsetAttribute: /^((width|height)|(top|left))$/,
3018 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3019 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3023 doMethod: function(attr, start, end) {
3024 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3028 setAttribute: function(attr, val, unit) {
3029 if (this.patterns.noNegatives.test(attr)) {
3030 val = (val > 0) ? val : 0;
3033 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3037 getAttribute: function(attr) {
3038 var el = this.getEl();
3039 var val = fly(el).getStyle(attr);
3041 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3042 return parseFloat(val);
3045 var a = this.patterns.offsetAttribute.exec(attr) || [];
3046 var pos = !!( a[3] );
3047 var box = !!( a[2] );
3050 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3051 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3060 getDefaultUnit: function(attr) {
3061 if (this.patterns.defaultUnit.test(attr)) {
3068 animateX : function(callback, scope) {
3069 var f = function() {
3070 this.onComplete.removeListener(f);
3071 if (typeof callback == "function") {
3072 callback.call(scope || this, this);
3075 this.onComplete.addListener(f, this);
3080 setRuntimeAttribute: function(attr) {
3083 var attributes = this.attributes;
3085 this.runtimeAttributes[attr] = {};
3087 var isset = function(prop) {
3088 return (typeof prop !== 'undefined');
3091 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3095 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3098 if (isset(attributes[attr]['to'])) {
3099 end = attributes[attr]['to'];
3100 } else if (isset(attributes[attr]['by'])) {
3101 if (start.constructor == Array) {
3103 for (var i = 0, len = start.length; i < len; ++i) {
3104 end[i] = start[i] + attributes[attr]['by'][i];
3107 end = start + attributes[attr]['by'];
3111 this.runtimeAttributes[attr].start = start;
3112 this.runtimeAttributes[attr].end = end;
3115 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3119 init: function(el, attributes, duration, method) {
3121 var isAnimated = false;
3124 var startTime = null;
3127 var actualFrames = 0;
3130 el = Roo.getDom(el);
3133 this.attributes = attributes || {};
3136 this.duration = duration || 1;
3139 this.method = method || Roo.lib.Easing.easeNone;
3142 this.useSeconds = true;
3145 this.currentFrame = 0;
3148 this.totalFrames = Roo.lib.AnimMgr.fps;
3151 this.getEl = function() {
3156 this.isAnimated = function() {
3161 this.getStartTime = function() {
3165 this.runtimeAttributes = {};
3168 this.animate = function() {
3169 if (this.isAnimated()) {
3173 this.currentFrame = 0;
3175 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3177 Roo.lib.AnimMgr.registerElement(this);
3181 this.stop = function(finish) {
3183 this.currentFrame = this.totalFrames;
3184 this._onTween.fire();
3186 Roo.lib.AnimMgr.stop(this);
3189 var onStart = function() {
3190 this.onStart.fire();
3192 this.runtimeAttributes = {};
3193 for (var attr in this.attributes) {
3194 this.setRuntimeAttribute(attr);
3199 startTime = new Date();
3203 var onTween = function() {
3205 duration: new Date() - this.getStartTime(),
3206 currentFrame: this.currentFrame
3209 data.toString = function() {
3211 'duration: ' + data.duration +
3212 ', currentFrame: ' + data.currentFrame
3216 this.onTween.fire(data);
3218 var runtimeAttributes = this.runtimeAttributes;
3220 for (var attr in runtimeAttributes) {
3221 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3227 var onComplete = function() {
3228 var actual_duration = (new Date() - startTime) / 1000 ;
3231 duration: actual_duration,
3232 frames: actualFrames,
3233 fps: actualFrames / actual_duration
3236 data.toString = function() {
3238 'duration: ' + data.duration +
3239 ', frames: ' + data.frames +
3240 ', fps: ' + data.fps
3246 this.onComplete.fire(data);
3250 this._onStart = new Roo.util.Event(this);
3251 this.onStart = new Roo.util.Event(this);
3252 this.onTween = new Roo.util.Event(this);
3253 this._onTween = new Roo.util.Event(this);
3254 this.onComplete = new Roo.util.Event(this);
3255 this._onComplete = new Roo.util.Event(this);
3256 this._onStart.addListener(onStart);
3257 this._onTween.addListener(onTween);
3258 this._onComplete.addListener(onComplete);
3263 * Portions of this file are based on pieces of Yahoo User Interface Library
3264 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3265 * YUI licensed under the BSD License:
3266 * http://developer.yahoo.net/yui/license.txt
3267 * <script type="text/javascript">
3271 Roo.lib.AnimMgr = new function() {
3288 this.registerElement = function(tween) {
3289 queue[queue.length] = tween;
3291 tween._onStart.fire();
3296 this.unRegister = function(tween, index) {
3297 tween._onComplete.fire();
3298 index = index || getIndex(tween);
3300 queue.splice(index, 1);
3304 if (tweenCount <= 0) {
3310 this.start = function() {
3311 if (thread === null) {
3312 thread = setInterval(this.run, this.delay);
3317 this.stop = function(tween) {
3319 clearInterval(thread);
3321 for (var i = 0, len = queue.length; i < len; ++i) {
3322 if (queue[0].isAnimated()) {
3323 this.unRegister(queue[0], 0);
3332 this.unRegister(tween);
3337 this.run = function() {
3338 for (var i = 0, len = queue.length; i < len; ++i) {
3339 var tween = queue[i];
3340 if (!tween || !tween.isAnimated()) {
3344 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3346 tween.currentFrame += 1;
3348 if (tween.useSeconds) {
3349 correctFrame(tween);
3351 tween._onTween.fire();
3354 Roo.lib.AnimMgr.stop(tween, i);
3359 var getIndex = function(anim) {
3360 for (var i = 0, len = queue.length; i < len; ++i) {
3361 if (queue[i] == anim) {
3369 var correctFrame = function(tween) {
3370 var frames = tween.totalFrames;
3371 var frame = tween.currentFrame;
3372 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3373 var elapsed = (new Date() - tween.getStartTime());
3376 if (elapsed < tween.duration * 1000) {
3377 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3379 tweak = frames - (frame + 1);
3381 if (tweak > 0 && isFinite(tweak)) {
3382 if (tween.currentFrame + tweak >= frames) {
3383 tweak = frames - (frame + 1);
3386 tween.currentFrame += tweak;
3390 * Portions of this file are based on pieces of Yahoo User Interface Library
3391 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3392 * YUI licensed under the BSD License:
3393 * http://developer.yahoo.net/yui/license.txt
3394 * <script type="text/javascript">
3397 Roo.lib.Bezier = new function() {
3399 this.getPosition = function(points, t) {
3400 var n = points.length;
3403 for (var i = 0; i < n; ++i) {
3404 tmp[i] = [points[i][0], points[i][1]];
3407 for (var j = 1; j < n; ++j) {
3408 for (i = 0; i < n - j; ++i) {
3409 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3410 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3414 return [ tmp[0][0], tmp[0][1] ];
3418 * Portions of this file are based on pieces of Yahoo User Interface Library
3419 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3420 * YUI licensed under the BSD License:
3421 * http://developer.yahoo.net/yui/license.txt
3422 * <script type="text/javascript">
3427 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3428 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3431 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3433 var fly = Roo.lib.AnimBase.fly;
3435 var superclass = Y.ColorAnim.superclass;
3436 var proto = Y.ColorAnim.prototype;
3438 proto.toString = function() {
3439 var el = this.getEl();
3440 var id = el.id || el.tagName;
3441 return ("ColorAnim " + id);
3444 proto.patterns.color = /color$/i;
3445 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3446 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3447 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3448 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3451 proto.parseColor = function(s) {
3452 if (s.length == 3) {
3456 var c = this.patterns.hex.exec(s);
3457 if (c && c.length == 4) {
3458 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3461 c = this.patterns.rgb.exec(s);
3462 if (c && c.length == 4) {
3463 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3466 c = this.patterns.hex3.exec(s);
3467 if (c && c.length == 4) {
3468 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3473 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3474 proto.getAttribute = function(attr) {
3475 var el = this.getEl();
3476 if (this.patterns.color.test(attr)) {
3477 var val = fly(el).getStyle(attr);
3479 if (this.patterns.transparent.test(val)) {
3480 var parent = el.parentNode;
3481 val = fly(parent).getStyle(attr);
3483 while (parent && this.patterns.transparent.test(val)) {
3484 parent = parent.parentNode;
3485 val = fly(parent).getStyle(attr);
3486 if (parent.tagName.toUpperCase() == 'HTML') {
3492 val = superclass.getAttribute.call(this, attr);
3497 proto.getAttribute = function(attr) {
3498 var el = this.getEl();
3499 if (this.patterns.color.test(attr)) {
3500 var val = fly(el).getStyle(attr);
3502 if (this.patterns.transparent.test(val)) {
3503 var parent = el.parentNode;
3504 val = fly(parent).getStyle(attr);
3506 while (parent && this.patterns.transparent.test(val)) {
3507 parent = parent.parentNode;
3508 val = fly(parent).getStyle(attr);
3509 if (parent.tagName.toUpperCase() == 'HTML') {
3515 val = superclass.getAttribute.call(this, attr);
3521 proto.doMethod = function(attr, start, end) {
3524 if (this.patterns.color.test(attr)) {
3526 for (var i = 0, len = start.length; i < len; ++i) {
3527 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3530 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3533 val = superclass.doMethod.call(this, attr, start, end);
3539 proto.setRuntimeAttribute = function(attr) {
3540 superclass.setRuntimeAttribute.call(this, attr);
3542 if (this.patterns.color.test(attr)) {
3543 var attributes = this.attributes;
3544 var start = this.parseColor(this.runtimeAttributes[attr].start);
3545 var end = this.parseColor(this.runtimeAttributes[attr].end);
3547 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3548 end = this.parseColor(attributes[attr].by);
3550 for (var i = 0, len = start.length; i < len; ++i) {
3551 end[i] = start[i] + end[i];
3555 this.runtimeAttributes[attr].start = start;
3556 this.runtimeAttributes[attr].end = end;
3562 * Portions of this file are based on pieces of Yahoo User Interface Library
3563 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3564 * YUI licensed under the BSD License:
3565 * http://developer.yahoo.net/yui/license.txt
3566 * <script type="text/javascript">
3572 easeNone: function (t, b, c, d) {
3573 return c * t / d + b;
3577 easeIn: function (t, b, c, d) {
3578 return c * (t /= d) * t + b;
3582 easeOut: function (t, b, c, d) {
3583 return -c * (t /= d) * (t - 2) + b;
3587 easeBoth: function (t, b, c, d) {
3588 if ((t /= d / 2) < 1) {
3589 return c / 2 * t * t + b;
3592 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3596 easeInStrong: function (t, b, c, d) {
3597 return c * (t /= d) * t * t * t + b;
3601 easeOutStrong: function (t, b, c, d) {
3602 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3606 easeBothStrong: function (t, b, c, d) {
3607 if ((t /= d / 2) < 1) {
3608 return c / 2 * t * t * t * t + b;
3611 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3616 elasticIn: function (t, b, c, d, a, p) {
3620 if ((t /= d) == 1) {
3627 if (!a || a < Math.abs(c)) {
3632 var s = p / (2 * Math.PI) * Math.asin(c / a);
3635 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3639 elasticOut: function (t, b, c, d, a, p) {
3643 if ((t /= d) == 1) {
3650 if (!a || a < Math.abs(c)) {
3655 var s = p / (2 * Math.PI) * Math.asin(c / a);
3658 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3662 elasticBoth: function (t, b, c, d, a, p) {
3667 if ((t /= d / 2) == 2) {
3675 if (!a || a < Math.abs(c)) {
3680 var s = p / (2 * Math.PI) * Math.asin(c / a);
3684 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3685 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3687 return a * Math.pow(2, -10 * (t -= 1)) *
3688 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3693 backIn: function (t, b, c, d, s) {
3694 if (typeof s == 'undefined') {
3697 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3701 backOut: function (t, b, c, d, s) {
3702 if (typeof s == 'undefined') {
3705 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3709 backBoth: function (t, b, c, d, s) {
3710 if (typeof s == 'undefined') {
3714 if ((t /= d / 2 ) < 1) {
3715 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3717 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3721 bounceIn: function (t, b, c, d) {
3722 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3726 bounceOut: function (t, b, c, d) {
3727 if ((t /= d) < (1 / 2.75)) {
3728 return c * (7.5625 * t * t) + b;
3729 } else if (t < (2 / 2.75)) {
3730 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3731 } else if (t < (2.5 / 2.75)) {
3732 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3734 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3738 bounceBoth: function (t, b, c, d) {
3740 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3742 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3745 * Portions of this file are based on pieces of Yahoo User Interface Library
3746 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3747 * YUI licensed under the BSD License:
3748 * http://developer.yahoo.net/yui/license.txt
3749 * <script type="text/javascript">
3753 Roo.lib.Motion = function(el, attributes, duration, method) {
3755 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3759 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3763 var superclass = Y.Motion.superclass;
3764 var proto = Y.Motion.prototype;
3766 proto.toString = function() {
3767 var el = this.getEl();
3768 var id = el.id || el.tagName;
3769 return ("Motion " + id);
3772 proto.patterns.points = /^points$/i;
3774 proto.setAttribute = function(attr, val, unit) {
3775 if (this.patterns.points.test(attr)) {
3776 unit = unit || 'px';
3777 superclass.setAttribute.call(this, 'left', val[0], unit);
3778 superclass.setAttribute.call(this, 'top', val[1], unit);
3780 superclass.setAttribute.call(this, attr, val, unit);
3784 proto.getAttribute = function(attr) {
3785 if (this.patterns.points.test(attr)) {
3787 superclass.getAttribute.call(this, 'left'),
3788 superclass.getAttribute.call(this, 'top')
3791 val = superclass.getAttribute.call(this, attr);
3797 proto.doMethod = function(attr, start, end) {
3800 if (this.patterns.points.test(attr)) {
3801 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3802 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3804 val = superclass.doMethod.call(this, attr, start, end);
3809 proto.setRuntimeAttribute = function(attr) {
3810 if (this.patterns.points.test(attr)) {
3811 var el = this.getEl();
3812 var attributes = this.attributes;
3814 var control = attributes['points']['control'] || [];
3818 if (control.length > 0 && !(control[0] instanceof Array)) {
3819 control = [control];
3822 for (i = 0,len = control.length; i < len; ++i) {
3823 tmp[i] = control[i];
3828 Roo.fly(el).position();
3830 if (isset(attributes['points']['from'])) {
3831 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3834 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3837 start = this.getAttribute('points');
3840 if (isset(attributes['points']['to'])) {
3841 end = translateValues.call(this, attributes['points']['to'], start);
3843 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3844 for (i = 0,len = control.length; i < len; ++i) {
3845 control[i] = translateValues.call(this, control[i], start);
3849 } else if (isset(attributes['points']['by'])) {
3850 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3852 for (i = 0,len = control.length; i < len; ++i) {
3853 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3857 this.runtimeAttributes[attr] = [start];
3859 if (control.length > 0) {
3860 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3863 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3866 superclass.setRuntimeAttribute.call(this, attr);
3870 var translateValues = function(val, start) {
3871 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3872 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3877 var isset = function(prop) {
3878 return (typeof prop !== 'undefined');
3882 * Portions of this file are based on pieces of Yahoo User Interface Library
3883 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3884 * YUI licensed under the BSD License:
3885 * http://developer.yahoo.net/yui/license.txt
3886 * <script type="text/javascript">
3890 Roo.lib.Scroll = function(el, attributes, duration, method) {
3892 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3896 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3900 var superclass = Y.Scroll.superclass;
3901 var proto = Y.Scroll.prototype;
3903 proto.toString = function() {
3904 var el = this.getEl();
3905 var id = el.id || el.tagName;
3906 return ("Scroll " + id);
3909 proto.doMethod = function(attr, start, end) {
3912 if (attr == 'scroll') {
3914 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3915 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3919 val = superclass.doMethod.call(this, attr, start, end);
3924 proto.getAttribute = function(attr) {
3926 var el = this.getEl();
3928 if (attr == 'scroll') {
3929 val = [ el.scrollLeft, el.scrollTop ];
3931 val = superclass.getAttribute.call(this, attr);
3937 proto.setAttribute = function(attr, val, unit) {
3938 var el = this.getEl();
3940 if (attr == 'scroll') {
3941 el.scrollLeft = val[0];
3942 el.scrollTop = val[1];
3944 superclass.setAttribute.call(this, attr, val, unit);
3950 * Ext JS Library 1.1.1
3951 * Copyright(c) 2006-2007, Ext JS, LLC.
3953 * Originally Released Under LGPL - original licence link has changed is not relivant.
3956 * <script type="text/javascript">
3961 * @class Roo.DomHelper
3962 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3963 * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
3966 Roo.DomHelper = function(){
3967 var tempTableEl = null;
3968 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3969 var tableRe = /^table|tbody|tr|td$/i;
3971 // build as innerHTML where available
3973 var createHtml = function(o){
3974 if(typeof o == 'string'){
3983 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
3984 if(attr == "style"){
3986 if(typeof s == "function"){
3989 if(typeof s == "string"){
3990 b += ' style="' + s + '"';
3991 }else if(typeof s == "object"){
3994 if(typeof s[key] != "function"){
3995 b += key + ":" + s[key] + ";";
4002 b += ' class="' + o["cls"] + '"';
4003 }else if(attr == "htmlFor"){
4004 b += ' for="' + o["htmlFor"] + '"';
4006 b += " " + attr + '="' + o[attr] + '"';
4010 if(emptyTags.test(o.tag)){
4014 var cn = o.children || o.cn;
4016 //http://bugs.kde.org/show_bug.cgi?id=71506
4017 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4018 for(var i = 0, len = cn.length; i < len; i++) {
4019 b += createHtml(cn[i], b);
4022 b += createHtml(cn, b);
4028 b += "</" + o.tag + ">";
4035 var createDom = function(o, parentNode){
4037 // defininition craeted..
4039 if (o.ns && o.ns != 'html') {
4041 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4042 xmlns[o.ns] = o.xmlns;
4045 if (typeof(xmlns[o.ns]) == 'undefined') {
4046 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4052 if (typeof(o) == 'string') {
4053 return parentNode.appendChild(document.createTextNode(o));
4055 o.tag = o.tag || div;
4056 if (o.ns && Roo.isIE) {
4058 o.tag = o.ns + ':' + o.tag;
4061 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4062 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4065 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4066 attr == "style" || typeof o[attr] == "function") continue;
4068 if(attr=="cls" && Roo.isIE){
4069 el.className = o["cls"];
4071 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4072 else el[attr] = o[attr];
4075 Roo.DomHelper.applyStyles(el, o.style);
4076 var cn = o.children || o.cn;
4078 //http://bugs.kde.org/show_bug.cgi?id=71506
4079 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4080 for(var i = 0, len = cn.length; i < len; i++) {
4081 createDom(cn[i], el);
4088 el.innerHTML = o.html;
4091 parentNode.appendChild(el);
4096 var ieTable = function(depth, s, h, e){
4097 tempTableEl.innerHTML = [s, h, e].join('');
4098 var i = -1, el = tempTableEl;
4105 // kill repeat to save bytes
4109 tbe = '</tbody>'+te,
4115 * Nasty code for IE's broken table implementation
4117 var insertIntoTable = function(tag, where, el, html){
4119 tempTableEl = document.createElement('div');
4124 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4127 if(where == 'beforebegin'){
4131 before = el.nextSibling;
4134 node = ieTable(4, trs, html, tre);
4136 else if(tag == 'tr'){
4137 if(where == 'beforebegin'){
4140 node = ieTable(3, tbs, html, tbe);
4141 } else if(where == 'afterend'){
4142 before = el.nextSibling;
4144 node = ieTable(3, tbs, html, tbe);
4145 } else{ // INTO a TR
4146 if(where == 'afterbegin'){
4147 before = el.firstChild;
4149 node = ieTable(4, trs, html, tre);
4151 } else if(tag == 'tbody'){
4152 if(where == 'beforebegin'){
4155 node = ieTable(2, ts, html, te);
4156 } else if(where == 'afterend'){
4157 before = el.nextSibling;
4159 node = ieTable(2, ts, html, te);
4161 if(where == 'afterbegin'){
4162 before = el.firstChild;
4164 node = ieTable(3, tbs, html, tbe);
4167 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4170 if(where == 'afterbegin'){
4171 before = el.firstChild;
4173 node = ieTable(2, ts, html, te);
4175 el.insertBefore(node, before);
4180 /** True to force the use of DOM instead of html fragments @type Boolean */
4184 * Returns the markup for the passed Element(s) config
4185 * @param {Object} o The Dom object spec (and children)
4188 markup : function(o){
4189 return createHtml(o);
4193 * Applies a style specification to an element
4194 * @param {String/HTMLElement} el The element to apply styles to
4195 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4196 * a function which returns such a specification.
4198 applyStyles : function(el, styles){
4201 if(typeof styles == "string"){
4202 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4204 while ((matches = re.exec(styles)) != null){
4205 el.setStyle(matches[1], matches[2]);
4207 }else if (typeof styles == "object"){
4208 for (var style in styles){
4209 el.setStyle(style, styles[style]);
4211 }else if (typeof styles == "function"){
4212 Roo.DomHelper.applyStyles(el, styles.call());
4218 * Inserts an HTML fragment into the Dom
4219 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4220 * @param {HTMLElement} el The context element
4221 * @param {String} html The HTML fragmenet
4222 * @return {HTMLElement} The new node
4224 insertHtml : function(where, el, html){
4225 where = where.toLowerCase();
4226 if(el.insertAdjacentHTML){
4227 if(tableRe.test(el.tagName)){
4229 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4235 el.insertAdjacentHTML('BeforeBegin', html);
4236 return el.previousSibling;
4238 el.insertAdjacentHTML('AfterBegin', html);
4239 return el.firstChild;
4241 el.insertAdjacentHTML('BeforeEnd', html);
4242 return el.lastChild;
4244 el.insertAdjacentHTML('AfterEnd', html);
4245 return el.nextSibling;
4247 throw 'Illegal insertion point -> "' + where + '"';
4249 var range = el.ownerDocument.createRange();
4253 range.setStartBefore(el);
4254 frag = range.createContextualFragment(html);
4255 el.parentNode.insertBefore(frag, el);
4256 return el.previousSibling;
4259 range.setStartBefore(el.firstChild);
4260 frag = range.createContextualFragment(html);
4261 el.insertBefore(frag, el.firstChild);
4262 return el.firstChild;
4264 el.innerHTML = html;
4265 return el.firstChild;
4269 range.setStartAfter(el.lastChild);
4270 frag = range.createContextualFragment(html);
4271 el.appendChild(frag);
4272 return el.lastChild;
4274 el.innerHTML = html;
4275 return el.lastChild;
4278 range.setStartAfter(el);
4279 frag = range.createContextualFragment(html);
4280 el.parentNode.insertBefore(frag, el.nextSibling);
4281 return el.nextSibling;
4283 throw 'Illegal insertion point -> "' + where + '"';
4287 * Creates new Dom element(s) and inserts them before el
4288 * @param {String/HTMLElement/Element} el The context element
4289 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4290 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4291 * @return {HTMLElement/Roo.Element} The new node
4293 insertBefore : function(el, o, returnElement){
4294 return this.doInsert(el, o, returnElement, "beforeBegin");
4298 * Creates new Dom element(s) and inserts them after el
4299 * @param {String/HTMLElement/Element} el The context element
4300 * @param {Object} o The Dom object spec (and children)
4301 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4302 * @return {HTMLElement/Roo.Element} The new node
4304 insertAfter : function(el, o, returnElement){
4305 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4309 * Creates new Dom element(s) and inserts them as the first child of el
4310 * @param {String/HTMLElement/Element} el The context element
4311 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4312 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4313 * @return {HTMLElement/Roo.Element} The new node
4315 insertFirst : function(el, o, returnElement){
4316 return this.doInsert(el, o, returnElement, "afterBegin");
4320 doInsert : function(el, o, returnElement, pos, sibling){
4321 el = Roo.getDom(el);
4323 if(this.useDom || o.ns){
4324 newNode = createDom(o, null);
4325 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4327 var html = createHtml(o);
4328 newNode = this.insertHtml(pos, el, html);
4330 return returnElement ? Roo.get(newNode, true) : newNode;
4334 * Creates new Dom element(s) and appends them to el
4335 * @param {String/HTMLElement/Element} el The context element
4336 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4337 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4338 * @return {HTMLElement/Roo.Element} The new node
4340 append : function(el, o, returnElement){
4341 el = Roo.getDom(el);
4343 if(this.useDom || o.ns){
4344 newNode = createDom(o, null);
4345 el.appendChild(newNode);
4347 var html = createHtml(o);
4348 newNode = this.insertHtml("beforeEnd", el, html);
4350 return returnElement ? Roo.get(newNode, true) : newNode;
4354 * Creates new Dom element(s) and overwrites the contents of el with them
4355 * @param {String/HTMLElement/Element} el The context element
4356 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4357 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4358 * @return {HTMLElement/Roo.Element} The new node
4360 overwrite : function(el, o, returnElement){
4361 el = Roo.getDom(el);
4364 while (el.childNodes.length) {
4365 el.removeChild(el.firstChild);
4369 el.innerHTML = createHtml(o);
4372 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4376 * Creates a new Roo.DomHelper.Template from the Dom object spec
4377 * @param {Object} o The Dom object spec (and children)
4378 * @return {Roo.DomHelper.Template} The new template
4380 createTemplate : function(o){
4381 var html = createHtml(o);
4382 return new Roo.Template(html);
4388 * Ext JS Library 1.1.1
4389 * Copyright(c) 2006-2007, Ext JS, LLC.
4391 * Originally Released Under LGPL - original licence link has changed is not relivant.
4394 * <script type="text/javascript">
4398 * @class Roo.Template
4399 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4400 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4403 var t = new Roo.Template({
4404 html : '<div name="{id}">' +
4405 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4407 myformat: function (value, allValues) {
4408 return 'XX' + value;
4411 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4413 * For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>.
4415 * @param {Object} cfg - Configuration object.
4417 Roo.Template = function(cfg){
4419 if(cfg instanceof Array){
4421 }else if(arguments.length > 1){
4422 cfg = Array.prototype.join.call(arguments, "");
4426 if (typeof(cfg) == 'object') {
4435 Roo.Template.prototype = {
4438 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4442 * Returns an HTML fragment of this template with the specified values applied.
4443 * @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'})
4444 * @return {String} The HTML fragment
4446 applyTemplate : function(values){
4450 return this.compiled(values);
4452 var useF = this.disableFormats !== true;
4453 var fm = Roo.util.Format, tpl = this;
4454 var fn = function(m, name, format, args){
4456 if(format.substr(0, 5) == "this."){
4457 return tpl.call(format.substr(5), values[name], values);
4460 // quoted values are required for strings in compiled templates,
4461 // but for non compiled we need to strip them
4462 // quoted reversed for jsmin
4463 var re = /^\s*['"](.*)["']\s*$/;
4464 args = args.split(',');
4465 for(var i = 0, len = args.length; i < len; i++){
4466 args[i] = args[i].replace(re, "$1");
4468 args = [values[name]].concat(args);
4470 args = [values[name]];
4472 return fm[format].apply(fm, args);
4475 return values[name] !== undefined ? values[name] : "";
4478 return this.html.replace(this.re, fn);
4487 * Sets the HTML used as the template and optionally compiles it.
4488 * @param {String} html
4489 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4490 * @return {Roo.Template} this
4492 set : function(html, compile){
4494 this.compiled = null;
4502 * True to disable format functions (defaults to false)
4505 disableFormats : false,
4508 * The regular expression used to match template variables
4512 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4515 * Compiles the template into an internal function, eliminating the RegEx overhead.
4516 * @return {Roo.Template} this
4518 compile : function(){
4519 var fm = Roo.util.Format;
4520 var useF = this.disableFormats !== true;
4521 var sep = Roo.isGecko ? "+" : ",";
4522 var fn = function(m, name, format, args){
4524 args = args ? ',' + args : "";
4525 if(format.substr(0, 5) != "this."){
4526 format = "fm." + format + '(';
4528 format = 'this.call("'+ format.substr(5) + '", ';
4532 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4534 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4537 // branched to use + in gecko and [].join() in others
4539 body = "this.compiled = function(values){ return '" +
4540 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4543 body = ["this.compiled = function(values){ return ['"];
4544 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4545 body.push("'].join('');};");
4546 body = body.join('');
4556 // private function used to call members
4557 call : function(fnName, value, allValues){
4558 return this[fnName](value, allValues);
4562 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4563 * @param {String/HTMLElement/Roo.Element} el The context element
4564 * @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'})
4565 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4566 * @return {HTMLElement/Roo.Element} The new node or Element
4568 insertFirst: function(el, values, returnElement){
4569 return this.doInsert('afterBegin', el, values, returnElement);
4573 * Applies the supplied values to the template and inserts the new node(s) before el.
4574 * @param {String/HTMLElement/Roo.Element} el The context element
4575 * @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'})
4576 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4577 * @return {HTMLElement/Roo.Element} The new node or Element
4579 insertBefore: function(el, values, returnElement){
4580 return this.doInsert('beforeBegin', el, values, returnElement);
4584 * Applies the supplied values to the template and inserts the new node(s) after el.
4585 * @param {String/HTMLElement/Roo.Element} el The context element
4586 * @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'})
4587 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4588 * @return {HTMLElement/Roo.Element} The new node or Element
4590 insertAfter : function(el, values, returnElement){
4591 return this.doInsert('afterEnd', el, values, returnElement);
4595 * Applies the supplied values to the template and appends the new node(s) to el.
4596 * @param {String/HTMLElement/Roo.Element} el The context element
4597 * @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'})
4598 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4599 * @return {HTMLElement/Roo.Element} The new node or Element
4601 append : function(el, values, returnElement){
4602 return this.doInsert('beforeEnd', el, values, returnElement);
4605 doInsert : function(where, el, values, returnEl){
4606 el = Roo.getDom(el);
4607 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4608 return returnEl ? Roo.get(newNode, true) : newNode;
4612 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4613 * @param {String/HTMLElement/Roo.Element} el The context element
4614 * @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'})
4615 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4616 * @return {HTMLElement/Roo.Element} The new node or Element
4618 overwrite : function(el, values, returnElement){
4619 el = Roo.getDom(el);
4620 el.innerHTML = this.applyTemplate(values);
4621 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4625 * Alias for {@link #applyTemplate}
4628 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4631 Roo.DomHelper.Template = Roo.Template;
4634 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4635 * @param {String/HTMLElement} el A DOM element or its id
4636 * @returns {Roo.Template} The created template
4639 Roo.Template.from = function(el){
4640 el = Roo.getDom(el);
4641 return new Roo.Template(el.value || el.innerHTML);
4644 * Ext JS Library 1.1.1
4645 * Copyright(c) 2006-2007, Ext JS, LLC.
4647 * Originally Released Under LGPL - original licence link has changed is not relivant.
4650 * <script type="text/javascript">
4655 * This is code is also distributed under MIT license for use
4656 * with jQuery and prototype JavaScript libraries.
4659 * @class Roo.DomQuery
4660 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).
4662 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>
4665 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.
4667 <h4>Element Selectors:</h4>
4669 <li> <b>*</b> any element</li>
4670 <li> <b>E</b> an element with the tag E</li>
4671 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4672 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4673 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4674 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4676 <h4>Attribute Selectors:</h4>
4677 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4679 <li> <b>E[foo]</b> has an attribute "foo"</li>
4680 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4681 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4682 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4683 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4684 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4685 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4687 <h4>Pseudo Classes:</h4>
4689 <li> <b>E:first-child</b> E is the first child of its parent</li>
4690 <li> <b>E:last-child</b> E is the last child of its parent</li>
4691 <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>
4692 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4693 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4694 <li> <b>E:only-child</b> E is the only child of its parent</li>
4695 <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>
4696 <li> <b>E:first</b> the first E in the resultset</li>
4697 <li> <b>E:last</b> the last E in the resultset</li>
4698 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4699 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4700 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4701 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4702 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4703 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4704 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4705 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4706 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4708 <h4>CSS Value Selectors:</h4>
4710 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4711 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4712 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4713 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4714 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4715 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4719 Roo.DomQuery = function(){
4720 var cache = {}, simpleCache = {}, valueCache = {};
4721 var nonSpace = /\S/;
4722 var trimRe = /^\s+|\s+$/g;
4723 var tplRe = /\{(\d+)\}/g;
4724 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4725 var tagTokenRe = /^(#)?([\w-\*]+)/;
4726 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4728 function child(p, index){
4730 var n = p.firstChild;
4732 if(n.nodeType == 1){
4743 while((n = n.nextSibling) && n.nodeType != 1);
4748 while((n = n.previousSibling) && n.nodeType != 1);
4752 function children(d){
4753 var n = d.firstChild, ni = -1;
4755 var nx = n.nextSibling;
4756 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4766 function byClassName(c, a, v){
4770 var r = [], ri = -1, cn;
4771 for(var i = 0, ci; ci = c[i]; i++){
4772 if((' '+ci.className+' ').indexOf(v) != -1){
4779 function attrValue(n, attr){
4780 if(!n.tagName && typeof n.length != "undefined"){
4789 if(attr == "class" || attr == "className"){
4792 return n.getAttribute(attr) || n[attr];
4796 function getNodes(ns, mode, tagName){
4797 var result = [], ri = -1, cs;
4801 tagName = tagName || "*";
4802 if(typeof ns.getElementsByTagName != "undefined"){
4806 for(var i = 0, ni; ni = ns[i]; i++){
4807 cs = ni.getElementsByTagName(tagName);
4808 for(var j = 0, ci; ci = cs[j]; j++){
4812 }else if(mode == "/" || mode == ">"){
4813 var utag = tagName.toUpperCase();
4814 for(var i = 0, ni, cn; ni = ns[i]; i++){
4815 cn = ni.children || ni.childNodes;
4816 for(var j = 0, cj; cj = cn[j]; j++){
4817 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4822 }else if(mode == "+"){
4823 var utag = tagName.toUpperCase();
4824 for(var i = 0, n; n = ns[i]; i++){
4825 while((n = n.nextSibling) && n.nodeType != 1);
4826 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4830 }else if(mode == "~"){
4831 for(var i = 0, n; n = ns[i]; i++){
4832 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4841 function concat(a, b){
4845 for(var i = 0, l = b.length; i < l; i++){
4851 function byTag(cs, tagName){
4852 if(cs.tagName || cs == document){
4858 var r = [], ri = -1;
4859 tagName = tagName.toLowerCase();
4860 for(var i = 0, ci; ci = cs[i]; i++){
4861 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4868 function byId(cs, attr, id){
4869 if(cs.tagName || cs == document){
4875 var r = [], ri = -1;
4876 for(var i = 0,ci; ci = cs[i]; i++){
4877 if(ci && ci.id == id){
4885 function byAttribute(cs, attr, value, op, custom){
4886 var r = [], ri = -1, st = custom=="{";
4887 var f = Roo.DomQuery.operators[op];
4888 for(var i = 0, ci; ci = cs[i]; i++){
4891 a = Roo.DomQuery.getStyle(ci, attr);
4893 else if(attr == "class" || attr == "className"){
4895 }else if(attr == "for"){
4897 }else if(attr == "href"){
4898 a = ci.getAttribute("href", 2);
4900 a = ci.getAttribute(attr);
4902 if((f && f(a, value)) || (!f && a)){
4909 function byPseudo(cs, name, value){
4910 return Roo.DomQuery.pseudos[name](cs, value);
4913 // This is for IE MSXML which does not support expandos.
4914 // IE runs the same speed using setAttribute, however FF slows way down
4915 // and Safari completely fails so they need to continue to use expandos.
4916 var isIE = window.ActiveXObject ? true : false;
4918 // this eval is stop the compressor from
4919 // renaming the variable to something shorter
4921 /** eval:var:batch */
4926 function nodupIEXml(cs){
4928 cs[0].setAttribute("_nodup", d);
4930 for(var i = 1, len = cs.length; i < len; i++){
4932 if(!c.getAttribute("_nodup") != d){
4933 c.setAttribute("_nodup", d);
4937 for(var i = 0, len = cs.length; i < len; i++){
4938 cs[i].removeAttribute("_nodup");
4947 var len = cs.length, c, i, r = cs, cj, ri = -1;
4948 if(!len || typeof cs.nodeType != "undefined" || len == 1){
4951 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4952 return nodupIEXml(cs);
4956 for(i = 1; c = cs[i]; i++){
4961 for(var j = 0; j < i; j++){
4964 for(j = i+1; cj = cs[j]; j++){
4976 function quickDiffIEXml(c1, c2){
4978 for(var i = 0, len = c1.length; i < len; i++){
4979 c1[i].setAttribute("_qdiff", d);
4982 for(var i = 0, len = c2.length; i < len; i++){
4983 if(c2[i].getAttribute("_qdiff") != d){
4984 r[r.length] = c2[i];
4987 for(var i = 0, len = c1.length; i < len; i++){
4988 c1[i].removeAttribute("_qdiff");
4993 function quickDiff(c1, c2){
4994 var len1 = c1.length;
4998 if(isIE && c1[0].selectSingleNode){
4999 return quickDiffIEXml(c1, c2);
5002 for(var i = 0; i < len1; i++){
5006 for(var i = 0, len = c2.length; i < len; i++){
5007 if(c2[i]._qdiff != d){
5008 r[r.length] = c2[i];
5014 function quickId(ns, mode, root, id){
5016 var d = root.ownerDocument || root;
5017 return d.getElementById(id);
5019 ns = getNodes(ns, mode, "*");
5020 return byId(ns, null, id);
5024 getStyle : function(el, name){
5025 return Roo.fly(el).getStyle(name);
5028 * Compiles a selector/xpath query into a reusable function. The returned function
5029 * takes one parameter "root" (optional), which is the context node from where the query should start.
5030 * @param {String} selector The selector/xpath query
5031 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5032 * @return {Function}
5034 compile : function(path, type){
5035 type = type || "select";
5037 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5038 var q = path, mode, lq;
5039 var tk = Roo.DomQuery.matchers;
5040 var tklen = tk.length;
5043 // accept leading mode switch
5044 var lmode = q.match(modeRe);
5045 if(lmode && lmode[1]){
5046 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5047 q = q.replace(lmode[1], "");
5049 // strip leading slashes
5050 while(path.substr(0, 1)=="/"){
5051 path = path.substr(1);
5054 while(q && lq != q){
5056 var tm = q.match(tagTokenRe);
5057 if(type == "select"){
5060 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5062 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5064 q = q.replace(tm[0], "");
5065 }else if(q.substr(0, 1) != '@'){
5066 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5071 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5073 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5075 q = q.replace(tm[0], "");
5078 while(!(mm = q.match(modeRe))){
5079 var matched = false;
5080 for(var j = 0; j < tklen; j++){
5082 var m = q.match(t.re);
5084 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5087 q = q.replace(m[0], "");
5092 // prevent infinite loop on bad selector
5094 throw 'Error parsing selector, parsing failed at "' + q + '"';
5098 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5099 q = q.replace(mm[1], "");
5102 fn[fn.length] = "return nodup(n);\n}";
5105 * list of variables that need from compression as they are used by eval.
5115 * eval:var:byClassName
5117 * eval:var:byAttribute
5118 * eval:var:attrValue
5126 * Selects a group of elements.
5127 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5128 * @param {Node} root (optional) The start of the query (defaults to document).
5131 select : function(path, root, type){
5132 if(!root || root == document){
5135 if(typeof root == "string"){
5136 root = document.getElementById(root);
5138 var paths = path.split(",");
5140 for(var i = 0, len = paths.length; i < len; i++){
5141 var p = paths[i].replace(trimRe, "");
5143 cache[p] = Roo.DomQuery.compile(p);
5145 throw p + " is not a valid selector";
5148 var result = cache[p](root);
5149 if(result && result != document){
5150 results = results.concat(result);
5153 if(paths.length > 1){
5154 return nodup(results);
5160 * Selects a single element.
5161 * @param {String} selector The selector/xpath query
5162 * @param {Node} root (optional) The start of the query (defaults to document).
5165 selectNode : function(path, root){
5166 return Roo.DomQuery.select(path, root)[0];
5170 * Selects the value of a node, optionally replacing null with the defaultValue.
5171 * @param {String} selector The selector/xpath query
5172 * @param {Node} root (optional) The start of the query (defaults to document).
5173 * @param {String} defaultValue
5175 selectValue : function(path, root, defaultValue){
5176 path = path.replace(trimRe, "");
5177 if(!valueCache[path]){
5178 valueCache[path] = Roo.DomQuery.compile(path, "select");
5180 var n = valueCache[path](root);
5181 n = n[0] ? n[0] : n;
5182 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5183 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5187 * Selects the value of a node, parsing integers and floats.
5188 * @param {String} selector The selector/xpath query
5189 * @param {Node} root (optional) The start of the query (defaults to document).
5190 * @param {Number} defaultValue
5193 selectNumber : function(path, root, defaultValue){
5194 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5195 return parseFloat(v);
5199 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5200 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5201 * @param {String} selector The simple selector to test
5204 is : function(el, ss){
5205 if(typeof el == "string"){
5206 el = document.getElementById(el);
5208 var isArray = (el instanceof Array);
5209 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5210 return isArray ? (result.length == el.length) : (result.length > 0);
5214 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5215 * @param {Array} el An array of elements to filter
5216 * @param {String} selector The simple selector to test
5217 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5218 * the selector instead of the ones that match
5221 filter : function(els, ss, nonMatches){
5222 ss = ss.replace(trimRe, "");
5223 if(!simpleCache[ss]){
5224 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5226 var result = simpleCache[ss](els);
5227 return nonMatches ? quickDiff(result, els) : result;
5231 * Collection of matching regular expressions and code snippets.
5235 select: 'n = byClassName(n, null, " {1} ");'
5237 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5238 select: 'n = byPseudo(n, "{1}", "{2}");'
5240 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5241 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5244 select: 'n = byId(n, null, "{1}");'
5247 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5252 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5253 * 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, > <.
5256 "=" : function(a, v){
5259 "!=" : function(a, v){
5262 "^=" : function(a, v){
5263 return a && a.substr(0, v.length) == v;
5265 "$=" : function(a, v){
5266 return a && a.substr(a.length-v.length) == v;
5268 "*=" : function(a, v){
5269 return a && a.indexOf(v) !== -1;
5271 "%=" : function(a, v){
5272 return (a % v) == 0;
5274 "|=" : function(a, v){
5275 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5277 "~=" : function(a, v){
5278 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5283 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5284 * and the argument (if any) supplied in the selector.
5287 "first-child" : function(c){
5288 var r = [], ri = -1, n;
5289 for(var i = 0, ci; ci = n = c[i]; i++){
5290 while((n = n.previousSibling) && n.nodeType != 1);
5298 "last-child" : function(c){
5299 var r = [], ri = -1, n;
5300 for(var i = 0, ci; ci = n = c[i]; i++){
5301 while((n = n.nextSibling) && n.nodeType != 1);
5309 "nth-child" : function(c, a) {
5310 var r = [], ri = -1;
5311 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5312 var f = (m[1] || 1) - 0, l = m[2] - 0;
5313 for(var i = 0, n; n = c[i]; i++){
5314 var pn = n.parentNode;
5315 if (batch != pn._batch) {
5317 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5318 if(cn.nodeType == 1){
5325 if (l == 0 || n.nodeIndex == l){
5328 } else if ((n.nodeIndex + l) % f == 0){
5336 "only-child" : function(c){
5337 var r = [], ri = -1;;
5338 for(var i = 0, ci; ci = c[i]; i++){
5339 if(!prev(ci) && !next(ci)){
5346 "empty" : function(c){
5347 var r = [], ri = -1;
5348 for(var i = 0, ci; ci = c[i]; i++){
5349 var cns = ci.childNodes, j = 0, cn, empty = true;
5352 if(cn.nodeType == 1 || cn.nodeType == 3){
5364 "contains" : function(c, v){
5365 var r = [], ri = -1;
5366 for(var i = 0, ci; ci = c[i]; i++){
5367 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5374 "nodeValue" : function(c, v){
5375 var r = [], ri = -1;
5376 for(var i = 0, ci; ci = c[i]; i++){
5377 if(ci.firstChild && ci.firstChild.nodeValue == v){
5384 "checked" : function(c){
5385 var r = [], ri = -1;
5386 for(var i = 0, ci; ci = c[i]; i++){
5387 if(ci.checked == true){
5394 "not" : function(c, ss){
5395 return Roo.DomQuery.filter(c, ss, true);
5398 "odd" : function(c){
5399 return this["nth-child"](c, "odd");
5402 "even" : function(c){
5403 return this["nth-child"](c, "even");
5406 "nth" : function(c, a){
5407 return c[a-1] || [];
5410 "first" : function(c){
5414 "last" : function(c){
5415 return c[c.length-1] || [];
5418 "has" : function(c, ss){
5419 var s = Roo.DomQuery.select;
5420 var r = [], ri = -1;
5421 for(var i = 0, ci; ci = c[i]; i++){
5422 if(s(ss, ci).length > 0){
5429 "next" : function(c, ss){
5430 var is = Roo.DomQuery.is;
5431 var r = [], ri = -1;
5432 for(var i = 0, ci; ci = c[i]; i++){
5441 "prev" : function(c, ss){
5442 var is = Roo.DomQuery.is;
5443 var r = [], ri = -1;
5444 for(var i = 0, ci; ci = c[i]; i++){
5457 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5458 * @param {String} path The selector/xpath query
5459 * @param {Node} root (optional) The start of the query (defaults to document).
5464 Roo.query = Roo.DomQuery.select;
5467 * Ext JS Library 1.1.1
5468 * Copyright(c) 2006-2007, Ext JS, LLC.
5470 * Originally Released Under LGPL - original licence link has changed is not relivant.
5473 * <script type="text/javascript">
5477 * @class Roo.util.Observable
5478 * Base class that provides a common interface for publishing events. Subclasses are expected to
5479 * to have a property "events" with all the events defined.<br>
5482 Employee = function(name){
5489 Roo.extend(Employee, Roo.util.Observable);
5491 * @param {Object} config properties to use (incuding events / listeners)
5494 Roo.util.Observable = function(cfg){
5497 this.addEvents(cfg.events || {});
5499 delete cfg.events; // make sure
5502 Roo.apply(this, cfg);
5505 this.on(this.listeners);
5506 delete this.listeners;
5509 Roo.util.Observable.prototype = {
5511 * @cfg {Object} listeners list of events and functions to call for this object,
5515 'click' : function(e) {
5525 * Fires the specified event with the passed parameters (minus the event name).
5526 * @param {String} eventName
5527 * @param {Object...} args Variable number of parameters are passed to handlers
5528 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5530 fireEvent : function(){
5531 var ce = this.events[arguments[0].toLowerCase()];
5532 if(typeof ce == "object"){
5533 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5540 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5543 * Appends an event handler to this component
5544 * @param {String} eventName The type of event to listen for
5545 * @param {Function} handler The method the event invokes
5546 * @param {Object} scope (optional) The scope in which to execute the handler
5547 * function. The handler function's "this" context.
5548 * @param {Object} options (optional) An object containing handler configuration
5549 * properties. This may contain any of the following properties:<ul>
5550 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5551 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5552 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5553 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5554 * by the specified number of milliseconds. If the event fires again within that time, the original
5555 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5558 * <b>Combining Options</b><br>
5559 * Using the options argument, it is possible to combine different types of listeners:<br>
5561 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5563 el.on('click', this.onClick, this, {
5570 * <b>Attaching multiple handlers in 1 call</b><br>
5571 * The method also allows for a single argument to be passed which is a config object containing properties
5572 * which specify multiple handlers.
5581 fn: this.onMouseOver,
5585 fn: this.onMouseOut,
5591 * Or a shorthand syntax which passes the same scope object to all handlers:
5594 'click': this.onClick,
5595 'mouseover': this.onMouseOver,
5596 'mouseout': this.onMouseOut,
5601 addListener : function(eventName, fn, scope, o){
5602 if(typeof eventName == "object"){
5605 if(this.filterOptRe.test(e)){
5608 if(typeof o[e] == "function"){
5610 this.addListener(e, o[e], o.scope, o);
5612 // individual options
5613 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5618 o = (!o || typeof o == "boolean") ? {} : o;
5619 eventName = eventName.toLowerCase();
5620 var ce = this.events[eventName] || true;
5621 if(typeof ce == "boolean"){
5622 ce = new Roo.util.Event(this, eventName);
5623 this.events[eventName] = ce;
5625 ce.addListener(fn, scope, o);
5629 * Removes a listener
5630 * @param {String} eventName The type of event to listen for
5631 * @param {Function} handler The handler to remove
5632 * @param {Object} scope (optional) The scope (this object) for the handler
5634 removeListener : function(eventName, fn, scope){
5635 var ce = this.events[eventName.toLowerCase()];
5636 if(typeof ce == "object"){
5637 ce.removeListener(fn, scope);
5642 * Removes all listeners for this object
5644 purgeListeners : function(){
5645 for(var evt in this.events){
5646 if(typeof this.events[evt] == "object"){
5647 this.events[evt].clearListeners();
5652 relayEvents : function(o, events){
5653 var createHandler = function(ename){
5655 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5658 for(var i = 0, len = events.length; i < len; i++){
5659 var ename = events[i];
5660 if(!this.events[ename]){ this.events[ename] = true; };
5661 o.on(ename, createHandler(ename), this);
5666 * Used to define events on this Observable
5667 * @param {Object} object The object with the events defined
5669 addEvents : function(o){
5673 Roo.applyIf(this.events, o);
5677 * Checks to see if this object has any listeners for a specified event
5678 * @param {String} eventName The name of the event to check for
5679 * @return {Boolean} True if the event is being listened for, else false
5681 hasListener : function(eventName){
5682 var e = this.events[eventName];
5683 return typeof e == "object" && e.listeners.length > 0;
5687 * Appends an event handler to this element (shorthand for addListener)
5688 * @param {String} eventName The type of event to listen for
5689 * @param {Function} handler The method the event invokes
5690 * @param {Object} scope (optional) The scope in which to execute the handler
5691 * function. The handler function's "this" context.
5692 * @param {Object} options (optional)
5695 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5697 * Removes a listener (shorthand for removeListener)
5698 * @param {String} eventName The type of event to listen for
5699 * @param {Function} handler The handler to remove
5700 * @param {Object} scope (optional) The scope (this object) for the handler
5703 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5706 * Starts capture on the specified Observable. All events will be passed
5707 * to the supplied function with the event name + standard signature of the event
5708 * <b>before</b> the event is fired. If the supplied function returns false,
5709 * the event will not fire.
5710 * @param {Observable} o The Observable to capture
5711 * @param {Function} fn The function to call
5712 * @param {Object} scope (optional) The scope (this object) for the fn
5715 Roo.util.Observable.capture = function(o, fn, scope){
5716 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5720 * Removes <b>all</b> added captures from the Observable.
5721 * @param {Observable} o The Observable to release
5724 Roo.util.Observable.releaseCapture = function(o){
5725 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5730 var createBuffered = function(h, o, scope){
5731 var task = new Roo.util.DelayedTask();
5733 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5737 var createSingle = function(h, e, fn, scope){
5739 e.removeListener(fn, scope);
5740 return h.apply(scope, arguments);
5744 var createDelayed = function(h, o, scope){
5746 var args = Array.prototype.slice.call(arguments, 0);
5747 setTimeout(function(){
5748 h.apply(scope, args);
5753 Roo.util.Event = function(obj, name){
5756 this.listeners = [];
5759 Roo.util.Event.prototype = {
5760 addListener : function(fn, scope, options){
5761 var o = options || {};
5762 scope = scope || this.obj;
5763 if(!this.isListening(fn, scope)){
5764 var l = {fn: fn, scope: scope, options: o};
5767 h = createDelayed(h, o, scope);
5770 h = createSingle(h, this, fn, scope);
5773 h = createBuffered(h, o, scope);
5776 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5777 this.listeners.push(l);
5779 this.listeners = this.listeners.slice(0);
5780 this.listeners.push(l);
5785 findListener : function(fn, scope){
5786 scope = scope || this.obj;
5787 var ls = this.listeners;
5788 for(var i = 0, len = ls.length; i < len; i++){
5790 if(l.fn == fn && l.scope == scope){
5797 isListening : function(fn, scope){
5798 return this.findListener(fn, scope) != -1;
5801 removeListener : function(fn, scope){
5803 if((index = this.findListener(fn, scope)) != -1){
5805 this.listeners.splice(index, 1);
5807 this.listeners = this.listeners.slice(0);
5808 this.listeners.splice(index, 1);
5815 clearListeners : function(){
5816 this.listeners = [];
5820 var ls = this.listeners, scope, len = ls.length;
5823 var args = Array.prototype.slice.call(arguments, 0);
5824 for(var i = 0; i < len; i++){
5826 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5827 this.firing = false;
5831 this.firing = false;
5838 * Ext JS Library 1.1.1
5839 * Copyright(c) 2006-2007, Ext JS, LLC.
5841 * Originally Released Under LGPL - original licence link has changed is not relivant.
5844 * <script type="text/javascript">
5848 * @class Roo.EventManager
5849 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5850 * several useful events directly.
5851 * See {@link Roo.EventObject} for more details on normalized event objects.
5854 Roo.EventManager = function(){
5855 var docReadyEvent, docReadyProcId, docReadyState = false;
5856 var resizeEvent, resizeTask, textEvent, textSize;
5857 var E = Roo.lib.Event;
5858 var D = Roo.lib.Dom;
5861 var fireDocReady = function(){
5863 docReadyState = true;
5866 clearInterval(docReadyProcId);
5868 if(Roo.isGecko || Roo.isOpera) {
5869 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5872 var defer = document.getElementById("ie-deferred-loader");
5874 defer.onreadystatechange = null;
5875 defer.parentNode.removeChild(defer);
5879 docReadyEvent.fire();
5880 docReadyEvent.clearListeners();
5885 var initDocReady = function(){
5886 docReadyEvent = new Roo.util.Event();
5887 if(Roo.isGecko || Roo.isOpera) {
5888 document.addEventListener("DOMContentLoaded", fireDocReady, false);
5890 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5891 var defer = document.getElementById("ie-deferred-loader");
5892 defer.onreadystatechange = function(){
5893 if(this.readyState == "complete"){
5897 }else if(Roo.isSafari){
5898 docReadyProcId = setInterval(function(){
5899 var rs = document.readyState;
5900 if(rs == "complete") {
5905 // no matter what, make sure it fires on load
5906 E.on(window, "load", fireDocReady);
5909 var createBuffered = function(h, o){
5910 var task = new Roo.util.DelayedTask(h);
5912 // create new event object impl so new events don't wipe out properties
5913 e = new Roo.EventObjectImpl(e);
5914 task.delay(o.buffer, h, null, [e]);
5918 var createSingle = function(h, el, ename, fn){
5920 Roo.EventManager.removeListener(el, ename, fn);
5925 var createDelayed = function(h, o){
5927 // create new event object impl so new events don't wipe out properties
5928 e = new Roo.EventObjectImpl(e);
5929 setTimeout(function(){
5935 var listen = function(element, ename, opt, fn, scope){
5936 var o = (!opt || typeof opt == "boolean") ? {} : opt;
5937 fn = fn || o.fn; scope = scope || o.scope;
5938 var el = Roo.getDom(element);
5940 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5942 var h = function(e){
5943 e = Roo.EventObject.setEvent(e);
5946 t = e.getTarget(o.delegate, el);
5953 if(o.stopEvent === true){
5956 if(o.preventDefault === true){
5959 if(o.stopPropagation === true){
5960 e.stopPropagation();
5963 if(o.normalized === false){
5967 fn.call(scope || el, e, t, o);
5970 h = createDelayed(h, o);
5973 h = createSingle(h, el, ename, fn);
5976 h = createBuffered(h, o);
5978 fn._handlers = fn._handlers || [];
5979 fn._handlers.push([Roo.id(el), ename, h]);
5982 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5983 el.addEventListener("DOMMouseScroll", h, false);
5984 E.on(window, 'unload', function(){
5985 el.removeEventListener("DOMMouseScroll", h, false);
5988 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5989 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
5994 var stopListening = function(el, ename, fn){
5995 var id = Roo.id(el), hds = fn._handlers, hd = fn;
5997 for(var i = 0, len = hds.length; i < len; i++){
5999 if(h[0] == id && h[1] == ename){
6006 E.un(el, ename, hd);
6007 el = Roo.getDom(el);
6008 if(ename == "mousewheel" && el.addEventListener){
6009 el.removeEventListener("DOMMouseScroll", hd, false);
6011 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6012 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6016 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6023 * @scope Roo.EventManager
6028 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6029 * object with a Roo.EventObject
6030 * @param {Function} fn The method the event invokes
6031 * @param {Object} scope An object that becomes the scope of the handler
6032 * @param {boolean} override If true, the obj passed in becomes
6033 * the execution scope of the listener
6034 * @return {Function} The wrapped function
6037 wrap : function(fn, scope, override){
6039 Roo.EventObject.setEvent(e);
6040 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6045 * Appends an event handler to an element (shorthand for addListener)
6046 * @param {String/HTMLElement} element The html element or id to assign the
6047 * @param {String} eventName The type of event to listen for
6048 * @param {Function} handler The method the event invokes
6049 * @param {Object} scope (optional) The scope in which to execute the handler
6050 * function. The handler function's "this" context.
6051 * @param {Object} options (optional) An object containing handler configuration
6052 * properties. This may contain any of the following properties:<ul>
6053 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6054 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6055 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6056 * <li>preventDefault {Boolean} True to prevent the default action</li>
6057 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6058 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6059 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6060 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6061 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6062 * by the specified number of milliseconds. If the event fires again within that time, the original
6063 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6066 * <b>Combining Options</b><br>
6067 * Using the options argument, it is possible to combine different types of listeners:<br>
6069 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6071 el.on('click', this.onClick, this, {
6078 * <b>Attaching multiple handlers in 1 call</b><br>
6079 * The method also allows for a single argument to be passed which is a config object containing properties
6080 * which specify multiple handlers.
6090 fn: this.onMouseOver
6099 * Or a shorthand syntax:<br>
6102 'click' : this.onClick,
6103 'mouseover' : this.onMouseOver,
6104 'mouseout' : this.onMouseOut
6108 addListener : function(element, eventName, fn, scope, options){
6109 if(typeof eventName == "object"){
6115 if(typeof o[e] == "function"){
6117 listen(element, e, o, o[e], o.scope);
6119 // individual options
6120 listen(element, e, o[e]);
6125 return listen(element, eventName, options, fn, scope);
6129 * Removes an event handler
6131 * @param {String/HTMLElement} element The id or html element to remove the
6133 * @param {String} eventName The type of event
6134 * @param {Function} fn
6135 * @return {Boolean} True if a listener was actually removed
6137 removeListener : function(element, eventName, fn){
6138 return stopListening(element, eventName, fn);
6142 * Fires when the document is ready (before onload and before images are loaded). Can be
6143 * accessed shorthanded Roo.onReady().
6144 * @param {Function} fn The method the event invokes
6145 * @param {Object} scope An object that becomes the scope of the handler
6146 * @param {boolean} options
6148 onDocumentReady : function(fn, scope, options){
6149 if(docReadyState){ // if it already fired
6150 docReadyEvent.addListener(fn, scope, options);
6151 docReadyEvent.fire();
6152 docReadyEvent.clearListeners();
6158 docReadyEvent.addListener(fn, scope, options);
6162 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6163 * @param {Function} fn The method the event invokes
6164 * @param {Object} scope An object that becomes the scope of the handler
6165 * @param {boolean} options
6167 onWindowResize : function(fn, scope, options){
6169 resizeEvent = new Roo.util.Event();
6170 resizeTask = new Roo.util.DelayedTask(function(){
6171 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6173 E.on(window, "resize", function(){
6175 resizeTask.delay(50);
6177 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6181 resizeEvent.addListener(fn, scope, options);
6185 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6186 * @param {Function} fn The method the event invokes
6187 * @param {Object} scope An object that becomes the scope of the handler
6188 * @param {boolean} options
6190 onTextResize : function(fn, scope, options){
6192 textEvent = new Roo.util.Event();
6193 var textEl = new Roo.Element(document.createElement('div'));
6194 textEl.dom.className = 'x-text-resize';
6195 textEl.dom.innerHTML = 'X';
6196 textEl.appendTo(document.body);
6197 textSize = textEl.dom.offsetHeight;
6198 setInterval(function(){
6199 if(textEl.dom.offsetHeight != textSize){
6200 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6202 }, this.textResizeInterval);
6204 textEvent.addListener(fn, scope, options);
6208 * Removes the passed window resize listener.
6209 * @param {Function} fn The method the event invokes
6210 * @param {Object} scope The scope of handler
6212 removeResizeListener : function(fn, scope){
6214 resizeEvent.removeListener(fn, scope);
6219 fireResize : function(){
6221 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6225 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6229 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6231 textResizeInterval : 50
6236 * @scopeAlias pub=Roo.EventManager
6240 * Appends an event handler to an element (shorthand for addListener)
6241 * @param {String/HTMLElement} element The html element or id to assign the
6242 * @param {String} eventName The type of event to listen for
6243 * @param {Function} handler The method the event invokes
6244 * @param {Object} scope (optional) The scope in which to execute the handler
6245 * function. The handler function's "this" context.
6246 * @param {Object} options (optional) An object containing handler configuration
6247 * properties. This may contain any of the following properties:<ul>
6248 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6249 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6250 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6251 * <li>preventDefault {Boolean} True to prevent the default action</li>
6252 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6253 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6254 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6255 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6256 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6257 * by the specified number of milliseconds. If the event fires again within that time, the original
6258 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6261 * <b>Combining Options</b><br>
6262 * Using the options argument, it is possible to combine different types of listeners:<br>
6264 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6266 el.on('click', this.onClick, this, {
6273 * <b>Attaching multiple handlers in 1 call</b><br>
6274 * The method also allows for a single argument to be passed which is a config object containing properties
6275 * which specify multiple handlers.
6285 fn: this.onMouseOver
6294 * Or a shorthand syntax:<br>
6297 'click' : this.onClick,
6298 'mouseover' : this.onMouseOver,
6299 'mouseout' : this.onMouseOut
6303 pub.on = pub.addListener;
6304 pub.un = pub.removeListener;
6306 pub.stoppedMouseDownEvent = new Roo.util.Event();
6310 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6311 * @param {Function} fn The method the event invokes
6312 * @param {Object} scope An object that becomes the scope of the handler
6313 * @param {boolean} override If true, the obj passed in becomes
6314 * the execution scope of the listener
6318 Roo.onReady = Roo.EventManager.onDocumentReady;
6320 Roo.onReady(function(){
6321 var bd = Roo.get(document.body);
6326 : Roo.isGecko ? "roo-gecko"
6327 : Roo.isOpera ? "roo-opera"
6328 : Roo.isSafari ? "roo-safari" : ""];
6331 cls.push("roo-mac");
6334 cls.push("roo-linux");
6336 if(Roo.isBorderBox){
6337 cls.push('roo-border-box');
6339 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6340 var p = bd.dom.parentNode;
6342 p.className += ' roo-strict';
6345 bd.addClass(cls.join(' '));
6349 * @class Roo.EventObject
6350 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6351 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6354 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6356 var target = e.getTarget();
6359 var myDiv = Roo.get("myDiv");
6360 myDiv.on("click", handleClick);
6362 Roo.EventManager.on("myDiv", 'click', handleClick);
6363 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6367 Roo.EventObject = function(){
6369 var E = Roo.lib.Event;
6371 // safari keypress events for special keys return bad keycodes
6374 63235 : 39, // right
6377 63276 : 33, // page up
6378 63277 : 34, // page down
6379 63272 : 46, // delete
6384 // normalize button clicks
6385 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6386 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6388 Roo.EventObjectImpl = function(e){
6390 this.setEvent(e.browserEvent || e);
6393 Roo.EventObjectImpl.prototype = {
6395 * Used to fix doc tools.
6396 * @scope Roo.EventObject.prototype
6402 /** The normal browser event */
6403 browserEvent : null,
6404 /** The button pressed in a mouse event */
6406 /** True if the shift key was down during the event */
6408 /** True if the control key was down during the event */
6410 /** True if the alt key was down during the event */
6469 setEvent : function(e){
6470 if(e == this || (e && e.browserEvent)){ // already wrapped
6473 this.browserEvent = e;
6475 // normalize buttons
6476 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6477 if(e.type == 'click' && this.button == -1){
6481 this.shiftKey = e.shiftKey;
6482 // mac metaKey behaves like ctrlKey
6483 this.ctrlKey = e.ctrlKey || e.metaKey;
6484 this.altKey = e.altKey;
6485 // in getKey these will be normalized for the mac
6486 this.keyCode = e.keyCode;
6487 // keyup warnings on firefox.
6488 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6489 // cache the target for the delayed and or buffered events
6490 this.target = E.getTarget(e);
6492 this.xy = E.getXY(e);
6495 this.shiftKey = false;
6496 this.ctrlKey = false;
6497 this.altKey = false;
6507 * Stop the event (preventDefault and stopPropagation)
6509 stopEvent : function(){
6510 if(this.browserEvent){
6511 if(this.browserEvent.type == 'mousedown'){
6512 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6514 E.stopEvent(this.browserEvent);
6519 * Prevents the browsers default handling of the event.
6521 preventDefault : function(){
6522 if(this.browserEvent){
6523 E.preventDefault(this.browserEvent);
6528 isNavKeyPress : function(){
6529 var k = this.keyCode;
6530 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6531 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6534 isSpecialKey : function(){
6535 var k = this.keyCode;
6536 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6537 (k == 16) || (k == 17) ||
6538 (k >= 18 && k <= 20) ||
6539 (k >= 33 && k <= 35) ||
6540 (k >= 36 && k <= 39) ||
6541 (k >= 44 && k <= 45);
6544 * Cancels bubbling of the event.
6546 stopPropagation : function(){
6547 if(this.browserEvent){
6548 if(this.type == 'mousedown'){
6549 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6551 E.stopPropagation(this.browserEvent);
6556 * Gets the key code for the event.
6559 getCharCode : function(){
6560 return this.charCode || this.keyCode;
6564 * Returns a normalized keyCode for the event.
6565 * @return {Number} The key code
6567 getKey : function(){
6568 var k = this.keyCode || this.charCode;
6569 return Roo.isSafari ? (safariKeys[k] || k) : k;
6573 * Gets the x coordinate of the event.
6576 getPageX : function(){
6581 * Gets the y coordinate of the event.
6584 getPageY : function(){
6589 * Gets the time of the event.
6592 getTime : function(){
6593 if(this.browserEvent){
6594 return E.getTime(this.browserEvent);
6600 * Gets the page coordinates of the event.
6601 * @return {Array} The xy values like [x, y]
6608 * Gets the target for the event.
6609 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6610 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6611 search as a number or element (defaults to 10 || document.body)
6612 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6613 * @return {HTMLelement}
6615 getTarget : function(selector, maxDepth, returnEl){
6616 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6619 * Gets the related target.
6620 * @return {HTMLElement}
6622 getRelatedTarget : function(){
6623 if(this.browserEvent){
6624 return E.getRelatedTarget(this.browserEvent);
6630 * Normalizes mouse wheel delta across browsers
6631 * @return {Number} The delta
6633 getWheelDelta : function(){
6634 var e = this.browserEvent;
6636 if(e.wheelDelta){ /* IE/Opera. */
6637 delta = e.wheelDelta/120;
6638 }else if(e.detail){ /* Mozilla case. */
6639 delta = -e.detail/3;
6645 * Returns true if the control, meta, shift or alt key was pressed during this event.
6648 hasModifier : function(){
6649 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6653 * Returns true if the target of this event equals el or is a child of el
6654 * @param {String/HTMLElement/Element} el
6655 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6658 within : function(el, related){
6659 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6660 return t && Roo.fly(el).contains(t);
6663 getPoint : function(){
6664 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6668 return new Roo.EventObjectImpl();
6673 * Ext JS Library 1.1.1
6674 * Copyright(c) 2006-2007, Ext JS, LLC.
6676 * Originally Released Under LGPL - original licence link has changed is not relivant.
6679 * <script type="text/javascript">
6683 // was in Composite Element!??!?!
6686 var D = Roo.lib.Dom;
6687 var E = Roo.lib.Event;
6688 var A = Roo.lib.Anim;
6690 // local style camelizing for speed
6692 var camelRe = /(-[a-z])/gi;
6693 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6694 var view = document.defaultView;
6697 * @class Roo.Element
6698 * Represents an Element in the DOM.<br><br>
6701 var el = Roo.get("my-div");
6704 var el = getEl("my-div");
6706 // or with a DOM element
6707 var el = Roo.get(myDivElement);
6709 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6710 * each call instead of constructing a new one.<br><br>
6711 * <b>Animations</b><br />
6712 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6713 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6715 Option Default Description
6716 --------- -------- ---------------------------------------------
6717 duration .35 The duration of the animation in seconds
6718 easing easeOut The YUI easing method
6719 callback none A function to execute when the anim completes
6720 scope this The scope (this) of the callback function
6722 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6723 * manipulate the animation. Here's an example:
6725 var el = Roo.get("my-div");
6730 // default animation
6731 el.setWidth(100, true);
6733 // animation with some options set
6740 // using the "anim" property to get the Anim object
6746 el.setWidth(100, opt);
6748 if(opt.anim.isAnimated()){
6752 * <b> Composite (Collections of) Elements</b><br />
6753 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6754 * @constructor Create a new Element directly.
6755 * @param {String/HTMLElement} element
6756 * @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).
6758 Roo.Element = function(element, forceNew){
6759 var dom = typeof element == "string" ?
6760 document.getElementById(element) : element;
6761 if(!dom){ // invalid id/element
6765 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6766 return Roo.Element.cache[id];
6776 * The DOM element ID
6779 this.id = id || Roo.id(dom);
6782 var El = Roo.Element;
6786 * The element's default display mode (defaults to "")
6789 originalDisplay : "",
6793 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6798 * Sets the element's visibility mode. When setVisible() is called it
6799 * will use this to determine whether to set the visibility or the display property.
6800 * @param visMode Element.VISIBILITY or Element.DISPLAY
6801 * @return {Roo.Element} this
6803 setVisibilityMode : function(visMode){
6804 this.visibilityMode = visMode;
6808 * Convenience method for setVisibilityMode(Element.DISPLAY)
6809 * @param {String} display (optional) What to set display to when visible
6810 * @return {Roo.Element} this
6812 enableDisplayMode : function(display){
6813 this.setVisibilityMode(El.DISPLAY);
6814 if(typeof display != "undefined") this.originalDisplay = display;
6819 * 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)
6820 * @param {String} selector The simple selector to test
6821 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6822 search as a number or element (defaults to 10 || document.body)
6823 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6824 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6826 findParent : function(simpleSelector, maxDepth, returnEl){
6827 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6828 maxDepth = maxDepth || 50;
6829 if(typeof maxDepth != "number"){
6830 stopEl = Roo.getDom(maxDepth);
6833 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6834 if(dq.is(p, simpleSelector)){
6835 return returnEl ? Roo.get(p) : p;
6845 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6846 * @param {String} selector The simple selector to test
6847 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6848 search as a number or element (defaults to 10 || document.body)
6849 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6850 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6852 findParentNode : function(simpleSelector, maxDepth, returnEl){
6853 var p = Roo.fly(this.dom.parentNode, '_internal');
6854 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6858 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6859 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6860 * @param {String} selector The simple selector to test
6861 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6862 search as a number or element (defaults to 10 || document.body)
6863 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6865 up : function(simpleSelector, maxDepth){
6866 return this.findParentNode(simpleSelector, maxDepth, true);
6872 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6873 * @param {String} selector The simple selector to test
6874 * @return {Boolean} True if this element matches the selector, else false
6876 is : function(simpleSelector){
6877 return Roo.DomQuery.is(this.dom, simpleSelector);
6881 * Perform animation on this element.
6882 * @param {Object} args The YUI animation control args
6883 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6884 * @param {Function} onComplete (optional) Function to call when animation completes
6885 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6886 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6887 * @return {Roo.Element} this
6889 animate : function(args, duration, onComplete, easing, animType){
6890 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6895 * @private Internal animation call
6897 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6898 animType = animType || 'run';
6900 var anim = Roo.lib.Anim[animType](
6902 (opt.duration || defaultDur) || .35,
6903 (opt.easing || defaultEase) || 'easeOut',
6905 Roo.callback(cb, this);
6906 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6914 // private legacy anim prep
6915 preanim : function(a, i){
6916 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6920 * Removes worthless text nodes
6921 * @param {Boolean} forceReclean (optional) By default the element
6922 * keeps track if it has been cleaned already so
6923 * you can call this over and over. However, if you update the element and
6924 * need to force a reclean, you can pass true.
6926 clean : function(forceReclean){
6927 if(this.isCleaned && forceReclean !== true){
6931 var d = this.dom, n = d.firstChild, ni = -1;
6933 var nx = n.nextSibling;
6934 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6941 this.isCleaned = true;
6946 calcOffsetsTo : function(el){
6949 var restorePos = false;
6950 if(el.getStyle('position') == 'static'){
6951 el.position('relative');
6956 while(op && op != d && op.tagName != 'HTML'){
6959 op = op.offsetParent;
6962 el.position('static');
6968 * Scrolls this element into view within the passed container.
6969 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6970 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6971 * @return {Roo.Element} this
6973 scrollIntoView : function(container, hscroll){
6974 var c = Roo.getDom(container) || document.body;
6977 var o = this.calcOffsetsTo(c),
6980 b = t+el.offsetHeight,
6981 r = l+el.offsetWidth;
6983 var ch = c.clientHeight;
6984 var ct = parseInt(c.scrollTop, 10);
6985 var cl = parseInt(c.scrollLeft, 10);
6987 var cr = cl + c.clientWidth;
6995 if(hscroll !== false){
6999 c.scrollLeft = r-c.clientWidth;
7006 scrollChildIntoView : function(child, hscroll){
7007 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7011 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7012 * the new height may not be available immediately.
7013 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7014 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7015 * @param {Function} onComplete (optional) Function to call when animation completes
7016 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7017 * @return {Roo.Element} this
7019 autoHeight : function(animate, duration, onComplete, easing){
7020 var oldHeight = this.getHeight();
7022 this.setHeight(1); // force clipping
7023 setTimeout(function(){
7024 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7026 this.setHeight(height);
7028 if(typeof onComplete == "function"){
7032 this.setHeight(oldHeight); // restore original height
7033 this.setHeight(height, animate, duration, function(){
7035 if(typeof onComplete == "function") onComplete();
7036 }.createDelegate(this), easing);
7038 }.createDelegate(this), 0);
7043 * Returns true if this element is an ancestor of the passed element
7044 * @param {HTMLElement/String} el The element to check
7045 * @return {Boolean} True if this element is an ancestor of el, else false
7047 contains : function(el){
7048 if(!el){return false;}
7049 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7053 * Checks whether the element is currently visible using both visibility and display properties.
7054 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7055 * @return {Boolean} True if the element is currently visible, else false
7057 isVisible : function(deep) {
7058 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7059 if(deep !== true || !vis){
7062 var p = this.dom.parentNode;
7063 while(p && p.tagName.toLowerCase() != "body"){
7064 if(!Roo.fly(p, '_isVisible').isVisible()){
7073 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7074 * @param {String} selector The CSS selector
7075 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7076 * @return {CompositeElement/CompositeElementLite} The composite element
7078 select : function(selector, unique){
7079 return El.select(selector, unique, this.dom);
7083 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7084 * @param {String} selector The CSS selector
7085 * @return {Array} An array of the matched nodes
7087 query : function(selector, unique){
7088 return Roo.DomQuery.select(selector, this.dom);
7092 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7093 * @param {String} selector The CSS selector
7094 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7095 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7097 child : function(selector, returnDom){
7098 var n = Roo.DomQuery.selectNode(selector, this.dom);
7099 return returnDom ? n : Roo.get(n);
7103 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7104 * @param {String} selector The CSS selector
7105 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7106 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7108 down : function(selector, returnDom){
7109 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7110 return returnDom ? n : Roo.get(n);
7114 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7115 * @param {String} group The group the DD object is member of
7116 * @param {Object} config The DD config object
7117 * @param {Object} overrides An object containing methods to override/implement on the DD object
7118 * @return {Roo.dd.DD} The DD object
7120 initDD : function(group, config, overrides){
7121 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7122 return Roo.apply(dd, overrides);
7126 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7127 * @param {String} group The group the DDProxy object is member of
7128 * @param {Object} config The DDProxy config object
7129 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7130 * @return {Roo.dd.DDProxy} The DDProxy object
7132 initDDProxy : function(group, config, overrides){
7133 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7134 return Roo.apply(dd, overrides);
7138 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7139 * @param {String} group The group the DDTarget object is member of
7140 * @param {Object} config The DDTarget config object
7141 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7142 * @return {Roo.dd.DDTarget} The DDTarget object
7144 initDDTarget : function(group, config, overrides){
7145 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7146 return Roo.apply(dd, overrides);
7150 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7151 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7152 * @param {Boolean} visible Whether the element is visible
7153 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7154 * @return {Roo.Element} this
7156 setVisible : function(visible, animate){
7158 if(this.visibilityMode == El.DISPLAY){
7159 this.setDisplayed(visible);
7162 this.dom.style.visibility = visible ? "visible" : "hidden";
7165 // closure for composites
7167 var visMode = this.visibilityMode;
7169 this.setOpacity(.01);
7170 this.setVisible(true);
7172 this.anim({opacity: { to: (visible?1:0) }},
7173 this.preanim(arguments, 1),
7174 null, .35, 'easeIn', function(){
7176 if(visMode == El.DISPLAY){
7177 dom.style.display = "none";
7179 dom.style.visibility = "hidden";
7181 Roo.get(dom).setOpacity(1);
7189 * Returns true if display is not "none"
7192 isDisplayed : function() {
7193 return this.getStyle("display") != "none";
7197 * Toggles the element's visibility or display, depending on visibility mode.
7198 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7199 * @return {Roo.Element} this
7201 toggle : function(animate){
7202 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7207 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7208 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7209 * @return {Roo.Element} this
7211 setDisplayed : function(value) {
7212 if(typeof value == "boolean"){
7213 value = value ? this.originalDisplay : "none";
7215 this.setStyle("display", value);
7220 * Tries to focus the element. Any exceptions are caught and ignored.
7221 * @return {Roo.Element} this
7223 focus : function() {
7231 * Tries to blur the element. Any exceptions are caught and ignored.
7232 * @return {Roo.Element} this
7242 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7243 * @param {String/Array} className The CSS class to add, or an array of classes
7244 * @return {Roo.Element} this
7246 addClass : function(className){
7247 if(className instanceof Array){
7248 for(var i = 0, len = className.length; i < len; i++) {
7249 this.addClass(className[i]);
7252 if(className && !this.hasClass(className)){
7253 this.dom.className = this.dom.className + " " + className;
7260 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7261 * @param {String/Array} className The CSS class to add, or an array of classes
7262 * @return {Roo.Element} this
7264 radioClass : function(className){
7265 var siblings = this.dom.parentNode.childNodes;
7266 for(var i = 0; i < siblings.length; i++) {
7267 var s = siblings[i];
7268 if(s.nodeType == 1){
7269 Roo.get(s).removeClass(className);
7272 this.addClass(className);
7277 * Removes one or more CSS classes from the element.
7278 * @param {String/Array} className The CSS class to remove, or an array of classes
7279 * @return {Roo.Element} this
7281 removeClass : function(className){
7282 if(!className || !this.dom.className){
7285 if(className instanceof Array){
7286 for(var i = 0, len = className.length; i < len; i++) {
7287 this.removeClass(className[i]);
7290 if(this.hasClass(className)){
7291 var re = this.classReCache[className];
7293 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7294 this.classReCache[className] = re;
7296 this.dom.className =
7297 this.dom.className.replace(re, " ");
7307 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7308 * @param {String} className The CSS class to toggle
7309 * @return {Roo.Element} this
7311 toggleClass : function(className){
7312 if(this.hasClass(className)){
7313 this.removeClass(className);
7315 this.addClass(className);
7321 * Checks if the specified CSS class exists on this element's DOM node.
7322 * @param {String} className The CSS class to check for
7323 * @return {Boolean} True if the class exists, else false
7325 hasClass : function(className){
7326 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7330 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7331 * @param {String} oldClassName The CSS class to replace
7332 * @param {String} newClassName The replacement CSS class
7333 * @return {Roo.Element} this
7335 replaceClass : function(oldClassName, newClassName){
7336 this.removeClass(oldClassName);
7337 this.addClass(newClassName);
7342 * Returns an object with properties matching the styles requested.
7343 * For example, el.getStyles('color', 'font-size', 'width') might return
7344 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7345 * @param {String} style1 A style name
7346 * @param {String} style2 A style name
7347 * @param {String} etc.
7348 * @return {Object} The style object
7350 getStyles : function(){
7351 var a = arguments, len = a.length, r = {};
7352 for(var i = 0; i < len; i++){
7353 r[a[i]] = this.getStyle(a[i]);
7359 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7360 * @param {String} property The style property whose value is returned.
7361 * @return {String} The current value of the style property for this element.
7363 getStyle : function(){
7364 return view && view.getComputedStyle ?
7366 var el = this.dom, v, cs, camel;
7367 if(prop == 'float'){
7370 if(el.style && (v = el.style[prop])){
7373 if(cs = view.getComputedStyle(el, "")){
7374 if(!(camel = propCache[prop])){
7375 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7382 var el = this.dom, v, cs, camel;
7383 if(prop == 'opacity'){
7384 if(typeof el.style.filter == 'string'){
7385 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7387 var fv = parseFloat(m[1]);
7389 return fv ? fv / 100 : 0;
7394 }else if(prop == 'float'){
7395 prop = "styleFloat";
7397 if(!(camel = propCache[prop])){
7398 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7400 if(v = el.style[camel]){
7403 if(cs = el.currentStyle){
7411 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7412 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7413 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7414 * @return {Roo.Element} this
7416 setStyle : function(prop, value){
7417 if(typeof prop == "string"){
7419 if (prop == 'float') {
7420 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7425 if(!(camel = propCache[prop])){
7426 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7429 if(camel == 'opacity') {
7430 this.setOpacity(value);
7432 this.dom.style[camel] = value;
7435 for(var style in prop){
7436 if(typeof prop[style] != "function"){
7437 this.setStyle(style, prop[style]);
7445 * More flexible version of {@link #setStyle} for setting style properties.
7446 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7447 * a function which returns such a specification.
7448 * @return {Roo.Element} this
7450 applyStyles : function(style){
7451 Roo.DomHelper.applyStyles(this.dom, style);
7456 * 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).
7457 * @return {Number} The X position of the element
7460 return D.getX(this.dom);
7464 * 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).
7465 * @return {Number} The Y position of the element
7468 return D.getY(this.dom);
7472 * 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).
7473 * @return {Array} The XY position of the element
7476 return D.getXY(this.dom);
7480 * 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).
7481 * @param {Number} The X position of the element
7482 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7483 * @return {Roo.Element} this
7485 setX : function(x, animate){
7487 D.setX(this.dom, x);
7489 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7495 * 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).
7496 * @param {Number} The Y position of the element
7497 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7498 * @return {Roo.Element} this
7500 setY : function(y, animate){
7502 D.setY(this.dom, y);
7504 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7510 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7511 * @param {String} left The left CSS property value
7512 * @return {Roo.Element} this
7514 setLeft : function(left){
7515 this.setStyle("left", this.addUnits(left));
7520 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7521 * @param {String} top The top CSS property value
7522 * @return {Roo.Element} this
7524 setTop : function(top){
7525 this.setStyle("top", this.addUnits(top));
7530 * Sets the element's CSS right style.
7531 * @param {String} right The right CSS property value
7532 * @return {Roo.Element} this
7534 setRight : function(right){
7535 this.setStyle("right", this.addUnits(right));
7540 * Sets the element's CSS bottom style.
7541 * @param {String} bottom The bottom CSS property value
7542 * @return {Roo.Element} this
7544 setBottom : function(bottom){
7545 this.setStyle("bottom", this.addUnits(bottom));
7550 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7551 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7552 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7553 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7554 * @return {Roo.Element} this
7556 setXY : function(pos, animate){
7558 D.setXY(this.dom, pos);
7560 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7566 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7567 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7568 * @param {Number} x X value for new position (coordinates are page-based)
7569 * @param {Number} y Y value for new position (coordinates are page-based)
7570 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7571 * @return {Roo.Element} this
7573 setLocation : function(x, y, animate){
7574 this.setXY([x, y], this.preanim(arguments, 2));
7579 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7580 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7581 * @param {Number} x X value for new position (coordinates are page-based)
7582 * @param {Number} y Y value for new position (coordinates are page-based)
7583 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7584 * @return {Roo.Element} this
7586 moveTo : function(x, y, animate){
7587 this.setXY([x, y], this.preanim(arguments, 2));
7592 * Returns the region of the given element.
7593 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7594 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7596 getRegion : function(){
7597 return D.getRegion(this.dom);
7601 * Returns the offset height of the element
7602 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7603 * @return {Number} The element's height
7605 getHeight : function(contentHeight){
7606 var h = this.dom.offsetHeight || 0;
7607 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7611 * Returns the offset width of the element
7612 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7613 * @return {Number} The element's width
7615 getWidth : function(contentWidth){
7616 var w = this.dom.offsetWidth || 0;
7617 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7621 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7622 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7623 * if a height has not been set using CSS.
7626 getComputedHeight : function(){
7627 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7629 h = parseInt(this.getStyle('height'), 10) || 0;
7630 if(!this.isBorderBox()){
7631 h += this.getFrameWidth('tb');
7638 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7639 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7640 * if a width has not been set using CSS.
7643 getComputedWidth : function(){
7644 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7646 w = parseInt(this.getStyle('width'), 10) || 0;
7647 if(!this.isBorderBox()){
7648 w += this.getFrameWidth('lr');
7655 * Returns the size of the element.
7656 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7657 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7659 getSize : function(contentSize){
7660 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7664 * Returns the width and height of the viewport.
7665 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7667 getViewSize : function(){
7668 var d = this.dom, doc = document, aw = 0, ah = 0;
7669 if(d == doc || d == doc.body){
7670 return {width : D.getViewWidth(), height: D.getViewHeight()};
7673 width : d.clientWidth,
7674 height: d.clientHeight
7680 * Returns the value of the "value" attribute
7681 * @param {Boolean} asNumber true to parse the value as a number
7682 * @return {String/Number}
7684 getValue : function(asNumber){
7685 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7689 adjustWidth : function(width){
7690 if(typeof width == "number"){
7691 if(this.autoBoxAdjust && !this.isBorderBox()){
7692 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7702 adjustHeight : function(height){
7703 if(typeof height == "number"){
7704 if(this.autoBoxAdjust && !this.isBorderBox()){
7705 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7715 * Set the width of the element
7716 * @param {Number} width The new width
7717 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7718 * @return {Roo.Element} this
7720 setWidth : function(width, animate){
7721 width = this.adjustWidth(width);
7723 this.dom.style.width = this.addUnits(width);
7725 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7731 * Set the height of the element
7732 * @param {Number} height The new height
7733 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7734 * @return {Roo.Element} this
7736 setHeight : function(height, animate){
7737 height = this.adjustHeight(height);
7739 this.dom.style.height = this.addUnits(height);
7741 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7747 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7748 * @param {Number} width The new width
7749 * @param {Number} height The new height
7750 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7751 * @return {Roo.Element} this
7753 setSize : function(width, height, animate){
7754 if(typeof width == "object"){ // in case of object from getSize()
7755 height = width.height; width = width.width;
7757 width = this.adjustWidth(width); height = this.adjustHeight(height);
7759 this.dom.style.width = this.addUnits(width);
7760 this.dom.style.height = this.addUnits(height);
7762 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7768 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7769 * @param {Number} x X value for new position (coordinates are page-based)
7770 * @param {Number} y Y value for new position (coordinates are page-based)
7771 * @param {Number} width The new width
7772 * @param {Number} height The new height
7773 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7774 * @return {Roo.Element} this
7776 setBounds : function(x, y, width, height, animate){
7778 this.setSize(width, height);
7779 this.setLocation(x, y);
7781 width = this.adjustWidth(width); height = this.adjustHeight(height);
7782 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7783 this.preanim(arguments, 4), 'motion');
7789 * 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.
7790 * @param {Roo.lib.Region} region The region to fill
7791 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7792 * @return {Roo.Element} this
7794 setRegion : function(region, animate){
7795 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7800 * Appends an event handler
7802 * @param {String} eventName The type of event to append
7803 * @param {Function} fn The method the event invokes
7804 * @param {Object} scope (optional) The scope (this object) of the fn
7805 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7807 addListener : function(eventName, fn, scope, options){
7808 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7812 * Removes an event handler from this element
7813 * @param {String} eventName the type of event to remove
7814 * @param {Function} fn the method the event invokes
7815 * @return {Roo.Element} this
7817 removeListener : function(eventName, fn){
7818 Roo.EventManager.removeListener(this.dom, eventName, fn);
7823 * Removes all previous added listeners from this element
7824 * @return {Roo.Element} this
7826 removeAllListeners : function(){
7827 E.purgeElement(this.dom);
7831 relayEvent : function(eventName, observable){
7832 this.on(eventName, function(e){
7833 observable.fireEvent(eventName, e);
7838 * Set the opacity of the element
7839 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7840 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7841 * @return {Roo.Element} this
7843 setOpacity : function(opacity, animate){
7845 var s = this.dom.style;
7848 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7849 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7851 s.opacity = opacity;
7854 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7860 * Gets the left X coordinate
7861 * @param {Boolean} local True to get the local css position instead of page coordinate
7864 getLeft : function(local){
7868 return parseInt(this.getStyle("left"), 10) || 0;
7873 * Gets the right X coordinate of the element (element X position + element width)
7874 * @param {Boolean} local True to get the local css position instead of page coordinate
7877 getRight : function(local){
7879 return this.getX() + this.getWidth();
7881 return (this.getLeft(true) + this.getWidth()) || 0;
7886 * Gets the top Y coordinate
7887 * @param {Boolean} local True to get the local css position instead of page coordinate
7890 getTop : function(local) {
7894 return parseInt(this.getStyle("top"), 10) || 0;
7899 * Gets the bottom Y coordinate of the element (element Y position + element height)
7900 * @param {Boolean} local True to get the local css position instead of page coordinate
7903 getBottom : function(local){
7905 return this.getY() + this.getHeight();
7907 return (this.getTop(true) + this.getHeight()) || 0;
7912 * Initializes positioning on this element. If a desired position is not passed, it will make the
7913 * the element positioned relative IF it is not already positioned.
7914 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7915 * @param {Number} zIndex (optional) The zIndex to apply
7916 * @param {Number} x (optional) Set the page X position
7917 * @param {Number} y (optional) Set the page Y position
7919 position : function(pos, zIndex, x, y){
7921 if(this.getStyle('position') == 'static'){
7922 this.setStyle('position', 'relative');
7925 this.setStyle("position", pos);
7928 this.setStyle("z-index", zIndex);
7930 if(x !== undefined && y !== undefined){
7932 }else if(x !== undefined){
7934 }else if(y !== undefined){
7940 * Clear positioning back to the default when the document was loaded
7941 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7942 * @return {Roo.Element} this
7944 clearPositioning : function(value){
7952 "position" : "static"
7958 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7959 * snapshot before performing an update and then restoring the element.
7962 getPositioning : function(){
7963 var l = this.getStyle("left");
7964 var t = this.getStyle("top");
7966 "position" : this.getStyle("position"),
7968 "right" : l ? "" : this.getStyle("right"),
7970 "bottom" : t ? "" : this.getStyle("bottom"),
7971 "z-index" : this.getStyle("z-index")
7976 * Gets the width of the border(s) for the specified side(s)
7977 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7978 * passing lr would get the border (l)eft width + the border (r)ight width.
7979 * @return {Number} The width of the sides passed added together
7981 getBorderWidth : function(side){
7982 return this.addStyles(side, El.borders);
7986 * Gets the width of the padding(s) for the specified side(s)
7987 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7988 * passing lr would get the padding (l)eft + the padding (r)ight.
7989 * @return {Number} The padding of the sides passed added together
7991 getPadding : function(side){
7992 return this.addStyles(side, El.paddings);
7996 * Set positioning with an object returned by getPositioning().
7997 * @param {Object} posCfg
7998 * @return {Roo.Element} this
8000 setPositioning : function(pc){
8001 this.applyStyles(pc);
8002 if(pc.right == "auto"){
8003 this.dom.style.right = "";
8005 if(pc.bottom == "auto"){
8006 this.dom.style.bottom = "";
8012 fixDisplay : function(){
8013 if(this.getStyle("display") == "none"){
8014 this.setStyle("visibility", "hidden");
8015 this.setStyle("display", this.originalDisplay); // first try reverting to default
8016 if(this.getStyle("display") == "none"){ // if that fails, default to block
8017 this.setStyle("display", "block");
8023 * Quick set left and top adding default units
8024 * @param {String} left The left CSS property value
8025 * @param {String} top The top CSS property value
8026 * @return {Roo.Element} this
8028 setLeftTop : function(left, top){
8029 this.dom.style.left = this.addUnits(left);
8030 this.dom.style.top = this.addUnits(top);
8035 * Move this element relative to its current position.
8036 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8037 * @param {Number} distance How far to move the element in pixels
8038 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8039 * @return {Roo.Element} this
8041 move : function(direction, distance, animate){
8042 var xy = this.getXY();
8043 direction = direction.toLowerCase();
8047 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8051 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8056 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8061 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8068 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8069 * @return {Roo.Element} this
8072 if(!this.isClipped){
8073 this.isClipped = true;
8074 this.originalClip = {
8075 "o": this.getStyle("overflow"),
8076 "x": this.getStyle("overflow-x"),
8077 "y": this.getStyle("overflow-y")
8079 this.setStyle("overflow", "hidden");
8080 this.setStyle("overflow-x", "hidden");
8081 this.setStyle("overflow-y", "hidden");
8087 * Return clipping (overflow) to original clipping before clip() was called
8088 * @return {Roo.Element} this
8090 unclip : function(){
8092 this.isClipped = false;
8093 var o = this.originalClip;
8094 if(o.o){this.setStyle("overflow", o.o);}
8095 if(o.x){this.setStyle("overflow-x", o.x);}
8096 if(o.y){this.setStyle("overflow-y", o.y);}
8103 * Gets the x,y coordinates specified by the anchor position on the element.
8104 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8105 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8106 * {width: (target width), height: (target height)} (defaults to the element's current size)
8107 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8108 * @return {Array} [x, y] An array containing the element's x and y coordinates
8110 getAnchorXY : function(anchor, local, s){
8111 //Passing a different size is useful for pre-calculating anchors,
8112 //especially for anchored animations that change the el size.
8114 var w, h, vp = false;
8117 if(d == document.body || d == document){
8119 w = D.getViewWidth(); h = D.getViewHeight();
8121 w = this.getWidth(); h = this.getHeight();
8124 w = s.width; h = s.height;
8126 var x = 0, y = 0, r = Math.round;
8127 switch((anchor || "tl").toLowerCase()){
8169 var sc = this.getScroll();
8170 return [x + sc.left, y + sc.top];
8172 //Add the element's offset xy
8173 var o = this.getXY();
8174 return [x+o[0], y+o[1]];
8178 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8179 * supported position values.
8180 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8181 * @param {String} position The position to align to.
8182 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8183 * @return {Array} [x, y]
8185 getAlignToXY : function(el, p, o){
8189 throw "Element.alignTo with an element that doesn't exist";
8191 var c = false; //constrain to viewport
8192 var p1 = "", p2 = "";
8199 }else if(p.indexOf("-") == -1){
8202 p = p.toLowerCase();
8203 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8205 throw "Element.alignTo with an invalid alignment " + p;
8207 p1 = m[1]; p2 = m[2]; c = !!m[3];
8209 //Subtract the aligned el's internal xy from the target's offset xy
8210 //plus custom offset to get the aligned el's new offset xy
8211 var a1 = this.getAnchorXY(p1, true);
8212 var a2 = el.getAnchorXY(p2, false);
8213 var x = a2[0] - a1[0] + o[0];
8214 var y = a2[1] - a1[1] + o[1];
8216 //constrain the aligned el to viewport if necessary
8217 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8218 // 5px of margin for ie
8219 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8221 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8222 //perpendicular to the vp border, allow the aligned el to slide on that border,
8223 //otherwise swap the aligned el to the opposite border of the target.
8224 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8225 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8226 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8227 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8230 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8231 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8233 if((x+w) > dw + scrollX){
8234 x = swapX ? r.left-w : dw+scrollX-w;
8237 x = swapX ? r.right : scrollX;
8239 if((y+h) > dh + scrollY){
8240 y = swapY ? r.top-h : dh+scrollY-h;
8243 y = swapY ? r.bottom : scrollY;
8250 getConstrainToXY : function(){
8251 var os = {top:0, left:0, bottom:0, right: 0};
8253 return function(el, local, offsets, proposedXY){
8255 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8257 var vw, vh, vx = 0, vy = 0;
8258 if(el.dom == document.body || el.dom == document){
8259 vw = Roo.lib.Dom.getViewWidth();
8260 vh = Roo.lib.Dom.getViewHeight();
8262 vw = el.dom.clientWidth;
8263 vh = el.dom.clientHeight;
8265 var vxy = el.getXY();
8271 var s = el.getScroll();
8273 vx += offsets.left + s.left;
8274 vy += offsets.top + s.top;
8276 vw -= offsets.right;
8277 vh -= offsets.bottom;
8282 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8283 var x = xy[0], y = xy[1];
8284 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8286 // only move it if it needs it
8289 // first validate right/bottom
8298 // then make sure top/left isn't negative
8307 return moved ? [x, y] : false;
8312 adjustForConstraints : function(xy, parent, offsets){
8313 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8317 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8318 * document it aligns it to the viewport.
8319 * The position parameter is optional, and can be specified in any one of the following formats:
8321 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8322 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8323 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8324 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8325 * <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
8326 * element's anchor point, and the second value is used as the target's anchor point.</li>
8328 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8329 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8330 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8331 * that specified in order to enforce the viewport constraints.
8332 * Following are all of the supported anchor positions:
8335 ----- -----------------------------
8336 tl The top left corner (default)
8337 t The center of the top edge
8338 tr The top right corner
8339 l The center of the left edge
8340 c In the center of the element
8341 r The center of the right edge
8342 bl The bottom left corner
8343 b The center of the bottom edge
8344 br The bottom right corner
8348 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8349 el.alignTo("other-el");
8351 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8352 el.alignTo("other-el", "tr?");
8354 // align the bottom right corner of el with the center left edge of other-el
8355 el.alignTo("other-el", "br-l?");
8357 // align the center of el with the bottom left corner of other-el and
8358 // adjust the x position by -6 pixels (and the y position by 0)
8359 el.alignTo("other-el", "c-bl", [-6, 0]);
8361 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8362 * @param {String} position The position to align to.
8363 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8364 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8365 * @return {Roo.Element} this
8367 alignTo : function(element, position, offsets, animate){
8368 var xy = this.getAlignToXY(element, position, offsets);
8369 this.setXY(xy, this.preanim(arguments, 3));
8374 * Anchors an element to another element and realigns it when the window is resized.
8375 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8376 * @param {String} position The position to align to.
8377 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8378 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8379 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8380 * is a number, it is used as the buffer delay (defaults to 50ms).
8381 * @param {Function} callback The function to call after the animation finishes
8382 * @return {Roo.Element} this
8384 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8385 var action = function(){
8386 this.alignTo(el, alignment, offsets, animate);
8387 Roo.callback(callback, this);
8389 Roo.EventManager.onWindowResize(action, this);
8390 var tm = typeof monitorScroll;
8391 if(tm != 'undefined'){
8392 Roo.EventManager.on(window, 'scroll', action, this,
8393 {buffer: tm == 'number' ? monitorScroll : 50});
8395 action.call(this); // align immediately
8399 * Clears any opacity settings from this element. Required in some cases for IE.
8400 * @return {Roo.Element} this
8402 clearOpacity : function(){
8403 if (window.ActiveXObject) {
8404 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8405 this.dom.style.filter = "";
8408 this.dom.style.opacity = "";
8409 this.dom.style["-moz-opacity"] = "";
8410 this.dom.style["-khtml-opacity"] = "";
8416 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8417 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8418 * @return {Roo.Element} this
8420 hide : function(animate){
8421 this.setVisible(false, this.preanim(arguments, 0));
8426 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8427 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8428 * @return {Roo.Element} this
8430 show : function(animate){
8431 this.setVisible(true, this.preanim(arguments, 0));
8436 * @private Test if size has a unit, otherwise appends the default
8438 addUnits : function(size){
8439 return Roo.Element.addUnits(size, this.defaultUnit);
8443 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8444 * @return {Roo.Element} this
8446 beginMeasure : function(){
8448 if(el.offsetWidth || el.offsetHeight){
8449 return this; // offsets work already
8452 var p = this.dom, b = document.body; // start with this element
8453 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8454 var pe = Roo.get(p);
8455 if(pe.getStyle('display') == 'none'){
8456 changed.push({el: p, visibility: pe.getStyle("visibility")});
8457 p.style.visibility = "hidden";
8458 p.style.display = "block";
8462 this._measureChanged = changed;
8468 * Restores displays to before beginMeasure was called
8469 * @return {Roo.Element} this
8471 endMeasure : function(){
8472 var changed = this._measureChanged;
8474 for(var i = 0, len = changed.length; i < len; i++) {
8476 r.el.style.visibility = r.visibility;
8477 r.el.style.display = "none";
8479 this._measureChanged = null;
8485 * Update the innerHTML of this element, optionally searching for and processing scripts
8486 * @param {String} html The new HTML
8487 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8488 * @param {Function} callback For async script loading you can be noticed when the update completes
8489 * @return {Roo.Element} this
8491 update : function(html, loadScripts, callback){
8492 if(typeof html == "undefined"){
8495 if(loadScripts !== true){
8496 this.dom.innerHTML = html;
8497 if(typeof callback == "function"){
8505 html += '<span id="' + id + '"></span>';
8507 E.onAvailable(id, function(){
8508 var hd = document.getElementsByTagName("head")[0];
8509 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8510 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8511 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8514 while(match = re.exec(html)){
8515 var attrs = match[1];
8516 var srcMatch = attrs ? attrs.match(srcRe) : false;
8517 if(srcMatch && srcMatch[2]){
8518 var s = document.createElement("script");
8519 s.src = srcMatch[2];
8520 var typeMatch = attrs.match(typeRe);
8521 if(typeMatch && typeMatch[2]){
8522 s.type = typeMatch[2];
8525 }else if(match[2] && match[2].length > 0){
8526 if(window.execScript) {
8527 window.execScript(match[2]);
8535 window.eval(match[2]);
8539 var el = document.getElementById(id);
8540 if(el){el.parentNode.removeChild(el);}
8541 if(typeof callback == "function"){
8545 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8550 * Direct access to the UpdateManager update() method (takes the same parameters).
8551 * @param {String/Function} url The url for this request or a function to call to get the url
8552 * @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}
8553 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8554 * @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.
8555 * @return {Roo.Element} this
8558 var um = this.getUpdateManager();
8559 um.update.apply(um, arguments);
8564 * Gets this element's UpdateManager
8565 * @return {Roo.UpdateManager} The UpdateManager
8567 getUpdateManager : function(){
8568 if(!this.updateManager){
8569 this.updateManager = new Roo.UpdateManager(this);
8571 return this.updateManager;
8575 * Disables text selection for this element (normalized across browsers)
8576 * @return {Roo.Element} this
8578 unselectable : function(){
8579 this.dom.unselectable = "on";
8580 this.swallowEvent("selectstart", true);
8581 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8582 this.addClass("x-unselectable");
8587 * Calculates the x, y to center this element on the screen
8588 * @return {Array} The x, y values [x, y]
8590 getCenterXY : function(){
8591 return this.getAlignToXY(document, 'c-c');
8595 * Centers the Element in either the viewport, or another Element.
8596 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8598 center : function(centerIn){
8599 this.alignTo(centerIn || document, 'c-c');
8604 * Tests various css rules/browsers to determine if this element uses a border box
8607 isBorderBox : function(){
8608 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8612 * Return a box {x, y, width, height} that can be used to set another elements
8613 * size/location to match this element.
8614 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8615 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8616 * @return {Object} box An object in the format {x, y, width, height}
8618 getBox : function(contentBox, local){
8623 var left = parseInt(this.getStyle("left"), 10) || 0;
8624 var top = parseInt(this.getStyle("top"), 10) || 0;
8627 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8629 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8631 var l = this.getBorderWidth("l")+this.getPadding("l");
8632 var r = this.getBorderWidth("r")+this.getPadding("r");
8633 var t = this.getBorderWidth("t")+this.getPadding("t");
8634 var b = this.getBorderWidth("b")+this.getPadding("b");
8635 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)};
8637 bx.right = bx.x + bx.width;
8638 bx.bottom = bx.y + bx.height;
8643 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8644 for more information about the sides.
8645 * @param {String} sides
8648 getFrameWidth : function(sides, onlyContentBox){
8649 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8653 * 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.
8654 * @param {Object} box The box to fill {x, y, width, height}
8655 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8656 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8657 * @return {Roo.Element} this
8659 setBox : function(box, adjust, animate){
8660 var w = box.width, h = box.height;
8661 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8662 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8663 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8665 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8670 * Forces the browser to repaint this element
8671 * @return {Roo.Element} this
8673 repaint : function(){
8675 this.addClass("x-repaint");
8676 setTimeout(function(){
8677 Roo.get(dom).removeClass("x-repaint");
8683 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8684 * then it returns the calculated width of the sides (see getPadding)
8685 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8686 * @return {Object/Number}
8688 getMargins : function(side){
8691 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8692 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8693 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8694 right: parseInt(this.getStyle("margin-right"), 10) || 0
8697 return this.addStyles(side, El.margins);
8702 addStyles : function(sides, styles){
8704 for(var i = 0, len = sides.length; i < len; i++){
8705 v = this.getStyle(styles[sides.charAt(i)]);
8707 w = parseInt(v, 10);
8715 * Creates a proxy element of this element
8716 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8717 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8718 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8719 * @return {Roo.Element} The new proxy element
8721 createProxy : function(config, renderTo, matchBox){
8723 renderTo = Roo.getDom(renderTo);
8725 renderTo = document.body;
8727 config = typeof config == "object" ?
8728 config : {tag : "div", cls: config};
8729 var proxy = Roo.DomHelper.append(renderTo, config, true);
8731 proxy.setBox(this.getBox());
8737 * Puts a mask over this element to disable user interaction. Requires core.css.
8738 * This method can only be applied to elements which accept child nodes.
8739 * @param {String} msg (optional) A message to display in the mask
8740 * @param {String} msgCls (optional) A css class to apply to the msg element
8741 * @return {Element} The mask element
8743 mask : function(msg, msgCls){
8744 if(this.getStyle("position") == "static"){
8745 this.setStyle("position", "relative");
8748 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8750 this.addClass("x-masked");
8751 this._mask.setDisplayed(true);
8752 if(typeof msg == 'string'){
8754 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8756 var mm = this._maskMsg;
8757 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8758 mm.dom.firstChild.innerHTML = msg;
8759 mm.setDisplayed(true);
8762 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8763 this._mask.setHeight(this.getHeight());
8769 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8770 * it is cached for reuse.
8772 unmask : function(removeEl){
8774 if(removeEl === true){
8775 this._mask.remove();
8778 this._maskMsg.remove();
8779 delete this._maskMsg;
8782 this._mask.setDisplayed(false);
8784 this._maskMsg.setDisplayed(false);
8788 this.removeClass("x-masked");
8792 * Returns true if this element is masked
8795 isMasked : function(){
8796 return this._mask && this._mask.isVisible();
8800 * Creates an iframe shim for this element to keep selects and other windowed objects from
8802 * @return {Roo.Element} The new shim element
8804 createShim : function(){
8805 var el = document.createElement('iframe');
8806 el.frameBorder = 'no';
8807 el.className = 'roo-shim';
8808 if(Roo.isIE && Roo.isSecure){
8809 el.src = Roo.SSL_SECURE_URL;
8811 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8812 shim.autoBoxAdjust = false;
8817 * Removes this element from the DOM and deletes it from the cache
8819 remove : function(){
8820 if(this.dom.parentNode){
8821 this.dom.parentNode.removeChild(this.dom);
8823 delete El.cache[this.dom.id];
8827 * Sets up event handlers to add and remove a css class when the mouse is over this element
8828 * @param {String} className
8829 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8830 * mouseout events for children elements
8831 * @return {Roo.Element} this
8833 addClassOnOver : function(className, preventFlicker){
8834 this.on("mouseover", function(){
8835 Roo.fly(this, '_internal').addClass(className);
8837 var removeFn = function(e){
8838 if(preventFlicker !== true || !e.within(this, true)){
8839 Roo.fly(this, '_internal').removeClass(className);
8842 this.on("mouseout", removeFn, this.dom);
8847 * Sets up event handlers to add and remove a css class when this element has the focus
8848 * @param {String} className
8849 * @return {Roo.Element} this
8851 addClassOnFocus : function(className){
8852 this.on("focus", function(){
8853 Roo.fly(this, '_internal').addClass(className);
8855 this.on("blur", function(){
8856 Roo.fly(this, '_internal').removeClass(className);
8861 * 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)
8862 * @param {String} className
8863 * @return {Roo.Element} this
8865 addClassOnClick : function(className){
8867 this.on("mousedown", function(){
8868 Roo.fly(dom, '_internal').addClass(className);
8869 var d = Roo.get(document);
8870 var fn = function(){
8871 Roo.fly(dom, '_internal').removeClass(className);
8872 d.removeListener("mouseup", fn);
8874 d.on("mouseup", fn);
8880 * Stops the specified event from bubbling and optionally prevents the default action
8881 * @param {String} eventName
8882 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8883 * @return {Roo.Element} this
8885 swallowEvent : function(eventName, preventDefault){
8886 var fn = function(e){
8887 e.stopPropagation();
8892 if(eventName instanceof Array){
8893 for(var i = 0, len = eventName.length; i < len; i++){
8894 this.on(eventName[i], fn);
8898 this.on(eventName, fn);
8905 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8908 * Sizes this element to its parent element's dimensions performing
8909 * neccessary box adjustments.
8910 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8911 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8912 * @return {Roo.Element} this
8914 fitToParent : function(monitorResize, targetParent) {
8915 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8916 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8917 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8920 var p = Roo.get(targetParent || this.dom.parentNode);
8921 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8922 if (monitorResize === true) {
8923 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8924 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8930 * Gets the next sibling, skipping text nodes
8931 * @return {HTMLElement} The next sibling or null
8933 getNextSibling : function(){
8934 var n = this.dom.nextSibling;
8935 while(n && n.nodeType != 1){
8942 * Gets the previous sibling, skipping text nodes
8943 * @return {HTMLElement} The previous sibling or null
8945 getPrevSibling : function(){
8946 var n = this.dom.previousSibling;
8947 while(n && n.nodeType != 1){
8948 n = n.previousSibling;
8955 * Appends the passed element(s) to this element
8956 * @param {String/HTMLElement/Array/Element/CompositeElement} el
8957 * @return {Roo.Element} this
8959 appendChild: function(el){
8966 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8967 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
8968 * automatically generated with the specified attributes.
8969 * @param {HTMLElement} insertBefore (optional) a child element of this element
8970 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8971 * @return {Roo.Element} The new child element
8973 createChild: function(config, insertBefore, returnDom){
8974 config = config || {tag:'div'};
8976 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8978 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
8982 * Appends this element to the passed element
8983 * @param {String/HTMLElement/Element} el The new parent element
8984 * @return {Roo.Element} this
8986 appendTo: function(el){
8987 el = Roo.getDom(el);
8988 el.appendChild(this.dom);
8993 * Inserts this element before the passed element in the DOM
8994 * @param {String/HTMLElement/Element} el The element to insert before
8995 * @return {Roo.Element} this
8997 insertBefore: function(el){
8998 el = Roo.getDom(el);
8999 el.parentNode.insertBefore(this.dom, el);
9004 * Inserts this element after the passed element in the DOM
9005 * @param {String/HTMLElement/Element} el The element to insert after
9006 * @return {Roo.Element} this
9008 insertAfter: function(el){
9009 el = Roo.getDom(el);
9010 el.parentNode.insertBefore(this.dom, el.nextSibling);
9015 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9016 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9017 * @return {Roo.Element} The new child
9019 insertFirst: function(el, returnDom){
9021 if(typeof el == 'object' && !el.nodeType){ // dh config
9022 return this.createChild(el, this.dom.firstChild, returnDom);
9024 el = Roo.getDom(el);
9025 this.dom.insertBefore(el, this.dom.firstChild);
9026 return !returnDom ? Roo.get(el) : el;
9031 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9032 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9033 * @param {String} where (optional) 'before' or 'after' defaults to before
9034 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9035 * @return {Roo.Element} the inserted Element
9037 insertSibling: function(el, where, returnDom){
9038 where = where ? where.toLowerCase() : 'before';
9040 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9042 if(typeof el == 'object' && !el.nodeType){ // dh config
9043 if(where == 'after' && !this.dom.nextSibling){
9044 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9046 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9050 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9051 where == 'before' ? this.dom : this.dom.nextSibling);
9060 * Creates and wraps this element with another element
9061 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9062 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9063 * @return {HTMLElement/Element} The newly created wrapper element
9065 wrap: function(config, returnDom){
9067 config = {tag: "div"};
9069 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9070 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9075 * Replaces the passed element with this element
9076 * @param {String/HTMLElement/Element} el The element to replace
9077 * @return {Roo.Element} this
9079 replace: function(el){
9081 this.insertBefore(el);
9087 * Inserts an html fragment into this element
9088 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9089 * @param {String} html The HTML fragment
9090 * @param {Boolean} returnEl True to return an Roo.Element
9091 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9093 insertHtml : function(where, html, returnEl){
9094 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9095 return returnEl ? Roo.get(el) : el;
9099 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9100 * @param {Object} o The object with the attributes
9101 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9102 * @return {Roo.Element} this
9104 set : function(o, useSet){
9106 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9108 if(attr == "style" || typeof o[attr] == "function") continue;
9110 el.className = o["cls"];
9112 if(useSet) el.setAttribute(attr, o[attr]);
9113 else el[attr] = o[attr];
9117 Roo.DomHelper.applyStyles(el, o.style);
9123 * Convenience method for constructing a KeyMap
9124 * @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:
9125 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9126 * @param {Function} fn The function to call
9127 * @param {Object} scope (optional) The scope of the function
9128 * @return {Roo.KeyMap} The KeyMap created
9130 addKeyListener : function(key, fn, scope){
9132 if(typeof key != "object" || key instanceof Array){
9148 return new Roo.KeyMap(this, config);
9152 * Creates a KeyMap for this element
9153 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9154 * @return {Roo.KeyMap} The KeyMap created
9156 addKeyMap : function(config){
9157 return new Roo.KeyMap(this, config);
9161 * Returns true if this element is scrollable.
9164 isScrollable : function(){
9166 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9170 * 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().
9171 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9172 * @param {Number} value The new scroll value
9173 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9174 * @return {Element} this
9177 scrollTo : function(side, value, animate){
9178 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9180 this.dom[prop] = value;
9182 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9183 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9189 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9190 * within this element's scrollable range.
9191 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9192 * @param {Number} distance How far to scroll the element in pixels
9193 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9194 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9195 * was scrolled as far as it could go.
9197 scroll : function(direction, distance, animate){
9198 if(!this.isScrollable()){
9202 var l = el.scrollLeft, t = el.scrollTop;
9203 var w = el.scrollWidth, h = el.scrollHeight;
9204 var cw = el.clientWidth, ch = el.clientHeight;
9205 direction = direction.toLowerCase();
9206 var scrolled = false;
9207 var a = this.preanim(arguments, 2);
9212 var v = Math.min(l + distance, w-cw);
9213 this.scrollTo("left", v, a);
9220 var v = Math.max(l - distance, 0);
9221 this.scrollTo("left", v, a);
9229 var v = Math.max(t - distance, 0);
9230 this.scrollTo("top", v, a);
9238 var v = Math.min(t + distance, h-ch);
9239 this.scrollTo("top", v, a);
9248 * Translates the passed page coordinates into left/top css values for this element
9249 * @param {Number/Array} x The page x or an array containing [x, y]
9250 * @param {Number} y The page y
9251 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9253 translatePoints : function(x, y){
9254 if(typeof x == 'object' || x instanceof Array){
9257 var p = this.getStyle('position');
9258 var o = this.getXY();
9260 var l = parseInt(this.getStyle('left'), 10);
9261 var t = parseInt(this.getStyle('top'), 10);
9264 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9267 t = (p == "relative") ? 0 : this.dom.offsetTop;
9270 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9274 * Returns the current scroll position of the element.
9275 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9277 getScroll : function(){
9278 var d = this.dom, doc = document;
9279 if(d == doc || d == doc.body){
9280 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9281 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9282 return {left: l, top: t};
9284 return {left: d.scrollLeft, top: d.scrollTop};
9289 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9290 * are convert to standard 6 digit hex color.
9291 * @param {String} attr The css attribute
9292 * @param {String} defaultValue The default value to use when a valid color isn't found
9293 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9296 getColor : function(attr, defaultValue, prefix){
9297 var v = this.getStyle(attr);
9298 if(!v || v == "transparent" || v == "inherit") {
9299 return defaultValue;
9301 var color = typeof prefix == "undefined" ? "#" : prefix;
9302 if(v.substr(0, 4) == "rgb("){
9303 var rvs = v.slice(4, v.length -1).split(",");
9304 for(var i = 0; i < 3; i++){
9305 var h = parseInt(rvs[i]).toString(16);
9312 if(v.substr(0, 1) == "#"){
9314 for(var i = 1; i < 4; i++){
9315 var c = v.charAt(i);
9318 }else if(v.length == 7){
9319 color += v.substr(1);
9323 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9327 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9328 * gradient background, rounded corners and a 4-way shadow.
9329 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9330 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9331 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9332 * @return {Roo.Element} this
9334 boxWrap : function(cls){
9335 cls = cls || 'x-box';
9336 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9337 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9342 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9343 * @param {String} namespace The namespace in which to look for the attribute
9344 * @param {String} name The attribute name
9345 * @return {String} The attribute value
9347 getAttributeNS : Roo.isIE ? function(ns, name){
9349 var type = typeof d[ns+":"+name];
9350 if(type != 'undefined' && type != 'unknown'){
9351 return d[ns+":"+name];
9354 } : function(ns, name){
9356 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9360 var ep = El.prototype;
9363 * Appends an event handler (Shorthand for addListener)
9364 * @param {String} eventName The type of event to append
9365 * @param {Function} fn The method the event invokes
9366 * @param {Object} scope (optional) The scope (this object) of the fn
9367 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9370 ep.on = ep.addListener;
9372 ep.mon = ep.addListener;
9375 * Removes an event handler from this element (shorthand for removeListener)
9376 * @param {String} eventName the type of event to remove
9377 * @param {Function} fn the method the event invokes
9378 * @return {Roo.Element} this
9381 ep.un = ep.removeListener;
9384 * true to automatically adjust width and height settings for box-model issues (default to true)
9386 ep.autoBoxAdjust = true;
9389 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9392 El.addUnits = function(v, defaultUnit){
9393 if(v === "" || v == "auto"){
9396 if(v === undefined){
9399 if(typeof v == "number" || !El.unitPattern.test(v)){
9400 return v + (defaultUnit || 'px');
9405 // special markup used throughout Roo when box wrapping elements
9406 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>';
9408 * Visibility mode constant - Use visibility to hide element
9414 * Visibility mode constant - Use display to hide element
9420 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9421 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9422 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9434 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9435 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9436 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9437 * @return {Element} The Element object
9440 El.get = function(el){
9442 if(!el){ return null; }
9443 if(typeof el == "string"){ // element id
9444 if(!(elm = document.getElementById(el))){
9447 if(ex = El.cache[el]){
9450 ex = El.cache[el] = new El(elm);
9453 }else if(el.tagName){ // dom element
9457 if(ex = El.cache[id]){
9460 ex = El.cache[id] = new El(el);
9463 }else if(el instanceof El){
9465 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9466 // catch case where it hasn't been appended
9467 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9470 }else if(el.isComposite){
9472 }else if(el instanceof Array){
9473 return El.select(el);
9474 }else if(el == document){
9475 // create a bogus element object representing the document object
9477 var f = function(){};
9478 f.prototype = El.prototype;
9480 docEl.dom = document;
9488 El.uncache = function(el){
9489 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9491 delete El.cache[a[i].id || a[i]];
9497 // Garbage collection - uncache elements/purge listeners on orphaned elements
9498 // so we don't hold a reference and cause the browser to retain them
9499 El.garbageCollect = function(){
9500 if(!Roo.enableGarbageCollector){
9501 clearInterval(El.collectorThread);
9504 for(var eid in El.cache){
9505 var el = El.cache[eid], d = el.dom;
9506 // -------------------------------------------------------
9507 // Determining what is garbage:
9508 // -------------------------------------------------------
9510 // dom node is null, definitely garbage
9511 // -------------------------------------------------------
9513 // no parentNode == direct orphan, definitely garbage
9514 // -------------------------------------------------------
9515 // !d.offsetParent && !document.getElementById(eid)
9516 // display none elements have no offsetParent so we will
9517 // also try to look it up by it's id. However, check
9518 // offsetParent first so we don't do unneeded lookups.
9519 // This enables collection of elements that are not orphans
9520 // directly, but somewhere up the line they have an orphan
9522 // -------------------------------------------------------
9523 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9524 delete El.cache[eid];
9525 if(d && Roo.enableListenerCollection){
9531 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9535 El.Flyweight = function(dom){
9538 El.Flyweight.prototype = El.prototype;
9540 El._flyweights = {};
9542 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9543 * the dom node can be overwritten by other code.
9544 * @param {String/HTMLElement} el The dom node or id
9545 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9546 * prevent conflicts (e.g. internally Roo uses "_internal")
9548 * @return {Element} The shared Element object
9550 El.fly = function(el, named){
9551 named = named || '_global';
9552 el = Roo.getDom(el);
9556 if(!El._flyweights[named]){
9557 El._flyweights[named] = new El.Flyweight();
9559 El._flyweights[named].dom = el;
9560 return El._flyweights[named];
9564 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9565 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9566 * Shorthand of {@link Roo.Element#get}
9567 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9568 * @return {Element} The Element object
9574 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9575 * the dom node can be overwritten by other code.
9576 * Shorthand of {@link Roo.Element#fly}
9577 * @param {String/HTMLElement} el The dom node or id
9578 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9579 * prevent conflicts (e.g. internally Roo uses "_internal")
9581 * @return {Element} The shared Element object
9587 // speedy lookup for elements never to box adjust
9588 var noBoxAdjust = Roo.isStrict ? {
9591 input:1, select:1, textarea:1
9593 if(Roo.isIE || Roo.isGecko){
9594 noBoxAdjust['button'] = 1;
9598 Roo.EventManager.on(window, 'unload', function(){
9600 delete El._flyweights;
9608 Roo.Element.selectorFunction = Roo.DomQuery.select;
9611 Roo.Element.select = function(selector, unique, root){
9613 if(typeof selector == "string"){
9614 els = Roo.Element.selectorFunction(selector, root);
9615 }else if(selector.length !== undefined){
9618 throw "Invalid selector";
9620 if(unique === true){
9621 return new Roo.CompositeElement(els);
9623 return new Roo.CompositeElementLite(els);
9627 * Selects elements based on the passed CSS selector to enable working on them as 1.
9628 * @param {String/Array} selector The CSS selector or an array of elements
9629 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9630 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9631 * @return {CompositeElementLite/CompositeElement}
9635 Roo.select = Roo.Element.select;
9652 * Ext JS Library 1.1.1
9653 * Copyright(c) 2006-2007, Ext JS, LLC.
9655 * Originally Released Under LGPL - original licence link has changed is not relivant.
9658 * <script type="text/javascript">
9663 //Notifies Element that fx methods are available
9664 Roo.enableFx = true;
9668 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9669 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9670 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9671 * Element effects to work.</p><br/>
9673 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9674 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9675 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9676 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9677 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9678 * expected results and should be done with care.</p><br/>
9680 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9681 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9684 ----- -----------------------------
9685 tl The top left corner
9686 t The center of the top edge
9687 tr The top right corner
9688 l The center of the left edge
9689 r The center of the right edge
9690 bl The bottom left corner
9691 b The center of the bottom edge
9692 br The bottom right corner
9694 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9695 * below are common options that can be passed to any Fx method.</b>
9696 * @cfg {Function} callback A function called when the effect is finished
9697 * @cfg {Object} scope The scope of the effect function
9698 * @cfg {String} easing A valid Easing value for the effect
9699 * @cfg {String} afterCls A css class to apply after the effect
9700 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9701 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9702 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9703 * effects that end with the element being visually hidden, ignored otherwise)
9704 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9705 * a function which returns such a specification that will be applied to the Element after the effect finishes
9706 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9707 * @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
9708 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9712 * Slides the element into view. An anchor point can be optionally passed to set the point of
9713 * origin for the slide effect. This function automatically handles wrapping the element with
9714 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9717 // default: slide the element in from the top
9720 // custom: slide the element in from the right with a 2-second duration
9721 el.slideIn('r', { duration: 2 });
9723 // common config options shown with default values
9729 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9730 * @param {Object} options (optional) Object literal with any of the Fx config options
9731 * @return {Roo.Element} The Element
9733 slideIn : function(anchor, o){
9734 var el = this.getFxEl();
9737 el.queueFx(o, function(){
9739 anchor = anchor || "t";
9741 // fix display to visibility
9744 // restore values after effect
9745 var r = this.getFxRestore();
9746 var b = this.getBox();
9747 // fixed size for slide
9751 var wrap = this.fxWrap(r.pos, o, "hidden");
9753 var st = this.dom.style;
9754 st.visibility = "visible";
9755 st.position = "absolute";
9757 // clear out temp styles after slide and unwrap
9758 var after = function(){
9759 el.fxUnwrap(wrap, r.pos, o);
9761 st.height = r.height;
9764 // time to calc the positions
9765 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9767 switch(anchor.toLowerCase()){
9769 wrap.setSize(b.width, 0);
9770 st.left = st.bottom = "0";
9774 wrap.setSize(0, b.height);
9775 st.right = st.top = "0";
9779 wrap.setSize(0, b.height);
9781 st.left = st.top = "0";
9782 a = {width: bw, points: pt};
9785 wrap.setSize(b.width, 0);
9786 wrap.setY(b.bottom);
9787 st.left = st.top = "0";
9788 a = {height: bh, points: pt};
9792 st.right = st.bottom = "0";
9793 a = {width: bw, height: bh};
9797 wrap.setY(b.y+b.height);
9798 st.right = st.top = "0";
9799 a = {width: bw, height: bh, points: pt};
9803 wrap.setXY([b.right, b.bottom]);
9804 st.left = st.top = "0";
9805 a = {width: bw, height: bh, points: pt};
9809 wrap.setX(b.x+b.width);
9810 st.left = st.bottom = "0";
9811 a = {width: bw, height: bh, points: pt};
9814 this.dom.style.visibility = "visible";
9817 arguments.callee.anim = wrap.fxanim(a,
9827 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9828 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9829 * 'hidden') but block elements will still take up space in the document. The element must be removed
9830 * from the DOM using the 'remove' config option if desired. This function automatically handles
9831 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9834 // default: slide the element out to the top
9837 // custom: slide the element out to the right with a 2-second duration
9838 el.slideOut('r', { duration: 2 });
9840 // common config options shown with default values
9848 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9849 * @param {Object} options (optional) Object literal with any of the Fx config options
9850 * @return {Roo.Element} The Element
9852 slideOut : function(anchor, o){
9853 var el = this.getFxEl();
9856 el.queueFx(o, function(){
9858 anchor = anchor || "t";
9860 // restore values after effect
9861 var r = this.getFxRestore();
9863 var b = this.getBox();
9864 // fixed size for slide
9868 var wrap = this.fxWrap(r.pos, o, "visible");
9870 var st = this.dom.style;
9871 st.visibility = "visible";
9872 st.position = "absolute";
9876 var after = function(){
9878 el.setDisplayed(false);
9883 el.fxUnwrap(wrap, r.pos, o);
9886 st.height = r.height;
9891 var a, zero = {to: 0};
9892 switch(anchor.toLowerCase()){
9894 st.left = st.bottom = "0";
9898 st.right = st.top = "0";
9902 st.left = st.top = "0";
9903 a = {width: zero, points: {to:[b.right, b.y]}};
9906 st.left = st.top = "0";
9907 a = {height: zero, points: {to:[b.x, b.bottom]}};
9910 st.right = st.bottom = "0";
9911 a = {width: zero, height: zero};
9914 st.right = st.top = "0";
9915 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9918 st.left = st.top = "0";
9919 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9922 st.left = st.bottom = "0";
9923 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9927 arguments.callee.anim = wrap.fxanim(a,
9937 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
9938 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
9939 * The element must be removed from the DOM using the 'remove' config option if desired.
9945 // common config options shown with default values
9953 * @param {Object} options (optional) Object literal with any of the Fx config options
9954 * @return {Roo.Element} The Element
9957 var el = this.getFxEl();
9960 el.queueFx(o, function(){
9961 this.clearOpacity();
9964 // restore values after effect
9965 var r = this.getFxRestore();
9966 var st = this.dom.style;
9968 var after = function(){
9970 el.setDisplayed(false);
9977 el.setPositioning(r.pos);
9979 st.height = r.height;
9984 var width = this.getWidth();
9985 var height = this.getHeight();
9987 arguments.callee.anim = this.fxanim({
9988 width : {to: this.adjustWidth(width * 2)},
9989 height : {to: this.adjustHeight(height * 2)},
9990 points : {by: [-(width * .5), -(height * .5)]},
9992 fontSize: {to:200, unit: "%"}
10003 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10004 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10005 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10011 // all config options shown with default values
10019 * @param {Object} options (optional) Object literal with any of the Fx config options
10020 * @return {Roo.Element} The Element
10022 switchOff : function(o){
10023 var el = this.getFxEl();
10026 el.queueFx(o, function(){
10027 this.clearOpacity();
10030 // restore values after effect
10031 var r = this.getFxRestore();
10032 var st = this.dom.style;
10034 var after = function(){
10036 el.setDisplayed(false);
10042 el.setPositioning(r.pos);
10043 st.width = r.width;
10044 st.height = r.height;
10049 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10050 this.clearOpacity();
10054 points:{by:[0, this.getHeight() * .5]}
10055 }, o, 'motion', 0.3, 'easeIn', after);
10056 }).defer(100, this);
10063 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10064 * changed using the "attr" config option) and then fading back to the original color. If no original
10065 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10068 // default: highlight background to yellow
10071 // custom: highlight foreground text to blue for 2 seconds
10072 el.highlight("0000ff", { attr: 'color', duration: 2 });
10074 // common config options shown with default values
10075 el.highlight("ffff9c", {
10076 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10077 endColor: (current color) or "ffffff",
10082 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10083 * @param {Object} options (optional) Object literal with any of the Fx config options
10084 * @return {Roo.Element} The Element
10086 highlight : function(color, o){
10087 var el = this.getFxEl();
10090 el.queueFx(o, function(){
10091 color = color || "ffff9c";
10092 attr = o.attr || "backgroundColor";
10094 this.clearOpacity();
10097 var origColor = this.getColor(attr);
10098 var restoreColor = this.dom.style[attr];
10099 endColor = (o.endColor || origColor) || "ffffff";
10101 var after = function(){
10102 el.dom.style[attr] = restoreColor;
10107 a[attr] = {from: color, to: endColor};
10108 arguments.callee.anim = this.fxanim(a,
10118 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10121 // default: a single light blue ripple
10124 // custom: 3 red ripples lasting 3 seconds total
10125 el.frame("ff0000", 3, { duration: 3 });
10127 // common config options shown with default values
10128 el.frame("C3DAF9", 1, {
10129 duration: 1 //duration of entire animation (not each individual ripple)
10130 // Note: Easing is not configurable and will be ignored if included
10133 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10134 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10135 * @param {Object} options (optional) Object literal with any of the Fx config options
10136 * @return {Roo.Element} The Element
10138 frame : function(color, count, o){
10139 var el = this.getFxEl();
10142 el.queueFx(o, function(){
10143 color = color || "#C3DAF9";
10144 if(color.length == 6){
10145 color = "#" + color;
10147 count = count || 1;
10148 duration = o.duration || 1;
10151 var b = this.getBox();
10152 var animFn = function(){
10153 var proxy = this.createProxy({
10156 visbility:"hidden",
10157 position:"absolute",
10158 "z-index":"35000", // yee haw
10159 border:"0px solid " + color
10162 var scale = Roo.isBorderBox ? 2 : 1;
10164 top:{from:b.y, to:b.y - 20},
10165 left:{from:b.x, to:b.x - 20},
10166 borderWidth:{from:0, to:10},
10167 opacity:{from:1, to:0},
10168 height:{from:b.height, to:(b.height + (20*scale))},
10169 width:{from:b.width, to:(b.width + (20*scale))}
10170 }, duration, function(){
10174 animFn.defer((duration/2)*1000, this);
10185 * Creates a pause before any subsequent queued effects begin. If there are
10186 * no effects queued after the pause it will have no effect.
10191 * @param {Number} seconds The length of time to pause (in seconds)
10192 * @return {Roo.Element} The Element
10194 pause : function(seconds){
10195 var el = this.getFxEl();
10198 el.queueFx(o, function(){
10199 setTimeout(function(){
10201 }, seconds * 1000);
10207 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10208 * using the "endOpacity" config option.
10211 // default: fade in from opacity 0 to 100%
10214 // custom: fade in from opacity 0 to 75% over 2 seconds
10215 el.fadeIn({ endOpacity: .75, duration: 2});
10217 // common config options shown with default values
10219 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10224 * @param {Object} options (optional) Object literal with any of the Fx config options
10225 * @return {Roo.Element} The Element
10227 fadeIn : function(o){
10228 var el = this.getFxEl();
10230 el.queueFx(o, function(){
10231 this.setOpacity(0);
10233 this.dom.style.visibility = 'visible';
10234 var to = o.endOpacity || 1;
10235 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10236 o, null, .5, "easeOut", function(){
10238 this.clearOpacity();
10247 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10248 * using the "endOpacity" config option.
10251 // default: fade out from the element's current opacity to 0
10254 // custom: fade out from the element's current opacity to 25% over 2 seconds
10255 el.fadeOut({ endOpacity: .25, duration: 2});
10257 // common config options shown with default values
10259 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10266 * @param {Object} options (optional) Object literal with any of the Fx config options
10267 * @return {Roo.Element} The Element
10269 fadeOut : function(o){
10270 var el = this.getFxEl();
10272 el.queueFx(o, function(){
10273 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10274 o, null, .5, "easeOut", function(){
10275 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10276 this.dom.style.display = "none";
10278 this.dom.style.visibility = "hidden";
10280 this.clearOpacity();
10288 * Animates the transition of an element's dimensions from a starting height/width
10289 * to an ending height/width.
10292 // change height and width to 100x100 pixels
10293 el.scale(100, 100);
10295 // common config options shown with default values. The height and width will default to
10296 // the element's existing values if passed as null.
10299 [element's height], {
10304 * @param {Number} width The new width (pass undefined to keep the original width)
10305 * @param {Number} height The new height (pass undefined to keep the original height)
10306 * @param {Object} options (optional) Object literal with any of the Fx config options
10307 * @return {Roo.Element} The Element
10309 scale : function(w, h, o){
10310 this.shift(Roo.apply({}, o, {
10318 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10319 * Any of these properties not specified in the config object will not be changed. This effect
10320 * requires that at least one new dimension, position or opacity setting must be passed in on
10321 * the config object in order for the function to have any effect.
10324 // slide the element horizontally to x position 200 while changing the height and opacity
10325 el.shift({ x: 200, height: 50, opacity: .8 });
10327 // common config options shown with default values.
10329 width: [element's width],
10330 height: [element's height],
10331 x: [element's x position],
10332 y: [element's y position],
10333 opacity: [element's opacity],
10338 * @param {Object} options Object literal with any of the Fx config options
10339 * @return {Roo.Element} The Element
10341 shift : function(o){
10342 var el = this.getFxEl();
10344 el.queueFx(o, function(){
10345 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10346 if(w !== undefined){
10347 a.width = {to: this.adjustWidth(w)};
10349 if(h !== undefined){
10350 a.height = {to: this.adjustHeight(h)};
10352 if(x !== undefined || y !== undefined){
10354 x !== undefined ? x : this.getX(),
10355 y !== undefined ? y : this.getY()
10358 if(op !== undefined){
10359 a.opacity = {to: op};
10361 if(o.xy !== undefined){
10362 a.points = {to: o.xy};
10364 arguments.callee.anim = this.fxanim(a,
10365 o, 'motion', .35, "easeOut", function(){
10373 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10374 * ending point of the effect.
10377 // default: slide the element downward while fading out
10380 // custom: slide the element out to the right with a 2-second duration
10381 el.ghost('r', { duration: 2 });
10383 // common config options shown with default values
10391 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10392 * @param {Object} options (optional) Object literal with any of the Fx config options
10393 * @return {Roo.Element} The Element
10395 ghost : function(anchor, o){
10396 var el = this.getFxEl();
10399 el.queueFx(o, function(){
10400 anchor = anchor || "b";
10402 // restore values after effect
10403 var r = this.getFxRestore();
10404 var w = this.getWidth(),
10405 h = this.getHeight();
10407 var st = this.dom.style;
10409 var after = function(){
10411 el.setDisplayed(false);
10417 el.setPositioning(r.pos);
10418 st.width = r.width;
10419 st.height = r.height;
10424 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10425 switch(anchor.toLowerCase()){
10452 arguments.callee.anim = this.fxanim(a,
10462 * Ensures that all effects queued after syncFx is called on the element are
10463 * run concurrently. This is the opposite of {@link #sequenceFx}.
10464 * @return {Roo.Element} The Element
10466 syncFx : function(){
10467 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10476 * Ensures that all effects queued after sequenceFx is called on the element are
10477 * run in sequence. This is the opposite of {@link #syncFx}.
10478 * @return {Roo.Element} The Element
10480 sequenceFx : function(){
10481 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10483 concurrent : false,
10490 nextFx : function(){
10491 var ef = this.fxQueue[0];
10498 * Returns true if the element has any effects actively running or queued, else returns false.
10499 * @return {Boolean} True if element has active effects, else false
10501 hasActiveFx : function(){
10502 return this.fxQueue && this.fxQueue[0];
10506 * Stops any running effects and clears the element's internal effects queue if it contains
10507 * any additional effects that haven't started yet.
10508 * @return {Roo.Element} The Element
10510 stopFx : function(){
10511 if(this.hasActiveFx()){
10512 var cur = this.fxQueue[0];
10513 if(cur && cur.anim && cur.anim.isAnimated()){
10514 this.fxQueue = [cur]; // clear out others
10515 cur.anim.stop(true);
10522 beforeFx : function(o){
10523 if(this.hasActiveFx() && !o.concurrent){
10534 * Returns true if the element is currently blocking so that no other effect can be queued
10535 * until this effect is finished, else returns false if blocking is not set. This is commonly
10536 * used to ensure that an effect initiated by a user action runs to completion prior to the
10537 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10538 * @return {Boolean} True if blocking, else false
10540 hasFxBlock : function(){
10541 var q = this.fxQueue;
10542 return q && q[0] && q[0].block;
10546 queueFx : function(o, fn){
10550 if(!this.hasFxBlock()){
10551 Roo.applyIf(o, this.fxDefaults);
10553 var run = this.beforeFx(o);
10554 fn.block = o.block;
10555 this.fxQueue.push(fn);
10567 fxWrap : function(pos, o, vis){
10569 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10572 wrapXY = this.getXY();
10574 var div = document.createElement("div");
10575 div.style.visibility = vis;
10576 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10577 wrap.setPositioning(pos);
10578 if(wrap.getStyle("position") == "static"){
10579 wrap.position("relative");
10581 this.clearPositioning('auto');
10583 wrap.dom.appendChild(this.dom);
10585 wrap.setXY(wrapXY);
10592 fxUnwrap : function(wrap, pos, o){
10593 this.clearPositioning();
10594 this.setPositioning(pos);
10596 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10602 getFxRestore : function(){
10603 var st = this.dom.style;
10604 return {pos: this.getPositioning(), width: st.width, height : st.height};
10608 afterFx : function(o){
10610 this.applyStyles(o.afterStyle);
10613 this.addClass(o.afterCls);
10615 if(o.remove === true){
10618 Roo.callback(o.callback, o.scope, [this]);
10620 this.fxQueue.shift();
10626 getFxEl : function(){ // support for composite element fx
10627 return Roo.get(this.dom);
10631 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10632 animType = animType || 'run';
10634 var anim = Roo.lib.Anim[animType](
10636 (opt.duration || defaultDur) || .35,
10637 (opt.easing || defaultEase) || 'easeOut',
10639 Roo.callback(cb, this);
10648 // backwords compat
10649 Roo.Fx.resize = Roo.Fx.scale;
10651 //When included, Roo.Fx is automatically applied to Element so that all basic
10652 //effects are available directly via the Element API
10653 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10655 * Ext JS Library 1.1.1
10656 * Copyright(c) 2006-2007, Ext JS, LLC.
10658 * Originally Released Under LGPL - original licence link has changed is not relivant.
10661 * <script type="text/javascript">
10666 * @class Roo.CompositeElement
10667 * Standard composite class. Creates a Roo.Element for every element in the collection.
10669 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10670 * actions will be performed on all the elements in this collection.</b>
10672 * All methods return <i>this</i> and can be chained.
10674 var els = Roo.select("#some-el div.some-class", true);
10675 // or select directly from an existing element
10676 var el = Roo.get('some-el');
10677 el.select('div.some-class', true);
10679 els.setWidth(100); // all elements become 100 width
10680 els.hide(true); // all elements fade out and hide
10682 els.setWidth(100).hide(true);
10685 Roo.CompositeElement = function(els){
10686 this.elements = [];
10687 this.addElements(els);
10689 Roo.CompositeElement.prototype = {
10691 addElements : function(els){
10692 if(!els) return this;
10693 if(typeof els == "string"){
10694 els = Roo.Element.selectorFunction(els);
10696 var yels = this.elements;
10697 var index = yels.length-1;
10698 for(var i = 0, len = els.length; i < len; i++) {
10699 yels[++index] = Roo.get(els[i]);
10705 * Clears this composite and adds the elements returned by the passed selector.
10706 * @param {String/Array} els A string CSS selector, an array of elements or an element
10707 * @return {CompositeElement} this
10709 fill : function(els){
10710 this.elements = [];
10716 * Filters this composite to only elements that match the passed selector.
10717 * @param {String} selector A string CSS selector
10718 * @return {CompositeElement} this
10720 filter : function(selector){
10722 this.each(function(el){
10723 if(el.is(selector)){
10724 els[els.length] = el.dom;
10731 invoke : function(fn, args){
10732 var els = this.elements;
10733 for(var i = 0, len = els.length; i < len; i++) {
10734 Roo.Element.prototype[fn].apply(els[i], args);
10739 * Adds elements to this composite.
10740 * @param {String/Array} els A string CSS selector, an array of elements or an element
10741 * @return {CompositeElement} this
10743 add : function(els){
10744 if(typeof els == "string"){
10745 this.addElements(Roo.Element.selectorFunction(els));
10746 }else if(els.length !== undefined){
10747 this.addElements(els);
10749 this.addElements([els]);
10754 * Calls the passed function passing (el, this, index) for each element in this composite.
10755 * @param {Function} fn The function to call
10756 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10757 * @return {CompositeElement} this
10759 each : function(fn, scope){
10760 var els = this.elements;
10761 for(var i = 0, len = els.length; i < len; i++){
10762 if(fn.call(scope || els[i], els[i], this, i) === false) {
10770 * Returns the Element object at the specified index
10771 * @param {Number} index
10772 * @return {Roo.Element}
10774 item : function(index){
10775 return this.elements[index] || null;
10779 * Returns the first Element
10780 * @return {Roo.Element}
10782 first : function(){
10783 return this.item(0);
10787 * Returns the last Element
10788 * @return {Roo.Element}
10791 return this.item(this.elements.length-1);
10795 * Returns the number of elements in this composite
10798 getCount : function(){
10799 return this.elements.length;
10803 * Returns true if this composite contains the passed element
10806 contains : function(el){
10807 return this.indexOf(el) !== -1;
10811 * Returns true if this composite contains the passed element
10814 indexOf : function(el){
10815 return this.elements.indexOf(Roo.get(el));
10820 * Removes the specified element(s).
10821 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10822 * or an array of any of those.
10823 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10824 * @return {CompositeElement} this
10826 removeElement : function(el, removeDom){
10827 if(el instanceof Array){
10828 for(var i = 0, len = el.length; i < len; i++){
10829 this.removeElement(el[i]);
10833 var index = typeof el == 'number' ? el : this.indexOf(el);
10836 var d = this.elements[index];
10840 d.parentNode.removeChild(d);
10843 this.elements.splice(index, 1);
10849 * Replaces the specified element with the passed element.
10850 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10852 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10853 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10854 * @return {CompositeElement} this
10856 replaceElement : function(el, replacement, domReplace){
10857 var index = typeof el == 'number' ? el : this.indexOf(el);
10860 this.elements[index].replaceWith(replacement);
10862 this.elements.splice(index, 1, Roo.get(replacement))
10869 * Removes all elements.
10871 clear : function(){
10872 this.elements = [];
10876 Roo.CompositeElement.createCall = function(proto, fnName){
10877 if(!proto[fnName]){
10878 proto[fnName] = function(){
10879 return this.invoke(fnName, arguments);
10883 for(var fnName in Roo.Element.prototype){
10884 if(typeof Roo.Element.prototype[fnName] == "function"){
10885 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10891 * Ext JS Library 1.1.1
10892 * Copyright(c) 2006-2007, Ext JS, LLC.
10894 * Originally Released Under LGPL - original licence link has changed is not relivant.
10897 * <script type="text/javascript">
10901 * @class Roo.CompositeElementLite
10902 * @extends Roo.CompositeElement
10903 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10905 var els = Roo.select("#some-el div.some-class");
10906 // or select directly from an existing element
10907 var el = Roo.get('some-el');
10908 el.select('div.some-class');
10910 els.setWidth(100); // all elements become 100 width
10911 els.hide(true); // all elements fade out and hide
10913 els.setWidth(100).hide(true);
10914 </code></pre><br><br>
10915 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10916 * actions will be performed on all the elements in this collection.</b>
10918 Roo.CompositeElementLite = function(els){
10919 Roo.CompositeElementLite.superclass.constructor.call(this, els);
10920 this.el = new Roo.Element.Flyweight();
10922 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10923 addElements : function(els){
10925 if(els instanceof Array){
10926 this.elements = this.elements.concat(els);
10928 var yels = this.elements;
10929 var index = yels.length-1;
10930 for(var i = 0, len = els.length; i < len; i++) {
10931 yels[++index] = els[i];
10937 invoke : function(fn, args){
10938 var els = this.elements;
10940 for(var i = 0, len = els.length; i < len; i++) {
10942 Roo.Element.prototype[fn].apply(el, args);
10947 * Returns a flyweight Element of the dom element object at the specified index
10948 * @param {Number} index
10949 * @return {Roo.Element}
10951 item : function(index){
10952 if(!this.elements[index]){
10955 this.el.dom = this.elements[index];
10959 // fixes scope with flyweight
10960 addListener : function(eventName, handler, scope, opt){
10961 var els = this.elements;
10962 for(var i = 0, len = els.length; i < len; i++) {
10963 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10969 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10970 * passed is the flyweight (shared) Roo.Element instance, so if you require a
10971 * a reference to the dom node, use el.dom.</b>
10972 * @param {Function} fn The function to call
10973 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10974 * @return {CompositeElement} this
10976 each : function(fn, scope){
10977 var els = this.elements;
10979 for(var i = 0, len = els.length; i < len; i++){
10981 if(fn.call(scope || el, el, this, i) === false){
10988 indexOf : function(el){
10989 return this.elements.indexOf(Roo.getDom(el));
10992 replaceElement : function(el, replacement, domReplace){
10993 var index = typeof el == 'number' ? el : this.indexOf(el);
10995 replacement = Roo.getDom(replacement);
10997 var d = this.elements[index];
10998 d.parentNode.insertBefore(replacement, d);
10999 d.parentNode.removeChild(d);
11001 this.elements.splice(index, 1, replacement);
11006 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11010 * Ext JS Library 1.1.1
11011 * Copyright(c) 2006-2007, Ext JS, LLC.
11013 * Originally Released Under LGPL - original licence link has changed is not relivant.
11016 * <script type="text/javascript">
11022 * @class Roo.data.Connection
11023 * @extends Roo.util.Observable
11024 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11025 * either to a configured URL, or to a URL specified at request time.<br><br>
11027 * Requests made by this class are asynchronous, and will return immediately. No data from
11028 * the server will be available to the statement immediately following the {@link #request} call.
11029 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11031 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11032 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11033 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11034 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11035 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11036 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11037 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11038 * standard DOM methods.
11040 * @param {Object} config a configuration object.
11042 Roo.data.Connection = function(config){
11043 Roo.apply(this, config);
11046 * @event beforerequest
11047 * Fires before a network request is made to retrieve a data object.
11048 * @param {Connection} conn This Connection object.
11049 * @param {Object} options The options config object passed to the {@link #request} method.
11051 "beforerequest" : true,
11053 * @event requestcomplete
11054 * Fires if the request was successfully completed.
11055 * @param {Connection} conn This Connection object.
11056 * @param {Object} response The XHR object containing the response data.
11057 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11058 * @param {Object} options The options config object passed to the {@link #request} method.
11060 "requestcomplete" : true,
11062 * @event requestexception
11063 * Fires if an error HTTP status was returned from the server.
11064 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11065 * @param {Connection} conn This Connection object.
11066 * @param {Object} response The XHR object containing the response data.
11067 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11068 * @param {Object} options The options config object passed to the {@link #request} method.
11070 "requestexception" : true
11072 Roo.data.Connection.superclass.constructor.call(this);
11075 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11077 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11080 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11081 * extra parameters to each request made by this object. (defaults to undefined)
11084 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11085 * to each request made by this object. (defaults to undefined)
11088 * @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)
11091 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11095 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11101 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11104 disableCaching: true,
11107 * Sends an HTTP request to a remote server.
11108 * @param {Object} options An object which may contain the following properties:<ul>
11109 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11110 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11111 * request, a url encoded string or a function to call to get either.</li>
11112 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11113 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11114 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11115 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11116 * <li>options {Object} The parameter to the request call.</li>
11117 * <li>success {Boolean} True if the request succeeded.</li>
11118 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11120 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11121 * The callback is passed the following parameters:<ul>
11122 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11123 * <li>options {Object} The parameter to the request call.</li>
11125 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11126 * The callback is passed the following parameters:<ul>
11127 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11128 * <li>options {Object} The parameter to the request call.</li>
11130 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11131 * for the callback function. Defaults to the browser window.</li>
11132 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11133 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11134 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11135 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11136 * params for the post data. Any params will be appended to the URL.</li>
11137 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11139 * @return {Number} transactionId
11141 request : function(o){
11142 if(this.fireEvent("beforerequest", this, o) !== false){
11145 if(typeof p == "function"){
11146 p = p.call(o.scope||window, o);
11148 if(typeof p == "object"){
11149 p = Roo.urlEncode(o.params);
11151 if(this.extraParams){
11152 var extras = Roo.urlEncode(this.extraParams);
11153 p = p ? (p + '&' + extras) : extras;
11156 var url = o.url || this.url;
11157 if(typeof url == 'function'){
11158 url = url.call(o.scope||window, o);
11162 var form = Roo.getDom(o.form);
11163 url = url || form.action;
11165 var enctype = form.getAttribute("enctype");
11166 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11167 return this.doFormUpload(o, p, url);
11169 var f = Roo.lib.Ajax.serializeForm(form);
11170 p = p ? (p + '&' + f) : f;
11173 var hs = o.headers;
11174 if(this.defaultHeaders){
11175 hs = Roo.apply(hs || {}, this.defaultHeaders);
11182 success: this.handleResponse,
11183 failure: this.handleFailure,
11185 argument: {options: o},
11186 timeout : this.timeout
11189 var method = o.method||this.method||(p ? "POST" : "GET");
11191 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11192 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11195 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11199 }else if(this.autoAbort !== false){
11203 if((method == 'GET' && p) || o.xmlData){
11204 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11207 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11208 return this.transId;
11210 Roo.callback(o.callback, o.scope, [o, null, null]);
11216 * Determine whether this object has a request outstanding.
11217 * @param {Number} transactionId (Optional) defaults to the last transaction
11218 * @return {Boolean} True if there is an outstanding request.
11220 isLoading : function(transId){
11222 return Roo.lib.Ajax.isCallInProgress(transId);
11224 return this.transId ? true : false;
11229 * Aborts any outstanding request.
11230 * @param {Number} transactionId (Optional) defaults to the last transaction
11232 abort : function(transId){
11233 if(transId || this.isLoading()){
11234 Roo.lib.Ajax.abort(transId || this.transId);
11239 handleResponse : function(response){
11240 this.transId = false;
11241 var options = response.argument.options;
11242 response.argument = options ? options.argument : null;
11243 this.fireEvent("requestcomplete", this, response, options);
11244 Roo.callback(options.success, options.scope, [response, options]);
11245 Roo.callback(options.callback, options.scope, [options, true, response]);
11249 handleFailure : function(response, e){
11250 this.transId = false;
11251 var options = response.argument.options;
11252 response.argument = options ? options.argument : null;
11253 this.fireEvent("requestexception", this, response, options, e);
11254 Roo.callback(options.failure, options.scope, [response, options]);
11255 Roo.callback(options.callback, options.scope, [options, false, response]);
11259 doFormUpload : function(o, ps, url){
11261 var frame = document.createElement('iframe');
11264 frame.className = 'x-hidden';
11266 frame.src = Roo.SSL_SECURE_URL;
11268 document.body.appendChild(frame);
11271 document.frames[id].name = id;
11274 var form = Roo.getDom(o.form);
11276 form.method = 'POST';
11277 form.enctype = form.encoding = 'multipart/form-data';
11283 if(ps){ // add dynamic params
11285 ps = Roo.urlDecode(ps, false);
11287 if(ps.hasOwnProperty(k)){
11288 hd = document.createElement('input');
11289 hd.type = 'hidden';
11292 form.appendChild(hd);
11299 var r = { // bogus response object
11304 r.argument = o ? o.argument : null;
11309 doc = frame.contentWindow.document;
11311 doc = (frame.contentDocument || window.frames[id].document);
11313 if(doc && doc.body){
11314 r.responseText = doc.body.innerHTML;
11316 if(doc && doc.XMLDocument){
11317 r.responseXML = doc.XMLDocument;
11319 r.responseXML = doc;
11326 Roo.EventManager.removeListener(frame, 'load', cb, this);
11328 this.fireEvent("requestcomplete", this, r, o);
11329 Roo.callback(o.success, o.scope, [r, o]);
11330 Roo.callback(o.callback, o.scope, [o, true, r]);
11332 setTimeout(function(){document.body.removeChild(frame);}, 100);
11335 Roo.EventManager.on(frame, 'load', cb, this);
11338 if(hiddens){ // remove dynamic params
11339 for(var i = 0, len = hiddens.length; i < len; i++){
11340 form.removeChild(hiddens[i]);
11348 * @extends Roo.data.Connection
11349 * Global Ajax request class.
11353 Roo.Ajax = new Roo.data.Connection({
11356 * @cfg {String} url @hide
11359 * @cfg {Object} extraParams @hide
11362 * @cfg {Object} defaultHeaders @hide
11365 * @cfg {String} method (Optional) @hide
11368 * @cfg {Number} timeout (Optional) @hide
11371 * @cfg {Boolean} autoAbort (Optional) @hide
11375 * @cfg {Boolean} disableCaching (Optional) @hide
11379 * @property disableCaching
11380 * True to add a unique cache-buster param to GET requests. (defaults to true)
11385 * The default URL to be used for requests to the server. (defaults to undefined)
11389 * @property extraParams
11390 * An object containing properties which are used as
11391 * extra parameters to each request made by this object. (defaults to undefined)
11395 * @property defaultHeaders
11396 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11401 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11405 * @property timeout
11406 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11411 * @property autoAbort
11412 * Whether a new request should abort any pending requests. (defaults to false)
11418 * Serialize the passed form into a url encoded string
11419 * @param {String/HTMLElement} form
11422 serializeForm : function(form){
11423 return Roo.lib.Ajax.serializeForm(form);
11427 * Ext JS Library 1.1.1
11428 * Copyright(c) 2006-2007, Ext JS, LLC.
11430 * Originally Released Under LGPL - original licence link has changed is not relivant.
11433 * <script type="text/javascript">
11438 * @extends Roo.data.Connection
11439 * Global Ajax request class.
11441 * @instanceOf Roo.data.Connection
11443 Roo.Ajax = new Roo.data.Connection({
11452 * @cfg {String} url @hide
11455 * @cfg {Object} extraParams @hide
11458 * @cfg {Object} defaultHeaders @hide
11461 * @cfg {String} method (Optional) @hide
11464 * @cfg {Number} timeout (Optional) @hide
11467 * @cfg {Boolean} autoAbort (Optional) @hide
11471 * @cfg {Boolean} disableCaching (Optional) @hide
11475 * @property disableCaching
11476 * True to add a unique cache-buster param to GET requests. (defaults to true)
11481 * The default URL to be used for requests to the server. (defaults to undefined)
11485 * @property extraParams
11486 * An object containing properties which are used as
11487 * extra parameters to each request made by this object. (defaults to undefined)
11491 * @property defaultHeaders
11492 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11497 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11501 * @property timeout
11502 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11507 * @property autoAbort
11508 * Whether a new request should abort any pending requests. (defaults to false)
11514 * Serialize the passed form into a url encoded string
11515 * @param {String/HTMLElement} form
11518 serializeForm : function(form){
11519 return Roo.lib.Ajax.serializeForm(form);
11523 * Ext JS Library 1.1.1
11524 * Copyright(c) 2006-2007, Ext JS, LLC.
11526 * Originally Released Under LGPL - original licence link has changed is not relivant.
11529 * <script type="text/javascript">
11534 * @class Roo.UpdateManager
11535 * @extends Roo.util.Observable
11536 * Provides AJAX-style update for Element object.<br><br>
11539 * // Get it from a Roo.Element object
11540 * var el = Roo.get("foo");
11541 * var mgr = el.getUpdateManager();
11542 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11544 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11546 * // or directly (returns the same UpdateManager instance)
11547 * var mgr = new Roo.UpdateManager("myElementId");
11548 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11549 * mgr.on("update", myFcnNeedsToKnow);
11551 // short handed call directly from the element object
11552 Roo.get("foo").load({
11556 text: "Loading Foo..."
11560 * Create new UpdateManager directly.
11561 * @param {String/HTMLElement/Roo.Element} el The element to update
11562 * @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).
11564 Roo.UpdateManager = function(el, forceNew){
11566 if(!forceNew && el.updateManager){
11567 return el.updateManager;
11570 * The Element object
11571 * @type Roo.Element
11575 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11578 this.defaultUrl = null;
11582 * @event beforeupdate
11583 * Fired before an update is made, return false from your handler and the update is cancelled.
11584 * @param {Roo.Element} el
11585 * @param {String/Object/Function} url
11586 * @param {String/Object} params
11588 "beforeupdate": true,
11591 * Fired after successful update is made.
11592 * @param {Roo.Element} el
11593 * @param {Object} oResponseObject The response Object
11598 * Fired on update failure.
11599 * @param {Roo.Element} el
11600 * @param {Object} oResponseObject The response Object
11604 var d = Roo.UpdateManager.defaults;
11606 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11609 this.sslBlankUrl = d.sslBlankUrl;
11611 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11614 this.disableCaching = d.disableCaching;
11616 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11619 this.indicatorText = d.indicatorText;
11621 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11624 this.showLoadIndicator = d.showLoadIndicator;
11626 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11629 this.timeout = d.timeout;
11632 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11635 this.loadScripts = d.loadScripts;
11638 * Transaction object of current executing transaction
11640 this.transaction = null;
11645 this.autoRefreshProcId = null;
11647 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11650 this.refreshDelegate = this.refresh.createDelegate(this);
11652 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11655 this.updateDelegate = this.update.createDelegate(this);
11657 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11660 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11664 this.successDelegate = this.processSuccess.createDelegate(this);
11668 this.failureDelegate = this.processFailure.createDelegate(this);
11670 if(!this.renderer){
11672 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11674 this.renderer = new Roo.UpdateManager.BasicRenderer();
11677 Roo.UpdateManager.superclass.constructor.call(this);
11680 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11682 * Get the Element this UpdateManager is bound to
11683 * @return {Roo.Element} The element
11685 getEl : function(){
11689 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11690 * @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:
11693 url: "your-url.php",<br/>
11694 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11695 callback: yourFunction,<br/>
11696 scope: yourObject, //(optional scope) <br/>
11697 discardUrl: false, <br/>
11698 nocache: false,<br/>
11699 text: "Loading...",<br/>
11701 scripts: false<br/>
11704 * The only required property is url. The optional properties nocache, text and scripts
11705 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11706 * @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}
11707 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11708 * @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.
11710 update : function(url, params, callback, discardUrl){
11711 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11712 var method = this.method, cfg;
11713 if(typeof url == "object"){ // must be config object
11716 params = params || cfg.params;
11717 callback = callback || cfg.callback;
11718 discardUrl = discardUrl || cfg.discardUrl;
11719 if(callback && cfg.scope){
11720 callback = callback.createDelegate(cfg.scope);
11722 if(typeof cfg.method != "undefined"){method = cfg.method;};
11723 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11724 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11725 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11726 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11728 this.showLoading();
11730 this.defaultUrl = url;
11732 if(typeof url == "function"){
11733 url = url.call(this);
11736 method = method || (params ? "POST" : "GET");
11737 if(method == "GET"){
11738 url = this.prepareUrl(url);
11741 var o = Roo.apply(cfg ||{}, {
11744 success: this.successDelegate,
11745 failure: this.failureDelegate,
11746 callback: undefined,
11747 timeout: (this.timeout*1000),
11748 argument: {"url": url, "form": null, "callback": callback, "params": params}
11751 this.transaction = Roo.Ajax.request(o);
11756 * 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.
11757 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11758 * @param {String/HTMLElement} form The form Id or form element
11759 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11760 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11761 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11763 formUpdate : function(form, url, reset, callback){
11764 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11765 if(typeof url == "function"){
11766 url = url.call(this);
11768 form = Roo.getDom(form);
11769 this.transaction = Roo.Ajax.request({
11772 success: this.successDelegate,
11773 failure: this.failureDelegate,
11774 timeout: (this.timeout*1000),
11775 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11777 this.showLoading.defer(1, this);
11782 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11783 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11785 refresh : function(callback){
11786 if(this.defaultUrl == null){
11789 this.update(this.defaultUrl, null, callback, true);
11793 * Set this element to auto refresh.
11794 * @param {Number} interval How often to update (in seconds).
11795 * @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)
11796 * @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}
11797 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11798 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11800 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11802 this.update(url || this.defaultUrl, params, callback, true);
11804 if(this.autoRefreshProcId){
11805 clearInterval(this.autoRefreshProcId);
11807 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11811 * Stop auto refresh on this element.
11813 stopAutoRefresh : function(){
11814 if(this.autoRefreshProcId){
11815 clearInterval(this.autoRefreshProcId);
11816 delete this.autoRefreshProcId;
11820 isAutoRefreshing : function(){
11821 return this.autoRefreshProcId ? true : false;
11824 * Called to update the element to "Loading" state. Override to perform custom action.
11826 showLoading : function(){
11827 if(this.showLoadIndicator){
11828 this.el.update(this.indicatorText);
11833 * Adds unique parameter to query string if disableCaching = true
11836 prepareUrl : function(url){
11837 if(this.disableCaching){
11838 var append = "_dc=" + (new Date().getTime());
11839 if(url.indexOf("?") !== -1){
11840 url += "&" + append;
11842 url += "?" + append;
11851 processSuccess : function(response){
11852 this.transaction = null;
11853 if(response.argument.form && response.argument.reset){
11854 try{ // put in try/catch since some older FF releases had problems with this
11855 response.argument.form.reset();
11858 if(this.loadScripts){
11859 this.renderer.render(this.el, response, this,
11860 this.updateComplete.createDelegate(this, [response]));
11862 this.renderer.render(this.el, response, this);
11863 this.updateComplete(response);
11867 updateComplete : function(response){
11868 this.fireEvent("update", this.el, response);
11869 if(typeof response.argument.callback == "function"){
11870 response.argument.callback(this.el, true, response);
11877 processFailure : function(response){
11878 this.transaction = null;
11879 this.fireEvent("failure", this.el, response);
11880 if(typeof response.argument.callback == "function"){
11881 response.argument.callback(this.el, false, response);
11886 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11887 * @param {Object} renderer The object implementing the render() method
11889 setRenderer : function(renderer){
11890 this.renderer = renderer;
11893 getRenderer : function(){
11894 return this.renderer;
11898 * Set the defaultUrl used for updates
11899 * @param {String/Function} defaultUrl The url or a function to call to get the url
11901 setDefaultUrl : function(defaultUrl){
11902 this.defaultUrl = defaultUrl;
11906 * Aborts the executing transaction
11908 abort : function(){
11909 if(this.transaction){
11910 Roo.Ajax.abort(this.transaction);
11915 * Returns true if an update is in progress
11916 * @return {Boolean}
11918 isUpdating : function(){
11919 if(this.transaction){
11920 return Roo.Ajax.isLoading(this.transaction);
11927 * @class Roo.UpdateManager.defaults
11928 * @static (not really - but it helps the doc tool)
11929 * The defaults collection enables customizing the default properties of UpdateManager
11931 Roo.UpdateManager.defaults = {
11933 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11939 * True to process scripts by default (Defaults to false).
11942 loadScripts : false,
11945 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11948 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11950 * Whether to append unique parameter on get request to disable caching (Defaults to false).
11953 disableCaching : false,
11955 * Whether to show indicatorText when loading (Defaults to true).
11958 showLoadIndicator : true,
11960 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
11963 indicatorText : '<div class="loading-indicator">Loading...</div>'
11967 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11969 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11970 * @param {String/HTMLElement/Roo.Element} el The element to update
11971 * @param {String} url The url
11972 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11973 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11976 * @member Roo.UpdateManager
11978 Roo.UpdateManager.updateElement = function(el, url, params, options){
11979 var um = Roo.get(el, true).getUpdateManager();
11980 Roo.apply(um, options);
11981 um.update(url, params, options ? options.callback : null);
11983 // alias for backwards compat
11984 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
11986 * @class Roo.UpdateManager.BasicRenderer
11987 * Default Content renderer. Updates the elements innerHTML with the responseText.
11989 Roo.UpdateManager.BasicRenderer = function(){};
11991 Roo.UpdateManager.BasicRenderer.prototype = {
11993 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
11994 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
11995 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
11996 * @param {Roo.Element} el The element being rendered
11997 * @param {Object} response The YUI Connect response object
11998 * @param {UpdateManager} updateManager The calling update manager
11999 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12001 render : function(el, response, updateManager, callback){
12002 el.update(response.responseText, updateManager.loadScripts, callback);
12007 * Ext JS Library 1.1.1
12008 * Copyright(c) 2006-2007, Ext JS, LLC.
12010 * Originally Released Under LGPL - original licence link has changed is not relivant.
12013 * <script type="text/javascript">
12017 * @class Roo.util.DelayedTask
12018 * Provides a convenient method of performing setTimeout where a new
12019 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12020 * You can use this class to buffer
12021 * the keypress events for a certain number of milliseconds, and perform only if they stop
12022 * for that amount of time.
12023 * @constructor The parameters to this constructor serve as defaults and are not required.
12024 * @param {Function} fn (optional) The default function to timeout
12025 * @param {Object} scope (optional) The default scope of that timeout
12026 * @param {Array} args (optional) The default Array of arguments
12028 Roo.util.DelayedTask = function(fn, scope, args){
12029 var id = null, d, t;
12031 var call = function(){
12032 var now = new Date().getTime();
12036 fn.apply(scope, args || []);
12040 * Cancels any pending timeout and queues a new one
12041 * @param {Number} delay The milliseconds to delay
12042 * @param {Function} newFn (optional) Overrides function passed to constructor
12043 * @param {Object} newScope (optional) Overrides scope passed to constructor
12044 * @param {Array} newArgs (optional) Overrides args passed to constructor
12046 this.delay = function(delay, newFn, newScope, newArgs){
12047 if(id && delay != d){
12051 t = new Date().getTime();
12053 scope = newScope || scope;
12054 args = newArgs || args;
12056 id = setInterval(call, d);
12061 * Cancel the last queued timeout
12063 this.cancel = function(){
12071 * Ext JS Library 1.1.1
12072 * Copyright(c) 2006-2007, Ext JS, LLC.
12074 * Originally Released Under LGPL - original licence link has changed is not relivant.
12077 * <script type="text/javascript">
12081 Roo.util.TaskRunner = function(interval){
12082 interval = interval || 10;
12083 var tasks = [], removeQueue = [];
12085 var running = false;
12087 var stopThread = function(){
12093 var startThread = function(){
12096 id = setInterval(runTasks, interval);
12100 var removeTask = function(task){
12101 removeQueue.push(task);
12107 var runTasks = function(){
12108 if(removeQueue.length > 0){
12109 for(var i = 0, len = removeQueue.length; i < len; i++){
12110 tasks.remove(removeQueue[i]);
12113 if(tasks.length < 1){
12118 var now = new Date().getTime();
12119 for(var i = 0, len = tasks.length; i < len; ++i){
12121 var itime = now - t.taskRunTime;
12122 if(t.interval <= itime){
12123 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12124 t.taskRunTime = now;
12125 if(rt === false || t.taskRunCount === t.repeat){
12130 if(t.duration && t.duration <= (now - t.taskStartTime)){
12137 * Queues a new task.
12138 * @param {Object} task
12140 this.start = function(task){
12142 task.taskStartTime = new Date().getTime();
12143 task.taskRunTime = 0;
12144 task.taskRunCount = 0;
12149 this.stop = function(task){
12154 this.stopAll = function(){
12156 for(var i = 0, len = tasks.length; i < len; i++){
12157 if(tasks[i].onStop){
12166 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12168 * Ext JS Library 1.1.1
12169 * Copyright(c) 2006-2007, Ext JS, LLC.
12171 * Originally Released Under LGPL - original licence link has changed is not relivant.
12174 * <script type="text/javascript">
12179 * @class Roo.util.MixedCollection
12180 * @extends Roo.util.Observable
12181 * A Collection class that maintains both numeric indexes and keys and exposes events.
12183 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12184 * collection (defaults to false)
12185 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12186 * and return the key value for that item. This is used when available to look up the key on items that
12187 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12188 * equivalent to providing an implementation for the {@link #getKey} method.
12190 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12198 * Fires when the collection is cleared.
12203 * Fires when an item is added to the collection.
12204 * @param {Number} index The index at which the item was added.
12205 * @param {Object} o The item added.
12206 * @param {String} key The key associated with the added item.
12211 * Fires when an item is replaced in the collection.
12212 * @param {String} key he key associated with the new added.
12213 * @param {Object} old The item being replaced.
12214 * @param {Object} new The new item.
12219 * Fires when an item is removed from the collection.
12220 * @param {Object} o The item being removed.
12221 * @param {String} key (optional) The key associated with the removed item.
12226 this.allowFunctions = allowFunctions === true;
12228 this.getKey = keyFn;
12230 Roo.util.MixedCollection.superclass.constructor.call(this);
12233 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12234 allowFunctions : false,
12237 * Adds an item to the collection.
12238 * @param {String} key The key to associate with the item
12239 * @param {Object} o The item to add.
12240 * @return {Object} The item added.
12242 add : function(key, o){
12243 if(arguments.length == 1){
12245 key = this.getKey(o);
12247 if(typeof key == "undefined" || key === null){
12249 this.items.push(o);
12250 this.keys.push(null);
12252 var old = this.map[key];
12254 return this.replace(key, o);
12257 this.items.push(o);
12259 this.keys.push(key);
12261 this.fireEvent("add", this.length-1, o, key);
12266 * MixedCollection has a generic way to fetch keys if you implement getKey.
12269 var mc = new Roo.util.MixedCollection();
12270 mc.add(someEl.dom.id, someEl);
12271 mc.add(otherEl.dom.id, otherEl);
12275 var mc = new Roo.util.MixedCollection();
12276 mc.getKey = function(el){
12282 // or via the constructor
12283 var mc = new Roo.util.MixedCollection(false, function(el){
12289 * @param o {Object} The item for which to find the key.
12290 * @return {Object} The key for the passed item.
12292 getKey : function(o){
12297 * Replaces an item in the collection.
12298 * @param {String} key The key associated with the item to replace, or the item to replace.
12299 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12300 * @return {Object} The new item.
12302 replace : function(key, o){
12303 if(arguments.length == 1){
12305 key = this.getKey(o);
12307 var old = this.item(key);
12308 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12309 return this.add(key, o);
12311 var index = this.indexOfKey(key);
12312 this.items[index] = o;
12314 this.fireEvent("replace", key, old, o);
12319 * Adds all elements of an Array or an Object to the collection.
12320 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12321 * an Array of values, each of which are added to the collection.
12323 addAll : function(objs){
12324 if(arguments.length > 1 || objs instanceof Array){
12325 var args = arguments.length > 1 ? arguments : objs;
12326 for(var i = 0, len = args.length; i < len; i++){
12330 for(var key in objs){
12331 if(this.allowFunctions || typeof objs[key] != "function"){
12332 this.add(key, objs[key]);
12339 * Executes the specified function once for every item in the collection, passing each
12340 * item as the first and only parameter. returning false from the function will stop the iteration.
12341 * @param {Function} fn The function to execute for each item.
12342 * @param {Object} scope (optional) The scope in which to execute the function.
12344 each : function(fn, scope){
12345 var items = [].concat(this.items); // each safe for removal
12346 for(var i = 0, len = items.length; i < len; i++){
12347 if(fn.call(scope || items[i], items[i], i, len) === false){
12354 * Executes the specified function once for every key in the collection, passing each
12355 * key, and its associated item as the first two parameters.
12356 * @param {Function} fn The function to execute for each item.
12357 * @param {Object} scope (optional) The scope in which to execute the function.
12359 eachKey : function(fn, scope){
12360 for(var i = 0, len = this.keys.length; i < len; i++){
12361 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12366 * Returns the first item in the collection which elicits a true return value from the
12367 * passed selection function.
12368 * @param {Function} fn The selection function to execute for each item.
12369 * @param {Object} scope (optional) The scope in which to execute the function.
12370 * @return {Object} The first item in the collection which returned true from the selection function.
12372 find : function(fn, scope){
12373 for(var i = 0, len = this.items.length; i < len; i++){
12374 if(fn.call(scope || window, this.items[i], this.keys[i])){
12375 return this.items[i];
12382 * Inserts an item at the specified index in the collection.
12383 * @param {Number} index The index to insert the item at.
12384 * @param {String} key The key to associate with the new item, or the item itself.
12385 * @param {Object} o (optional) If the second parameter was a key, the new item.
12386 * @return {Object} The item inserted.
12388 insert : function(index, key, o){
12389 if(arguments.length == 2){
12391 key = this.getKey(o);
12393 if(index >= this.length){
12394 return this.add(key, o);
12397 this.items.splice(index, 0, o);
12398 if(typeof key != "undefined" && key != null){
12401 this.keys.splice(index, 0, key);
12402 this.fireEvent("add", index, o, key);
12407 * Removed an item from the collection.
12408 * @param {Object} o The item to remove.
12409 * @return {Object} The item removed.
12411 remove : function(o){
12412 return this.removeAt(this.indexOf(o));
12416 * Remove an item from a specified index in the collection.
12417 * @param {Number} index The index within the collection of the item to remove.
12419 removeAt : function(index){
12420 if(index < this.length && index >= 0){
12422 var o = this.items[index];
12423 this.items.splice(index, 1);
12424 var key = this.keys[index];
12425 if(typeof key != "undefined"){
12426 delete this.map[key];
12428 this.keys.splice(index, 1);
12429 this.fireEvent("remove", o, key);
12434 * Removed an item associated with the passed key fom the collection.
12435 * @param {String} key The key of the item to remove.
12437 removeKey : function(key){
12438 return this.removeAt(this.indexOfKey(key));
12442 * Returns the number of items in the collection.
12443 * @return {Number} the number of items in the collection.
12445 getCount : function(){
12446 return this.length;
12450 * Returns index within the collection of the passed Object.
12451 * @param {Object} o The item to find the index of.
12452 * @return {Number} index of the item.
12454 indexOf : function(o){
12455 if(!this.items.indexOf){
12456 for(var i = 0, len = this.items.length; i < len; i++){
12457 if(this.items[i] == o) return i;
12461 return this.items.indexOf(o);
12466 * Returns index within the collection of the passed key.
12467 * @param {String} key The key to find the index of.
12468 * @return {Number} index of the key.
12470 indexOfKey : function(key){
12471 if(!this.keys.indexOf){
12472 for(var i = 0, len = this.keys.length; i < len; i++){
12473 if(this.keys[i] == key) return i;
12477 return this.keys.indexOf(key);
12482 * Returns the item associated with the passed key OR index. Key has priority over index.
12483 * @param {String/Number} key The key or index of the item.
12484 * @return {Object} The item associated with the passed key.
12486 item : function(key){
12487 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12488 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12492 * Returns the item at the specified index.
12493 * @param {Number} index The index of the item.
12496 itemAt : function(index){
12497 return this.items[index];
12501 * Returns the item associated with the passed key.
12502 * @param {String/Number} key The key of the item.
12503 * @return {Object} The item associated with the passed key.
12505 key : function(key){
12506 return this.map[key];
12510 * Returns true if the collection contains the passed Object as an item.
12511 * @param {Object} o The Object to look for in the collection.
12512 * @return {Boolean} True if the collection contains the Object as an item.
12514 contains : function(o){
12515 return this.indexOf(o) != -1;
12519 * Returns true if the collection contains the passed Object as a key.
12520 * @param {String} key The key to look for in the collection.
12521 * @return {Boolean} True if the collection contains the Object as a key.
12523 containsKey : function(key){
12524 return typeof this.map[key] != "undefined";
12528 * Removes all items from the collection.
12530 clear : function(){
12535 this.fireEvent("clear");
12539 * Returns the first item in the collection.
12540 * @return {Object} the first item in the collection..
12542 first : function(){
12543 return this.items[0];
12547 * Returns the last item in the collection.
12548 * @return {Object} the last item in the collection..
12551 return this.items[this.length-1];
12554 _sort : function(property, dir, fn){
12555 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12556 fn = fn || function(a, b){
12559 var c = [], k = this.keys, items = this.items;
12560 for(var i = 0, len = items.length; i < len; i++){
12561 c[c.length] = {key: k[i], value: items[i], index: i};
12563 c.sort(function(a, b){
12564 var v = fn(a[property], b[property]) * dsc;
12566 v = (a.index < b.index ? -1 : 1);
12570 for(var i = 0, len = c.length; i < len; i++){
12571 items[i] = c[i].value;
12574 this.fireEvent("sort", this);
12578 * Sorts this collection with the passed comparison function
12579 * @param {String} direction (optional) "ASC" or "DESC"
12580 * @param {Function} fn (optional) comparison function
12582 sort : function(dir, fn){
12583 this._sort("value", dir, fn);
12587 * Sorts this collection by keys
12588 * @param {String} direction (optional) "ASC" or "DESC"
12589 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12591 keySort : function(dir, fn){
12592 this._sort("key", dir, fn || function(a, b){
12593 return String(a).toUpperCase()-String(b).toUpperCase();
12598 * Returns a range of items in this collection
12599 * @param {Number} startIndex (optional) defaults to 0
12600 * @param {Number} endIndex (optional) default to the last item
12601 * @return {Array} An array of items
12603 getRange : function(start, end){
12604 var items = this.items;
12605 if(items.length < 1){
12608 start = start || 0;
12609 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12612 for(var i = start; i <= end; i++) {
12613 r[r.length] = items[i];
12616 for(var i = start; i >= end; i--) {
12617 r[r.length] = items[i];
12624 * Filter the <i>objects</i> in this collection by a specific property.
12625 * Returns a new collection that has been filtered.
12626 * @param {String} property A property on your objects
12627 * @param {String/RegExp} value Either string that the property values
12628 * should start with or a RegExp to test against the property
12629 * @return {MixedCollection} The new filtered collection
12631 filter : function(property, value){
12632 if(!value.exec){ // not a regex
12633 value = String(value);
12634 if(value.length == 0){
12635 return this.clone();
12637 value = new RegExp("^" + Roo.escapeRe(value), "i");
12639 return this.filterBy(function(o){
12640 return o && value.test(o[property]);
12645 * Filter by a function. * Returns a new collection that has been filtered.
12646 * The passed function will be called with each
12647 * object in the collection. If the function returns true, the value is included
12648 * otherwise it is filtered.
12649 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12650 * @param {Object} scope (optional) The scope of the function (defaults to this)
12651 * @return {MixedCollection} The new filtered collection
12653 filterBy : function(fn, scope){
12654 var r = new Roo.util.MixedCollection();
12655 r.getKey = this.getKey;
12656 var k = this.keys, it = this.items;
12657 for(var i = 0, len = it.length; i < len; i++){
12658 if(fn.call(scope||this, it[i], k[i])){
12659 r.add(k[i], it[i]);
12666 * Creates a duplicate of this collection
12667 * @return {MixedCollection}
12669 clone : function(){
12670 var r = new Roo.util.MixedCollection();
12671 var k = this.keys, it = this.items;
12672 for(var i = 0, len = it.length; i < len; i++){
12673 r.add(k[i], it[i]);
12675 r.getKey = this.getKey;
12680 * Returns the item associated with the passed key or index.
12682 * @param {String/Number} key The key or index of the item.
12683 * @return {Object} The item associated with the passed key.
12685 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12687 * Ext JS Library 1.1.1
12688 * Copyright(c) 2006-2007, Ext JS, LLC.
12690 * Originally Released Under LGPL - original licence link has changed is not relivant.
12693 * <script type="text/javascript">
12696 * @class Roo.util.JSON
12697 * Modified version of Douglas Crockford"s json.js that doesn"t
12698 * mess with the Object prototype
12699 * http://www.json.org/js.html
12702 Roo.util.JSON = new (function(){
12703 var useHasOwn = {}.hasOwnProperty ? true : false;
12705 // crashes Safari in some instances
12706 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12708 var pad = function(n) {
12709 return n < 10 ? "0" + n : n;
12722 var encodeString = function(s){
12723 if (/["\\\x00-\x1f]/.test(s)) {
12724 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12729 c = b.charCodeAt();
12731 Math.floor(c / 16).toString(16) +
12732 (c % 16).toString(16);
12735 return '"' + s + '"';
12738 var encodeArray = function(o){
12739 var a = ["["], b, i, l = o.length, v;
12740 for (i = 0; i < l; i += 1) {
12742 switch (typeof v) {
12751 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12759 var encodeDate = function(o){
12760 return '"' + o.getFullYear() + "-" +
12761 pad(o.getMonth() + 1) + "-" +
12762 pad(o.getDate()) + "T" +
12763 pad(o.getHours()) + ":" +
12764 pad(o.getMinutes()) + ":" +
12765 pad(o.getSeconds()) + '"';
12769 * Encodes an Object, Array or other value
12770 * @param {Mixed} o The variable to encode
12771 * @return {String} The JSON string
12773 this.encode = function(o)
12775 // should this be extended to fully wrap stringify..
12777 if(typeof o == "undefined" || o === null){
12779 }else if(o instanceof Array){
12780 return encodeArray(o);
12781 }else if(o instanceof Date){
12782 return encodeDate(o);
12783 }else if(typeof o == "string"){
12784 return encodeString(o);
12785 }else if(typeof o == "number"){
12786 return isFinite(o) ? String(o) : "null";
12787 }else if(typeof o == "boolean"){
12790 var a = ["{"], b, i, v;
12792 if(!useHasOwn || o.hasOwnProperty(i)) {
12794 switch (typeof v) {
12803 a.push(this.encode(i), ":",
12804 v === null ? "null" : this.encode(v));
12815 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12816 * @param {String} json The JSON string
12817 * @return {Object} The resulting object
12819 this.decode = function(json){
12821 return /** eval:var:json */ eval("(" + json + ')');
12825 * Shorthand for {@link Roo.util.JSON#encode}
12826 * @member Roo encode
12828 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12830 * Shorthand for {@link Roo.util.JSON#decode}
12831 * @member Roo decode
12833 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12836 * Ext JS Library 1.1.1
12837 * Copyright(c) 2006-2007, Ext JS, LLC.
12839 * Originally Released Under LGPL - original licence link has changed is not relivant.
12842 * <script type="text/javascript">
12846 * @class Roo.util.Format
12847 * Reusable data formatting functions
12850 Roo.util.Format = function(){
12851 var trimRe = /^\s+|\s+$/g;
12854 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12855 * @param {String} value The string to truncate
12856 * @param {Number} length The maximum length to allow before truncating
12857 * @return {String} The converted text
12859 ellipsis : function(value, len){
12860 if(value && value.length > len){
12861 return value.substr(0, len-3)+"...";
12867 * Checks a reference and converts it to empty string if it is undefined
12868 * @param {Mixed} value Reference to check
12869 * @return {Mixed} Empty string if converted, otherwise the original value
12871 undef : function(value){
12872 return typeof value != "undefined" ? value : "";
12876 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12877 * @param {String} value The string to encode
12878 * @return {String} The encoded text
12880 htmlEncode : function(value){
12881 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12885 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12886 * @param {String} value The string to decode
12887 * @return {String} The decoded text
12889 htmlDecode : function(value){
12890 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12894 * Trims any whitespace from either side of a string
12895 * @param {String} value The text to trim
12896 * @return {String} The trimmed text
12898 trim : function(value){
12899 return String(value).replace(trimRe, "");
12903 * Returns a substring from within an original string
12904 * @param {String} value The original text
12905 * @param {Number} start The start index of the substring
12906 * @param {Number} length The length of the substring
12907 * @return {String} The substring
12909 substr : function(value, start, length){
12910 return String(value).substr(start, length);
12914 * Converts a string to all lower case letters
12915 * @param {String} value The text to convert
12916 * @return {String} The converted text
12918 lowercase : function(value){
12919 return String(value).toLowerCase();
12923 * Converts a string to all upper case letters
12924 * @param {String} value The text to convert
12925 * @return {String} The converted text
12927 uppercase : function(value){
12928 return String(value).toUpperCase();
12932 * Converts the first character only of a string to upper case
12933 * @param {String} value The text to convert
12934 * @return {String} The converted text
12936 capitalize : function(value){
12937 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12941 call : function(value, fn){
12942 if(arguments.length > 2){
12943 var args = Array.prototype.slice.call(arguments, 2);
12944 args.unshift(value);
12946 return /** eval:var:value */ eval(fn).apply(window, args);
12948 /** eval:var:value */
12949 return /** eval:var:value */ eval(fn).call(window, value);
12955 * safer version of Math.toFixed..??/
12956 * @param {Number/String} value The numeric value to format
12957 * @param {Number/String} value Decimal places
12958 * @return {String} The formatted currency string
12960 toFixed : function(v, n)
12962 // why not use to fixed - precision is buggered???
12964 return Math.round(v-0);
12966 var fact = Math.pow(10,n+1);
12967 v = (Math.round((v-0)*fact))/fact;
12968 var z = (''+fact).substring(2);
12969 if (v == Math.floor(v)) {
12970 return Math.floor(v) + '.' + z;
12973 // now just padd decimals..
12974 var ps = String(v).split('.');
12975 var fd = (ps[1] + z);
12976 var r = fd.substring(0,n);
12977 var rm = fd.substring(n);
12979 return ps[0] + '.' + r;
12981 r*=1; // turn it into a number;
12983 if (String(r).length != n) {
12986 r = String(r).substring(1); // chop the end off.
12989 return ps[0] + '.' + r;
12994 * Format a number as US currency
12995 * @param {Number/String} value The numeric value to format
12996 * @return {String} The formatted currency string
12998 usMoney : function(v){
12999 v = (Math.round((v-0)*100))/100;
13000 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13002 var ps = v.split('.');
13004 var sub = ps[1] ? '.'+ ps[1] : '.00';
13005 var r = /(\d+)(\d{3})/;
13006 while (r.test(whole)) {
13007 whole = whole.replace(r, '$1' + ',' + '$2');
13009 return "$" + whole + sub ;
13013 * Parse a value into a formatted date using the specified format pattern.
13014 * @param {Mixed} value The value to format
13015 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13016 * @return {String} The formatted date string
13018 date : function(v, format){
13022 if(!(v instanceof Date)){
13023 v = new Date(Date.parse(v));
13025 return v.dateFormat(format || "m/d/Y");
13029 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13030 * @param {String} format Any valid date format string
13031 * @return {Function} The date formatting function
13033 dateRenderer : function(format){
13034 return function(v){
13035 return Roo.util.Format.date(v, format);
13040 stripTagsRE : /<\/?[^>]+>/gi,
13043 * Strips all HTML tags
13044 * @param {Mixed} value The text from which to strip tags
13045 * @return {String} The stripped text
13047 stripTags : function(v){
13048 return !v ? v : String(v).replace(this.stripTagsRE, "");
13053 * Ext JS Library 1.1.1
13054 * Copyright(c) 2006-2007, Ext JS, LLC.
13056 * Originally Released Under LGPL - original licence link has changed is not relivant.
13059 * <script type="text/javascript">
13066 * @class Roo.MasterTemplate
13067 * @extends Roo.Template
13068 * Provides a template that can have child templates. The syntax is:
13070 var t = new Roo.MasterTemplate(
13071 '<select name="{name}">',
13072 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13075 t.add('options', {value: 'foo', text: 'bar'});
13076 // or you can add multiple child elements in one shot
13077 t.addAll('options', [
13078 {value: 'foo', text: 'bar'},
13079 {value: 'foo2', text: 'bar2'},
13080 {value: 'foo3', text: 'bar3'}
13082 // then append, applying the master template values
13083 t.append('my-form', {name: 'my-select'});
13085 * A name attribute for the child template is not required if you have only one child
13086 * template or you want to refer to them by index.
13088 Roo.MasterTemplate = function(){
13089 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13090 this.originalHtml = this.html;
13092 var m, re = this.subTemplateRe;
13095 while(m = re.exec(this.html)){
13096 var name = m[1], content = m[2];
13101 tpl : new Roo.Template(content)
13104 st[name] = st[subIndex];
13106 st[subIndex].tpl.compile();
13107 st[subIndex].tpl.call = this.call.createDelegate(this);
13110 this.subCount = subIndex;
13113 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13115 * The regular expression used to match sub templates
13119 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13122 * Applies the passed values to a child template.
13123 * @param {String/Number} name (optional) The name or index of the child template
13124 * @param {Array/Object} values The values to be applied to the template
13125 * @return {MasterTemplate} this
13127 add : function(name, values){
13128 if(arguments.length == 1){
13129 values = arguments[0];
13132 var s = this.subs[name];
13133 s.buffer[s.buffer.length] = s.tpl.apply(values);
13138 * Applies all the passed values to a child template.
13139 * @param {String/Number} name (optional) The name or index of the child template
13140 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13141 * @param {Boolean} reset (optional) True to reset the template first
13142 * @return {MasterTemplate} this
13144 fill : function(name, values, reset){
13146 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13154 for(var i = 0, len = values.length; i < len; i++){
13155 this.add(name, values[i]);
13161 * Resets the template for reuse
13162 * @return {MasterTemplate} this
13164 reset : function(){
13166 for(var i = 0; i < this.subCount; i++){
13172 applyTemplate : function(values){
13174 var replaceIndex = -1;
13175 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13176 return s[++replaceIndex].buffer.join("");
13178 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13181 apply : function(){
13182 return this.applyTemplate.apply(this, arguments);
13185 compile : function(){return this;}
13189 * Alias for fill().
13192 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13194 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13195 * var tpl = Roo.MasterTemplate.from('element-id');
13196 * @param {String/HTMLElement} el
13197 * @param {Object} config
13200 Roo.MasterTemplate.from = function(el, config){
13201 el = Roo.getDom(el);
13202 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13205 * Ext JS Library 1.1.1
13206 * Copyright(c) 2006-2007, Ext JS, LLC.
13208 * Originally Released Under LGPL - original licence link has changed is not relivant.
13211 * <script type="text/javascript">
13216 * @class Roo.util.CSS
13217 * Utility class for manipulating CSS rules
13220 Roo.util.CSS = function(){
13222 var doc = document;
13224 var camelRe = /(-[a-z])/gi;
13225 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13229 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13230 * tag and appended to the HEAD of the document.
13231 * @param {String|Object} cssText The text containing the css rules
13232 * @param {String} id An id to add to the stylesheet for later removal
13233 * @return {StyleSheet}
13235 createStyleSheet : function(cssText, id){
13237 var head = doc.getElementsByTagName("head")[0];
13238 var nrules = doc.createElement("style");
13239 nrules.setAttribute("type", "text/css");
13241 nrules.setAttribute("id", id);
13243 if (typeof(cssText) != 'string') {
13244 // support object maps..
13245 // not sure if this a good idea..
13246 // perhaps it should be merged with the general css handling
13247 // and handle js style props.
13248 var cssTextNew = [];
13249 for(var n in cssText) {
13251 for(var k in cssText[n]) {
13252 citems.push( k + ' : ' +cssText[n][k] + ';' );
13254 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13257 cssText = cssTextNew.join("\n");
13263 head.appendChild(nrules);
13264 ss = nrules.styleSheet;
13265 ss.cssText = cssText;
13268 nrules.appendChild(doc.createTextNode(cssText));
13270 nrules.cssText = cssText;
13272 head.appendChild(nrules);
13273 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13275 this.cacheStyleSheet(ss);
13280 * Removes a style or link tag by id
13281 * @param {String} id The id of the tag
13283 removeStyleSheet : function(id){
13284 var existing = doc.getElementById(id);
13286 existing.parentNode.removeChild(existing);
13291 * Dynamically swaps an existing stylesheet reference for a new one
13292 * @param {String} id The id of an existing link tag to remove
13293 * @param {String} url The href of the new stylesheet to include
13295 swapStyleSheet : function(id, url){
13296 this.removeStyleSheet(id);
13297 var ss = doc.createElement("link");
13298 ss.setAttribute("rel", "stylesheet");
13299 ss.setAttribute("type", "text/css");
13300 ss.setAttribute("id", id);
13301 ss.setAttribute("href", url);
13302 doc.getElementsByTagName("head")[0].appendChild(ss);
13306 * Refresh the rule cache if you have dynamically added stylesheets
13307 * @return {Object} An object (hash) of rules indexed by selector
13309 refreshCache : function(){
13310 return this.getRules(true);
13314 cacheStyleSheet : function(stylesheet){
13318 try{// try catch for cross domain access issue
13319 var ssRules = stylesheet.cssRules || stylesheet.rules;
13320 for(var j = ssRules.length-1; j >= 0; --j){
13321 rules[ssRules[j].selectorText] = ssRules[j];
13327 * Gets all css rules for the document
13328 * @param {Boolean} refreshCache true to refresh the internal cache
13329 * @return {Object} An object (hash) of rules indexed by selector
13331 getRules : function(refreshCache){
13332 if(rules == null || refreshCache){
13334 var ds = doc.styleSheets;
13335 for(var i =0, len = ds.length; i < len; i++){
13337 this.cacheStyleSheet(ds[i]);
13345 * Gets an an individual CSS rule by selector(s)
13346 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13347 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13348 * @return {CSSRule} The CSS rule or null if one is not found
13350 getRule : function(selector, refreshCache){
13351 var rs = this.getRules(refreshCache);
13352 if(!(selector instanceof Array)){
13353 return rs[selector];
13355 for(var i = 0; i < selector.length; i++){
13356 if(rs[selector[i]]){
13357 return rs[selector[i]];
13365 * Updates a rule property
13366 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13367 * @param {String} property The css property
13368 * @param {String} value The new value for the property
13369 * @return {Boolean} true If a rule was found and updated
13371 updateRule : function(selector, property, value){
13372 if(!(selector instanceof Array)){
13373 var rule = this.getRule(selector);
13375 rule.style[property.replace(camelRe, camelFn)] = value;
13379 for(var i = 0; i < selector.length; i++){
13380 if(this.updateRule(selector[i], property, value)){
13390 * Ext JS Library 1.1.1
13391 * Copyright(c) 2006-2007, Ext JS, LLC.
13393 * Originally Released Under LGPL - original licence link has changed is not relivant.
13396 * <script type="text/javascript">
13402 * @class Roo.util.ClickRepeater
13403 * @extends Roo.util.Observable
13405 * A wrapper class which can be applied to any element. Fires a "click" event while the
13406 * mouse is pressed. The interval between firings may be specified in the config but
13407 * defaults to 10 milliseconds.
13409 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13411 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13412 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13413 * Similar to an autorepeat key delay.
13414 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13415 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13416 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13417 * "interval" and "delay" are ignored. "immediate" is honored.
13418 * @cfg {Boolean} preventDefault True to prevent the default click event
13419 * @cfg {Boolean} stopDefault True to stop the default click event
13422 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13423 * 2007-02-02 jvs Renamed to ClickRepeater
13424 * 2007-02-03 jvs Modifications for FF Mac and Safari
13427 * @param {String/HTMLElement/Element} el The element to listen on
13428 * @param {Object} config
13430 Roo.util.ClickRepeater = function(el, config)
13432 this.el = Roo.get(el);
13433 this.el.unselectable();
13435 Roo.apply(this, config);
13440 * Fires when the mouse button is depressed.
13441 * @param {Roo.util.ClickRepeater} this
13443 "mousedown" : true,
13446 * Fires on a specified interval during the time the element is pressed.
13447 * @param {Roo.util.ClickRepeater} this
13452 * Fires when the mouse key is released.
13453 * @param {Roo.util.ClickRepeater} this
13458 this.el.on("mousedown", this.handleMouseDown, this);
13459 if(this.preventDefault || this.stopDefault){
13460 this.el.on("click", function(e){
13461 if(this.preventDefault){
13462 e.preventDefault();
13464 if(this.stopDefault){
13470 // allow inline handler
13472 this.on("click", this.handler, this.scope || this);
13475 Roo.util.ClickRepeater.superclass.constructor.call(this);
13478 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13481 preventDefault : true,
13482 stopDefault : false,
13486 handleMouseDown : function(){
13487 clearTimeout(this.timer);
13489 if(this.pressClass){
13490 this.el.addClass(this.pressClass);
13492 this.mousedownTime = new Date();
13494 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13495 this.el.on("mouseout", this.handleMouseOut, this);
13497 this.fireEvent("mousedown", this);
13498 this.fireEvent("click", this);
13500 this.timer = this.click.defer(this.delay || this.interval, this);
13504 click : function(){
13505 this.fireEvent("click", this);
13506 this.timer = this.click.defer(this.getInterval(), this);
13510 getInterval: function(){
13511 if(!this.accelerate){
13512 return this.interval;
13514 var pressTime = this.mousedownTime.getElapsed();
13515 if(pressTime < 500){
13517 }else if(pressTime < 1700){
13519 }else if(pressTime < 2600){
13521 }else if(pressTime < 3500){
13523 }else if(pressTime < 4400){
13525 }else if(pressTime < 5300){
13527 }else if(pressTime < 6200){
13535 handleMouseOut : function(){
13536 clearTimeout(this.timer);
13537 if(this.pressClass){
13538 this.el.removeClass(this.pressClass);
13540 this.el.on("mouseover", this.handleMouseReturn, this);
13544 handleMouseReturn : function(){
13545 this.el.un("mouseover", this.handleMouseReturn);
13546 if(this.pressClass){
13547 this.el.addClass(this.pressClass);
13553 handleMouseUp : function(){
13554 clearTimeout(this.timer);
13555 this.el.un("mouseover", this.handleMouseReturn);
13556 this.el.un("mouseout", this.handleMouseOut);
13557 Roo.get(document).un("mouseup", this.handleMouseUp);
13558 this.el.removeClass(this.pressClass);
13559 this.fireEvent("mouseup", this);
13563 * Ext JS Library 1.1.1
13564 * Copyright(c) 2006-2007, Ext JS, LLC.
13566 * Originally Released Under LGPL - original licence link has changed is not relivant.
13569 * <script type="text/javascript">
13574 * @class Roo.KeyNav
13575 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13576 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13577 * way to implement custom navigation schemes for any UI component.</p>
13578 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13579 * pageUp, pageDown, del, home, end. Usage:</p>
13581 var nav = new Roo.KeyNav("my-element", {
13582 "left" : function(e){
13583 this.moveLeft(e.ctrlKey);
13585 "right" : function(e){
13586 this.moveRight(e.ctrlKey);
13588 "enter" : function(e){
13595 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13596 * @param {Object} config The config
13598 Roo.KeyNav = function(el, config){
13599 this.el = Roo.get(el);
13600 Roo.apply(this, config);
13601 if(!this.disabled){
13602 this.disabled = true;
13607 Roo.KeyNav.prototype = {
13609 * @cfg {Boolean} disabled
13610 * True to disable this KeyNav instance (defaults to false)
13614 * @cfg {String} defaultEventAction
13615 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13616 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13617 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13619 defaultEventAction: "stopEvent",
13621 * @cfg {Boolean} forceKeyDown
13622 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13623 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13624 * handle keydown instead of keypress.
13626 forceKeyDown : false,
13629 prepareEvent : function(e){
13630 var k = e.getKey();
13631 var h = this.keyToHandler[k];
13632 //if(h && this[h]){
13633 // e.stopPropagation();
13635 if(Roo.isSafari && h && k >= 37 && k <= 40){
13641 relay : function(e){
13642 var k = e.getKey();
13643 var h = this.keyToHandler[k];
13645 if(this.doRelay(e, this[h], h) !== true){
13646 e[this.defaultEventAction]();
13652 doRelay : function(e, h, hname){
13653 return h.call(this.scope || this, e);
13656 // possible handlers
13670 // quick lookup hash
13687 * Enable this KeyNav
13689 enable: function(){
13691 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13692 // the EventObject will normalize Safari automatically
13693 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13694 this.el.on("keydown", this.relay, this);
13696 this.el.on("keydown", this.prepareEvent, this);
13697 this.el.on("keypress", this.relay, this);
13699 this.disabled = false;
13704 * Disable this KeyNav
13706 disable: function(){
13707 if(!this.disabled){
13708 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13709 this.el.un("keydown", this.relay);
13711 this.el.un("keydown", this.prepareEvent);
13712 this.el.un("keypress", this.relay);
13714 this.disabled = true;
13719 * Ext JS Library 1.1.1
13720 * Copyright(c) 2006-2007, Ext JS, LLC.
13722 * Originally Released Under LGPL - original licence link has changed is not relivant.
13725 * <script type="text/javascript">
13730 * @class Roo.KeyMap
13731 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13732 * The constructor accepts the same config object as defined by {@link #addBinding}.
13733 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13734 * combination it will call the function with this signature (if the match is a multi-key
13735 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13736 * A KeyMap can also handle a string representation of keys.<br />
13739 // map one key by key code
13740 var map = new Roo.KeyMap("my-element", {
13741 key: 13, // or Roo.EventObject.ENTER
13746 // map multiple keys to one action by string
13747 var map = new Roo.KeyMap("my-element", {
13753 // map multiple keys to multiple actions by strings and array of codes
13754 var map = new Roo.KeyMap("my-element", [
13757 fn: function(){ alert("Return was pressed"); }
13760 fn: function(){ alert('a, b or c was pressed'); }
13765 fn: function(){ alert('Control + shift + tab was pressed.'); }
13769 * <b>Note: A KeyMap starts enabled</b>
13771 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13772 * @param {Object} config The config (see {@link #addBinding})
13773 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13775 Roo.KeyMap = function(el, config, eventName){
13776 this.el = Roo.get(el);
13777 this.eventName = eventName || "keydown";
13778 this.bindings = [];
13780 this.addBinding(config);
13785 Roo.KeyMap.prototype = {
13787 * True to stop the event from bubbling and prevent the default browser action if the
13788 * key was handled by the KeyMap (defaults to false)
13794 * Add a new binding to this KeyMap. The following config object properties are supported:
13796 Property Type Description
13797 ---------- --------------- ----------------------------------------------------------------------
13798 key String/Array A single keycode or an array of keycodes to handle
13799 shift Boolean True to handle key only when shift is pressed (defaults to false)
13800 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13801 alt Boolean True to handle key only when alt is pressed (defaults to false)
13802 fn Function The function to call when KeyMap finds the expected key combination
13803 scope Object The scope of the callback function
13809 var map = new Roo.KeyMap(document, {
13810 key: Roo.EventObject.ENTER,
13815 //Add a new binding to the existing KeyMap later
13823 * @param {Object/Array} config A single KeyMap config or an array of configs
13825 addBinding : function(config){
13826 if(config instanceof Array){
13827 for(var i = 0, len = config.length; i < len; i++){
13828 this.addBinding(config[i]);
13832 var keyCode = config.key,
13833 shift = config.shift,
13834 ctrl = config.ctrl,
13837 scope = config.scope;
13838 if(typeof keyCode == "string"){
13840 var keyString = keyCode.toUpperCase();
13841 for(var j = 0, len = keyString.length; j < len; j++){
13842 ks.push(keyString.charCodeAt(j));
13846 var keyArray = keyCode instanceof Array;
13847 var handler = function(e){
13848 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13849 var k = e.getKey();
13851 for(var i = 0, len = keyCode.length; i < len; i++){
13852 if(keyCode[i] == k){
13853 if(this.stopEvent){
13856 fn.call(scope || window, k, e);
13862 if(this.stopEvent){
13865 fn.call(scope || window, k, e);
13870 this.bindings.push(handler);
13874 * Shorthand for adding a single key listener
13875 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13876 * following options:
13877 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13878 * @param {Function} fn The function to call
13879 * @param {Object} scope (optional) The scope of the function
13881 on : function(key, fn, scope){
13882 var keyCode, shift, ctrl, alt;
13883 if(typeof key == "object" && !(key instanceof Array)){
13902 handleKeyDown : function(e){
13903 if(this.enabled){ //just in case
13904 var b = this.bindings;
13905 for(var i = 0, len = b.length; i < len; i++){
13906 b[i].call(this, e);
13912 * Returns true if this KeyMap is enabled
13913 * @return {Boolean}
13915 isEnabled : function(){
13916 return this.enabled;
13920 * Enables this KeyMap
13922 enable: function(){
13924 this.el.on(this.eventName, this.handleKeyDown, this);
13925 this.enabled = true;
13930 * Disable this KeyMap
13932 disable: function(){
13934 this.el.removeListener(this.eventName, this.handleKeyDown, this);
13935 this.enabled = false;
13940 * Ext JS Library 1.1.1
13941 * Copyright(c) 2006-2007, Ext JS, LLC.
13943 * Originally Released Under LGPL - original licence link has changed is not relivant.
13946 * <script type="text/javascript">
13951 * @class Roo.util.TextMetrics
13952 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13953 * wide, in pixels, a given block of text will be.
13956 Roo.util.TextMetrics = function(){
13960 * Measures the size of the specified text
13961 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13962 * that can affect the size of the rendered text
13963 * @param {String} text The text to measure
13964 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13965 * in order to accurately measure the text height
13966 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13968 measure : function(el, text, fixedWidth){
13970 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13973 shared.setFixedWidth(fixedWidth || 'auto');
13974 return shared.getSize(text);
13978 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
13979 * the overhead of multiple calls to initialize the style properties on each measurement.
13980 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13981 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13982 * in order to accurately measure the text height
13983 * @return {Roo.util.TextMetrics.Instance} instance The new instance
13985 createInstance : function(el, fixedWidth){
13986 return Roo.util.TextMetrics.Instance(el, fixedWidth);
13993 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13994 var ml = new Roo.Element(document.createElement('div'));
13995 document.body.appendChild(ml.dom);
13996 ml.position('absolute');
13997 ml.setLeftTop(-1000, -1000);
14001 ml.setWidth(fixedWidth);
14006 * Returns the size of the specified text based on the internal element's style and width properties
14007 * @memberOf Roo.util.TextMetrics.Instance#
14008 * @param {String} text The text to measure
14009 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14011 getSize : function(text){
14013 var s = ml.getSize();
14019 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14020 * that can affect the size of the rendered text
14021 * @memberOf Roo.util.TextMetrics.Instance#
14022 * @param {String/HTMLElement} el The element, dom node or id
14024 bind : function(el){
14026 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14031 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14032 * to set a fixed width in order to accurately measure the text height.
14033 * @memberOf Roo.util.TextMetrics.Instance#
14034 * @param {Number} width The width to set on the element
14036 setFixedWidth : function(width){
14037 ml.setWidth(width);
14041 * Returns the measured width of the specified text
14042 * @memberOf Roo.util.TextMetrics.Instance#
14043 * @param {String} text The text to measure
14044 * @return {Number} width The width in pixels
14046 getWidth : function(text){
14047 ml.dom.style.width = 'auto';
14048 return this.getSize(text).width;
14052 * Returns the measured height of the specified text. For multiline text, be sure to call
14053 * {@link #setFixedWidth} if necessary.
14054 * @memberOf Roo.util.TextMetrics.Instance#
14055 * @param {String} text The text to measure
14056 * @return {Number} height The height in pixels
14058 getHeight : function(text){
14059 return this.getSize(text).height;
14063 instance.bind(bindTo);
14068 // backwards compat
14069 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14071 * Ext JS Library 1.1.1
14072 * Copyright(c) 2006-2007, Ext JS, LLC.
14074 * Originally Released Under LGPL - original licence link has changed is not relivant.
14077 * <script type="text/javascript">
14081 * @class Roo.state.Provider
14082 * Abstract base class for state provider implementations. This class provides methods
14083 * for encoding and decoding <b>typed</b> variables including dates and defines the
14084 * Provider interface.
14086 Roo.state.Provider = function(){
14088 * @event statechange
14089 * Fires when a state change occurs.
14090 * @param {Provider} this This state provider
14091 * @param {String} key The state key which was changed
14092 * @param {String} value The encoded value for the state
14095 "statechange": true
14098 Roo.state.Provider.superclass.constructor.call(this);
14100 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14102 * Returns the current value for a key
14103 * @param {String} name The key name
14104 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14105 * @return {Mixed} The state data
14107 get : function(name, defaultValue){
14108 return typeof this.state[name] == "undefined" ?
14109 defaultValue : this.state[name];
14113 * Clears a value from the state
14114 * @param {String} name The key name
14116 clear : function(name){
14117 delete this.state[name];
14118 this.fireEvent("statechange", this, name, null);
14122 * Sets the value for a key
14123 * @param {String} name The key name
14124 * @param {Mixed} value The value to set
14126 set : function(name, value){
14127 this.state[name] = value;
14128 this.fireEvent("statechange", this, name, value);
14132 * Decodes a string previously encoded with {@link #encodeValue}.
14133 * @param {String} value The value to decode
14134 * @return {Mixed} The decoded value
14136 decodeValue : function(cookie){
14137 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14138 var matches = re.exec(unescape(cookie));
14139 if(!matches || !matches[1]) return; // non state cookie
14140 var type = matches[1];
14141 var v = matches[2];
14144 return parseFloat(v);
14146 return new Date(Date.parse(v));
14151 var values = v.split("^");
14152 for(var i = 0, len = values.length; i < len; i++){
14153 all.push(this.decodeValue(values[i]));
14158 var values = v.split("^");
14159 for(var i = 0, len = values.length; i < len; i++){
14160 var kv = values[i].split("=");
14161 all[kv[0]] = this.decodeValue(kv[1]);
14170 * Encodes a value including type information. Decode with {@link #decodeValue}.
14171 * @param {Mixed} value The value to encode
14172 * @return {String} The encoded value
14174 encodeValue : function(v){
14176 if(typeof v == "number"){
14178 }else if(typeof v == "boolean"){
14179 enc = "b:" + (v ? "1" : "0");
14180 }else if(v instanceof Date){
14181 enc = "d:" + v.toGMTString();
14182 }else if(v instanceof Array){
14184 for(var i = 0, len = v.length; i < len; i++){
14185 flat += this.encodeValue(v[i]);
14186 if(i != len-1) flat += "^";
14189 }else if(typeof v == "object"){
14192 if(typeof v[key] != "function"){
14193 flat += key + "=" + this.encodeValue(v[key]) + "^";
14196 enc = "o:" + flat.substring(0, flat.length-1);
14200 return escape(enc);
14206 * Ext JS Library 1.1.1
14207 * Copyright(c) 2006-2007, Ext JS, LLC.
14209 * Originally Released Under LGPL - original licence link has changed is not relivant.
14212 * <script type="text/javascript">
14215 * @class Roo.state.Manager
14216 * This is the global state manager. By default all components that are "state aware" check this class
14217 * for state information if you don't pass them a custom state provider. In order for this class
14218 * to be useful, it must be initialized with a provider when your application initializes.
14220 // in your initialization function
14222 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14224 // supposed you have a {@link Roo.BorderLayout}
14225 var layout = new Roo.BorderLayout(...);
14226 layout.restoreState();
14227 // or a {Roo.BasicDialog}
14228 var dialog = new Roo.BasicDialog(...);
14229 dialog.restoreState();
14233 Roo.state.Manager = function(){
14234 var provider = new Roo.state.Provider();
14238 * Configures the default state provider for your application
14239 * @param {Provider} stateProvider The state provider to set
14241 setProvider : function(stateProvider){
14242 provider = stateProvider;
14246 * Returns the current value for a key
14247 * @param {String} name The key name
14248 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14249 * @return {Mixed} The state data
14251 get : function(key, defaultValue){
14252 return provider.get(key, defaultValue);
14256 * Sets the value for a key
14257 * @param {String} name The key name
14258 * @param {Mixed} value The state data
14260 set : function(key, value){
14261 provider.set(key, value);
14265 * Clears a value from the state
14266 * @param {String} name The key name
14268 clear : function(key){
14269 provider.clear(key);
14273 * Gets the currently configured state provider
14274 * @return {Provider} The state provider
14276 getProvider : function(){
14283 * Ext JS Library 1.1.1
14284 * Copyright(c) 2006-2007, Ext JS, LLC.
14286 * Originally Released Under LGPL - original licence link has changed is not relivant.
14289 * <script type="text/javascript">
14292 * @class Roo.state.CookieProvider
14293 * @extends Roo.state.Provider
14294 * The default Provider implementation which saves state via cookies.
14297 var cp = new Roo.state.CookieProvider({
14299 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14300 domain: "roojs.com"
14302 Roo.state.Manager.setProvider(cp);
14304 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14305 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14306 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14307 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14308 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14309 * domain the page is running on including the 'www' like 'www.roojs.com')
14310 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14312 * Create a new CookieProvider
14313 * @param {Object} config The configuration object
14315 Roo.state.CookieProvider = function(config){
14316 Roo.state.CookieProvider.superclass.constructor.call(this);
14318 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14319 this.domain = null;
14320 this.secure = false;
14321 Roo.apply(this, config);
14322 this.state = this.readCookies();
14325 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14327 set : function(name, value){
14328 if(typeof value == "undefined" || value === null){
14332 this.setCookie(name, value);
14333 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14337 clear : function(name){
14338 this.clearCookie(name);
14339 Roo.state.CookieProvider.superclass.clear.call(this, name);
14343 readCookies : function(){
14345 var c = document.cookie + ";";
14346 var re = /\s?(.*?)=(.*?);/g;
14348 while((matches = re.exec(c)) != null){
14349 var name = matches[1];
14350 var value = matches[2];
14351 if(name && name.substring(0,3) == "ys-"){
14352 cookies[name.substr(3)] = this.decodeValue(value);
14359 setCookie : function(name, value){
14360 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14361 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14362 ((this.path == null) ? "" : ("; path=" + this.path)) +
14363 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14364 ((this.secure == true) ? "; secure" : "");
14368 clearCookie : function(name){
14369 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14370 ((this.path == null) ? "" : ("; path=" + this.path)) +
14371 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14372 ((this.secure == true) ? "; secure" : "");
14376 * Ext JS Library 1.1.1
14377 * Copyright(c) 2006-2007, Ext JS, LLC.
14379 * Originally Released Under LGPL - original licence link has changed is not relivant.
14382 * <script type="text/javascript">
14388 * These classes are derivatives of the similarly named classes in the YUI Library.
14389 * The original license:
14390 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14391 * Code licensed under the BSD License:
14392 * http://developer.yahoo.net/yui/license.txt
14397 var Event=Roo.EventManager;
14398 var Dom=Roo.lib.Dom;
14401 * @class Roo.dd.DragDrop
14402 * Defines the interface and base operation of items that that can be
14403 * dragged or can be drop targets. It was designed to be extended, overriding
14404 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14405 * Up to three html elements can be associated with a DragDrop instance:
14407 * <li>linked element: the element that is passed into the constructor.
14408 * This is the element which defines the boundaries for interaction with
14409 * other DragDrop objects.</li>
14410 * <li>handle element(s): The drag operation only occurs if the element that
14411 * was clicked matches a handle element. By default this is the linked
14412 * element, but there are times that you will want only a portion of the
14413 * linked element to initiate the drag operation, and the setHandleElId()
14414 * method provides a way to define this.</li>
14415 * <li>drag element: this represents the element that would be moved along
14416 * with the cursor during a drag operation. By default, this is the linked
14417 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14418 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14421 * This class should not be instantiated until the onload event to ensure that
14422 * the associated elements are available.
14423 * The following would define a DragDrop obj that would interact with any
14424 * other DragDrop obj in the "group1" group:
14426 * dd = new Roo.dd.DragDrop("div1", "group1");
14428 * Since none of the event handlers have been implemented, nothing would
14429 * actually happen if you were to run the code above. Normally you would
14430 * override this class or one of the default implementations, but you can
14431 * also override the methods you want on an instance of the class...
14433 * dd.onDragDrop = function(e, id) {
14434 * alert("dd was dropped on " + id);
14438 * @param {String} id of the element that is linked to this instance
14439 * @param {String} sGroup the group of related DragDrop objects
14440 * @param {object} config an object containing configurable attributes
14441 * Valid properties for DragDrop:
14442 * padding, isTarget, maintainOffset, primaryButtonOnly
14444 Roo.dd.DragDrop = function(id, sGroup, config) {
14446 this.init(id, sGroup, config);
14451 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
14454 * The id of the element associated with this object. This is what we
14455 * refer to as the "linked element" because the size and position of
14456 * this element is used to determine when the drag and drop objects have
14464 * Configuration attributes passed into the constructor
14471 * The id of the element that will be dragged. By default this is same
14472 * as the linked element , but could be changed to another element. Ex:
14474 * @property dragElId
14481 * the id of the element that initiates the drag operation. By default
14482 * this is the linked element, but could be changed to be a child of this
14483 * element. This lets us do things like only starting the drag when the
14484 * header element within the linked html element is clicked.
14485 * @property handleElId
14492 * An associative array of HTML tags that will be ignored if clicked.
14493 * @property invalidHandleTypes
14494 * @type {string: string}
14496 invalidHandleTypes: null,
14499 * An associative array of ids for elements that will be ignored if clicked
14500 * @property invalidHandleIds
14501 * @type {string: string}
14503 invalidHandleIds: null,
14506 * An indexted array of css class names for elements that will be ignored
14508 * @property invalidHandleClasses
14511 invalidHandleClasses: null,
14514 * The linked element's absolute X position at the time the drag was
14516 * @property startPageX
14523 * The linked element's absolute X position at the time the drag was
14525 * @property startPageY
14532 * The group defines a logical collection of DragDrop objects that are
14533 * related. Instances only get events when interacting with other
14534 * DragDrop object in the same group. This lets us define multiple
14535 * groups using a single DragDrop subclass if we want.
14537 * @type {string: string}
14542 * Individual drag/drop instances can be locked. This will prevent
14543 * onmousedown start drag.
14551 * Lock this instance
14554 lock: function() { this.locked = true; },
14557 * Unlock this instace
14560 unlock: function() { this.locked = false; },
14563 * By default, all insances can be a drop target. This can be disabled by
14564 * setting isTarget to false.
14571 * The padding configured for this drag and drop object for calculating
14572 * the drop zone intersection with this object.
14579 * Cached reference to the linked element
14580 * @property _domRef
14586 * Internal typeof flag
14587 * @property __ygDragDrop
14590 __ygDragDrop: true,
14593 * Set to true when horizontal contraints are applied
14594 * @property constrainX
14601 * Set to true when vertical contraints are applied
14602 * @property constrainY
14609 * The left constraint
14617 * The right constraint
14625 * The up constraint
14634 * The down constraint
14642 * Maintain offsets when we resetconstraints. Set to true when you want
14643 * the position of the element relative to its parent to stay the same
14644 * when the page changes
14646 * @property maintainOffset
14649 maintainOffset: false,
14652 * Array of pixel locations the element will snap to if we specified a
14653 * horizontal graduation/interval. This array is generated automatically
14654 * when you define a tick interval.
14661 * Array of pixel locations the element will snap to if we specified a
14662 * vertical graduation/interval. This array is generated automatically
14663 * when you define a tick interval.
14670 * By default the drag and drop instance will only respond to the primary
14671 * button click (left button for a right-handed mouse). Set to true to
14672 * allow drag and drop to start with any mouse click that is propogated
14674 * @property primaryButtonOnly
14677 primaryButtonOnly: true,
14680 * The availabe property is false until the linked dom element is accessible.
14681 * @property available
14687 * By default, drags can only be initiated if the mousedown occurs in the
14688 * region the linked element is. This is done in part to work around a
14689 * bug in some browsers that mis-report the mousedown if the previous
14690 * mouseup happened outside of the window. This property is set to true
14691 * if outer handles are defined.
14693 * @property hasOuterHandles
14697 hasOuterHandles: false,
14700 * Code that executes immediately before the startDrag event
14701 * @method b4StartDrag
14704 b4StartDrag: function(x, y) { },
14707 * Abstract method called after a drag/drop object is clicked
14708 * and the drag or mousedown time thresholds have beeen met.
14709 * @method startDrag
14710 * @param {int} X click location
14711 * @param {int} Y click location
14713 startDrag: function(x, y) { /* override this */ },
14716 * Code that executes immediately before the onDrag event
14720 b4Drag: function(e) { },
14723 * Abstract method called during the onMouseMove event while dragging an
14726 * @param {Event} e the mousemove event
14728 onDrag: function(e) { /* override this */ },
14731 * Abstract method called when this element fist begins hovering over
14732 * another DragDrop obj
14733 * @method onDragEnter
14734 * @param {Event} e the mousemove event
14735 * @param {String|DragDrop[]} id In POINT mode, the element
14736 * id this is hovering over. In INTERSECT mode, an array of one or more
14737 * dragdrop items being hovered over.
14739 onDragEnter: function(e, id) { /* override this */ },
14742 * Code that executes immediately before the onDragOver event
14743 * @method b4DragOver
14746 b4DragOver: function(e) { },
14749 * Abstract method called when this element is hovering over another
14751 * @method onDragOver
14752 * @param {Event} e the mousemove event
14753 * @param {String|DragDrop[]} id In POINT mode, the element
14754 * id this is hovering over. In INTERSECT mode, an array of dd items
14755 * being hovered over.
14757 onDragOver: function(e, id) { /* override this */ },
14760 * Code that executes immediately before the onDragOut event
14761 * @method b4DragOut
14764 b4DragOut: function(e) { },
14767 * Abstract method called when we are no longer hovering over an element
14768 * @method onDragOut
14769 * @param {Event} e the mousemove event
14770 * @param {String|DragDrop[]} id In POINT mode, the element
14771 * id this was hovering over. In INTERSECT mode, an array of dd items
14772 * that the mouse is no longer over.
14774 onDragOut: function(e, id) { /* override this */ },
14777 * Code that executes immediately before the onDragDrop event
14778 * @method b4DragDrop
14781 b4DragDrop: function(e) { },
14784 * Abstract method called when this item is dropped on another DragDrop
14786 * @method onDragDrop
14787 * @param {Event} e the mouseup event
14788 * @param {String|DragDrop[]} id In POINT mode, the element
14789 * id this was dropped on. In INTERSECT mode, an array of dd items this
14792 onDragDrop: function(e, id) { /* override this */ },
14795 * Abstract method called when this item is dropped on an area with no
14797 * @method onInvalidDrop
14798 * @param {Event} e the mouseup event
14800 onInvalidDrop: function(e) { /* override this */ },
14803 * Code that executes immediately before the endDrag event
14804 * @method b4EndDrag
14807 b4EndDrag: function(e) { },
14810 * Fired when we are done dragging the object
14812 * @param {Event} e the mouseup event
14814 endDrag: function(e) { /* override this */ },
14817 * Code executed immediately before the onMouseDown event
14818 * @method b4MouseDown
14819 * @param {Event} e the mousedown event
14822 b4MouseDown: function(e) { },
14825 * Event handler that fires when a drag/drop obj gets a mousedown
14826 * @method onMouseDown
14827 * @param {Event} e the mousedown event
14829 onMouseDown: function(e) { /* override this */ },
14832 * Event handler that fires when a drag/drop obj gets a mouseup
14833 * @method onMouseUp
14834 * @param {Event} e the mouseup event
14836 onMouseUp: function(e) { /* override this */ },
14839 * Override the onAvailable method to do what is needed after the initial
14840 * position was determined.
14841 * @method onAvailable
14843 onAvailable: function () {
14847 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14850 defaultPadding : {left:0, right:0, top:0, bottom:0},
14853 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14857 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14858 { dragElId: "existingProxyDiv" });
14859 dd.startDrag = function(){
14860 this.constrainTo("parent-id");
14863 * Or you can initalize it using the {@link Roo.Element} object:
14865 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14866 startDrag : function(){
14867 this.constrainTo("parent-id");
14871 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14872 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14873 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14874 * an object containing the sides to pad. For example: {right:10, bottom:10}
14875 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14877 constrainTo : function(constrainTo, pad, inContent){
14878 if(typeof pad == "number"){
14879 pad = {left: pad, right:pad, top:pad, bottom:pad};
14881 pad = pad || this.defaultPadding;
14882 var b = Roo.get(this.getEl()).getBox();
14883 var ce = Roo.get(constrainTo);
14884 var s = ce.getScroll();
14885 var c, cd = ce.dom;
14886 if(cd == document.body){
14887 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14890 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14894 var topSpace = b.y - c.y;
14895 var leftSpace = b.x - c.x;
14897 this.resetConstraints();
14898 this.setXConstraint(leftSpace - (pad.left||0), // left
14899 c.width - leftSpace - b.width - (pad.right||0) //right
14901 this.setYConstraint(topSpace - (pad.top||0), //top
14902 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14907 * Returns a reference to the linked element
14909 * @return {HTMLElement} the html element
14911 getEl: function() {
14912 if (!this._domRef) {
14913 this._domRef = Roo.getDom(this.id);
14916 return this._domRef;
14920 * Returns a reference to the actual element to drag. By default this is
14921 * the same as the html element, but it can be assigned to another
14922 * element. An example of this can be found in Roo.dd.DDProxy
14923 * @method getDragEl
14924 * @return {HTMLElement} the html element
14926 getDragEl: function() {
14927 return Roo.getDom(this.dragElId);
14931 * Sets up the DragDrop object. Must be called in the constructor of any
14932 * Roo.dd.DragDrop subclass
14934 * @param id the id of the linked element
14935 * @param {String} sGroup the group of related items
14936 * @param {object} config configuration attributes
14938 init: function(id, sGroup, config) {
14939 this.initTarget(id, sGroup, config);
14940 Event.on(this.id, "mousedown", this.handleMouseDown, this);
14941 // Event.on(this.id, "selectstart", Event.preventDefault);
14945 * Initializes Targeting functionality only... the object does not
14946 * get a mousedown handler.
14947 * @method initTarget
14948 * @param id the id of the linked element
14949 * @param {String} sGroup the group of related items
14950 * @param {object} config configuration attributes
14952 initTarget: function(id, sGroup, config) {
14954 // configuration attributes
14955 this.config = config || {};
14957 // create a local reference to the drag and drop manager
14958 this.DDM = Roo.dd.DDM;
14959 // initialize the groups array
14962 // assume that we have an element reference instead of an id if the
14963 // parameter is not a string
14964 if (typeof id !== "string") {
14971 // add to an interaction group
14972 this.addToGroup((sGroup) ? sGroup : "default");
14974 // We don't want to register this as the handle with the manager
14975 // so we just set the id rather than calling the setter.
14976 this.handleElId = id;
14978 // the linked element is the element that gets dragged by default
14979 this.setDragElId(id);
14981 // by default, clicked anchors will not start drag operations.
14982 this.invalidHandleTypes = { A: "A" };
14983 this.invalidHandleIds = {};
14984 this.invalidHandleClasses = [];
14986 this.applyConfig();
14988 this.handleOnAvailable();
14992 * Applies the configuration parameters that were passed into the constructor.
14993 * This is supposed to happen at each level through the inheritance chain. So
14994 * a DDProxy implentation will execute apply config on DDProxy, DD, and
14995 * DragDrop in order to get all of the parameters that are available in
14997 * @method applyConfig
14999 applyConfig: function() {
15001 // configurable properties:
15002 // padding, isTarget, maintainOffset, primaryButtonOnly
15003 this.padding = this.config.padding || [0, 0, 0, 0];
15004 this.isTarget = (this.config.isTarget !== false);
15005 this.maintainOffset = (this.config.maintainOffset);
15006 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15011 * Executed when the linked element is available
15012 * @method handleOnAvailable
15015 handleOnAvailable: function() {
15016 this.available = true;
15017 this.resetConstraints();
15018 this.onAvailable();
15022 * Configures the padding for the target zone in px. Effectively expands
15023 * (or reduces) the virtual object size for targeting calculations.
15024 * Supports css-style shorthand; if only one parameter is passed, all sides
15025 * will have that padding, and if only two are passed, the top and bottom
15026 * will have the first param, the left and right the second.
15027 * @method setPadding
15028 * @param {int} iTop Top pad
15029 * @param {int} iRight Right pad
15030 * @param {int} iBot Bot pad
15031 * @param {int} iLeft Left pad
15033 setPadding: function(iTop, iRight, iBot, iLeft) {
15034 // this.padding = [iLeft, iRight, iTop, iBot];
15035 if (!iRight && 0 !== iRight) {
15036 this.padding = [iTop, iTop, iTop, iTop];
15037 } else if (!iBot && 0 !== iBot) {
15038 this.padding = [iTop, iRight, iTop, iRight];
15040 this.padding = [iTop, iRight, iBot, iLeft];
15045 * Stores the initial placement of the linked element.
15046 * @method setInitialPosition
15047 * @param {int} diffX the X offset, default 0
15048 * @param {int} diffY the Y offset, default 0
15050 setInitPosition: function(diffX, diffY) {
15051 var el = this.getEl();
15053 if (!this.DDM.verifyEl(el)) {
15057 var dx = diffX || 0;
15058 var dy = diffY || 0;
15060 var p = Dom.getXY( el );
15062 this.initPageX = p[0] - dx;
15063 this.initPageY = p[1] - dy;
15065 this.lastPageX = p[0];
15066 this.lastPageY = p[1];
15069 this.setStartPosition(p);
15073 * Sets the start position of the element. This is set when the obj
15074 * is initialized, the reset when a drag is started.
15075 * @method setStartPosition
15076 * @param pos current position (from previous lookup)
15079 setStartPosition: function(pos) {
15080 var p = pos || Dom.getXY( this.getEl() );
15081 this.deltaSetXY = null;
15083 this.startPageX = p[0];
15084 this.startPageY = p[1];
15088 * Add this instance to a group of related drag/drop objects. All
15089 * instances belong to at least one group, and can belong to as many
15090 * groups as needed.
15091 * @method addToGroup
15092 * @param sGroup {string} the name of the group
15094 addToGroup: function(sGroup) {
15095 this.groups[sGroup] = true;
15096 this.DDM.regDragDrop(this, sGroup);
15100 * Remove's this instance from the supplied interaction group
15101 * @method removeFromGroup
15102 * @param {string} sGroup The group to drop
15104 removeFromGroup: function(sGroup) {
15105 if (this.groups[sGroup]) {
15106 delete this.groups[sGroup];
15109 this.DDM.removeDDFromGroup(this, sGroup);
15113 * Allows you to specify that an element other than the linked element
15114 * will be moved with the cursor during a drag
15115 * @method setDragElId
15116 * @param id {string} the id of the element that will be used to initiate the drag
15118 setDragElId: function(id) {
15119 this.dragElId = id;
15123 * Allows you to specify a child of the linked element that should be
15124 * used to initiate the drag operation. An example of this would be if
15125 * you have a content div with text and links. Clicking anywhere in the
15126 * content area would normally start the drag operation. Use this method
15127 * to specify that an element inside of the content div is the element
15128 * that starts the drag operation.
15129 * @method setHandleElId
15130 * @param id {string} the id of the element that will be used to
15131 * initiate the drag.
15133 setHandleElId: function(id) {
15134 if (typeof id !== "string") {
15137 this.handleElId = id;
15138 this.DDM.regHandle(this.id, id);
15142 * Allows you to set an element outside of the linked element as a drag
15144 * @method setOuterHandleElId
15145 * @param id the id of the element that will be used to initiate the drag
15147 setOuterHandleElId: function(id) {
15148 if (typeof id !== "string") {
15151 Event.on(id, "mousedown",
15152 this.handleMouseDown, this);
15153 this.setHandleElId(id);
15155 this.hasOuterHandles = true;
15159 * Remove all drag and drop hooks for this element
15162 unreg: function() {
15163 Event.un(this.id, "mousedown",
15164 this.handleMouseDown);
15165 this._domRef = null;
15166 this.DDM._remove(this);
15169 destroy : function(){
15174 * Returns true if this instance is locked, or the drag drop mgr is locked
15175 * (meaning that all drag/drop is disabled on the page.)
15177 * @return {boolean} true if this obj or all drag/drop is locked, else
15180 isLocked: function() {
15181 return (this.DDM.isLocked() || this.locked);
15185 * Fired when this object is clicked
15186 * @method handleMouseDown
15188 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15191 handleMouseDown: function(e, oDD){
15192 if (this.primaryButtonOnly && e.button != 0) {
15196 if (this.isLocked()) {
15200 this.DDM.refreshCache(this.groups);
15202 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15203 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15205 if (this.clickValidator(e)) {
15207 // set the initial element position
15208 this.setStartPosition();
15211 this.b4MouseDown(e);
15212 this.onMouseDown(e);
15214 this.DDM.handleMouseDown(e, this);
15216 this.DDM.stopEvent(e);
15224 clickValidator: function(e) {
15225 var target = e.getTarget();
15226 return ( this.isValidHandleChild(target) &&
15227 (this.id == this.handleElId ||
15228 this.DDM.handleWasClicked(target, this.id)) );
15232 * Allows you to specify a tag name that should not start a drag operation
15233 * when clicked. This is designed to facilitate embedding links within a
15234 * drag handle that do something other than start the drag.
15235 * @method addInvalidHandleType
15236 * @param {string} tagName the type of element to exclude
15238 addInvalidHandleType: function(tagName) {
15239 var type = tagName.toUpperCase();
15240 this.invalidHandleTypes[type] = type;
15244 * Lets you to specify an element id for a child of a drag handle
15245 * that should not initiate a drag
15246 * @method addInvalidHandleId
15247 * @param {string} id the element id of the element you wish to ignore
15249 addInvalidHandleId: function(id) {
15250 if (typeof id !== "string") {
15253 this.invalidHandleIds[id] = id;
15257 * Lets you specify a css class of elements that will not initiate a drag
15258 * @method addInvalidHandleClass
15259 * @param {string} cssClass the class of the elements you wish to ignore
15261 addInvalidHandleClass: function(cssClass) {
15262 this.invalidHandleClasses.push(cssClass);
15266 * Unsets an excluded tag name set by addInvalidHandleType
15267 * @method removeInvalidHandleType
15268 * @param {string} tagName the type of element to unexclude
15270 removeInvalidHandleType: function(tagName) {
15271 var type = tagName.toUpperCase();
15272 // this.invalidHandleTypes[type] = null;
15273 delete this.invalidHandleTypes[type];
15277 * Unsets an invalid handle id
15278 * @method removeInvalidHandleId
15279 * @param {string} id the id of the element to re-enable
15281 removeInvalidHandleId: function(id) {
15282 if (typeof id !== "string") {
15285 delete this.invalidHandleIds[id];
15289 * Unsets an invalid css class
15290 * @method removeInvalidHandleClass
15291 * @param {string} cssClass the class of the element(s) you wish to
15294 removeInvalidHandleClass: function(cssClass) {
15295 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15296 if (this.invalidHandleClasses[i] == cssClass) {
15297 delete this.invalidHandleClasses[i];
15303 * Checks the tag exclusion list to see if this click should be ignored
15304 * @method isValidHandleChild
15305 * @param {HTMLElement} node the HTMLElement to evaluate
15306 * @return {boolean} true if this is a valid tag type, false if not
15308 isValidHandleChild: function(node) {
15311 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15314 nodeName = node.nodeName.toUpperCase();
15316 nodeName = node.nodeName;
15318 valid = valid && !this.invalidHandleTypes[nodeName];
15319 valid = valid && !this.invalidHandleIds[node.id];
15321 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15322 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15331 * Create the array of horizontal tick marks if an interval was specified
15332 * in setXConstraint().
15333 * @method setXTicks
15336 setXTicks: function(iStartX, iTickSize) {
15338 this.xTickSize = iTickSize;
15342 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15344 this.xTicks[this.xTicks.length] = i;
15349 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15351 this.xTicks[this.xTicks.length] = i;
15356 this.xTicks.sort(this.DDM.numericSort) ;
15360 * Create the array of vertical tick marks if an interval was specified in
15361 * setYConstraint().
15362 * @method setYTicks
15365 setYTicks: function(iStartY, iTickSize) {
15367 this.yTickSize = iTickSize;
15371 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15373 this.yTicks[this.yTicks.length] = i;
15378 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15380 this.yTicks[this.yTicks.length] = i;
15385 this.yTicks.sort(this.DDM.numericSort) ;
15389 * By default, the element can be dragged any place on the screen. Use
15390 * this method to limit the horizontal travel of the element. Pass in
15391 * 0,0 for the parameters if you want to lock the drag to the y axis.
15392 * @method setXConstraint
15393 * @param {int} iLeft the number of pixels the element can move to the left
15394 * @param {int} iRight the number of pixels the element can move to the
15396 * @param {int} iTickSize optional parameter for specifying that the
15398 * should move iTickSize pixels at a time.
15400 setXConstraint: function(iLeft, iRight, iTickSize) {
15401 this.leftConstraint = iLeft;
15402 this.rightConstraint = iRight;
15404 this.minX = this.initPageX - iLeft;
15405 this.maxX = this.initPageX + iRight;
15406 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15408 this.constrainX = true;
15412 * Clears any constraints applied to this instance. Also clears ticks
15413 * since they can't exist independent of a constraint at this time.
15414 * @method clearConstraints
15416 clearConstraints: function() {
15417 this.constrainX = false;
15418 this.constrainY = false;
15423 * Clears any tick interval defined for this instance
15424 * @method clearTicks
15426 clearTicks: function() {
15427 this.xTicks = null;
15428 this.yTicks = null;
15429 this.xTickSize = 0;
15430 this.yTickSize = 0;
15434 * By default, the element can be dragged any place on the screen. Set
15435 * this to limit the vertical travel of the element. Pass in 0,0 for the
15436 * parameters if you want to lock the drag to the x axis.
15437 * @method setYConstraint
15438 * @param {int} iUp the number of pixels the element can move up
15439 * @param {int} iDown the number of pixels the element can move down
15440 * @param {int} iTickSize optional parameter for specifying that the
15441 * element should move iTickSize pixels at a time.
15443 setYConstraint: function(iUp, iDown, iTickSize) {
15444 this.topConstraint = iUp;
15445 this.bottomConstraint = iDown;
15447 this.minY = this.initPageY - iUp;
15448 this.maxY = this.initPageY + iDown;
15449 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15451 this.constrainY = true;
15456 * resetConstraints must be called if you manually reposition a dd element.
15457 * @method resetConstraints
15458 * @param {boolean} maintainOffset
15460 resetConstraints: function() {
15463 // Maintain offsets if necessary
15464 if (this.initPageX || this.initPageX === 0) {
15465 // figure out how much this thing has moved
15466 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15467 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15469 this.setInitPosition(dx, dy);
15471 // This is the first time we have detected the element's position
15473 this.setInitPosition();
15476 if (this.constrainX) {
15477 this.setXConstraint( this.leftConstraint,
15478 this.rightConstraint,
15482 if (this.constrainY) {
15483 this.setYConstraint( this.topConstraint,
15484 this.bottomConstraint,
15490 * Normally the drag element is moved pixel by pixel, but we can specify
15491 * that it move a number of pixels at a time. This method resolves the
15492 * location when we have it set up like this.
15494 * @param {int} val where we want to place the object
15495 * @param {int[]} tickArray sorted array of valid points
15496 * @return {int} the closest tick
15499 getTick: function(val, tickArray) {
15502 // If tick interval is not defined, it is effectively 1 pixel,
15503 // so we return the value passed to us.
15505 } else if (tickArray[0] >= val) {
15506 // The value is lower than the first tick, so we return the first
15508 return tickArray[0];
15510 for (var i=0, len=tickArray.length; i<len; ++i) {
15512 if (tickArray[next] && tickArray[next] >= val) {
15513 var diff1 = val - tickArray[i];
15514 var diff2 = tickArray[next] - val;
15515 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15519 // The value is larger than the last tick, so we return the last
15521 return tickArray[tickArray.length - 1];
15528 * @return {string} string representation of the dd obj
15530 toString: function() {
15531 return ("DragDrop " + this.id);
15539 * Ext JS Library 1.1.1
15540 * Copyright(c) 2006-2007, Ext JS, LLC.
15542 * Originally Released Under LGPL - original licence link has changed is not relivant.
15545 * <script type="text/javascript">
15550 * The drag and drop utility provides a framework for building drag and drop
15551 * applications. In addition to enabling drag and drop for specific elements,
15552 * the drag and drop elements are tracked by the manager class, and the
15553 * interactions between the various elements are tracked during the drag and
15554 * the implementing code is notified about these important moments.
15557 // Only load the library once. Rewriting the manager class would orphan
15558 // existing drag and drop instances.
15559 if (!Roo.dd.DragDropMgr) {
15562 * @class Roo.dd.DragDropMgr
15563 * DragDropMgr is a singleton that tracks the element interaction for
15564 * all DragDrop items in the window. Generally, you will not call
15565 * this class directly, but it does have helper methods that could
15566 * be useful in your DragDrop implementations.
15569 Roo.dd.DragDropMgr = function() {
15571 var Event = Roo.EventManager;
15576 * Two dimensional Array of registered DragDrop objects. The first
15577 * dimension is the DragDrop item group, the second the DragDrop
15580 * @type {string: string}
15587 * Array of element ids defined as drag handles. Used to determine
15588 * if the element that generated the mousedown event is actually the
15589 * handle and not the html element itself.
15590 * @property handleIds
15591 * @type {string: string}
15598 * the DragDrop object that is currently being dragged
15599 * @property dragCurrent
15607 * the DragDrop object(s) that are being hovered over
15608 * @property dragOvers
15616 * the X distance between the cursor and the object being dragged
15625 * the Y distance between the cursor and the object being dragged
15634 * Flag to determine if we should prevent the default behavior of the
15635 * events we define. By default this is true, but this can be set to
15636 * false if you need the default behavior (not recommended)
15637 * @property preventDefault
15641 preventDefault: true,
15644 * Flag to determine if we should stop the propagation of the events
15645 * we generate. This is true by default but you may want to set it to
15646 * false if the html element contains other features that require the
15648 * @property stopPropagation
15652 stopPropagation: true,
15655 * Internal flag that is set to true when drag and drop has been
15657 * @property initialized
15664 * All drag and drop can be disabled.
15672 * Called the first time an element is registered.
15678 this.initialized = true;
15682 * In point mode, drag and drop interaction is defined by the
15683 * location of the cursor during the drag/drop
15691 * In intersect mode, drag and drop interactio nis defined by the
15692 * overlap of two or more drag and drop objects.
15693 * @property INTERSECT
15700 * The current drag and drop mode. Default: POINT
15708 * Runs method on all drag and drop objects
15709 * @method _execOnAll
15713 _execOnAll: function(sMethod, args) {
15714 for (var i in this.ids) {
15715 for (var j in this.ids[i]) {
15716 var oDD = this.ids[i][j];
15717 if (! this.isTypeOfDD(oDD)) {
15720 oDD[sMethod].apply(oDD, args);
15726 * Drag and drop initialization. Sets up the global event handlers
15731 _onLoad: function() {
15736 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15737 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15738 Event.on(window, "unload", this._onUnload, this, true);
15739 Event.on(window, "resize", this._onResize, this, true);
15740 // Event.on(window, "mouseout", this._test);
15745 * Reset constraints on all drag and drop objs
15746 * @method _onResize
15750 _onResize: function(e) {
15751 this._execOnAll("resetConstraints", []);
15755 * Lock all drag and drop functionality
15759 lock: function() { this.locked = true; },
15762 * Unlock all drag and drop functionality
15766 unlock: function() { this.locked = false; },
15769 * Is drag and drop locked?
15771 * @return {boolean} True if drag and drop is locked, false otherwise.
15774 isLocked: function() { return this.locked; },
15777 * Location cache that is set for all drag drop objects when a drag is
15778 * initiated, cleared when the drag is finished.
15779 * @property locationCache
15786 * Set useCache to false if you want to force object the lookup of each
15787 * drag and drop linked element constantly during a drag.
15788 * @property useCache
15795 * The number of pixels that the mouse needs to move after the
15796 * mousedown before the drag is initiated. Default=3;
15797 * @property clickPixelThresh
15801 clickPixelThresh: 3,
15804 * The number of milliseconds after the mousedown event to initiate the
15805 * drag if we don't get a mouseup event. Default=1000
15806 * @property clickTimeThresh
15810 clickTimeThresh: 350,
15813 * Flag that indicates that either the drag pixel threshold or the
15814 * mousdown time threshold has been met
15815 * @property dragThreshMet
15820 dragThreshMet: false,
15823 * Timeout used for the click time threshold
15824 * @property clickTimeout
15829 clickTimeout: null,
15832 * The X position of the mousedown event stored for later use when a
15833 * drag threshold is met.
15842 * The Y position of the mousedown event stored for later use when a
15843 * drag threshold is met.
15852 * Each DragDrop instance must be registered with the DragDropMgr.
15853 * This is executed in DragDrop.init()
15854 * @method regDragDrop
15855 * @param {DragDrop} oDD the DragDrop object to register
15856 * @param {String} sGroup the name of the group this element belongs to
15859 regDragDrop: function(oDD, sGroup) {
15860 if (!this.initialized) { this.init(); }
15862 if (!this.ids[sGroup]) {
15863 this.ids[sGroup] = {};
15865 this.ids[sGroup][oDD.id] = oDD;
15869 * Removes the supplied dd instance from the supplied group. Executed
15870 * by DragDrop.removeFromGroup, so don't call this function directly.
15871 * @method removeDDFromGroup
15875 removeDDFromGroup: function(oDD, sGroup) {
15876 if (!this.ids[sGroup]) {
15877 this.ids[sGroup] = {};
15880 var obj = this.ids[sGroup];
15881 if (obj && obj[oDD.id]) {
15882 delete obj[oDD.id];
15887 * Unregisters a drag and drop item. This is executed in
15888 * DragDrop.unreg, use that method instead of calling this directly.
15893 _remove: function(oDD) {
15894 for (var g in oDD.groups) {
15895 if (g && this.ids[g][oDD.id]) {
15896 delete this.ids[g][oDD.id];
15899 delete this.handleIds[oDD.id];
15903 * Each DragDrop handle element must be registered. This is done
15904 * automatically when executing DragDrop.setHandleElId()
15905 * @method regHandle
15906 * @param {String} sDDId the DragDrop id this element is a handle for
15907 * @param {String} sHandleId the id of the element that is the drag
15911 regHandle: function(sDDId, sHandleId) {
15912 if (!this.handleIds[sDDId]) {
15913 this.handleIds[sDDId] = {};
15915 this.handleIds[sDDId][sHandleId] = sHandleId;
15919 * Utility function to determine if a given element has been
15920 * registered as a drag drop item.
15921 * @method isDragDrop
15922 * @param {String} id the element id to check
15923 * @return {boolean} true if this element is a DragDrop item,
15927 isDragDrop: function(id) {
15928 return ( this.getDDById(id) ) ? true : false;
15932 * Returns the drag and drop instances that are in all groups the
15933 * passed in instance belongs to.
15934 * @method getRelated
15935 * @param {DragDrop} p_oDD the obj to get related data for
15936 * @param {boolean} bTargetsOnly if true, only return targetable objs
15937 * @return {DragDrop[]} the related instances
15940 getRelated: function(p_oDD, bTargetsOnly) {
15942 for (var i in p_oDD.groups) {
15943 for (j in this.ids[i]) {
15944 var dd = this.ids[i][j];
15945 if (! this.isTypeOfDD(dd)) {
15948 if (!bTargetsOnly || dd.isTarget) {
15949 oDDs[oDDs.length] = dd;
15958 * Returns true if the specified dd target is a legal target for
15959 * the specifice drag obj
15960 * @method isLegalTarget
15961 * @param {DragDrop} the drag obj
15962 * @param {DragDrop} the target
15963 * @return {boolean} true if the target is a legal target for the
15967 isLegalTarget: function (oDD, oTargetDD) {
15968 var targets = this.getRelated(oDD, true);
15969 for (var i=0, len=targets.length;i<len;++i) {
15970 if (targets[i].id == oTargetDD.id) {
15979 * My goal is to be able to transparently determine if an object is
15980 * typeof DragDrop, and the exact subclass of DragDrop. typeof
15981 * returns "object", oDD.constructor.toString() always returns
15982 * "DragDrop" and not the name of the subclass. So for now it just
15983 * evaluates a well-known variable in DragDrop.
15984 * @method isTypeOfDD
15985 * @param {Object} the object to evaluate
15986 * @return {boolean} true if typeof oDD = DragDrop
15989 isTypeOfDD: function (oDD) {
15990 return (oDD && oDD.__ygDragDrop);
15994 * Utility function to determine if a given element has been
15995 * registered as a drag drop handle for the given Drag Drop object.
15997 * @param {String} id the element id to check
15998 * @return {boolean} true if this element is a DragDrop handle, false
16002 isHandle: function(sDDId, sHandleId) {
16003 return ( this.handleIds[sDDId] &&
16004 this.handleIds[sDDId][sHandleId] );
16008 * Returns the DragDrop instance for a given id
16009 * @method getDDById
16010 * @param {String} id the id of the DragDrop object
16011 * @return {DragDrop} the drag drop object, null if it is not found
16014 getDDById: function(id) {
16015 for (var i in this.ids) {
16016 if (this.ids[i][id]) {
16017 return this.ids[i][id];
16024 * Fired after a registered DragDrop object gets the mousedown event.
16025 * Sets up the events required to track the object being dragged
16026 * @method handleMouseDown
16027 * @param {Event} e the event
16028 * @param oDD the DragDrop object being dragged
16032 handleMouseDown: function(e, oDD) {
16034 Roo.QuickTips.disable();
16036 this.currentTarget = e.getTarget();
16038 this.dragCurrent = oDD;
16040 var el = oDD.getEl();
16042 // track start position
16043 this.startX = e.getPageX();
16044 this.startY = e.getPageY();
16046 this.deltaX = this.startX - el.offsetLeft;
16047 this.deltaY = this.startY - el.offsetTop;
16049 this.dragThreshMet = false;
16051 this.clickTimeout = setTimeout(
16053 var DDM = Roo.dd.DDM;
16054 DDM.startDrag(DDM.startX, DDM.startY);
16056 this.clickTimeThresh );
16060 * Fired when either the drag pixel threshol or the mousedown hold
16061 * time threshold has been met.
16062 * @method startDrag
16063 * @param x {int} the X position of the original mousedown
16064 * @param y {int} the Y position of the original mousedown
16067 startDrag: function(x, y) {
16068 clearTimeout(this.clickTimeout);
16069 if (this.dragCurrent) {
16070 this.dragCurrent.b4StartDrag(x, y);
16071 this.dragCurrent.startDrag(x, y);
16073 this.dragThreshMet = true;
16077 * Internal function to handle the mouseup event. Will be invoked
16078 * from the context of the document.
16079 * @method handleMouseUp
16080 * @param {Event} e the event
16084 handleMouseUp: function(e) {
16087 Roo.QuickTips.enable();
16089 if (! this.dragCurrent) {
16093 clearTimeout(this.clickTimeout);
16095 if (this.dragThreshMet) {
16096 this.fireEvents(e, true);
16106 * Utility to stop event propagation and event default, if these
16107 * features are turned on.
16108 * @method stopEvent
16109 * @param {Event} e the event as returned by this.getEvent()
16112 stopEvent: function(e){
16113 if(this.stopPropagation) {
16114 e.stopPropagation();
16117 if (this.preventDefault) {
16118 e.preventDefault();
16123 * Internal function to clean up event handlers after the drag
16124 * operation is complete
16126 * @param {Event} e the event
16130 stopDrag: function(e) {
16131 // Fire the drag end event for the item that was dragged
16132 if (this.dragCurrent) {
16133 if (this.dragThreshMet) {
16134 this.dragCurrent.b4EndDrag(e);
16135 this.dragCurrent.endDrag(e);
16138 this.dragCurrent.onMouseUp(e);
16141 this.dragCurrent = null;
16142 this.dragOvers = {};
16146 * Internal function to handle the mousemove event. Will be invoked
16147 * from the context of the html element.
16149 * @TODO figure out what we can do about mouse events lost when the
16150 * user drags objects beyond the window boundary. Currently we can
16151 * detect this in internet explorer by verifying that the mouse is
16152 * down during the mousemove event. Firefox doesn't give us the
16153 * button state on the mousemove event.
16154 * @method handleMouseMove
16155 * @param {Event} e the event
16159 handleMouseMove: function(e) {
16160 if (! this.dragCurrent) {
16164 // var button = e.which || e.button;
16166 // check for IE mouseup outside of page boundary
16167 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16169 return this.handleMouseUp(e);
16172 if (!this.dragThreshMet) {
16173 var diffX = Math.abs(this.startX - e.getPageX());
16174 var diffY = Math.abs(this.startY - e.getPageY());
16175 if (diffX > this.clickPixelThresh ||
16176 diffY > this.clickPixelThresh) {
16177 this.startDrag(this.startX, this.startY);
16181 if (this.dragThreshMet) {
16182 this.dragCurrent.b4Drag(e);
16183 this.dragCurrent.onDrag(e);
16184 if(!this.dragCurrent.moveOnly){
16185 this.fireEvents(e, false);
16195 * Iterates over all of the DragDrop elements to find ones we are
16196 * hovering over or dropping on
16197 * @method fireEvents
16198 * @param {Event} e the event
16199 * @param {boolean} isDrop is this a drop op or a mouseover op?
16203 fireEvents: function(e, isDrop) {
16204 var dc = this.dragCurrent;
16206 // If the user did the mouse up outside of the window, we could
16207 // get here even though we have ended the drag.
16208 if (!dc || dc.isLocked()) {
16212 var pt = e.getPoint();
16214 // cache the previous dragOver array
16220 var enterEvts = [];
16222 // Check to see if the object(s) we were hovering over is no longer
16223 // being hovered over so we can fire the onDragOut event
16224 for (var i in this.dragOvers) {
16226 var ddo = this.dragOvers[i];
16228 if (! this.isTypeOfDD(ddo)) {
16232 if (! this.isOverTarget(pt, ddo, this.mode)) {
16233 outEvts.push( ddo );
16236 oldOvers[i] = true;
16237 delete this.dragOvers[i];
16240 for (var sGroup in dc.groups) {
16242 if ("string" != typeof sGroup) {
16246 for (i in this.ids[sGroup]) {
16247 var oDD = this.ids[sGroup][i];
16248 if (! this.isTypeOfDD(oDD)) {
16252 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16253 if (this.isOverTarget(pt, oDD, this.mode)) {
16254 // look for drop interactions
16256 dropEvts.push( oDD );
16257 // look for drag enter and drag over interactions
16260 // initial drag over: dragEnter fires
16261 if (!oldOvers[oDD.id]) {
16262 enterEvts.push( oDD );
16263 // subsequent drag overs: dragOver fires
16265 overEvts.push( oDD );
16268 this.dragOvers[oDD.id] = oDD;
16276 if (outEvts.length) {
16277 dc.b4DragOut(e, outEvts);
16278 dc.onDragOut(e, outEvts);
16281 if (enterEvts.length) {
16282 dc.onDragEnter(e, enterEvts);
16285 if (overEvts.length) {
16286 dc.b4DragOver(e, overEvts);
16287 dc.onDragOver(e, overEvts);
16290 if (dropEvts.length) {
16291 dc.b4DragDrop(e, dropEvts);
16292 dc.onDragDrop(e, dropEvts);
16296 // fire dragout events
16298 for (i=0, len=outEvts.length; i<len; ++i) {
16299 dc.b4DragOut(e, outEvts[i].id);
16300 dc.onDragOut(e, outEvts[i].id);
16303 // fire enter events
16304 for (i=0,len=enterEvts.length; i<len; ++i) {
16305 // dc.b4DragEnter(e, oDD.id);
16306 dc.onDragEnter(e, enterEvts[i].id);
16309 // fire over events
16310 for (i=0,len=overEvts.length; i<len; ++i) {
16311 dc.b4DragOver(e, overEvts[i].id);
16312 dc.onDragOver(e, overEvts[i].id);
16315 // fire drop events
16316 for (i=0, len=dropEvts.length; i<len; ++i) {
16317 dc.b4DragDrop(e, dropEvts[i].id);
16318 dc.onDragDrop(e, dropEvts[i].id);
16323 // notify about a drop that did not find a target
16324 if (isDrop && !dropEvts.length) {
16325 dc.onInvalidDrop(e);
16331 * Helper function for getting the best match from the list of drag
16332 * and drop objects returned by the drag and drop events when we are
16333 * in INTERSECT mode. It returns either the first object that the
16334 * cursor is over, or the object that has the greatest overlap with
16335 * the dragged element.
16336 * @method getBestMatch
16337 * @param {DragDrop[]} dds The array of drag and drop objects
16339 * @return {DragDrop} The best single match
16342 getBestMatch: function(dds) {
16344 // Return null if the input is not what we expect
16345 //if (!dds || !dds.length || dds.length == 0) {
16347 // If there is only one item, it wins
16348 //} else if (dds.length == 1) {
16350 var len = dds.length;
16355 // Loop through the targeted items
16356 for (var i=0; i<len; ++i) {
16358 // If the cursor is over the object, it wins. If the
16359 // cursor is over multiple matches, the first one we come
16361 if (dd.cursorIsOver) {
16364 // Otherwise the object with the most overlap wins
16367 winner.overlap.getArea() < dd.overlap.getArea()) {
16378 * Refreshes the cache of the top-left and bottom-right points of the
16379 * drag and drop objects in the specified group(s). This is in the
16380 * format that is stored in the drag and drop instance, so typical
16383 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16387 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16389 * @TODO this really should be an indexed array. Alternatively this
16390 * method could accept both.
16391 * @method refreshCache
16392 * @param {Object} groups an associative array of groups to refresh
16395 refreshCache: function(groups) {
16396 for (var sGroup in groups) {
16397 if ("string" != typeof sGroup) {
16400 for (var i in this.ids[sGroup]) {
16401 var oDD = this.ids[sGroup][i];
16403 if (this.isTypeOfDD(oDD)) {
16404 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16405 var loc = this.getLocation(oDD);
16407 this.locationCache[oDD.id] = loc;
16409 delete this.locationCache[oDD.id];
16410 // this will unregister the drag and drop object if
16411 // the element is not in a usable state
16420 * This checks to make sure an element exists and is in the DOM. The
16421 * main purpose is to handle cases where innerHTML is used to remove
16422 * drag and drop objects from the DOM. IE provides an 'unspecified
16423 * error' when trying to access the offsetParent of such an element
16425 * @param {HTMLElement} el the element to check
16426 * @return {boolean} true if the element looks usable
16429 verifyEl: function(el) {
16434 parent = el.offsetParent;
16437 parent = el.offsetParent;
16448 * Returns a Region object containing the drag and drop element's position
16449 * and size, including the padding configured for it
16450 * @method getLocation
16451 * @param {DragDrop} oDD the drag and drop object to get the
16453 * @return {Roo.lib.Region} a Region object representing the total area
16454 * the element occupies, including any padding
16455 * the instance is configured for.
16458 getLocation: function(oDD) {
16459 if (! this.isTypeOfDD(oDD)) {
16463 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16466 pos= Roo.lib.Dom.getXY(el);
16474 x2 = x1 + el.offsetWidth;
16476 y2 = y1 + el.offsetHeight;
16478 t = y1 - oDD.padding[0];
16479 r = x2 + oDD.padding[1];
16480 b = y2 + oDD.padding[2];
16481 l = x1 - oDD.padding[3];
16483 return new Roo.lib.Region( t, r, b, l );
16487 * Checks the cursor location to see if it over the target
16488 * @method isOverTarget
16489 * @param {Roo.lib.Point} pt The point to evaluate
16490 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16491 * @return {boolean} true if the mouse is over the target
16495 isOverTarget: function(pt, oTarget, intersect) {
16496 // use cache if available
16497 var loc = this.locationCache[oTarget.id];
16498 if (!loc || !this.useCache) {
16499 loc = this.getLocation(oTarget);
16500 this.locationCache[oTarget.id] = loc;
16508 oTarget.cursorIsOver = loc.contains( pt );
16510 // DragDrop is using this as a sanity check for the initial mousedown
16511 // in this case we are done. In POINT mode, if the drag obj has no
16512 // contraints, we are also done. Otherwise we need to evaluate the
16513 // location of the target as related to the actual location of the
16514 // dragged element.
16515 var dc = this.dragCurrent;
16516 if (!dc || !dc.getTargetCoord ||
16517 (!intersect && !dc.constrainX && !dc.constrainY)) {
16518 return oTarget.cursorIsOver;
16521 oTarget.overlap = null;
16523 // Get the current location of the drag element, this is the
16524 // location of the mouse event less the delta that represents
16525 // where the original mousedown happened on the element. We
16526 // need to consider constraints and ticks as well.
16527 var pos = dc.getTargetCoord(pt.x, pt.y);
16529 var el = dc.getDragEl();
16530 var curRegion = new Roo.lib.Region( pos.y,
16531 pos.x + el.offsetWidth,
16532 pos.y + el.offsetHeight,
16535 var overlap = curRegion.intersect(loc);
16538 oTarget.overlap = overlap;
16539 return (intersect) ? true : oTarget.cursorIsOver;
16546 * unload event handler
16547 * @method _onUnload
16551 _onUnload: function(e, me) {
16552 Roo.dd.DragDropMgr.unregAll();
16556 * Cleans up the drag and drop events and objects.
16561 unregAll: function() {
16563 if (this.dragCurrent) {
16565 this.dragCurrent = null;
16568 this._execOnAll("unreg", []);
16570 for (i in this.elementCache) {
16571 delete this.elementCache[i];
16574 this.elementCache = {};
16579 * A cache of DOM elements
16580 * @property elementCache
16587 * Get the wrapper for the DOM element specified
16588 * @method getElWrapper
16589 * @param {String} id the id of the element to get
16590 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16592 * @deprecated This wrapper isn't that useful
16595 getElWrapper: function(id) {
16596 var oWrapper = this.elementCache[id];
16597 if (!oWrapper || !oWrapper.el) {
16598 oWrapper = this.elementCache[id] =
16599 new this.ElementWrapper(Roo.getDom(id));
16605 * Returns the actual DOM element
16606 * @method getElement
16607 * @param {String} id the id of the elment to get
16608 * @return {Object} The element
16609 * @deprecated use Roo.getDom instead
16612 getElement: function(id) {
16613 return Roo.getDom(id);
16617 * Returns the style property for the DOM element (i.e.,
16618 * document.getElById(id).style)
16620 * @param {String} id the id of the elment to get
16621 * @return {Object} The style property of the element
16622 * @deprecated use Roo.getDom instead
16625 getCss: function(id) {
16626 var el = Roo.getDom(id);
16627 return (el) ? el.style : null;
16631 * Inner class for cached elements
16632 * @class DragDropMgr.ElementWrapper
16637 ElementWrapper: function(el) {
16642 this.el = el || null;
16647 this.id = this.el && el.id;
16649 * A reference to the style property
16652 this.css = this.el && el.style;
16656 * Returns the X position of an html element
16658 * @param el the element for which to get the position
16659 * @return {int} the X coordinate
16661 * @deprecated use Roo.lib.Dom.getX instead
16664 getPosX: function(el) {
16665 return Roo.lib.Dom.getX(el);
16669 * Returns the Y position of an html element
16671 * @param el the element for which to get the position
16672 * @return {int} the Y coordinate
16673 * @deprecated use Roo.lib.Dom.getY instead
16676 getPosY: function(el) {
16677 return Roo.lib.Dom.getY(el);
16681 * Swap two nodes. In IE, we use the native method, for others we
16682 * emulate the IE behavior
16684 * @param n1 the first node to swap
16685 * @param n2 the other node to swap
16688 swapNode: function(n1, n2) {
16692 var p = n2.parentNode;
16693 var s = n2.nextSibling;
16696 p.insertBefore(n1, n2);
16697 } else if (n2 == n1.nextSibling) {
16698 p.insertBefore(n2, n1);
16700 n1.parentNode.replaceChild(n2, n1);
16701 p.insertBefore(n1, s);
16707 * Returns the current scroll position
16708 * @method getScroll
16712 getScroll: function () {
16713 var t, l, dde=document.documentElement, db=document.body;
16714 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16716 l = dde.scrollLeft;
16723 return { top: t, left: l };
16727 * Returns the specified element style property
16729 * @param {HTMLElement} el the element
16730 * @param {string} styleProp the style property
16731 * @return {string} The value of the style property
16732 * @deprecated use Roo.lib.Dom.getStyle
16735 getStyle: function(el, styleProp) {
16736 return Roo.fly(el).getStyle(styleProp);
16740 * Gets the scrollTop
16741 * @method getScrollTop
16742 * @return {int} the document's scrollTop
16745 getScrollTop: function () { return this.getScroll().top; },
16748 * Gets the scrollLeft
16749 * @method getScrollLeft
16750 * @return {int} the document's scrollTop
16753 getScrollLeft: function () { return this.getScroll().left; },
16756 * Sets the x/y position of an element to the location of the
16759 * @param {HTMLElement} moveEl The element to move
16760 * @param {HTMLElement} targetEl The position reference element
16763 moveToEl: function (moveEl, targetEl) {
16764 var aCoord = Roo.lib.Dom.getXY(targetEl);
16765 Roo.lib.Dom.setXY(moveEl, aCoord);
16769 * Numeric array sort function
16770 * @method numericSort
16773 numericSort: function(a, b) { return (a - b); },
16777 * @property _timeoutCount
16784 * Trying to make the load order less important. Without this we get
16785 * an error if this file is loaded before the Event Utility.
16786 * @method _addListeners
16790 _addListeners: function() {
16791 var DDM = Roo.dd.DDM;
16792 if ( Roo.lib.Event && document ) {
16795 if (DDM._timeoutCount > 2000) {
16797 setTimeout(DDM._addListeners, 10);
16798 if (document && document.body) {
16799 DDM._timeoutCount += 1;
16806 * Recursively searches the immediate parent and all child nodes for
16807 * the handle element in order to determine wheter or not it was
16809 * @method handleWasClicked
16810 * @param node the html element to inspect
16813 handleWasClicked: function(node, id) {
16814 if (this.isHandle(id, node.id)) {
16817 // check to see if this is a text node child of the one we want
16818 var p = node.parentNode;
16821 if (this.isHandle(id, p.id)) {
16836 // shorter alias, save a few bytes
16837 Roo.dd.DDM = Roo.dd.DragDropMgr;
16838 Roo.dd.DDM._addListeners();
16842 * Ext JS Library 1.1.1
16843 * Copyright(c) 2006-2007, Ext JS, LLC.
16845 * Originally Released Under LGPL - original licence link has changed is not relivant.
16848 * <script type="text/javascript">
16853 * A DragDrop implementation where the linked element follows the
16854 * mouse cursor during a drag.
16855 * @extends Roo.dd.DragDrop
16857 * @param {String} id the id of the linked element
16858 * @param {String} sGroup the group of related DragDrop items
16859 * @param {object} config an object containing configurable attributes
16860 * Valid properties for DD:
16863 Roo.dd.DD = function(id, sGroup, config) {
16865 this.init(id, sGroup, config);
16869 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16872 * When set to true, the utility automatically tries to scroll the browser
16873 * window wehn a drag and drop element is dragged near the viewport boundary.
16874 * Defaults to true.
16881 * Sets the pointer offset to the distance between the linked element's top
16882 * left corner and the location the element was clicked
16883 * @method autoOffset
16884 * @param {int} iPageX the X coordinate of the click
16885 * @param {int} iPageY the Y coordinate of the click
16887 autoOffset: function(iPageX, iPageY) {
16888 var x = iPageX - this.startPageX;
16889 var y = iPageY - this.startPageY;
16890 this.setDelta(x, y);
16894 * Sets the pointer offset. You can call this directly to force the
16895 * offset to be in a particular location (e.g., pass in 0,0 to set it
16896 * to the center of the object)
16898 * @param {int} iDeltaX the distance from the left
16899 * @param {int} iDeltaY the distance from the top
16901 setDelta: function(iDeltaX, iDeltaY) {
16902 this.deltaX = iDeltaX;
16903 this.deltaY = iDeltaY;
16907 * Sets the drag element to the location of the mousedown or click event,
16908 * maintaining the cursor location relative to the location on the element
16909 * that was clicked. Override this if you want to place the element in a
16910 * location other than where the cursor is.
16911 * @method setDragElPos
16912 * @param {int} iPageX the X coordinate of the mousedown or drag event
16913 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16915 setDragElPos: function(iPageX, iPageY) {
16916 // the first time we do this, we are going to check to make sure
16917 // the element has css positioning
16919 var el = this.getDragEl();
16920 this.alignElWithMouse(el, iPageX, iPageY);
16924 * Sets the element to the location of the mousedown or click event,
16925 * maintaining the cursor location relative to the location on the element
16926 * that was clicked. Override this if you want to place the element in a
16927 * location other than where the cursor is.
16928 * @method alignElWithMouse
16929 * @param {HTMLElement} el the element to move
16930 * @param {int} iPageX the X coordinate of the mousedown or drag event
16931 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16933 alignElWithMouse: function(el, iPageX, iPageY) {
16934 var oCoord = this.getTargetCoord(iPageX, iPageY);
16935 var fly = el.dom ? el : Roo.fly(el);
16936 if (!this.deltaSetXY) {
16937 var aCoord = [oCoord.x, oCoord.y];
16939 var newLeft = fly.getLeft(true);
16940 var newTop = fly.getTop(true);
16941 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
16943 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
16946 this.cachePosition(oCoord.x, oCoord.y);
16947 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
16952 * Saves the most recent position so that we can reset the constraints and
16953 * tick marks on-demand. We need to know this so that we can calculate the
16954 * number of pixels the element is offset from its original position.
16955 * @method cachePosition
16956 * @param iPageX the current x position (optional, this just makes it so we
16957 * don't have to look it up again)
16958 * @param iPageY the current y position (optional, this just makes it so we
16959 * don't have to look it up again)
16961 cachePosition: function(iPageX, iPageY) {
16963 this.lastPageX = iPageX;
16964 this.lastPageY = iPageY;
16966 var aCoord = Roo.lib.Dom.getXY(this.getEl());
16967 this.lastPageX = aCoord[0];
16968 this.lastPageY = aCoord[1];
16973 * Auto-scroll the window if the dragged object has been moved beyond the
16974 * visible window boundary.
16975 * @method autoScroll
16976 * @param {int} x the drag element's x position
16977 * @param {int} y the drag element's y position
16978 * @param {int} h the height of the drag element
16979 * @param {int} w the width of the drag element
16982 autoScroll: function(x, y, h, w) {
16985 // The client height
16986 var clientH = Roo.lib.Dom.getViewWidth();
16988 // The client width
16989 var clientW = Roo.lib.Dom.getViewHeight();
16991 // The amt scrolled down
16992 var st = this.DDM.getScrollTop();
16994 // The amt scrolled right
16995 var sl = this.DDM.getScrollLeft();
16997 // Location of the bottom of the element
17000 // Location of the right of the element
17003 // The distance from the cursor to the bottom of the visible area,
17004 // adjusted so that we don't scroll if the cursor is beyond the
17005 // element drag constraints
17006 var toBot = (clientH + st - y - this.deltaY);
17008 // The distance from the cursor to the right of the visible area
17009 var toRight = (clientW + sl - x - this.deltaX);
17012 // How close to the edge the cursor must be before we scroll
17013 // var thresh = (document.all) ? 100 : 40;
17016 // How many pixels to scroll per autoscroll op. This helps to reduce
17017 // clunky scrolling. IE is more sensitive about this ... it needs this
17018 // value to be higher.
17019 var scrAmt = (document.all) ? 80 : 30;
17021 // Scroll down if we are near the bottom of the visible page and the
17022 // obj extends below the crease
17023 if ( bot > clientH && toBot < thresh ) {
17024 window.scrollTo(sl, st + scrAmt);
17027 // Scroll up if the window is scrolled down and the top of the object
17028 // goes above the top border
17029 if ( y < st && st > 0 && y - st < thresh ) {
17030 window.scrollTo(sl, st - scrAmt);
17033 // Scroll right if the obj is beyond the right border and the cursor is
17034 // near the border.
17035 if ( right > clientW && toRight < thresh ) {
17036 window.scrollTo(sl + scrAmt, st);
17039 // Scroll left if the window has been scrolled to the right and the obj
17040 // extends past the left border
17041 if ( x < sl && sl > 0 && x - sl < thresh ) {
17042 window.scrollTo(sl - scrAmt, st);
17048 * Finds the location the element should be placed if we want to move
17049 * it to where the mouse location less the click offset would place us.
17050 * @method getTargetCoord
17051 * @param {int} iPageX the X coordinate of the click
17052 * @param {int} iPageY the Y coordinate of the click
17053 * @return an object that contains the coordinates (Object.x and Object.y)
17056 getTargetCoord: function(iPageX, iPageY) {
17059 var x = iPageX - this.deltaX;
17060 var y = iPageY - this.deltaY;
17062 if (this.constrainX) {
17063 if (x < this.minX) { x = this.minX; }
17064 if (x > this.maxX) { x = this.maxX; }
17067 if (this.constrainY) {
17068 if (y < this.minY) { y = this.minY; }
17069 if (y > this.maxY) { y = this.maxY; }
17072 x = this.getTick(x, this.xTicks);
17073 y = this.getTick(y, this.yTicks);
17080 * Sets up config options specific to this class. Overrides
17081 * Roo.dd.DragDrop, but all versions of this method through the
17082 * inheritance chain are called
17084 applyConfig: function() {
17085 Roo.dd.DD.superclass.applyConfig.call(this);
17086 this.scroll = (this.config.scroll !== false);
17090 * Event that fires prior to the onMouseDown event. Overrides
17093 b4MouseDown: function(e) {
17094 // this.resetConstraints();
17095 this.autoOffset(e.getPageX(),
17100 * Event that fires prior to the onDrag event. Overrides
17103 b4Drag: function(e) {
17104 this.setDragElPos(e.getPageX(),
17108 toString: function() {
17109 return ("DD " + this.id);
17112 //////////////////////////////////////////////////////////////////////////
17113 // Debugging ygDragDrop events that can be overridden
17114 //////////////////////////////////////////////////////////////////////////
17116 startDrag: function(x, y) {
17119 onDrag: function(e) {
17122 onDragEnter: function(e, id) {
17125 onDragOver: function(e, id) {
17128 onDragOut: function(e, id) {
17131 onDragDrop: function(e, id) {
17134 endDrag: function(e) {
17141 * Ext JS Library 1.1.1
17142 * Copyright(c) 2006-2007, Ext JS, LLC.
17144 * Originally Released Under LGPL - original licence link has changed is not relivant.
17147 * <script type="text/javascript">
17151 * @class Roo.dd.DDProxy
17152 * A DragDrop implementation that inserts an empty, bordered div into
17153 * the document that follows the cursor during drag operations. At the time of
17154 * the click, the frame div is resized to the dimensions of the linked html
17155 * element, and moved to the exact location of the linked element.
17157 * References to the "frame" element refer to the single proxy element that
17158 * was created to be dragged in place of all DDProxy elements on the
17161 * @extends Roo.dd.DD
17163 * @param {String} id the id of the linked html element
17164 * @param {String} sGroup the group of related DragDrop objects
17165 * @param {object} config an object containing configurable attributes
17166 * Valid properties for DDProxy in addition to those in DragDrop:
17167 * resizeFrame, centerFrame, dragElId
17169 Roo.dd.DDProxy = function(id, sGroup, config) {
17171 this.init(id, sGroup, config);
17177 * The default drag frame div id
17178 * @property Roo.dd.DDProxy.dragElId
17182 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17184 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17187 * By default we resize the drag frame to be the same size as the element
17188 * we want to drag (this is to get the frame effect). We can turn it off
17189 * if we want a different behavior.
17190 * @property resizeFrame
17196 * By default the frame is positioned exactly where the drag element is, so
17197 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17198 * you do not have constraints on the obj is to have the drag frame centered
17199 * around the cursor. Set centerFrame to true for this effect.
17200 * @property centerFrame
17203 centerFrame: false,
17206 * Creates the proxy element if it does not yet exist
17207 * @method createFrame
17209 createFrame: function() {
17211 var body = document.body;
17213 if (!body || !body.firstChild) {
17214 setTimeout( function() { self.createFrame(); }, 50 );
17218 var div = this.getDragEl();
17221 div = document.createElement("div");
17222 div.id = this.dragElId;
17225 s.position = "absolute";
17226 s.visibility = "hidden";
17228 s.border = "2px solid #aaa";
17231 // appendChild can blow up IE if invoked prior to the window load event
17232 // while rendering a table. It is possible there are other scenarios
17233 // that would cause this to happen as well.
17234 body.insertBefore(div, body.firstChild);
17239 * Initialization for the drag frame element. Must be called in the
17240 * constructor of all subclasses
17241 * @method initFrame
17243 initFrame: function() {
17244 this.createFrame();
17247 applyConfig: function() {
17248 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17250 this.resizeFrame = (this.config.resizeFrame !== false);
17251 this.centerFrame = (this.config.centerFrame);
17252 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17256 * Resizes the drag frame to the dimensions of the clicked object, positions
17257 * it over the object, and finally displays it
17258 * @method showFrame
17259 * @param {int} iPageX X click position
17260 * @param {int} iPageY Y click position
17263 showFrame: function(iPageX, iPageY) {
17264 var el = this.getEl();
17265 var dragEl = this.getDragEl();
17266 var s = dragEl.style;
17268 this._resizeProxy();
17270 if (this.centerFrame) {
17271 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17272 Math.round(parseInt(s.height, 10)/2) );
17275 this.setDragElPos(iPageX, iPageY);
17277 Roo.fly(dragEl).show();
17281 * The proxy is automatically resized to the dimensions of the linked
17282 * element when a drag is initiated, unless resizeFrame is set to false
17283 * @method _resizeProxy
17286 _resizeProxy: function() {
17287 if (this.resizeFrame) {
17288 var el = this.getEl();
17289 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17293 // overrides Roo.dd.DragDrop
17294 b4MouseDown: function(e) {
17295 var x = e.getPageX();
17296 var y = e.getPageY();
17297 this.autoOffset(x, y);
17298 this.setDragElPos(x, y);
17301 // overrides Roo.dd.DragDrop
17302 b4StartDrag: function(x, y) {
17303 // show the drag frame
17304 this.showFrame(x, y);
17307 // overrides Roo.dd.DragDrop
17308 b4EndDrag: function(e) {
17309 Roo.fly(this.getDragEl()).hide();
17312 // overrides Roo.dd.DragDrop
17313 // By default we try to move the element to the last location of the frame.
17314 // This is so that the default behavior mirrors that of Roo.dd.DD.
17315 endDrag: function(e) {
17317 var lel = this.getEl();
17318 var del = this.getDragEl();
17320 // Show the drag frame briefly so we can get its position
17321 del.style.visibility = "";
17324 // Hide the linked element before the move to get around a Safari
17326 lel.style.visibility = "hidden";
17327 Roo.dd.DDM.moveToEl(lel, del);
17328 del.style.visibility = "hidden";
17329 lel.style.visibility = "";
17334 beforeMove : function(){
17338 afterDrag : function(){
17342 toString: function() {
17343 return ("DDProxy " + this.id);
17349 * Ext JS Library 1.1.1
17350 * Copyright(c) 2006-2007, Ext JS, LLC.
17352 * Originally Released Under LGPL - original licence link has changed is not relivant.
17355 * <script type="text/javascript">
17359 * @class Roo.dd.DDTarget
17360 * A DragDrop implementation that does not move, but can be a drop
17361 * target. You would get the same result by simply omitting implementation
17362 * for the event callbacks, but this way we reduce the processing cost of the
17363 * event listener and the callbacks.
17364 * @extends Roo.dd.DragDrop
17366 * @param {String} id the id of the element that is a drop target
17367 * @param {String} sGroup the group of related DragDrop objects
17368 * @param {object} config an object containing configurable attributes
17369 * Valid properties for DDTarget in addition to those in
17373 Roo.dd.DDTarget = function(id, sGroup, config) {
17375 this.initTarget(id, sGroup, config);
17377 if (config.listeners || config.events) {
17378 Roo.dd.DragDrop.superclass.constructor.call(this, {
17379 listeners : config.listeners || {},
17380 events : config.events || {}
17385 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17386 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17387 toString: function() {
17388 return ("DDTarget " + this.id);
17393 * Ext JS Library 1.1.1
17394 * Copyright(c) 2006-2007, Ext JS, LLC.
17396 * Originally Released Under LGPL - original licence link has changed is not relivant.
17399 * <script type="text/javascript">
17404 * @class Roo.dd.ScrollManager
17405 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17406 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17409 Roo.dd.ScrollManager = function(){
17410 var ddm = Roo.dd.DragDropMgr;
17415 var onStop = function(e){
17420 var triggerRefresh = function(){
17421 if(ddm.dragCurrent){
17422 ddm.refreshCache(ddm.dragCurrent.groups);
17426 var doScroll = function(){
17427 if(ddm.dragCurrent){
17428 var dds = Roo.dd.ScrollManager;
17430 if(proc.el.scroll(proc.dir, dds.increment)){
17434 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17439 var clearProc = function(){
17441 clearInterval(proc.id);
17448 var startProc = function(el, dir){
17452 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17455 var onFire = function(e, isDrop){
17456 if(isDrop || !ddm.dragCurrent){ return; }
17457 var dds = Roo.dd.ScrollManager;
17458 if(!dragEl || dragEl != ddm.dragCurrent){
17459 dragEl = ddm.dragCurrent;
17460 // refresh regions on drag start
17461 dds.refreshCache();
17464 var xy = Roo.lib.Event.getXY(e);
17465 var pt = new Roo.lib.Point(xy[0], xy[1]);
17466 for(var id in els){
17467 var el = els[id], r = el._region;
17468 if(r && r.contains(pt) && el.isScrollable()){
17469 if(r.bottom - pt.y <= dds.thresh){
17471 startProc(el, "down");
17474 }else if(r.right - pt.x <= dds.thresh){
17476 startProc(el, "left");
17479 }else if(pt.y - r.top <= dds.thresh){
17481 startProc(el, "up");
17484 }else if(pt.x - r.left <= dds.thresh){
17486 startProc(el, "right");
17495 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17496 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17500 * Registers new overflow element(s) to auto scroll
17501 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17503 register : function(el){
17504 if(el instanceof Array){
17505 for(var i = 0, len = el.length; i < len; i++) {
17506 this.register(el[i]);
17515 * Unregisters overflow element(s) so they are no longer scrolled
17516 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17518 unregister : function(el){
17519 if(el instanceof Array){
17520 for(var i = 0, len = el.length; i < len; i++) {
17521 this.unregister(el[i]);
17530 * The number of pixels from the edge of a container the pointer needs to be to
17531 * trigger scrolling (defaults to 25)
17537 * The number of pixels to scroll in each scroll increment (defaults to 50)
17543 * The frequency of scrolls in milliseconds (defaults to 500)
17549 * True to animate the scroll (defaults to true)
17555 * The animation duration in seconds -
17556 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17562 * Manually trigger a cache refresh.
17564 refreshCache : function(){
17565 for(var id in els){
17566 if(typeof els[id] == 'object'){ // for people extending the object prototype
17567 els[id]._region = els[id].getRegion();
17574 * Ext JS Library 1.1.1
17575 * Copyright(c) 2006-2007, Ext JS, LLC.
17577 * Originally Released Under LGPL - original licence link has changed is not relivant.
17580 * <script type="text/javascript">
17585 * @class Roo.dd.Registry
17586 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17587 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17590 Roo.dd.Registry = function(){
17593 var autoIdSeed = 0;
17595 var getId = function(el, autogen){
17596 if(typeof el == "string"){
17600 if(!id && autogen !== false){
17601 id = "roodd-" + (++autoIdSeed);
17609 * Register a drag drop element
17610 * @param {String|HTMLElement} element The id or DOM node to register
17611 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17612 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17613 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17614 * populated in the data object (if applicable):
17616 Value Description<br />
17617 --------- ------------------------------------------<br />
17618 handles Array of DOM nodes that trigger dragging<br />
17619 for the element being registered<br />
17620 isHandle True if the element passed in triggers<br />
17621 dragging itself, else false
17624 register : function(el, data){
17626 if(typeof el == "string"){
17627 el = document.getElementById(el);
17630 elements[getId(el)] = data;
17631 if(data.isHandle !== false){
17632 handles[data.ddel.id] = data;
17635 var hs = data.handles;
17636 for(var i = 0, len = hs.length; i < len; i++){
17637 handles[getId(hs[i])] = data;
17643 * Unregister a drag drop element
17644 * @param {String|HTMLElement} element The id or DOM node to unregister
17646 unregister : function(el){
17647 var id = getId(el, false);
17648 var data = elements[id];
17650 delete elements[id];
17652 var hs = data.handles;
17653 for(var i = 0, len = hs.length; i < len; i++){
17654 delete handles[getId(hs[i], false)];
17661 * Returns the handle registered for a DOM Node by id
17662 * @param {String|HTMLElement} id The DOM node or id to look up
17663 * @return {Object} handle The custom handle data
17665 getHandle : function(id){
17666 if(typeof id != "string"){ // must be element?
17669 return handles[id];
17673 * Returns the handle that is registered for the DOM node that is the target of the event
17674 * @param {Event} e The event
17675 * @return {Object} handle The custom handle data
17677 getHandleFromEvent : function(e){
17678 var t = Roo.lib.Event.getTarget(e);
17679 return t ? handles[t.id] : null;
17683 * Returns a custom data object that is registered for a DOM node by id
17684 * @param {String|HTMLElement} id The DOM node or id to look up
17685 * @return {Object} data The custom data
17687 getTarget : function(id){
17688 if(typeof id != "string"){ // must be element?
17691 return elements[id];
17695 * Returns a custom data object that is registered for the DOM node that is the target of the event
17696 * @param {Event} e The event
17697 * @return {Object} data The custom data
17699 getTargetFromEvent : function(e){
17700 var t = Roo.lib.Event.getTarget(e);
17701 return t ? elements[t.id] || handles[t.id] : null;
17706 * Ext JS Library 1.1.1
17707 * Copyright(c) 2006-2007, Ext JS, LLC.
17709 * Originally Released Under LGPL - original licence link has changed is not relivant.
17712 * <script type="text/javascript">
17717 * @class Roo.dd.StatusProxy
17718 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17719 * default drag proxy used by all Roo.dd components.
17721 * @param {Object} config
17723 Roo.dd.StatusProxy = function(config){
17724 Roo.apply(this, config);
17725 this.id = this.id || Roo.id();
17726 this.el = new Roo.Layer({
17728 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17729 {tag: "div", cls: "x-dd-drop-icon"},
17730 {tag: "div", cls: "x-dd-drag-ghost"}
17733 shadow: !config || config.shadow !== false
17735 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17736 this.dropStatus = this.dropNotAllowed;
17739 Roo.dd.StatusProxy.prototype = {
17741 * @cfg {String} dropAllowed
17742 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17744 dropAllowed : "x-dd-drop-ok",
17746 * @cfg {String} dropNotAllowed
17747 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17749 dropNotAllowed : "x-dd-drop-nodrop",
17752 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17753 * over the current target element.
17754 * @param {String} cssClass The css class for the new drop status indicator image
17756 setStatus : function(cssClass){
17757 cssClass = cssClass || this.dropNotAllowed;
17758 if(this.dropStatus != cssClass){
17759 this.el.replaceClass(this.dropStatus, cssClass);
17760 this.dropStatus = cssClass;
17765 * Resets the status indicator to the default dropNotAllowed value
17766 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17768 reset : function(clearGhost){
17769 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17770 this.dropStatus = this.dropNotAllowed;
17772 this.ghost.update("");
17777 * Updates the contents of the ghost element
17778 * @param {String} html The html that will replace the current innerHTML of the ghost element
17780 update : function(html){
17781 if(typeof html == "string"){
17782 this.ghost.update(html);
17784 this.ghost.update("");
17785 html.style.margin = "0";
17786 this.ghost.dom.appendChild(html);
17788 // ensure float = none set?? cant remember why though.
17789 var el = this.ghost.dom.firstChild;
17791 Roo.fly(el).setStyle('float', 'none');
17796 * Returns the underlying proxy {@link Roo.Layer}
17797 * @return {Roo.Layer} el
17799 getEl : function(){
17804 * Returns the ghost element
17805 * @return {Roo.Element} el
17807 getGhost : function(){
17813 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17815 hide : function(clear){
17823 * Stops the repair animation if it's currently running
17826 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17832 * Displays this proxy
17839 * Force the Layer to sync its shadow and shim positions to the element
17846 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17847 * invalid drop operation by the item being dragged.
17848 * @param {Array} xy The XY position of the element ([x, y])
17849 * @param {Function} callback The function to call after the repair is complete
17850 * @param {Object} scope The scope in which to execute the callback
17852 repair : function(xy, callback, scope){
17853 this.callback = callback;
17854 this.scope = scope;
17855 if(xy && this.animRepair !== false){
17856 this.el.addClass("x-dd-drag-repair");
17857 this.el.hideUnders(true);
17858 this.anim = this.el.shift({
17859 duration: this.repairDuration || .5,
17863 callback: this.afterRepair,
17867 this.afterRepair();
17872 afterRepair : function(){
17874 if(typeof this.callback == "function"){
17875 this.callback.call(this.scope || this);
17877 this.callback = null;
17882 * Ext JS Library 1.1.1
17883 * Copyright(c) 2006-2007, Ext JS, LLC.
17885 * Originally Released Under LGPL - original licence link has changed is not relivant.
17888 * <script type="text/javascript">
17892 * @class Roo.dd.DragSource
17893 * @extends Roo.dd.DDProxy
17894 * A simple class that provides the basic implementation needed to make any element draggable.
17896 * @param {String/HTMLElement/Element} el The container element
17897 * @param {Object} config
17899 Roo.dd.DragSource = function(el, config){
17900 this.el = Roo.get(el);
17901 this.dragData = {};
17903 Roo.apply(this, config);
17906 this.proxy = new Roo.dd.StatusProxy();
17909 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17910 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
17912 this.dragging = false;
17915 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
17917 * @cfg {String} dropAllowed
17918 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
17920 dropAllowed : "x-dd-drop-ok",
17922 * @cfg {String} dropNotAllowed
17923 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
17925 dropNotAllowed : "x-dd-drop-nodrop",
17928 * Returns the data object associated with this drag source
17929 * @return {Object} data An object containing arbitrary data
17931 getDragData : function(e){
17932 return this.dragData;
17936 onDragEnter : function(e, id){
17937 var target = Roo.dd.DragDropMgr.getDDById(id);
17938 this.cachedTarget = target;
17939 if(this.beforeDragEnter(target, e, id) !== false){
17940 if(target.isNotifyTarget){
17941 var status = target.notifyEnter(this, e, this.dragData);
17942 this.proxy.setStatus(status);
17944 this.proxy.setStatus(this.dropAllowed);
17947 if(this.afterDragEnter){
17949 * An empty function by default, but provided so that you can perform a custom action
17950 * when the dragged item enters the drop target by providing an implementation.
17951 * @param {Roo.dd.DragDrop} target The drop target
17952 * @param {Event} e The event object
17953 * @param {String} id The id of the dragged element
17954 * @method afterDragEnter
17956 this.afterDragEnter(target, e, id);
17962 * An empty function by default, but provided so that you can perform a custom action
17963 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
17964 * @param {Roo.dd.DragDrop} target The drop target
17965 * @param {Event} e The event object
17966 * @param {String} id The id of the dragged element
17967 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17969 beforeDragEnter : function(target, e, id){
17974 alignElWithMouse: function() {
17975 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
17980 onDragOver : function(e, id){
17981 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17982 if(this.beforeDragOver(target, e, id) !== false){
17983 if(target.isNotifyTarget){
17984 var status = target.notifyOver(this, e, this.dragData);
17985 this.proxy.setStatus(status);
17988 if(this.afterDragOver){
17990 * An empty function by default, but provided so that you can perform a custom action
17991 * while the dragged item is over the drop target by providing an implementation.
17992 * @param {Roo.dd.DragDrop} target The drop target
17993 * @param {Event} e The event object
17994 * @param {String} id The id of the dragged element
17995 * @method afterDragOver
17997 this.afterDragOver(target, e, id);
18003 * An empty function by default, but provided so that you can perform a custom action
18004 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18005 * @param {Roo.dd.DragDrop} target The drop target
18006 * @param {Event} e The event object
18007 * @param {String} id The id of the dragged element
18008 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18010 beforeDragOver : function(target, e, id){
18015 onDragOut : function(e, id){
18016 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18017 if(this.beforeDragOut(target, e, id) !== false){
18018 if(target.isNotifyTarget){
18019 target.notifyOut(this, e, this.dragData);
18021 this.proxy.reset();
18022 if(this.afterDragOut){
18024 * An empty function by default, but provided so that you can perform a custom action
18025 * after the dragged item is dragged out of the target without dropping.
18026 * @param {Roo.dd.DragDrop} target The drop target
18027 * @param {Event} e The event object
18028 * @param {String} id The id of the dragged element
18029 * @method afterDragOut
18031 this.afterDragOut(target, e, id);
18034 this.cachedTarget = null;
18038 * An empty function by default, but provided so that you can perform a custom action before the dragged
18039 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18040 * @param {Roo.dd.DragDrop} target The drop target
18041 * @param {Event} e The event object
18042 * @param {String} id The id of the dragged element
18043 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18045 beforeDragOut : function(target, e, id){
18050 onDragDrop : function(e, id){
18051 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18052 if(this.beforeDragDrop(target, e, id) !== false){
18053 if(target.isNotifyTarget){
18054 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18055 this.onValidDrop(target, e, id);
18057 this.onInvalidDrop(target, e, id);
18060 this.onValidDrop(target, e, id);
18063 if(this.afterDragDrop){
18065 * An empty function by default, but provided so that you can perform a custom action
18066 * after a valid drag drop has occurred by providing an implementation.
18067 * @param {Roo.dd.DragDrop} target The drop target
18068 * @param {Event} e The event object
18069 * @param {String} id The id of the dropped element
18070 * @method afterDragDrop
18072 this.afterDragDrop(target, e, id);
18075 delete this.cachedTarget;
18079 * An empty function by default, but provided so that you can perform a custom action before the dragged
18080 * item is dropped onto the target and optionally cancel the onDragDrop.
18081 * @param {Roo.dd.DragDrop} target The drop target
18082 * @param {Event} e The event object
18083 * @param {String} id The id of the dragged element
18084 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18086 beforeDragDrop : function(target, e, id){
18091 onValidDrop : function(target, e, id){
18093 if(this.afterValidDrop){
18095 * An empty function by default, but provided so that you can perform a custom action
18096 * after a valid drop has occurred by providing an implementation.
18097 * @param {Object} target The target DD
18098 * @param {Event} e The event object
18099 * @param {String} id The id of the dropped element
18100 * @method afterInvalidDrop
18102 this.afterValidDrop(target, e, id);
18107 getRepairXY : function(e, data){
18108 return this.el.getXY();
18112 onInvalidDrop : function(target, e, id){
18113 this.beforeInvalidDrop(target, e, id);
18114 if(this.cachedTarget){
18115 if(this.cachedTarget.isNotifyTarget){
18116 this.cachedTarget.notifyOut(this, e, this.dragData);
18118 this.cacheTarget = null;
18120 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18122 if(this.afterInvalidDrop){
18124 * An empty function by default, but provided so that you can perform a custom action
18125 * after an invalid drop has occurred by providing an implementation.
18126 * @param {Event} e The event object
18127 * @param {String} id The id of the dropped element
18128 * @method afterInvalidDrop
18130 this.afterInvalidDrop(e, id);
18135 afterRepair : function(){
18137 this.el.highlight(this.hlColor || "c3daf9");
18139 this.dragging = false;
18143 * An empty function by default, but provided so that you can perform a custom action after an invalid
18144 * drop has occurred.
18145 * @param {Roo.dd.DragDrop} target The drop target
18146 * @param {Event} e The event object
18147 * @param {String} id The id of the dragged element
18148 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18150 beforeInvalidDrop : function(target, e, id){
18155 handleMouseDown : function(e){
18156 if(this.dragging) {
18159 var data = this.getDragData(e);
18160 if(data && this.onBeforeDrag(data, e) !== false){
18161 this.dragData = data;
18163 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18168 * An empty function by default, but provided so that you can perform a custom action before the initial
18169 * drag event begins and optionally cancel it.
18170 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18171 * @param {Event} e The event object
18172 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18174 onBeforeDrag : function(data, e){
18179 * An empty function by default, but provided so that you can perform a custom action once the initial
18180 * drag event has begun. The drag cannot be canceled from this function.
18181 * @param {Number} x The x position of the click on the dragged object
18182 * @param {Number} y The y position of the click on the dragged object
18184 onStartDrag : Roo.emptyFn,
18186 // private - YUI override
18187 startDrag : function(x, y){
18188 this.proxy.reset();
18189 this.dragging = true;
18190 this.proxy.update("");
18191 this.onInitDrag(x, y);
18196 onInitDrag : function(x, y){
18197 var clone = this.el.dom.cloneNode(true);
18198 clone.id = Roo.id(); // prevent duplicate ids
18199 this.proxy.update(clone);
18200 this.onStartDrag(x, y);
18205 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18206 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18208 getProxy : function(){
18213 * Hides the drag source's {@link Roo.dd.StatusProxy}
18215 hideProxy : function(){
18217 this.proxy.reset(true);
18218 this.dragging = false;
18222 triggerCacheRefresh : function(){
18223 Roo.dd.DDM.refreshCache(this.groups);
18226 // private - override to prevent hiding
18227 b4EndDrag: function(e) {
18230 // private - override to prevent moving
18231 endDrag : function(e){
18232 this.onEndDrag(this.dragData, e);
18236 onEndDrag : function(data, e){
18239 // private - pin to cursor
18240 autoOffset : function(x, y) {
18241 this.setDelta(-12, -20);
18245 * Ext JS Library 1.1.1
18246 * Copyright(c) 2006-2007, Ext JS, LLC.
18248 * Originally Released Under LGPL - original licence link has changed is not relivant.
18251 * <script type="text/javascript">
18256 * @class Roo.dd.DropTarget
18257 * @extends Roo.dd.DDTarget
18258 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18259 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18261 * @param {String/HTMLElement/Element} el The container element
18262 * @param {Object} config
18264 Roo.dd.DropTarget = function(el, config){
18265 this.el = Roo.get(el);
18267 var listeners = false; ;
18268 if (config && config.listeners) {
18269 listeners= config.listeners;
18270 delete config.listeners;
18272 Roo.apply(this, config);
18274 if(this.containerScroll){
18275 Roo.dd.ScrollManager.register(this.el);
18279 * @scope Roo.dd.DropTarget
18284 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18285 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18286 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18288 * IMPORTANT : it should set this.overClass and this.dropAllowed
18290 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18291 * @param {Event} e The event
18292 * @param {Object} data An object containing arbitrary data supplied by the drag source
18298 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18299 * This method will be called on every mouse movement while the drag source is over the drop target.
18300 * This default implementation simply returns the dropAllowed config value.
18302 * IMPORTANT : it should set this.dropAllowed
18304 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18305 * @param {Event} e The event
18306 * @param {Object} data An object containing arbitrary data supplied by the drag source
18312 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18313 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18314 * overClass (if any) from the drop element.
18315 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18316 * @param {Event} e The event
18317 * @param {Object} data An object containing arbitrary data supplied by the drag source
18323 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18324 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18325 * implementation that does something to process the drop event and returns true so that the drag source's
18326 * repair action does not run.
18328 * IMPORTANT : it should set this.success
18330 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18331 * @param {Event} e The event
18332 * @param {Object} data An object containing arbitrary data supplied by the drag source
18338 Roo.dd.DropTarget.superclass.constructor.call( this,
18340 this.ddGroup || this.group,
18343 listeners : listeners || {}
18351 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18353 * @cfg {String} overClass
18354 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18357 * @cfg {String} ddGroup
18358 * The drag drop group to handle drop events for
18362 * @cfg {String} dropAllowed
18363 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18365 dropAllowed : "x-dd-drop-ok",
18367 * @cfg {String} dropNotAllowed
18368 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18370 dropNotAllowed : "x-dd-drop-nodrop",
18372 * @cfg {boolean} success
18373 * set this after drop listener..
18377 * @cfg {boolean|String} valid true/false or string (add/sub/ok/nodrop)
18378 * if the drop point is valid for over/enter..
18385 isNotifyTarget : true,
18390 notifyEnter : function(dd, e, data){
18392 this.fireEvent('enter', this, dd, e, data);
18393 if(this.overClass){
18394 this.el.addClass(this.overClass);
18396 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18397 this.valid ? this.dropAllowed : this.dropNotAllowed
18404 notifyOver : function(dd, e, data){
18406 this.fireEvent('over', this, dd, e, data);
18407 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18408 this.valid ? this.dropAllowed : this.dropNotAllowed
18415 notifyOut : function(dd, e, data){
18416 this.fireEvent('out', this, dd, e, data);
18417 if(this.overClass){
18418 this.el.removeClass(this.overClass);
18425 notifyDrop : function(dd, e, data){
18426 this.success = false;
18427 this.fireEvent('drop', this, dd, e, data);
18428 return this.success;
18432 * Ext JS Library 1.1.1
18433 * Copyright(c) 2006-2007, Ext JS, LLC.
18435 * Originally Released Under LGPL - original licence link has changed is not relivant.
18438 * <script type="text/javascript">
18443 * @class Roo.dd.DragZone
18444 * @extends Roo.dd.DragSource
18445 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18446 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18448 * @param {String/HTMLElement/Element} el The container element
18449 * @param {Object} config
18451 Roo.dd.DragZone = function(el, config){
18452 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18453 if(this.containerScroll){
18454 Roo.dd.ScrollManager.register(this.el);
18458 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18460 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18461 * for auto scrolling during drag operations.
18464 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18465 * method after a failed drop (defaults to "c3daf9" - light blue)
18469 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18470 * for a valid target to drag based on the mouse down. Override this method
18471 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18472 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18473 * @param {EventObject} e The mouse down event
18474 * @return {Object} The dragData
18476 getDragData : function(e){
18477 return Roo.dd.Registry.getHandleFromEvent(e);
18481 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18482 * this.dragData.ddel
18483 * @param {Number} x The x position of the click on the dragged object
18484 * @param {Number} y The y position of the click on the dragged object
18485 * @return {Boolean} true to continue the drag, false to cancel
18487 onInitDrag : function(x, y){
18488 this.proxy.update(this.dragData.ddel.cloneNode(true));
18489 this.onStartDrag(x, y);
18494 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18496 afterRepair : function(){
18498 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18500 this.dragging = false;
18504 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18505 * the XY of this.dragData.ddel
18506 * @param {EventObject} e The mouse up event
18507 * @return {Array} The xy location (e.g. [100, 200])
18509 getRepairXY : function(e){
18510 return Roo.Element.fly(this.dragData.ddel).getXY();
18514 * Ext JS Library 1.1.1
18515 * Copyright(c) 2006-2007, Ext JS, LLC.
18517 * Originally Released Under LGPL - original licence link has changed is not relivant.
18520 * <script type="text/javascript">
18523 * @class Roo.dd.DropZone
18524 * @extends Roo.dd.DropTarget
18525 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18526 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18528 * @param {String/HTMLElement/Element} el The container element
18529 * @param {Object} config
18531 Roo.dd.DropZone = function(el, config){
18532 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18535 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18537 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18538 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18539 * provide your own custom lookup.
18540 * @param {Event} e The event
18541 * @return {Object} data The custom data
18543 getTargetFromEvent : function(e){
18544 return Roo.dd.Registry.getTargetFromEvent(e);
18548 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18549 * that it has registered. This method has no default implementation and should be overridden to provide
18550 * node-specific processing if necessary.
18551 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18552 * {@link #getTargetFromEvent} for this node)
18553 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18554 * @param {Event} e The event
18555 * @param {Object} data An object containing arbitrary data supplied by the drag source
18557 onNodeEnter : function(n, dd, e, data){
18562 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18563 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18564 * overridden to provide the proper feedback.
18565 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18566 * {@link #getTargetFromEvent} for this node)
18567 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18568 * @param {Event} e The event
18569 * @param {Object} data An object containing arbitrary data supplied by the drag source
18570 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18571 * underlying {@link Roo.dd.StatusProxy} can be updated
18573 onNodeOver : function(n, dd, e, data){
18574 return this.dropAllowed;
18578 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18579 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18580 * node-specific processing if necessary.
18581 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18582 * {@link #getTargetFromEvent} for this node)
18583 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18584 * @param {Event} e The event
18585 * @param {Object} data An object containing arbitrary data supplied by the drag source
18587 onNodeOut : function(n, dd, e, data){
18592 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18593 * the drop node. The default implementation returns false, so it should be overridden to provide the
18594 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18595 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18596 * {@link #getTargetFromEvent} for this node)
18597 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18598 * @param {Event} e The event
18599 * @param {Object} data An object containing arbitrary data supplied by the drag source
18600 * @return {Boolean} True if the drop was valid, else false
18602 onNodeDrop : function(n, dd, e, data){
18607 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18608 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18609 * it should be overridden to provide the proper feedback if necessary.
18610 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18611 * @param {Event} e The event
18612 * @param {Object} data An object containing arbitrary data supplied by the drag source
18613 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18614 * underlying {@link Roo.dd.StatusProxy} can be updated
18616 onContainerOver : function(dd, e, data){
18617 return this.dropNotAllowed;
18621 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18622 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18623 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18624 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18625 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18626 * @param {Event} e The event
18627 * @param {Object} data An object containing arbitrary data supplied by the drag source
18628 * @return {Boolean} True if the drop was valid, else false
18630 onContainerDrop : function(dd, e, data){
18635 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18636 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18637 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18638 * you should override this method and provide a custom implementation.
18639 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18640 * @param {Event} e The event
18641 * @param {Object} data An object containing arbitrary data supplied by the drag source
18642 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18643 * underlying {@link Roo.dd.StatusProxy} can be updated
18645 notifyEnter : function(dd, e, data){
18646 return this.dropNotAllowed;
18650 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18651 * This method will be called on every mouse movement while the drag source is over the drop zone.
18652 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18653 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18654 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18655 * registered node, it will call {@link #onContainerOver}.
18656 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18657 * @param {Event} e The event
18658 * @param {Object} data An object containing arbitrary data supplied by the drag source
18659 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18660 * underlying {@link Roo.dd.StatusProxy} can be updated
18662 notifyOver : function(dd, e, data){
18663 var n = this.getTargetFromEvent(e);
18664 if(!n){ // not over valid drop target
18665 if(this.lastOverNode){
18666 this.onNodeOut(this.lastOverNode, dd, e, data);
18667 this.lastOverNode = null;
18669 return this.onContainerOver(dd, e, data);
18671 if(this.lastOverNode != n){
18672 if(this.lastOverNode){
18673 this.onNodeOut(this.lastOverNode, dd, e, data);
18675 this.onNodeEnter(n, dd, e, data);
18676 this.lastOverNode = n;
18678 return this.onNodeOver(n, dd, e, data);
18682 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18683 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18684 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18685 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18686 * @param {Event} e The event
18687 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18689 notifyOut : function(dd, e, data){
18690 if(this.lastOverNode){
18691 this.onNodeOut(this.lastOverNode, dd, e, data);
18692 this.lastOverNode = null;
18697 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18698 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18699 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18700 * otherwise it will call {@link #onContainerDrop}.
18701 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18702 * @param {Event} e The event
18703 * @param {Object} data An object containing arbitrary data supplied by the drag source
18704 * @return {Boolean} True if the drop was valid, else false
18706 notifyDrop : function(dd, e, data){
18707 if(this.lastOverNode){
18708 this.onNodeOut(this.lastOverNode, dd, e, data);
18709 this.lastOverNode = null;
18711 var n = this.getTargetFromEvent(e);
18713 this.onNodeDrop(n, dd, e, data) :
18714 this.onContainerDrop(dd, e, data);
18718 triggerCacheRefresh : function(){
18719 Roo.dd.DDM.refreshCache(this.groups);
18723 * Ext JS Library 1.1.1
18724 * Copyright(c) 2006-2007, Ext JS, LLC.
18726 * Originally Released Under LGPL - original licence link has changed is not relivant.
18729 * <script type="text/javascript">
18734 * @class Roo.data.SortTypes
18736 * Defines the default sorting (casting?) comparison functions used when sorting data.
18738 Roo.data.SortTypes = {
18740 * Default sort that does nothing
18741 * @param {Mixed} s The value being converted
18742 * @return {Mixed} The comparison value
18744 none : function(s){
18749 * The regular expression used to strip tags
18753 stripTagsRE : /<\/?[^>]+>/gi,
18756 * Strips all HTML tags to sort on text only
18757 * @param {Mixed} s The value being converted
18758 * @return {String} The comparison value
18760 asText : function(s){
18761 return String(s).replace(this.stripTagsRE, "");
18765 * Strips all HTML tags to sort on text only - Case insensitive
18766 * @param {Mixed} s The value being converted
18767 * @return {String} The comparison value
18769 asUCText : function(s){
18770 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18774 * Case insensitive string
18775 * @param {Mixed} s The value being converted
18776 * @return {String} The comparison value
18778 asUCString : function(s) {
18779 return String(s).toUpperCase();
18784 * @param {Mixed} s The value being converted
18785 * @return {Number} The comparison value
18787 asDate : function(s) {
18791 if(s instanceof Date){
18792 return s.getTime();
18794 return Date.parse(String(s));
18799 * @param {Mixed} s The value being converted
18800 * @return {Float} The comparison value
18802 asFloat : function(s) {
18803 var val = parseFloat(String(s).replace(/,/g, ""));
18804 if(isNaN(val)) val = 0;
18810 * @param {Mixed} s The value being converted
18811 * @return {Number} The comparison value
18813 asInt : function(s) {
18814 var val = parseInt(String(s).replace(/,/g, ""));
18815 if(isNaN(val)) val = 0;
18820 * Ext JS Library 1.1.1
18821 * Copyright(c) 2006-2007, Ext JS, LLC.
18823 * Originally Released Under LGPL - original licence link has changed is not relivant.
18826 * <script type="text/javascript">
18830 * @class Roo.data.Record
18831 * Instances of this class encapsulate both record <em>definition</em> information, and record
18832 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18833 * to access Records cached in an {@link Roo.data.Store} object.<br>
18835 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18836 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18839 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18841 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18842 * {@link #create}. The parameters are the same.
18843 * @param {Array} data An associative Array of data values keyed by the field name.
18844 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18845 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18846 * not specified an integer id is generated.
18848 Roo.data.Record = function(data, id){
18849 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18854 * Generate a constructor for a specific record layout.
18855 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18856 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18857 * Each field definition object may contain the following properties: <ul>
18858 * <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,
18859 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18860 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18861 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18862 * is being used, then this is a string containing the javascript expression to reference the data relative to
18863 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18864 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18865 * this may be omitted.</p></li>
18866 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18867 * <ul><li>auto (Default, implies no conversion)</li>
18872 * <li>date</li></ul></p></li>
18873 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18874 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18875 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18876 * by the Reader into an object that will be stored in the Record. It is passed the
18877 * following parameters:<ul>
18878 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18880 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18882 * <br>usage:<br><pre><code>
18883 var TopicRecord = Roo.data.Record.create(
18884 {name: 'title', mapping: 'topic_title'},
18885 {name: 'author', mapping: 'username'},
18886 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18887 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18888 {name: 'lastPoster', mapping: 'user2'},
18889 {name: 'excerpt', mapping: 'post_text'}
18892 var myNewRecord = new TopicRecord({
18893 title: 'Do my job please',
18896 lastPost: new Date(),
18897 lastPoster: 'Animal',
18898 excerpt: 'No way dude!'
18900 myStore.add(myNewRecord);
18905 Roo.data.Record.create = function(o){
18906 var f = function(){
18907 f.superclass.constructor.apply(this, arguments);
18909 Roo.extend(f, Roo.data.Record);
18910 var p = f.prototype;
18911 p.fields = new Roo.util.MixedCollection(false, function(field){
18914 for(var i = 0, len = o.length; i < len; i++){
18915 p.fields.add(new Roo.data.Field(o[i]));
18917 f.getField = function(name){
18918 return p.fields.get(name);
18923 Roo.data.Record.AUTO_ID = 1000;
18924 Roo.data.Record.EDIT = 'edit';
18925 Roo.data.Record.REJECT = 'reject';
18926 Roo.data.Record.COMMIT = 'commit';
18928 Roo.data.Record.prototype = {
18930 * Readonly flag - true if this record has been modified.
18939 join : function(store){
18940 this.store = store;
18944 * Set the named field to the specified value.
18945 * @param {String} name The name of the field to set.
18946 * @param {Object} value The value to set the field to.
18948 set : function(name, value){
18949 if(this.data[name] == value){
18953 if(!this.modified){
18954 this.modified = {};
18956 if(typeof this.modified[name] == 'undefined'){
18957 this.modified[name] = this.data[name];
18959 this.data[name] = value;
18961 this.store.afterEdit(this);
18966 * Get the value of the named field.
18967 * @param {String} name The name of the field to get the value of.
18968 * @return {Object} The value of the field.
18970 get : function(name){
18971 return this.data[name];
18975 beginEdit : function(){
18976 this.editing = true;
18977 this.modified = {};
18981 cancelEdit : function(){
18982 this.editing = false;
18983 delete this.modified;
18987 endEdit : function(){
18988 this.editing = false;
18989 if(this.dirty && this.store){
18990 this.store.afterEdit(this);
18995 * Usually called by the {@link Roo.data.Store} which owns the Record.
18996 * Rejects all changes made to the Record since either creation, or the last commit operation.
18997 * Modified fields are reverted to their original values.
18999 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19000 * of reject operations.
19002 reject : function(){
19003 var m = this.modified;
19005 if(typeof m[n] != "function"){
19006 this.data[n] = m[n];
19009 this.dirty = false;
19010 delete this.modified;
19011 this.editing = false;
19013 this.store.afterReject(this);
19018 * Usually called by the {@link Roo.data.Store} which owns the Record.
19019 * Commits all changes made to the Record since either creation, or the last commit operation.
19021 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19022 * of commit operations.
19024 commit : function(){
19025 this.dirty = false;
19026 delete this.modified;
19027 this.editing = false;
19029 this.store.afterCommit(this);
19034 hasError : function(){
19035 return this.error != null;
19039 clearError : function(){
19044 * Creates a copy of this record.
19045 * @param {String} id (optional) A new record id if you don't want to use this record's id
19048 copy : function(newId) {
19049 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19053 * Ext JS Library 1.1.1
19054 * Copyright(c) 2006-2007, Ext JS, LLC.
19056 * Originally Released Under LGPL - original licence link has changed is not relivant.
19059 * <script type="text/javascript">
19065 * @class Roo.data.Store
19066 * @extends Roo.util.Observable
19067 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19068 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19070 * 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
19071 * has no knowledge of the format of the data returned by the Proxy.<br>
19073 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19074 * instances from the data object. These records are cached and made available through accessor functions.
19076 * Creates a new Store.
19077 * @param {Object} config A config object containing the objects needed for the Store to access data,
19078 * and read the data into Records.
19080 Roo.data.Store = function(config){
19081 this.data = new Roo.util.MixedCollection(false);
19082 this.data.getKey = function(o){
19085 this.baseParams = {};
19087 this.paramNames = {
19094 if(config && config.data){
19095 this.inlineData = config.data;
19096 delete config.data;
19099 Roo.apply(this, config);
19101 if(this.reader){ // reader passed
19102 this.reader = Roo.factory(this.reader, Roo.data);
19103 this.reader.xmodule = this.xmodule || false;
19104 if(!this.recordType){
19105 this.recordType = this.reader.recordType;
19107 if(this.reader.onMetaChange){
19108 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19112 if(this.recordType){
19113 this.fields = this.recordType.prototype.fields;
19115 this.modified = [];
19119 * @event datachanged
19120 * Fires when the data cache has changed, and a widget which is using this Store
19121 * as a Record cache should refresh its view.
19122 * @param {Store} this
19124 datachanged : true,
19126 * @event metachange
19127 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19128 * @param {Store} this
19129 * @param {Object} meta The JSON metadata
19134 * Fires when Records have been added to the Store
19135 * @param {Store} this
19136 * @param {Roo.data.Record[]} records The array of Records added
19137 * @param {Number} index The index at which the record(s) were added
19142 * Fires when a Record has been removed from the Store
19143 * @param {Store} this
19144 * @param {Roo.data.Record} record The Record that was removed
19145 * @param {Number} index The index at which the record was removed
19150 * Fires when a Record has been updated
19151 * @param {Store} this
19152 * @param {Roo.data.Record} record The Record that was updated
19153 * @param {String} operation The update operation being performed. Value may be one of:
19155 Roo.data.Record.EDIT
19156 Roo.data.Record.REJECT
19157 Roo.data.Record.COMMIT
19163 * Fires when the data cache has been cleared.
19164 * @param {Store} this
19168 * @event beforeload
19169 * Fires before a request is made for a new data object. If the beforeload handler returns false
19170 * the load action will be canceled.
19171 * @param {Store} this
19172 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19177 * Fires after a new set of Records has been loaded.
19178 * @param {Store} this
19179 * @param {Roo.data.Record[]} records The Records that were loaded
19180 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19184 * @event loadexception
19185 * Fires if an exception occurs in the Proxy during loading.
19186 * Called with the signature of the Proxy's "loadexception" event.
19187 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19190 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19191 * @param {Object} load options
19192 * @param {Object} jsonData from your request (normally this contains the Exception)
19194 loadexception : true
19198 this.proxy = Roo.factory(this.proxy, Roo.data);
19199 this.proxy.xmodule = this.xmodule || false;
19200 this.relayEvents(this.proxy, ["loadexception"]);
19202 this.sortToggle = {};
19204 Roo.data.Store.superclass.constructor.call(this);
19206 if(this.inlineData){
19207 this.loadData(this.inlineData);
19208 delete this.inlineData;
19211 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19213 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19214 * without a remote query - used by combo/forms at present.
19218 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19221 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19224 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19225 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19228 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19229 * on any HTTP request
19232 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19235 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19236 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19238 remoteSort : false,
19241 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19242 * loaded or when a record is removed. (defaults to false).
19244 pruneModifiedRecords : false,
19247 lastOptions : null,
19250 * Add Records to the Store and fires the add event.
19251 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19253 add : function(records){
19254 records = [].concat(records);
19255 for(var i = 0, len = records.length; i < len; i++){
19256 records[i].join(this);
19258 var index = this.data.length;
19259 this.data.addAll(records);
19260 this.fireEvent("add", this, records, index);
19264 * Remove a Record from the Store and fires the remove event.
19265 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19267 remove : function(record){
19268 var index = this.data.indexOf(record);
19269 this.data.removeAt(index);
19270 if(this.pruneModifiedRecords){
19271 this.modified.remove(record);
19273 this.fireEvent("remove", this, record, index);
19277 * Remove all Records from the Store and fires the clear event.
19279 removeAll : function(){
19281 if(this.pruneModifiedRecords){
19282 this.modified = [];
19284 this.fireEvent("clear", this);
19288 * Inserts Records to the Store at the given index and fires the add event.
19289 * @param {Number} index The start index at which to insert the passed Records.
19290 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19292 insert : function(index, records){
19293 records = [].concat(records);
19294 for(var i = 0, len = records.length; i < len; i++){
19295 this.data.insert(index, records[i]);
19296 records[i].join(this);
19298 this.fireEvent("add", this, records, index);
19302 * Get the index within the cache of the passed Record.
19303 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19304 * @return {Number} The index of the passed Record. Returns -1 if not found.
19306 indexOf : function(record){
19307 return this.data.indexOf(record);
19311 * Get the index within the cache of the Record with the passed id.
19312 * @param {String} id The id of the Record to find.
19313 * @return {Number} The index of the Record. Returns -1 if not found.
19315 indexOfId : function(id){
19316 return this.data.indexOfKey(id);
19320 * Get the Record with the specified id.
19321 * @param {String} id The id of the Record to find.
19322 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19324 getById : function(id){
19325 return this.data.key(id);
19329 * Get the Record at the specified index.
19330 * @param {Number} index The index of the Record to find.
19331 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19333 getAt : function(index){
19334 return this.data.itemAt(index);
19338 * Returns a range of Records between specified indices.
19339 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19340 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19341 * @return {Roo.data.Record[]} An array of Records
19343 getRange : function(start, end){
19344 return this.data.getRange(start, end);
19348 storeOptions : function(o){
19349 o = Roo.apply({}, o);
19352 this.lastOptions = o;
19356 * Loads the Record cache from the configured Proxy using the configured Reader.
19358 * If using remote paging, then the first load call must specify the <em>start</em>
19359 * and <em>limit</em> properties in the options.params property to establish the initial
19360 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19362 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19363 * and this call will return before the new data has been loaded. Perform any post-processing
19364 * in a callback function, or in a "load" event handler.</strong>
19366 * @param {Object} options An object containing properties which control loading options:<ul>
19367 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19368 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19369 * passed the following arguments:<ul>
19370 * <li>r : Roo.data.Record[]</li>
19371 * <li>options: Options object from the load call</li>
19372 * <li>success: Boolean success indicator</li></ul></li>
19373 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19374 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19377 load : function(options){
19378 options = options || {};
19379 if(this.fireEvent("beforeload", this, options) !== false){
19380 this.storeOptions(options);
19381 var p = Roo.apply(options.params || {}, this.baseParams);
19382 // if meta was not loaded from remote source.. try requesting it.
19383 if (!this.reader.metaFromRemote) {
19384 p._requestMeta = 1;
19386 if(this.sortInfo && this.remoteSort){
19387 var pn = this.paramNames;
19388 p[pn["sort"]] = this.sortInfo.field;
19389 p[pn["dir"]] = this.sortInfo.direction;
19391 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19396 * Reloads the Record cache from the configured Proxy using the configured Reader and
19397 * the options from the last load operation performed.
19398 * @param {Object} options (optional) An object containing properties which may override the options
19399 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19400 * the most recently used options are reused).
19402 reload : function(options){
19403 this.load(Roo.applyIf(options||{}, this.lastOptions));
19407 // Called as a callback by the Reader during a load operation.
19408 loadRecords : function(o, options, success){
19409 if(!o || success === false){
19410 if(success !== false){
19411 this.fireEvent("load", this, [], options);
19413 if(options.callback){
19414 options.callback.call(options.scope || this, [], options, false);
19418 // if data returned failure - throw an exception.
19419 if (o.success === false) {
19420 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19423 var r = o.records, t = o.totalRecords || r.length;
19424 if(!options || options.add !== true){
19425 if(this.pruneModifiedRecords){
19426 this.modified = [];
19428 for(var i = 0, len = r.length; i < len; i++){
19432 this.data = this.snapshot;
19433 delete this.snapshot;
19436 this.data.addAll(r);
19437 this.totalLength = t;
19439 this.fireEvent("datachanged", this);
19441 this.totalLength = Math.max(t, this.data.length+r.length);
19444 this.fireEvent("load", this, r, options);
19445 if(options.callback){
19446 options.callback.call(options.scope || this, r, options, true);
19451 * Loads data from a passed data block. A Reader which understands the format of the data
19452 * must have been configured in the constructor.
19453 * @param {Object} data The data block from which to read the Records. The format of the data expected
19454 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19455 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19457 loadData : function(o, append){
19458 var r = this.reader.readRecords(o);
19459 this.loadRecords(r, {add: append}, true);
19463 * Gets the number of cached records.
19465 * <em>If using paging, this may not be the total size of the dataset. If the data object
19466 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19467 * the data set size</em>
19469 getCount : function(){
19470 return this.data.length || 0;
19474 * Gets the total number of records in the dataset as returned by the server.
19476 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19477 * the dataset size</em>
19479 getTotalCount : function(){
19480 return this.totalLength || 0;
19484 * Returns the sort state of the Store as an object with two properties:
19486 field {String} The name of the field by which the Records are sorted
19487 direction {String} The sort order, "ASC" or "DESC"
19490 getSortState : function(){
19491 return this.sortInfo;
19495 applySort : function(){
19496 if(this.sortInfo && !this.remoteSort){
19497 var s = this.sortInfo, f = s.field;
19498 var st = this.fields.get(f).sortType;
19499 var fn = function(r1, r2){
19500 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19501 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19503 this.data.sort(s.direction, fn);
19504 if(this.snapshot && this.snapshot != this.data){
19505 this.snapshot.sort(s.direction, fn);
19511 * Sets the default sort column and order to be used by the next load operation.
19512 * @param {String} fieldName The name of the field to sort by.
19513 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19515 setDefaultSort : function(field, dir){
19516 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19520 * Sort the Records.
19521 * If remote sorting is used, the sort is performed on the server, and the cache is
19522 * reloaded. If local sorting is used, the cache is sorted internally.
19523 * @param {String} fieldName The name of the field to sort by.
19524 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19526 sort : function(fieldName, dir){
19527 var f = this.fields.get(fieldName);
19529 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19530 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19535 this.sortToggle[f.name] = dir;
19536 this.sortInfo = {field: f.name, direction: dir};
19537 if(!this.remoteSort){
19539 this.fireEvent("datachanged", this);
19541 this.load(this.lastOptions);
19546 * Calls the specified function for each of the Records in the cache.
19547 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19548 * Returning <em>false</em> aborts and exits the iteration.
19549 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19551 each : function(fn, scope){
19552 this.data.each(fn, scope);
19556 * Gets all records modified since the last commit. Modified records are persisted across load operations
19557 * (e.g., during paging).
19558 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19560 getModifiedRecords : function(){
19561 return this.modified;
19565 createFilterFn : function(property, value, anyMatch){
19566 if(!value.exec){ // not a regex
19567 value = String(value);
19568 if(value.length == 0){
19571 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19573 return function(r){
19574 return value.test(r.data[property]);
19579 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19580 * @param {String} property A field on your records
19581 * @param {Number} start The record index to start at (defaults to 0)
19582 * @param {Number} end The last record index to include (defaults to length - 1)
19583 * @return {Number} The sum
19585 sum : function(property, start, end){
19586 var rs = this.data.items, v = 0;
19587 start = start || 0;
19588 end = (end || end === 0) ? end : rs.length-1;
19590 for(var i = start; i <= end; i++){
19591 v += (rs[i].data[property] || 0);
19597 * Filter the records by a specified property.
19598 * @param {String} field A field on your records
19599 * @param {String/RegExp} value Either a string that the field
19600 * should start with or a RegExp to test against the field
19601 * @param {Boolean} anyMatch True to match any part not just the beginning
19603 filter : function(property, value, anyMatch){
19604 var fn = this.createFilterFn(property, value, anyMatch);
19605 return fn ? this.filterBy(fn) : this.clearFilter();
19609 * Filter by a function. The specified function will be called with each
19610 * record in this data source. If the function returns true the record is included,
19611 * otherwise it is filtered.
19612 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19613 * @param {Object} scope (optional) The scope of the function (defaults to this)
19615 filterBy : function(fn, scope){
19616 this.snapshot = this.snapshot || this.data;
19617 this.data = this.queryBy(fn, scope||this);
19618 this.fireEvent("datachanged", this);
19622 * Query the records by a specified property.
19623 * @param {String} field A field on your records
19624 * @param {String/RegExp} value Either a string that the field
19625 * should start with or a RegExp to test against the field
19626 * @param {Boolean} anyMatch True to match any part not just the beginning
19627 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19629 query : function(property, value, anyMatch){
19630 var fn = this.createFilterFn(property, value, anyMatch);
19631 return fn ? this.queryBy(fn) : this.data.clone();
19635 * Query by a function. The specified function will be called with each
19636 * record in this data source. If the function returns true the record is included
19638 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19639 * @param {Object} scope (optional) The scope of the function (defaults to this)
19640 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19642 queryBy : function(fn, scope){
19643 var data = this.snapshot || this.data;
19644 return data.filterBy(fn, scope||this);
19648 * Collects unique values for a particular dataIndex from this store.
19649 * @param {String} dataIndex The property to collect
19650 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19651 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19652 * @return {Array} An array of the unique values
19654 collect : function(dataIndex, allowNull, bypassFilter){
19655 var d = (bypassFilter === true && this.snapshot) ?
19656 this.snapshot.items : this.data.items;
19657 var v, sv, r = [], l = {};
19658 for(var i = 0, len = d.length; i < len; i++){
19659 v = d[i].data[dataIndex];
19661 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19670 * Revert to a view of the Record cache with no filtering applied.
19671 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19673 clearFilter : function(suppressEvent){
19674 if(this.snapshot && this.snapshot != this.data){
19675 this.data = this.snapshot;
19676 delete this.snapshot;
19677 if(suppressEvent !== true){
19678 this.fireEvent("datachanged", this);
19684 afterEdit : function(record){
19685 if(this.modified.indexOf(record) == -1){
19686 this.modified.push(record);
19688 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19692 afterReject : function(record){
19693 this.modified.remove(record);
19694 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19698 afterCommit : function(record){
19699 this.modified.remove(record);
19700 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19704 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19705 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19707 commitChanges : function(){
19708 var m = this.modified.slice(0);
19709 this.modified = [];
19710 for(var i = 0, len = m.length; i < len; i++){
19716 * Cancel outstanding changes on all changed records.
19718 rejectChanges : function(){
19719 var m = this.modified.slice(0);
19720 this.modified = [];
19721 for(var i = 0, len = m.length; i < len; i++){
19726 onMetaChange : function(meta, rtype, o){
19727 this.recordType = rtype;
19728 this.fields = rtype.prototype.fields;
19729 delete this.snapshot;
19730 this.sortInfo = meta.sortInfo || this.sortInfo;
19731 this.modified = [];
19732 this.fireEvent('metachange', this, this.reader.meta);
19736 * Ext JS Library 1.1.1
19737 * Copyright(c) 2006-2007, Ext JS, LLC.
19739 * Originally Released Under LGPL - original licence link has changed is not relivant.
19742 * <script type="text/javascript">
19746 * @class Roo.data.SimpleStore
19747 * @extends Roo.data.Store
19748 * Small helper class to make creating Stores from Array data easier.
19749 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19750 * @cfg {Array} fields An array of field definition objects, or field name strings.
19751 * @cfg {Array} data The multi-dimensional array of data
19753 * @param {Object} config
19755 Roo.data.SimpleStore = function(config){
19756 Roo.data.SimpleStore.superclass.constructor.call(this, {
19758 reader: new Roo.data.ArrayReader({
19761 Roo.data.Record.create(config.fields)
19763 proxy : new Roo.data.MemoryProxy(config.data)
19767 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19769 * Ext JS Library 1.1.1
19770 * Copyright(c) 2006-2007, Ext JS, LLC.
19772 * Originally Released Under LGPL - original licence link has changed is not relivant.
19775 * <script type="text/javascript">
19780 * @extends Roo.data.Store
19781 * @class Roo.data.JsonStore
19782 * Small helper class to make creating Stores for JSON data easier. <br/>
19784 var store = new Roo.data.JsonStore({
19785 url: 'get-images.php',
19787 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19790 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19791 * JsonReader and HttpProxy (unless inline data is provided).</b>
19792 * @cfg {Array} fields An array of field definition objects, or field name strings.
19794 * @param {Object} config
19796 Roo.data.JsonStore = function(c){
19797 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19798 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19799 reader: new Roo.data.JsonReader(c, c.fields)
19802 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19804 * Ext JS Library 1.1.1
19805 * Copyright(c) 2006-2007, Ext JS, LLC.
19807 * Originally Released Under LGPL - original licence link has changed is not relivant.
19810 * <script type="text/javascript">
19814 Roo.data.Field = function(config){
19815 if(typeof config == "string"){
19816 config = {name: config};
19818 Roo.apply(this, config);
19821 this.type = "auto";
19824 var st = Roo.data.SortTypes;
19825 // named sortTypes are supported, here we look them up
19826 if(typeof this.sortType == "string"){
19827 this.sortType = st[this.sortType];
19830 // set default sortType for strings and dates
19831 if(!this.sortType){
19834 this.sortType = st.asUCString;
19837 this.sortType = st.asDate;
19840 this.sortType = st.none;
19845 var stripRe = /[\$,%]/g;
19847 // prebuilt conversion function for this field, instead of
19848 // switching every time we're reading a value
19850 var cv, dateFormat = this.dateFormat;
19855 cv = function(v){ return v; };
19858 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19862 return v !== undefined && v !== null && v !== '' ?
19863 parseInt(String(v).replace(stripRe, ""), 10) : '';
19868 return v !== undefined && v !== null && v !== '' ?
19869 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19874 cv = function(v){ return v === true || v === "true" || v == 1; };
19881 if(v instanceof Date){
19885 if(dateFormat == "timestamp"){
19886 return new Date(v*1000);
19888 return Date.parseDate(v, dateFormat);
19890 var parsed = Date.parse(v);
19891 return parsed ? new Date(parsed) : null;
19900 Roo.data.Field.prototype = {
19908 * Ext JS Library 1.1.1
19909 * Copyright(c) 2006-2007, Ext JS, LLC.
19911 * Originally Released Under LGPL - original licence link has changed is not relivant.
19914 * <script type="text/javascript">
19917 // Base class for reading structured data from a data source. This class is intended to be
19918 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19921 * @class Roo.data.DataReader
19922 * Base class for reading structured data from a data source. This class is intended to be
19923 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
19926 Roo.data.DataReader = function(meta, recordType){
19930 this.recordType = recordType instanceof Array ?
19931 Roo.data.Record.create(recordType) : recordType;
19934 Roo.data.DataReader.prototype = {
19936 * Create an empty record
19937 * @param {Object} data (optional) - overlay some values
19938 * @return {Roo.data.Record} record created.
19940 newRow : function(d) {
19942 this.recordType.prototype.fields.each(function(c) {
19944 case 'int' : da[c.name] = 0; break;
19945 case 'date' : da[c.name] = new Date(); break;
19946 case 'float' : da[c.name] = 0.0; break;
19947 case 'boolean' : da[c.name] = false; break;
19948 default : da[c.name] = ""; break;
19952 return new this.recordType(Roo.apply(da, d));
19957 * Ext JS Library 1.1.1
19958 * Copyright(c) 2006-2007, Ext JS, LLC.
19960 * Originally Released Under LGPL - original licence link has changed is not relivant.
19963 * <script type="text/javascript">
19967 * @class Roo.data.DataProxy
19968 * @extends Roo.data.Observable
19969 * This class is an abstract base class for implementations which provide retrieval of
19970 * unformatted data objects.<br>
19972 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
19973 * (of the appropriate type which knows how to parse the data object) to provide a block of
19974 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
19976 * Custom implementations must implement the load method as described in
19977 * {@link Roo.data.HttpProxy#load}.
19979 Roo.data.DataProxy = function(){
19982 * @event beforeload
19983 * Fires before a network request is made to retrieve a data object.
19984 * @param {Object} This DataProxy object.
19985 * @param {Object} params The params parameter to the load function.
19990 * Fires before the load method's callback is called.
19991 * @param {Object} This DataProxy object.
19992 * @param {Object} o The data object.
19993 * @param {Object} arg The callback argument object passed to the load function.
19997 * @event loadexception
19998 * Fires if an Exception occurs during data retrieval.
19999 * @param {Object} This DataProxy object.
20000 * @param {Object} o The data object.
20001 * @param {Object} arg The callback argument object passed to the load function.
20002 * @param {Object} e The Exception.
20004 loadexception : true
20006 Roo.data.DataProxy.superclass.constructor.call(this);
20009 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20012 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20016 * Ext JS Library 1.1.1
20017 * Copyright(c) 2006-2007, Ext JS, LLC.
20019 * Originally Released Under LGPL - original licence link has changed is not relivant.
20022 * <script type="text/javascript">
20025 * @class Roo.data.MemoryProxy
20026 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20027 * to the Reader when its load method is called.
20029 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20031 Roo.data.MemoryProxy = function(data){
20035 Roo.data.MemoryProxy.superclass.constructor.call(this);
20039 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20041 * Load data from the requested source (in this case an in-memory
20042 * data object passed to the constructor), read the data object into
20043 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20044 * process that block using the passed callback.
20045 * @param {Object} params This parameter is not used by the MemoryProxy class.
20046 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20047 * object into a block of Roo.data.Records.
20048 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20049 * The function must be passed <ul>
20050 * <li>The Record block object</li>
20051 * <li>The "arg" argument from the load function</li>
20052 * <li>A boolean success indicator</li>
20054 * @param {Object} scope The scope in which to call the callback
20055 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20057 load : function(params, reader, callback, scope, arg){
20058 params = params || {};
20061 result = reader.readRecords(this.data);
20063 this.fireEvent("loadexception", this, arg, null, e);
20064 callback.call(scope, null, arg, false);
20067 callback.call(scope, result, arg, true);
20071 update : function(params, records){
20076 * Ext JS Library 1.1.1
20077 * Copyright(c) 2006-2007, Ext JS, LLC.
20079 * Originally Released Under LGPL - original licence link has changed is not relivant.
20082 * <script type="text/javascript">
20085 * @class Roo.data.HttpProxy
20086 * @extends Roo.data.DataProxy
20087 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20088 * configured to reference a certain URL.<br><br>
20090 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20091 * from which the running page was served.<br><br>
20093 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20095 * Be aware that to enable the browser to parse an XML document, the server must set
20096 * the Content-Type header in the HTTP response to "text/xml".
20098 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20099 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20100 * will be used to make the request.
20102 Roo.data.HttpProxy = function(conn){
20103 Roo.data.HttpProxy.superclass.constructor.call(this);
20104 // is conn a conn config or a real conn?
20106 this.useAjax = !conn || !conn.events;
20110 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20111 // thse are take from connection...
20114 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20117 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20118 * extra parameters to each request made by this object. (defaults to undefined)
20121 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20122 * to each request made by this object. (defaults to undefined)
20125 * @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)
20128 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20131 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20137 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20141 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20142 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20143 * a finer-grained basis than the DataProxy events.
20145 getConnection : function(){
20146 return this.useAjax ? Roo.Ajax : this.conn;
20150 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20151 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20152 * process that block using the passed callback.
20153 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20154 * for the request to the remote server.
20155 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20156 * object into a block of Roo.data.Records.
20157 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20158 * The function must be passed <ul>
20159 * <li>The Record block object</li>
20160 * <li>The "arg" argument from the load function</li>
20161 * <li>A boolean success indicator</li>
20163 * @param {Object} scope The scope in which to call the callback
20164 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20166 load : function(params, reader, callback, scope, arg){
20167 if(this.fireEvent("beforeload", this, params) !== false){
20169 params : params || {},
20171 callback : callback,
20176 callback : this.loadResponse,
20180 Roo.applyIf(o, this.conn);
20181 if(this.activeRequest){
20182 Roo.Ajax.abort(this.activeRequest);
20184 this.activeRequest = Roo.Ajax.request(o);
20186 this.conn.request(o);
20189 callback.call(scope||this, null, arg, false);
20194 loadResponse : function(o, success, response){
20195 delete this.activeRequest;
20197 this.fireEvent("loadexception", this, o, response);
20198 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20203 result = o.reader.read(response);
20205 this.fireEvent("loadexception", this, o, response, e);
20206 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20210 this.fireEvent("load", this, o, o.request.arg);
20211 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20215 update : function(dataSet){
20220 updateResponse : function(dataSet){
20225 * Ext JS Library 1.1.1
20226 * Copyright(c) 2006-2007, Ext JS, LLC.
20228 * Originally Released Under LGPL - original licence link has changed is not relivant.
20231 * <script type="text/javascript">
20235 * @class Roo.data.ScriptTagProxy
20236 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20237 * other than the originating domain of the running page.<br><br>
20239 * <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
20240 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20242 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20243 * source code that is used as the source inside a <script> tag.<br><br>
20245 * In order for the browser to process the returned data, the server must wrap the data object
20246 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20247 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20248 * depending on whether the callback name was passed:
20251 boolean scriptTag = false;
20252 String cb = request.getParameter("callback");
20255 response.setContentType("text/javascript");
20257 response.setContentType("application/x-json");
20259 Writer out = response.getWriter();
20261 out.write(cb + "(");
20263 out.print(dataBlock.toJsonString());
20270 * @param {Object} config A configuration object.
20272 Roo.data.ScriptTagProxy = function(config){
20273 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20274 Roo.apply(this, config);
20275 this.head = document.getElementsByTagName("head")[0];
20278 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20280 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20282 * @cfg {String} url The URL from which to request the data object.
20285 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20289 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20290 * the server the name of the callback function set up by the load call to process the returned data object.
20291 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20292 * javascript output which calls this named function passing the data object as its only parameter.
20294 callbackParam : "callback",
20296 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20297 * name to the request.
20302 * Load data from the configured URL, read the data object into
20303 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20304 * process that block using the passed callback.
20305 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20306 * for the request to the remote server.
20307 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20308 * object into a block of Roo.data.Records.
20309 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20310 * The function must be passed <ul>
20311 * <li>The Record block object</li>
20312 * <li>The "arg" argument from the load function</li>
20313 * <li>A boolean success indicator</li>
20315 * @param {Object} scope The scope in which to call the callback
20316 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20318 load : function(params, reader, callback, scope, arg){
20319 if(this.fireEvent("beforeload", this, params) !== false){
20321 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20323 var url = this.url;
20324 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20326 url += "&_dc=" + (new Date().getTime());
20328 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20331 cb : "stcCallback"+transId,
20332 scriptId : "stcScript"+transId,
20336 callback : callback,
20342 window[trans.cb] = function(o){
20343 conn.handleResponse(o, trans);
20346 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20348 if(this.autoAbort !== false){
20352 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20354 var script = document.createElement("script");
20355 script.setAttribute("src", url);
20356 script.setAttribute("type", "text/javascript");
20357 script.setAttribute("id", trans.scriptId);
20358 this.head.appendChild(script);
20360 this.trans = trans;
20362 callback.call(scope||this, null, arg, false);
20367 isLoading : function(){
20368 return this.trans ? true : false;
20372 * Abort the current server request.
20374 abort : function(){
20375 if(this.isLoading()){
20376 this.destroyTrans(this.trans);
20381 destroyTrans : function(trans, isLoaded){
20382 this.head.removeChild(document.getElementById(trans.scriptId));
20383 clearTimeout(trans.timeoutId);
20385 window[trans.cb] = undefined;
20387 delete window[trans.cb];
20390 // if hasn't been loaded, wait for load to remove it to prevent script error
20391 window[trans.cb] = function(){
20392 window[trans.cb] = undefined;
20394 delete window[trans.cb];
20401 handleResponse : function(o, trans){
20402 this.trans = false;
20403 this.destroyTrans(trans, true);
20406 result = trans.reader.readRecords(o);
20408 this.fireEvent("loadexception", this, o, trans.arg, e);
20409 trans.callback.call(trans.scope||window, null, trans.arg, false);
20412 this.fireEvent("load", this, o, trans.arg);
20413 trans.callback.call(trans.scope||window, result, trans.arg, true);
20417 handleFailure : function(trans){
20418 this.trans = false;
20419 this.destroyTrans(trans, false);
20420 this.fireEvent("loadexception", this, null, trans.arg);
20421 trans.callback.call(trans.scope||window, null, trans.arg, false);
20425 * Ext JS Library 1.1.1
20426 * Copyright(c) 2006-2007, Ext JS, LLC.
20428 * Originally Released Under LGPL - original licence link has changed is not relivant.
20431 * <script type="text/javascript">
20435 * @class Roo.data.JsonReader
20436 * @extends Roo.data.DataReader
20437 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20438 * based on mappings in a provided Roo.data.Record constructor.
20440 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20441 * in the reply previously.
20446 var RecordDef = Roo.data.Record.create([
20447 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20448 {name: 'occupation'} // This field will use "occupation" as the mapping.
20450 var myReader = new Roo.data.JsonReader({
20451 totalProperty: "results", // The property which contains the total dataset size (optional)
20452 root: "rows", // The property which contains an Array of row objects
20453 id: "id" // The property within each row object that provides an ID for the record (optional)
20457 * This would consume a JSON file like this:
20459 { 'results': 2, 'rows': [
20460 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20461 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20464 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20465 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20466 * paged from the remote server.
20467 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20468 * @cfg {String} root name of the property which contains the Array of row objects.
20469 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20471 * Create a new JsonReader
20472 * @param {Object} meta Metadata configuration options
20473 * @param {Object} recordType Either an Array of field definition objects,
20474 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20476 Roo.data.JsonReader = function(meta, recordType){
20479 // set some defaults:
20480 Roo.applyIf(meta, {
20481 totalProperty: 'total',
20482 successProperty : 'success',
20487 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20489 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20492 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20493 * Used by Store query builder to append _requestMeta to params.
20496 metaFromRemote : false,
20498 * This method is only used by a DataProxy which has retrieved data from a remote server.
20499 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20500 * @return {Object} data A data block which is used by an Roo.data.Store object as
20501 * a cache of Roo.data.Records.
20503 read : function(response){
20504 var json = response.responseText;
20506 var o = /* eval:var:o */ eval("("+json+")");
20508 throw {message: "JsonReader.read: Json object not found"};
20514 this.metaFromRemote = true;
20515 this.meta = o.metaData;
20516 this.recordType = Roo.data.Record.create(o.metaData.fields);
20517 this.onMetaChange(this.meta, this.recordType, o);
20519 return this.readRecords(o);
20522 // private function a store will implement
20523 onMetaChange : function(meta, recordType, o){
20530 simpleAccess: function(obj, subsc) {
20537 getJsonAccessor: function(){
20539 return function(expr) {
20541 return(re.test(expr))
20542 ? new Function("obj", "return obj." + expr)
20547 return Roo.emptyFn;
20552 * Create a data block containing Roo.data.Records from an XML document.
20553 * @param {Object} o An object which contains an Array of row objects in the property specified
20554 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20555 * which contains the total size of the dataset.
20556 * @return {Object} data A data block which is used by an Roo.data.Store object as
20557 * a cache of Roo.data.Records.
20559 readRecords : function(o){
20561 * After any data loads, the raw JSON data is available for further custom processing.
20565 var s = this.meta, Record = this.recordType,
20566 f = Record.prototype.fields, fi = f.items, fl = f.length;
20568 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20570 if(s.totalProperty) {
20571 this.getTotal = this.getJsonAccessor(s.totalProperty);
20573 if(s.successProperty) {
20574 this.getSuccess = this.getJsonAccessor(s.successProperty);
20576 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20578 var g = this.getJsonAccessor(s.id);
20579 this.getId = function(rec) {
20581 return (r === undefined || r === "") ? null : r;
20584 this.getId = function(){return null;};
20587 for(var jj = 0; jj < fl; jj++){
20589 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20590 this.ef[jj] = this.getJsonAccessor(map);
20594 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20595 if(s.totalProperty){
20596 var vt = parseInt(this.getTotal(o), 10);
20601 if(s.successProperty){
20602 var vs = this.getSuccess(o);
20603 if(vs === false || vs === 'false'){
20608 for(var i = 0; i < c; i++){
20611 var id = this.getId(n);
20612 for(var j = 0; j < fl; j++){
20614 var v = this.ef[j](n);
20616 Roo.log('missing convert for ' + f.name);
20620 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20622 var record = new Record(values, id);
20624 records[i] = record;
20629 totalRecords : totalRecords
20634 * Ext JS Library 1.1.1
20635 * Copyright(c) 2006-2007, Ext JS, LLC.
20637 * Originally Released Under LGPL - original licence link has changed is not relivant.
20640 * <script type="text/javascript">
20644 * @class Roo.data.XmlReader
20645 * @extends Roo.data.DataReader
20646 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20647 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20649 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20650 * header in the HTTP response must be set to "text/xml".</em>
20654 var RecordDef = Roo.data.Record.create([
20655 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20656 {name: 'occupation'} // This field will use "occupation" as the mapping.
20658 var myReader = new Roo.data.XmlReader({
20659 totalRecords: "results", // The element which contains the total dataset size (optional)
20660 record: "row", // The repeated element which contains row information
20661 id: "id" // The element within the row that provides an ID for the record (optional)
20665 * This would consume an XML file like this:
20669 <results>2</results>
20672 <name>Bill</name>
20673 <occupation>Gardener</occupation>
20677 <name>Ben</name>
20678 <occupation>Horticulturalist</occupation>
20682 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20683 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20684 * paged from the remote server.
20685 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20686 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20687 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20688 * a record identifier value.
20690 * Create a new XmlReader
20691 * @param {Object} meta Metadata configuration options
20692 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20693 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20694 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20696 Roo.data.XmlReader = function(meta, recordType){
20698 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20700 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20702 * This method is only used by a DataProxy which has retrieved data from a remote server.
20703 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20704 * to contain a method called 'responseXML' that returns an XML document object.
20705 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20706 * a cache of Roo.data.Records.
20708 read : function(response){
20709 var doc = response.responseXML;
20711 throw {message: "XmlReader.read: XML Document not available"};
20713 return this.readRecords(doc);
20717 * Create a data block containing Roo.data.Records from an XML document.
20718 * @param {Object} doc A parsed XML document.
20719 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20720 * a cache of Roo.data.Records.
20722 readRecords : function(doc){
20724 * After any data loads/reads, the raw XML Document is available for further custom processing.
20725 * @type XMLDocument
20727 this.xmlData = doc;
20728 var root = doc.documentElement || doc;
20729 var q = Roo.DomQuery;
20730 var recordType = this.recordType, fields = recordType.prototype.fields;
20731 var sid = this.meta.id;
20732 var totalRecords = 0, success = true;
20733 if(this.meta.totalRecords){
20734 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20737 if(this.meta.success){
20738 var sv = q.selectValue(this.meta.success, root, true);
20739 success = sv !== false && sv !== 'false';
20742 var ns = q.select(this.meta.record, root);
20743 for(var i = 0, len = ns.length; i < len; i++) {
20746 var id = sid ? q.selectValue(sid, n) : undefined;
20747 for(var j = 0, jlen = fields.length; j < jlen; j++){
20748 var f = fields.items[j];
20749 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20751 values[f.name] = v;
20753 var record = new recordType(values, id);
20755 records[records.length] = record;
20761 totalRecords : totalRecords || records.length
20766 * Ext JS Library 1.1.1
20767 * Copyright(c) 2006-2007, Ext JS, LLC.
20769 * Originally Released Under LGPL - original licence link has changed is not relivant.
20772 * <script type="text/javascript">
20776 * @class Roo.data.ArrayReader
20777 * @extends Roo.data.DataReader
20778 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20779 * Each element of that Array represents a row of data fields. The
20780 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20781 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20785 var RecordDef = Roo.data.Record.create([
20786 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20787 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20789 var myReader = new Roo.data.ArrayReader({
20790 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20794 * This would consume an Array like this:
20796 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20798 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20800 * Create a new JsonReader
20801 * @param {Object} meta Metadata configuration options.
20802 * @param {Object} recordType Either an Array of field definition objects
20803 * as specified to {@link Roo.data.Record#create},
20804 * or an {@link Roo.data.Record} object
20805 * created using {@link Roo.data.Record#create}.
20807 Roo.data.ArrayReader = function(meta, recordType){
20808 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20811 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20813 * Create a data block containing Roo.data.Records from an XML document.
20814 * @param {Object} o An Array of row objects which represents the dataset.
20815 * @return {Object} data A data block which is used by an Roo.data.Store object as
20816 * a cache of Roo.data.Records.
20818 readRecords : function(o){
20819 var sid = this.meta ? this.meta.id : null;
20820 var recordType = this.recordType, fields = recordType.prototype.fields;
20823 for(var i = 0; i < root.length; i++){
20826 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20827 for(var j = 0, jlen = fields.length; j < jlen; j++){
20828 var f = fields.items[j];
20829 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20830 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20832 values[f.name] = v;
20834 var record = new recordType(values, id);
20836 records[records.length] = record;
20840 totalRecords : records.length
20845 * Ext JS Library 1.1.1
20846 * Copyright(c) 2006-2007, Ext JS, LLC.
20848 * Originally Released Under LGPL - original licence link has changed is not relivant.
20851 * <script type="text/javascript">
20856 * @class Roo.data.Tree
20857 * @extends Roo.util.Observable
20858 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20859 * in the tree have most standard DOM functionality.
20861 * @param {Node} root (optional) The root node
20863 Roo.data.Tree = function(root){
20864 this.nodeHash = {};
20866 * The root node for this tree
20871 this.setRootNode(root);
20876 * Fires when a new child node is appended to a node in this tree.
20877 * @param {Tree} tree The owner tree
20878 * @param {Node} parent The parent node
20879 * @param {Node} node The newly appended node
20880 * @param {Number} index The index of the newly appended node
20885 * Fires when a child node is removed from a node in this tree.
20886 * @param {Tree} tree The owner tree
20887 * @param {Node} parent The parent node
20888 * @param {Node} node The child node removed
20893 * Fires when a node is moved to a new location in the tree
20894 * @param {Tree} tree The owner tree
20895 * @param {Node} node The node moved
20896 * @param {Node} oldParent The old parent of this node
20897 * @param {Node} newParent The new parent of this node
20898 * @param {Number} index The index it was moved to
20903 * Fires when a new child node is inserted in a node in this tree.
20904 * @param {Tree} tree The owner tree
20905 * @param {Node} parent The parent node
20906 * @param {Node} node The child node inserted
20907 * @param {Node} refNode The child node the node was inserted before
20911 * @event beforeappend
20912 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20913 * @param {Tree} tree The owner tree
20914 * @param {Node} parent The parent node
20915 * @param {Node} node The child node to be appended
20917 "beforeappend" : true,
20919 * @event beforeremove
20920 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20921 * @param {Tree} tree The owner tree
20922 * @param {Node} parent The parent node
20923 * @param {Node} node The child node to be removed
20925 "beforeremove" : true,
20927 * @event beforemove
20928 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
20929 * @param {Tree} tree The owner tree
20930 * @param {Node} node The node being moved
20931 * @param {Node} oldParent The parent of the node
20932 * @param {Node} newParent The new parent the node is moving to
20933 * @param {Number} index The index it is being moved to
20935 "beforemove" : true,
20937 * @event beforeinsert
20938 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
20939 * @param {Tree} tree The owner tree
20940 * @param {Node} parent The parent node
20941 * @param {Node} node The child node to be inserted
20942 * @param {Node} refNode The child node the node is being inserted before
20944 "beforeinsert" : true
20947 Roo.data.Tree.superclass.constructor.call(this);
20950 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
20951 pathSeparator: "/",
20953 proxyNodeEvent : function(){
20954 return this.fireEvent.apply(this, arguments);
20958 * Returns the root node for this tree.
20961 getRootNode : function(){
20966 * Sets the root node for this tree.
20967 * @param {Node} node
20970 setRootNode : function(node){
20972 node.ownerTree = this;
20973 node.isRoot = true;
20974 this.registerNode(node);
20979 * Gets a node in this tree by its id.
20980 * @param {String} id
20983 getNodeById : function(id){
20984 return this.nodeHash[id];
20987 registerNode : function(node){
20988 this.nodeHash[node.id] = node;
20991 unregisterNode : function(node){
20992 delete this.nodeHash[node.id];
20995 toString : function(){
20996 return "[Tree"+(this.id?" "+this.id:"")+"]";
21001 * @class Roo.data.Node
21002 * @extends Roo.util.Observable
21003 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21004 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21006 * @param {Object} attributes The attributes/config for the node
21008 Roo.data.Node = function(attributes){
21010 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21013 this.attributes = attributes || {};
21014 this.leaf = this.attributes.leaf;
21016 * The node id. @type String
21018 this.id = this.attributes.id;
21020 this.id = Roo.id(null, "ynode-");
21021 this.attributes.id = this.id;
21024 * All child nodes of this node. @type Array
21026 this.childNodes = [];
21027 if(!this.childNodes.indexOf){ // indexOf is a must
21028 this.childNodes.indexOf = function(o){
21029 for(var i = 0, len = this.length; i < len; i++){
21038 * The parent node for this node. @type Node
21040 this.parentNode = null;
21042 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21044 this.firstChild = null;
21046 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21048 this.lastChild = null;
21050 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21052 this.previousSibling = null;
21054 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21056 this.nextSibling = null;
21061 * Fires when a new child node is appended
21062 * @param {Tree} tree The owner tree
21063 * @param {Node} this This node
21064 * @param {Node} node The newly appended node
21065 * @param {Number} index The index of the newly appended node
21070 * Fires when a child node is removed
21071 * @param {Tree} tree The owner tree
21072 * @param {Node} this This node
21073 * @param {Node} node The removed node
21078 * Fires when this node is moved to a new location in the tree
21079 * @param {Tree} tree The owner tree
21080 * @param {Node} this This node
21081 * @param {Node} oldParent The old parent of this node
21082 * @param {Node} newParent The new parent of this node
21083 * @param {Number} index The index it was moved to
21088 * Fires when a new child node is inserted.
21089 * @param {Tree} tree The owner tree
21090 * @param {Node} this This node
21091 * @param {Node} node The child node inserted
21092 * @param {Node} refNode The child node the node was inserted before
21096 * @event beforeappend
21097 * Fires before a new child is appended, return false to cancel the append.
21098 * @param {Tree} tree The owner tree
21099 * @param {Node} this This node
21100 * @param {Node} node The child node to be appended
21102 "beforeappend" : true,
21104 * @event beforeremove
21105 * Fires before a child is removed, return false to cancel the remove.
21106 * @param {Tree} tree The owner tree
21107 * @param {Node} this This node
21108 * @param {Node} node The child node to be removed
21110 "beforeremove" : true,
21112 * @event beforemove
21113 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21114 * @param {Tree} tree The owner tree
21115 * @param {Node} this This node
21116 * @param {Node} oldParent The parent of this node
21117 * @param {Node} newParent The new parent this node is moving to
21118 * @param {Number} index The index it is being moved to
21120 "beforemove" : true,
21122 * @event beforeinsert
21123 * Fires before a new child is inserted, return false to cancel the insert.
21124 * @param {Tree} tree The owner tree
21125 * @param {Node} this This node
21126 * @param {Node} node The child node to be inserted
21127 * @param {Node} refNode The child node the node is being inserted before
21129 "beforeinsert" : true
21131 this.listeners = this.attributes.listeners;
21132 Roo.data.Node.superclass.constructor.call(this);
21135 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21136 fireEvent : function(evtName){
21137 // first do standard event for this node
21138 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21141 // then bubble it up to the tree if the event wasn't cancelled
21142 var ot = this.getOwnerTree();
21144 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21152 * Returns true if this node is a leaf
21153 * @return {Boolean}
21155 isLeaf : function(){
21156 return this.leaf === true;
21160 setFirstChild : function(node){
21161 this.firstChild = node;
21165 setLastChild : function(node){
21166 this.lastChild = node;
21171 * Returns true if this node is the last child of its parent
21172 * @return {Boolean}
21174 isLast : function(){
21175 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21179 * Returns true if this node is the first child of its parent
21180 * @return {Boolean}
21182 isFirst : function(){
21183 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21186 hasChildNodes : function(){
21187 return !this.isLeaf() && this.childNodes.length > 0;
21191 * Insert node(s) as the last child node of this node.
21192 * @param {Node/Array} node The node or Array of nodes to append
21193 * @return {Node} The appended node if single append, or null if an array was passed
21195 appendChild : function(node){
21197 if(node instanceof Array){
21199 }else if(arguments.length > 1){
21202 // if passed an array or multiple args do them one by one
21204 for(var i = 0, len = multi.length; i < len; i++) {
21205 this.appendChild(multi[i]);
21208 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21211 var index = this.childNodes.length;
21212 var oldParent = node.parentNode;
21213 // it's a move, make sure we move it cleanly
21215 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21218 oldParent.removeChild(node);
21220 index = this.childNodes.length;
21222 this.setFirstChild(node);
21224 this.childNodes.push(node);
21225 node.parentNode = this;
21226 var ps = this.childNodes[index-1];
21228 node.previousSibling = ps;
21229 ps.nextSibling = node;
21231 node.previousSibling = null;
21233 node.nextSibling = null;
21234 this.setLastChild(node);
21235 node.setOwnerTree(this.getOwnerTree());
21236 this.fireEvent("append", this.ownerTree, this, node, index);
21238 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21245 * Removes a child node from this node.
21246 * @param {Node} node The node to remove
21247 * @return {Node} The removed node
21249 removeChild : function(node){
21250 var index = this.childNodes.indexOf(node);
21254 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21258 // remove it from childNodes collection
21259 this.childNodes.splice(index, 1);
21262 if(node.previousSibling){
21263 node.previousSibling.nextSibling = node.nextSibling;
21265 if(node.nextSibling){
21266 node.nextSibling.previousSibling = node.previousSibling;
21269 // update child refs
21270 if(this.firstChild == node){
21271 this.setFirstChild(node.nextSibling);
21273 if(this.lastChild == node){
21274 this.setLastChild(node.previousSibling);
21277 node.setOwnerTree(null);
21278 // clear any references from the node
21279 node.parentNode = null;
21280 node.previousSibling = null;
21281 node.nextSibling = null;
21282 this.fireEvent("remove", this.ownerTree, this, node);
21287 * Inserts the first node before the second node in this nodes childNodes collection.
21288 * @param {Node} node The node to insert
21289 * @param {Node} refNode The node to insert before (if null the node is appended)
21290 * @return {Node} The inserted node
21292 insertBefore : function(node, refNode){
21293 if(!refNode){ // like standard Dom, refNode can be null for append
21294 return this.appendChild(node);
21297 if(node == refNode){
21301 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21304 var index = this.childNodes.indexOf(refNode);
21305 var oldParent = node.parentNode;
21306 var refIndex = index;
21308 // when moving internally, indexes will change after remove
21309 if(oldParent == this && this.childNodes.indexOf(node) < index){
21313 // it's a move, make sure we move it cleanly
21315 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21318 oldParent.removeChild(node);
21321 this.setFirstChild(node);
21323 this.childNodes.splice(refIndex, 0, node);
21324 node.parentNode = this;
21325 var ps = this.childNodes[refIndex-1];
21327 node.previousSibling = ps;
21328 ps.nextSibling = node;
21330 node.previousSibling = null;
21332 node.nextSibling = refNode;
21333 refNode.previousSibling = node;
21334 node.setOwnerTree(this.getOwnerTree());
21335 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21337 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21343 * Returns the child node at the specified index.
21344 * @param {Number} index
21347 item : function(index){
21348 return this.childNodes[index];
21352 * Replaces one child node in this node with another.
21353 * @param {Node} newChild The replacement node
21354 * @param {Node} oldChild The node to replace
21355 * @return {Node} The replaced node
21357 replaceChild : function(newChild, oldChild){
21358 this.insertBefore(newChild, oldChild);
21359 this.removeChild(oldChild);
21364 * Returns the index of a child node
21365 * @param {Node} node
21366 * @return {Number} The index of the node or -1 if it was not found
21368 indexOf : function(child){
21369 return this.childNodes.indexOf(child);
21373 * Returns the tree this node is in.
21376 getOwnerTree : function(){
21377 // if it doesn't have one, look for one
21378 if(!this.ownerTree){
21382 this.ownerTree = p.ownerTree;
21388 return this.ownerTree;
21392 * Returns depth of this node (the root node has a depth of 0)
21395 getDepth : function(){
21398 while(p.parentNode){
21406 setOwnerTree : function(tree){
21407 // if it's move, we need to update everyone
21408 if(tree != this.ownerTree){
21409 if(this.ownerTree){
21410 this.ownerTree.unregisterNode(this);
21412 this.ownerTree = tree;
21413 var cs = this.childNodes;
21414 for(var i = 0, len = cs.length; i < len; i++) {
21415 cs[i].setOwnerTree(tree);
21418 tree.registerNode(this);
21424 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21425 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21426 * @return {String} The path
21428 getPath : function(attr){
21429 attr = attr || "id";
21430 var p = this.parentNode;
21431 var b = [this.attributes[attr]];
21433 b.unshift(p.attributes[attr]);
21436 var sep = this.getOwnerTree().pathSeparator;
21437 return sep + b.join(sep);
21441 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21442 * function call will be the scope provided or the current node. The arguments to the function
21443 * will be the args provided or the current node. If the function returns false at any point,
21444 * the bubble is stopped.
21445 * @param {Function} fn The function to call
21446 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21447 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21449 bubble : function(fn, scope, args){
21452 if(fn.call(scope || p, args || p) === false){
21460 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21461 * function call will be the scope provided or the current node. The arguments to the function
21462 * will be the args provided or the current node. If the function returns false at any point,
21463 * the cascade is stopped on that branch.
21464 * @param {Function} fn The function to call
21465 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21466 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21468 cascade : function(fn, scope, args){
21469 if(fn.call(scope || this, args || this) !== false){
21470 var cs = this.childNodes;
21471 for(var i = 0, len = cs.length; i < len; i++) {
21472 cs[i].cascade(fn, scope, args);
21478 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21479 * function call will be the scope provided or the current node. The arguments to the function
21480 * will be the args provided or the current node. If the function returns false at any point,
21481 * the iteration stops.
21482 * @param {Function} fn The function to call
21483 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21484 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21486 eachChild : function(fn, scope, args){
21487 var cs = this.childNodes;
21488 for(var i = 0, len = cs.length; i < len; i++) {
21489 if(fn.call(scope || this, args || cs[i]) === false){
21496 * Finds the first child that has the attribute with the specified value.
21497 * @param {String} attribute The attribute name
21498 * @param {Mixed} value The value to search for
21499 * @return {Node} The found child or null if none was found
21501 findChild : function(attribute, value){
21502 var cs = this.childNodes;
21503 for(var i = 0, len = cs.length; i < len; i++) {
21504 if(cs[i].attributes[attribute] == value){
21512 * Finds the first child by a custom function. The child matches if the function passed
21514 * @param {Function} fn
21515 * @param {Object} scope (optional)
21516 * @return {Node} The found child or null if none was found
21518 findChildBy : function(fn, scope){
21519 var cs = this.childNodes;
21520 for(var i = 0, len = cs.length; i < len; i++) {
21521 if(fn.call(scope||cs[i], cs[i]) === true){
21529 * Sorts this nodes children using the supplied sort function
21530 * @param {Function} fn
21531 * @param {Object} scope (optional)
21533 sort : function(fn, scope){
21534 var cs = this.childNodes;
21535 var len = cs.length;
21537 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21539 for(var i = 0; i < len; i++){
21541 n.previousSibling = cs[i-1];
21542 n.nextSibling = cs[i+1];
21544 this.setFirstChild(n);
21547 this.setLastChild(n);
21554 * Returns true if this node is an ancestor (at any point) of the passed node.
21555 * @param {Node} node
21556 * @return {Boolean}
21558 contains : function(node){
21559 return node.isAncestor(this);
21563 * Returns true if the passed node is an ancestor (at any point) of this node.
21564 * @param {Node} node
21565 * @return {Boolean}
21567 isAncestor : function(node){
21568 var p = this.parentNode;
21578 toString : function(){
21579 return "[Node"+(this.id?" "+this.id:"")+"]";
21583 * Ext JS Library 1.1.1
21584 * Copyright(c) 2006-2007, Ext JS, LLC.
21586 * Originally Released Under LGPL - original licence link has changed is not relivant.
21589 * <script type="text/javascript">
21594 * @class Roo.ComponentMgr
21595 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21598 Roo.ComponentMgr = function(){
21599 var all = new Roo.util.MixedCollection();
21603 * Registers a component.
21604 * @param {Roo.Component} c The component
21606 register : function(c){
21611 * Unregisters a component.
21612 * @param {Roo.Component} c The component
21614 unregister : function(c){
21619 * Returns a component by id
21620 * @param {String} id The component id
21622 get : function(id){
21623 return all.get(id);
21627 * Registers a function that will be called when a specified component is added to ComponentMgr
21628 * @param {String} id The component id
21629 * @param {Funtction} fn The callback function
21630 * @param {Object} scope The scope of the callback
21632 onAvailable : function(id, fn, scope){
21633 all.on("add", function(index, o){
21635 fn.call(scope || o, o);
21636 all.un("add", fn, scope);
21643 * Ext JS Library 1.1.1
21644 * Copyright(c) 2006-2007, Ext JS, LLC.
21646 * Originally Released Under LGPL - original licence link has changed is not relivant.
21649 * <script type="text/javascript">
21653 * @class Roo.Component
21654 * @extends Roo.util.Observable
21655 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21656 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21657 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21658 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21659 * All visual components (widgets) that require rendering into a layout should subclass Component.
21661 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21662 * 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
21663 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21665 Roo.Component = function(config){
21666 config = config || {};
21667 if(config.tagName || config.dom || typeof config == "string"){ // element object
21668 config = {el: config, id: config.id || config};
21670 this.initialConfig = config;
21672 Roo.apply(this, config);
21676 * Fires after the component is disabled.
21677 * @param {Roo.Component} this
21682 * Fires after the component is enabled.
21683 * @param {Roo.Component} this
21687 * @event beforeshow
21688 * Fires before the component is shown. Return false to stop the show.
21689 * @param {Roo.Component} this
21694 * Fires after the component is shown.
21695 * @param {Roo.Component} this
21699 * @event beforehide
21700 * Fires before the component is hidden. Return false to stop the hide.
21701 * @param {Roo.Component} this
21706 * Fires after the component is hidden.
21707 * @param {Roo.Component} this
21711 * @event beforerender
21712 * Fires before the component is rendered. Return false to stop the render.
21713 * @param {Roo.Component} this
21715 beforerender : true,
21718 * Fires after the component is rendered.
21719 * @param {Roo.Component} this
21723 * @event beforedestroy
21724 * Fires before the component is destroyed. Return false to stop the destroy.
21725 * @param {Roo.Component} this
21727 beforedestroy : true,
21730 * Fires after the component is destroyed.
21731 * @param {Roo.Component} this
21736 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21738 Roo.ComponentMgr.register(this);
21739 Roo.Component.superclass.constructor.call(this);
21740 this.initComponent();
21741 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21742 this.render(this.renderTo);
21743 delete this.renderTo;
21748 Roo.Component.AUTO_ID = 1000;
21750 Roo.extend(Roo.Component, Roo.util.Observable, {
21752 * @property {Boolean} hidden
21753 * true if this component is hidden. Read-only.
21757 * true if this component is disabled. Read-only.
21761 * true if this component has been rendered. Read-only.
21765 /** @cfg {String} disableClass
21766 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21768 disabledClass : "x-item-disabled",
21769 /** @cfg {Boolean} allowDomMove
21770 * Whether the component can move the Dom node when rendering (defaults to true).
21772 allowDomMove : true,
21773 /** @cfg {String} hideMode
21774 * How this component should hidden. Supported values are
21775 * "visibility" (css visibility), "offsets" (negative offset position) and
21776 * "display" (css display) - defaults to "display".
21778 hideMode: 'display',
21781 ctype : "Roo.Component",
21783 /** @cfg {String} actionMode
21784 * which property holds the element that used for hide() / show() / disable() / enable()
21790 getActionEl : function(){
21791 return this[this.actionMode];
21794 initComponent : Roo.emptyFn,
21796 * If this is a lazy rendering component, render it to its container element.
21797 * @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.
21799 render : function(container, position){
21800 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21801 if(!container && this.el){
21802 this.el = Roo.get(this.el);
21803 container = this.el.dom.parentNode;
21804 this.allowDomMove = false;
21806 this.container = Roo.get(container);
21807 this.rendered = true;
21808 if(position !== undefined){
21809 if(typeof position == 'number'){
21810 position = this.container.dom.childNodes[position];
21812 position = Roo.getDom(position);
21815 this.onRender(this.container, position || null);
21817 this.el.addClass(this.cls);
21821 this.el.applyStyles(this.style);
21824 this.fireEvent("render", this);
21825 this.afterRender(this.container);
21837 // default function is not really useful
21838 onRender : function(ct, position){
21840 this.el = Roo.get(this.el);
21841 if(this.allowDomMove !== false){
21842 ct.dom.insertBefore(this.el.dom, position);
21848 getAutoCreate : function(){
21849 var cfg = typeof this.autoCreate == "object" ?
21850 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21851 if(this.id && !cfg.id){
21858 afterRender : Roo.emptyFn,
21861 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21862 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21864 destroy : function(){
21865 if(this.fireEvent("beforedestroy", this) !== false){
21866 this.purgeListeners();
21867 this.beforeDestroy();
21869 this.el.removeAllListeners();
21871 if(this.actionMode == "container"){
21872 this.container.remove();
21876 Roo.ComponentMgr.unregister(this);
21877 this.fireEvent("destroy", this);
21882 beforeDestroy : function(){
21887 onDestroy : function(){
21892 * Returns the underlying {@link Roo.Element}.
21893 * @return {Roo.Element} The element
21895 getEl : function(){
21900 * Returns the id of this component.
21903 getId : function(){
21908 * Try to focus this component.
21909 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21910 * @return {Roo.Component} this
21912 focus : function(selectText){
21915 if(selectText === true){
21916 this.el.dom.select();
21931 * Disable this component.
21932 * @return {Roo.Component} this
21934 disable : function(){
21938 this.disabled = true;
21939 this.fireEvent("disable", this);
21944 onDisable : function(){
21945 this.getActionEl().addClass(this.disabledClass);
21946 this.el.dom.disabled = true;
21950 * Enable this component.
21951 * @return {Roo.Component} this
21953 enable : function(){
21957 this.disabled = false;
21958 this.fireEvent("enable", this);
21963 onEnable : function(){
21964 this.getActionEl().removeClass(this.disabledClass);
21965 this.el.dom.disabled = false;
21969 * Convenience function for setting disabled/enabled by boolean.
21970 * @param {Boolean} disabled
21972 setDisabled : function(disabled){
21973 this[disabled ? "disable" : "enable"]();
21977 * Show this component.
21978 * @return {Roo.Component} this
21981 if(this.fireEvent("beforeshow", this) !== false){
21982 this.hidden = false;
21986 this.fireEvent("show", this);
21992 onShow : function(){
21993 var ae = this.getActionEl();
21994 if(this.hideMode == 'visibility'){
21995 ae.dom.style.visibility = "visible";
21996 }else if(this.hideMode == 'offsets'){
21997 ae.removeClass('x-hidden');
21999 ae.dom.style.display = "";
22004 * Hide this component.
22005 * @return {Roo.Component} this
22008 if(this.fireEvent("beforehide", this) !== false){
22009 this.hidden = true;
22013 this.fireEvent("hide", this);
22019 onHide : function(){
22020 var ae = this.getActionEl();
22021 if(this.hideMode == 'visibility'){
22022 ae.dom.style.visibility = "hidden";
22023 }else if(this.hideMode == 'offsets'){
22024 ae.addClass('x-hidden');
22026 ae.dom.style.display = "none";
22031 * Convenience function to hide or show this component by boolean.
22032 * @param {Boolean} visible True to show, false to hide
22033 * @return {Roo.Component} this
22035 setVisible: function(visible){
22045 * Returns true if this component is visible.
22047 isVisible : function(){
22048 return this.getActionEl().isVisible();
22051 cloneConfig : function(overrides){
22052 overrides = overrides || {};
22053 var id = overrides.id || Roo.id();
22054 var cfg = Roo.applyIf(overrides, this.initialConfig);
22055 cfg.id = id; // prevent dup id
22056 return new this.constructor(cfg);
22060 * Ext JS Library 1.1.1
22061 * Copyright(c) 2006-2007, Ext JS, LLC.
22063 * Originally Released Under LGPL - original licence link has changed is not relivant.
22066 * <script type="text/javascript">
22071 * @extends Roo.Element
22072 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22073 * automatic maintaining of shadow/shim positions.
22074 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22075 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22076 * you can pass a string with a CSS class name. False turns off the shadow.
22077 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22078 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22079 * @cfg {String} cls CSS class to add to the element
22080 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22081 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22083 * @param {Object} config An object with config options.
22084 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22087 Roo.Layer = function(config, existingEl){
22088 config = config || {};
22089 var dh = Roo.DomHelper;
22090 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22092 this.dom = Roo.getDom(existingEl);
22095 var o = config.dh || {tag: "div", cls: "x-layer"};
22096 this.dom = dh.append(pel, o);
22099 this.addClass(config.cls);
22101 this.constrain = config.constrain !== false;
22102 this.visibilityMode = Roo.Element.VISIBILITY;
22104 this.id = this.dom.id = config.id;
22106 this.id = Roo.id(this.dom);
22108 this.zindex = config.zindex || this.getZIndex();
22109 this.position("absolute", this.zindex);
22111 this.shadowOffset = config.shadowOffset || 4;
22112 this.shadow = new Roo.Shadow({
22113 offset : this.shadowOffset,
22114 mode : config.shadow
22117 this.shadowOffset = 0;
22119 this.useShim = config.shim !== false && Roo.useShims;
22120 this.useDisplay = config.useDisplay;
22124 var supr = Roo.Element.prototype;
22126 // shims are shared among layer to keep from having 100 iframes
22129 Roo.extend(Roo.Layer, Roo.Element, {
22131 getZIndex : function(){
22132 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22135 getShim : function(){
22142 var shim = shims.shift();
22144 shim = this.createShim();
22145 shim.enableDisplayMode('block');
22146 shim.dom.style.display = 'none';
22147 shim.dom.style.visibility = 'visible';
22149 var pn = this.dom.parentNode;
22150 if(shim.dom.parentNode != pn){
22151 pn.insertBefore(shim.dom, this.dom);
22153 shim.setStyle('z-index', this.getZIndex()-2);
22158 hideShim : function(){
22160 this.shim.setDisplayed(false);
22161 shims.push(this.shim);
22166 disableShadow : function(){
22168 this.shadowDisabled = true;
22169 this.shadow.hide();
22170 this.lastShadowOffset = this.shadowOffset;
22171 this.shadowOffset = 0;
22175 enableShadow : function(show){
22177 this.shadowDisabled = false;
22178 this.shadowOffset = this.lastShadowOffset;
22179 delete this.lastShadowOffset;
22187 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22188 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22189 sync : function(doShow){
22190 var sw = this.shadow;
22191 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22192 var sh = this.getShim();
22194 var w = this.getWidth(),
22195 h = this.getHeight();
22197 var l = this.getLeft(true),
22198 t = this.getTop(true);
22200 if(sw && !this.shadowDisabled){
22201 if(doShow && !sw.isVisible()){
22204 sw.realign(l, t, w, h);
22210 // fit the shim behind the shadow, so it is shimmed too
22211 var a = sw.adjusts, s = sh.dom.style;
22212 s.left = (Math.min(l, l+a.l))+"px";
22213 s.top = (Math.min(t, t+a.t))+"px";
22214 s.width = (w+a.w)+"px";
22215 s.height = (h+a.h)+"px";
22222 sh.setLeftTop(l, t);
22229 destroy : function(){
22232 this.shadow.hide();
22234 this.removeAllListeners();
22235 var pn = this.dom.parentNode;
22237 pn.removeChild(this.dom);
22239 Roo.Element.uncache(this.id);
22242 remove : function(){
22247 beginUpdate : function(){
22248 this.updating = true;
22252 endUpdate : function(){
22253 this.updating = false;
22258 hideUnders : function(negOffset){
22260 this.shadow.hide();
22266 constrainXY : function(){
22267 if(this.constrain){
22268 var vw = Roo.lib.Dom.getViewWidth(),
22269 vh = Roo.lib.Dom.getViewHeight();
22270 var s = Roo.get(document).getScroll();
22272 var xy = this.getXY();
22273 var x = xy[0], y = xy[1];
22274 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22275 // only move it if it needs it
22277 // first validate right/bottom
22278 if((x + w) > vw+s.left){
22279 x = vw - w - this.shadowOffset;
22282 if((y + h) > vh+s.top){
22283 y = vh - h - this.shadowOffset;
22286 // then make sure top/left isn't negative
22297 var ay = this.avoidY;
22298 if(y <= ay && (y+h) >= ay){
22304 supr.setXY.call(this, xy);
22310 isVisible : function(){
22311 return this.visible;
22315 showAction : function(){
22316 this.visible = true; // track visibility to prevent getStyle calls
22317 if(this.useDisplay === true){
22318 this.setDisplayed("");
22319 }else if(this.lastXY){
22320 supr.setXY.call(this, this.lastXY);
22321 }else if(this.lastLT){
22322 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22327 hideAction : function(){
22328 this.visible = false;
22329 if(this.useDisplay === true){
22330 this.setDisplayed(false);
22332 this.setLeftTop(-10000,-10000);
22336 // overridden Element method
22337 setVisible : function(v, a, d, c, e){
22342 var cb = function(){
22347 }.createDelegate(this);
22348 supr.setVisible.call(this, true, true, d, cb, e);
22351 this.hideUnders(true);
22360 }.createDelegate(this);
22362 supr.setVisible.call(this, v, a, d, cb, e);
22371 storeXY : function(xy){
22372 delete this.lastLT;
22376 storeLeftTop : function(left, top){
22377 delete this.lastXY;
22378 this.lastLT = [left, top];
22382 beforeFx : function(){
22383 this.beforeAction();
22384 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22388 afterFx : function(){
22389 Roo.Layer.superclass.afterFx.apply(this, arguments);
22390 this.sync(this.isVisible());
22394 beforeAction : function(){
22395 if(!this.updating && this.shadow){
22396 this.shadow.hide();
22400 // overridden Element method
22401 setLeft : function(left){
22402 this.storeLeftTop(left, this.getTop(true));
22403 supr.setLeft.apply(this, arguments);
22407 setTop : function(top){
22408 this.storeLeftTop(this.getLeft(true), top);
22409 supr.setTop.apply(this, arguments);
22413 setLeftTop : function(left, top){
22414 this.storeLeftTop(left, top);
22415 supr.setLeftTop.apply(this, arguments);
22419 setXY : function(xy, a, d, c, e){
22421 this.beforeAction();
22423 var cb = this.createCB(c);
22424 supr.setXY.call(this, xy, a, d, cb, e);
22431 createCB : function(c){
22442 // overridden Element method
22443 setX : function(x, a, d, c, e){
22444 this.setXY([x, this.getY()], a, d, c, e);
22447 // overridden Element method
22448 setY : function(y, a, d, c, e){
22449 this.setXY([this.getX(), y], a, d, c, e);
22452 // overridden Element method
22453 setSize : function(w, h, a, d, c, e){
22454 this.beforeAction();
22455 var cb = this.createCB(c);
22456 supr.setSize.call(this, w, h, a, d, cb, e);
22462 // overridden Element method
22463 setWidth : function(w, a, d, c, e){
22464 this.beforeAction();
22465 var cb = this.createCB(c);
22466 supr.setWidth.call(this, w, a, d, cb, e);
22472 // overridden Element method
22473 setHeight : function(h, a, d, c, e){
22474 this.beforeAction();
22475 var cb = this.createCB(c);
22476 supr.setHeight.call(this, h, a, d, cb, e);
22482 // overridden Element method
22483 setBounds : function(x, y, w, h, a, d, c, e){
22484 this.beforeAction();
22485 var cb = this.createCB(c);
22487 this.storeXY([x, y]);
22488 supr.setXY.call(this, [x, y]);
22489 supr.setSize.call(this, w, h, a, d, cb, e);
22492 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22498 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22499 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22500 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22501 * @param {Number} zindex The new z-index to set
22502 * @return {this} The Layer
22504 setZIndex : function(zindex){
22505 this.zindex = zindex;
22506 this.setStyle("z-index", zindex + 2);
22508 this.shadow.setZIndex(zindex + 1);
22511 this.shim.setStyle("z-index", zindex);
22517 * Ext JS Library 1.1.1
22518 * Copyright(c) 2006-2007, Ext JS, LLC.
22520 * Originally Released Under LGPL - original licence link has changed is not relivant.
22523 * <script type="text/javascript">
22528 * @class Roo.Shadow
22529 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22530 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22531 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22533 * Create a new Shadow
22534 * @param {Object} config The config object
22536 Roo.Shadow = function(config){
22537 Roo.apply(this, config);
22538 if(typeof this.mode != "string"){
22539 this.mode = this.defaultMode;
22541 var o = this.offset, a = {h: 0};
22542 var rad = Math.floor(this.offset/2);
22543 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22549 a.l -= this.offset + rad;
22550 a.t -= this.offset + rad;
22561 a.l -= (this.offset - rad);
22562 a.t -= this.offset + rad;
22564 a.w -= (this.offset - rad)*2;
22575 a.l -= (this.offset - rad);
22576 a.t -= (this.offset - rad);
22578 a.w -= (this.offset + rad + 1);
22579 a.h -= (this.offset + rad);
22588 Roo.Shadow.prototype = {
22590 * @cfg {String} mode
22591 * The shadow display mode. Supports the following options:<br />
22592 * sides: Shadow displays on both sides and bottom only<br />
22593 * frame: Shadow displays equally on all four sides<br />
22594 * drop: Traditional bottom-right drop shadow (default)
22597 * @cfg {String} offset
22598 * The number of pixels to offset the shadow from the element (defaults to 4)
22603 defaultMode: "drop",
22606 * Displays the shadow under the target element
22607 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22609 show : function(target){
22610 target = Roo.get(target);
22612 this.el = Roo.Shadow.Pool.pull();
22613 if(this.el.dom.nextSibling != target.dom){
22614 this.el.insertBefore(target);
22617 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22619 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22622 target.getLeft(true),
22623 target.getTop(true),
22627 this.el.dom.style.display = "block";
22631 * Returns true if the shadow is visible, else false
22633 isVisible : function(){
22634 return this.el ? true : false;
22638 * Direct alignment when values are already available. Show must be called at least once before
22639 * calling this method to ensure it is initialized.
22640 * @param {Number} left The target element left position
22641 * @param {Number} top The target element top position
22642 * @param {Number} width The target element width
22643 * @param {Number} height The target element height
22645 realign : function(l, t, w, h){
22649 var a = this.adjusts, d = this.el.dom, s = d.style;
22651 s.left = (l+a.l)+"px";
22652 s.top = (t+a.t)+"px";
22653 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22655 if(s.width != sws || s.height != shs){
22659 var cn = d.childNodes;
22660 var sww = Math.max(0, (sw-12))+"px";
22661 cn[0].childNodes[1].style.width = sww;
22662 cn[1].childNodes[1].style.width = sww;
22663 cn[2].childNodes[1].style.width = sww;
22664 cn[1].style.height = Math.max(0, (sh-12))+"px";
22670 * Hides this shadow
22674 this.el.dom.style.display = "none";
22675 Roo.Shadow.Pool.push(this.el);
22681 * Adjust the z-index of this shadow
22682 * @param {Number} zindex The new z-index
22684 setZIndex : function(z){
22687 this.el.setStyle("z-index", z);
22692 // Private utility class that manages the internal Shadow cache
22693 Roo.Shadow.Pool = function(){
22695 var markup = Roo.isIE ?
22696 '<div class="x-ie-shadow"></div>' :
22697 '<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>';
22700 var sh = p.shift();
22702 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22703 sh.autoBoxAdjust = false;
22708 push : function(sh){
22714 * Ext JS Library 1.1.1
22715 * Copyright(c) 2006-2007, Ext JS, LLC.
22717 * Originally Released Under LGPL - original licence link has changed is not relivant.
22720 * <script type="text/javascript">
22724 * @class Roo.BoxComponent
22725 * @extends Roo.Component
22726 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22727 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22728 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22729 * layout containers.
22731 * @param {Roo.Element/String/Object} config The configuration options.
22733 Roo.BoxComponent = function(config){
22734 Roo.Component.call(this, config);
22738 * Fires after the component is resized.
22739 * @param {Roo.Component} this
22740 * @param {Number} adjWidth The box-adjusted width that was set
22741 * @param {Number} adjHeight The box-adjusted height that was set
22742 * @param {Number} rawWidth The width that was originally specified
22743 * @param {Number} rawHeight The height that was originally specified
22748 * Fires after the component is moved.
22749 * @param {Roo.Component} this
22750 * @param {Number} x The new x position
22751 * @param {Number} y The new y position
22757 Roo.extend(Roo.BoxComponent, Roo.Component, {
22758 // private, set in afterRender to signify that the component has been rendered
22760 // private, used to defer height settings to subclasses
22761 deferHeight: false,
22762 /** @cfg {Number} width
22763 * width (optional) size of component
22765 /** @cfg {Number} height
22766 * height (optional) size of component
22770 * Sets the width and height of the component. This method fires the resize event. This method can accept
22771 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22772 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22773 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22774 * @return {Roo.BoxComponent} this
22776 setSize : function(w, h){
22777 // support for standard size objects
22778 if(typeof w == 'object'){
22783 if(!this.boxReady){
22789 // prevent recalcs when not needed
22790 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22793 this.lastSize = {width: w, height: h};
22795 var adj = this.adjustSize(w, h);
22796 var aw = adj.width, ah = adj.height;
22797 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22798 var rz = this.getResizeEl();
22799 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22800 rz.setSize(aw, ah);
22801 }else if(!this.deferHeight && ah !== undefined){
22803 }else if(aw !== undefined){
22806 this.onResize(aw, ah, w, h);
22807 this.fireEvent('resize', this, aw, ah, w, h);
22813 * Gets the current size of the component's underlying element.
22814 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22816 getSize : function(){
22817 return this.el.getSize();
22821 * Gets the current XY position of the component's underlying element.
22822 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22823 * @return {Array} The XY position of the element (e.g., [100, 200])
22825 getPosition : function(local){
22826 if(local === true){
22827 return [this.el.getLeft(true), this.el.getTop(true)];
22829 return this.xy || this.el.getXY();
22833 * Gets the current box measurements of the component's underlying element.
22834 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22835 * @returns {Object} box An object in the format {x, y, width, height}
22837 getBox : function(local){
22838 var s = this.el.getSize();
22840 s.x = this.el.getLeft(true);
22841 s.y = this.el.getTop(true);
22843 var xy = this.xy || this.el.getXY();
22851 * Sets the current box measurements of the component's underlying element.
22852 * @param {Object} box An object in the format {x, y, width, height}
22853 * @returns {Roo.BoxComponent} this
22855 updateBox : function(box){
22856 this.setSize(box.width, box.height);
22857 this.setPagePosition(box.x, box.y);
22862 getResizeEl : function(){
22863 return this.resizeEl || this.el;
22867 getPositionEl : function(){
22868 return this.positionEl || this.el;
22872 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22873 * This method fires the move event.
22874 * @param {Number} left The new left
22875 * @param {Number} top The new top
22876 * @returns {Roo.BoxComponent} this
22878 setPosition : function(x, y){
22881 if(!this.boxReady){
22884 var adj = this.adjustPosition(x, y);
22885 var ax = adj.x, ay = adj.y;
22887 var el = this.getPositionEl();
22888 if(ax !== undefined || ay !== undefined){
22889 if(ax !== undefined && ay !== undefined){
22890 el.setLeftTop(ax, ay);
22891 }else if(ax !== undefined){
22893 }else if(ay !== undefined){
22896 this.onPosition(ax, ay);
22897 this.fireEvent('move', this, ax, ay);
22903 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22904 * This method fires the move event.
22905 * @param {Number} x The new x position
22906 * @param {Number} y The new y position
22907 * @returns {Roo.BoxComponent} this
22909 setPagePosition : function(x, y){
22912 if(!this.boxReady){
22915 if(x === undefined || y === undefined){ // cannot translate undefined points
22918 var p = this.el.translatePoints(x, y);
22919 this.setPosition(p.left, p.top);
22924 onRender : function(ct, position){
22925 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
22927 this.resizeEl = Roo.get(this.resizeEl);
22929 if(this.positionEl){
22930 this.positionEl = Roo.get(this.positionEl);
22935 afterRender : function(){
22936 Roo.BoxComponent.superclass.afterRender.call(this);
22937 this.boxReady = true;
22938 this.setSize(this.width, this.height);
22939 if(this.x || this.y){
22940 this.setPosition(this.x, this.y);
22942 if(this.pageX || this.pageY){
22943 this.setPagePosition(this.pageX, this.pageY);
22948 * Force the component's size to recalculate based on the underlying element's current height and width.
22949 * @returns {Roo.BoxComponent} this
22951 syncSize : function(){
22952 delete this.lastSize;
22953 this.setSize(this.el.getWidth(), this.el.getHeight());
22958 * Called after the component is resized, this method is empty by default but can be implemented by any
22959 * subclass that needs to perform custom logic after a resize occurs.
22960 * @param {Number} adjWidth The box-adjusted width that was set
22961 * @param {Number} adjHeight The box-adjusted height that was set
22962 * @param {Number} rawWidth The width that was originally specified
22963 * @param {Number} rawHeight The height that was originally specified
22965 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
22970 * Called after the component is moved, this method is empty by default but can be implemented by any
22971 * subclass that needs to perform custom logic after a move occurs.
22972 * @param {Number} x The new x position
22973 * @param {Number} y The new y position
22975 onPosition : function(x, y){
22980 adjustSize : function(w, h){
22981 if(this.autoWidth){
22984 if(this.autoHeight){
22987 return {width : w, height: h};
22991 adjustPosition : function(x, y){
22992 return {x : x, y: y};
22996 * Ext JS Library 1.1.1
22997 * Copyright(c) 2006-2007, Ext JS, LLC.
22999 * Originally Released Under LGPL - original licence link has changed is not relivant.
23002 * <script type="text/javascript">
23007 * @class Roo.SplitBar
23008 * @extends Roo.util.Observable
23009 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23013 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23014 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23015 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23016 split.minSize = 100;
23017 split.maxSize = 600;
23018 split.animate = true;
23019 split.on('moved', splitterMoved);
23022 * Create a new SplitBar
23023 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23024 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23025 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23026 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23027 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23028 position of the SplitBar).
23030 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23033 this.el = Roo.get(dragElement, true);
23034 this.el.dom.unselectable = "on";
23036 this.resizingEl = Roo.get(resizingElement, true);
23040 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23041 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23044 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23047 * The minimum size of the resizing element. (Defaults to 0)
23053 * The maximum size of the resizing element. (Defaults to 2000)
23056 this.maxSize = 2000;
23059 * Whether to animate the transition to the new size
23062 this.animate = false;
23065 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23068 this.useShim = false;
23073 if(!existingProxy){
23075 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23077 this.proxy = Roo.get(existingProxy).dom;
23080 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23083 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23086 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23089 this.dragSpecs = {};
23092 * @private The adapter to use to positon and resize elements
23094 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23095 this.adapter.init(this);
23097 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23099 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23100 this.el.addClass("x-splitbar-h");
23103 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23104 this.el.addClass("x-splitbar-v");
23110 * Fires when the splitter is moved (alias for {@link #event-moved})
23111 * @param {Roo.SplitBar} this
23112 * @param {Number} newSize the new width or height
23117 * Fires when the splitter is moved
23118 * @param {Roo.SplitBar} this
23119 * @param {Number} newSize the new width or height
23123 * @event beforeresize
23124 * Fires before the splitter is dragged
23125 * @param {Roo.SplitBar} this
23127 "beforeresize" : true,
23129 "beforeapply" : true
23132 Roo.util.Observable.call(this);
23135 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23136 onStartProxyDrag : function(x, y){
23137 this.fireEvent("beforeresize", this);
23139 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23141 o.enableDisplayMode("block");
23142 // all splitbars share the same overlay
23143 Roo.SplitBar.prototype.overlay = o;
23145 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23146 this.overlay.show();
23147 Roo.get(this.proxy).setDisplayed("block");
23148 var size = this.adapter.getElementSize(this);
23149 this.activeMinSize = this.getMinimumSize();;
23150 this.activeMaxSize = this.getMaximumSize();;
23151 var c1 = size - this.activeMinSize;
23152 var c2 = Math.max(this.activeMaxSize - size, 0);
23153 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23154 this.dd.resetConstraints();
23155 this.dd.setXConstraint(
23156 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23157 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23159 this.dd.setYConstraint(0, 0);
23161 this.dd.resetConstraints();
23162 this.dd.setXConstraint(0, 0);
23163 this.dd.setYConstraint(
23164 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23165 this.placement == Roo.SplitBar.TOP ? c2 : c1
23168 this.dragSpecs.startSize = size;
23169 this.dragSpecs.startPoint = [x, y];
23170 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23174 * @private Called after the drag operation by the DDProxy
23176 onEndProxyDrag : function(e){
23177 Roo.get(this.proxy).setDisplayed(false);
23178 var endPoint = Roo.lib.Event.getXY(e);
23180 this.overlay.hide();
23183 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23184 newSize = this.dragSpecs.startSize +
23185 (this.placement == Roo.SplitBar.LEFT ?
23186 endPoint[0] - this.dragSpecs.startPoint[0] :
23187 this.dragSpecs.startPoint[0] - endPoint[0]
23190 newSize = this.dragSpecs.startSize +
23191 (this.placement == Roo.SplitBar.TOP ?
23192 endPoint[1] - this.dragSpecs.startPoint[1] :
23193 this.dragSpecs.startPoint[1] - endPoint[1]
23196 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23197 if(newSize != this.dragSpecs.startSize){
23198 if(this.fireEvent('beforeapply', this, newSize) !== false){
23199 this.adapter.setElementSize(this, newSize);
23200 this.fireEvent("moved", this, newSize);
23201 this.fireEvent("resize", this, newSize);
23207 * Get the adapter this SplitBar uses
23208 * @return The adapter object
23210 getAdapter : function(){
23211 return this.adapter;
23215 * Set the adapter this SplitBar uses
23216 * @param {Object} adapter A SplitBar adapter object
23218 setAdapter : function(adapter){
23219 this.adapter = adapter;
23220 this.adapter.init(this);
23224 * Gets the minimum size for the resizing element
23225 * @return {Number} The minimum size
23227 getMinimumSize : function(){
23228 return this.minSize;
23232 * Sets the minimum size for the resizing element
23233 * @param {Number} minSize The minimum size
23235 setMinimumSize : function(minSize){
23236 this.minSize = minSize;
23240 * Gets the maximum size for the resizing element
23241 * @return {Number} The maximum size
23243 getMaximumSize : function(){
23244 return this.maxSize;
23248 * Sets the maximum size for the resizing element
23249 * @param {Number} maxSize The maximum size
23251 setMaximumSize : function(maxSize){
23252 this.maxSize = maxSize;
23256 * Sets the initialize size for the resizing element
23257 * @param {Number} size The initial size
23259 setCurrentSize : function(size){
23260 var oldAnimate = this.animate;
23261 this.animate = false;
23262 this.adapter.setElementSize(this, size);
23263 this.animate = oldAnimate;
23267 * Destroy this splitbar.
23268 * @param {Boolean} removeEl True to remove the element
23270 destroy : function(removeEl){
23272 this.shim.remove();
23275 this.proxy.parentNode.removeChild(this.proxy);
23283 * @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.
23285 Roo.SplitBar.createProxy = function(dir){
23286 var proxy = new Roo.Element(document.createElement("div"));
23287 proxy.unselectable();
23288 var cls = 'x-splitbar-proxy';
23289 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23290 document.body.appendChild(proxy.dom);
23295 * @class Roo.SplitBar.BasicLayoutAdapter
23296 * Default Adapter. It assumes the splitter and resizing element are not positioned
23297 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23299 Roo.SplitBar.BasicLayoutAdapter = function(){
23302 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23303 // do nothing for now
23304 init : function(s){
23308 * Called before drag operations to get the current size of the resizing element.
23309 * @param {Roo.SplitBar} s The SplitBar using this adapter
23311 getElementSize : function(s){
23312 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23313 return s.resizingEl.getWidth();
23315 return s.resizingEl.getHeight();
23320 * Called after drag operations to set the size of the resizing element.
23321 * @param {Roo.SplitBar} s The SplitBar using this adapter
23322 * @param {Number} newSize The new size to set
23323 * @param {Function} onComplete A function to be invoked when resizing is complete
23325 setElementSize : function(s, newSize, onComplete){
23326 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23328 s.resizingEl.setWidth(newSize);
23330 onComplete(s, newSize);
23333 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23338 s.resizingEl.setHeight(newSize);
23340 onComplete(s, newSize);
23343 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23350 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23351 * @extends Roo.SplitBar.BasicLayoutAdapter
23352 * Adapter that moves the splitter element to align with the resized sizing element.
23353 * Used with an absolute positioned SplitBar.
23354 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23355 * document.body, make sure you assign an id to the body element.
23357 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23358 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23359 this.container = Roo.get(container);
23362 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23363 init : function(s){
23364 this.basic.init(s);
23367 getElementSize : function(s){
23368 return this.basic.getElementSize(s);
23371 setElementSize : function(s, newSize, onComplete){
23372 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23375 moveSplitter : function(s){
23376 var yes = Roo.SplitBar;
23377 switch(s.placement){
23379 s.el.setX(s.resizingEl.getRight());
23382 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23385 s.el.setY(s.resizingEl.getBottom());
23388 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23395 * Orientation constant - Create a vertical SplitBar
23399 Roo.SplitBar.VERTICAL = 1;
23402 * Orientation constant - Create a horizontal SplitBar
23406 Roo.SplitBar.HORIZONTAL = 2;
23409 * Placement constant - The resizing element is to the left of the splitter element
23413 Roo.SplitBar.LEFT = 1;
23416 * Placement constant - The resizing element is to the right of the splitter element
23420 Roo.SplitBar.RIGHT = 2;
23423 * Placement constant - The resizing element is positioned above the splitter element
23427 Roo.SplitBar.TOP = 3;
23430 * Placement constant - The resizing element is positioned under splitter element
23434 Roo.SplitBar.BOTTOM = 4;
23437 * Ext JS Library 1.1.1
23438 * Copyright(c) 2006-2007, Ext JS, LLC.
23440 * Originally Released Under LGPL - original licence link has changed is not relivant.
23443 * <script type="text/javascript">
23448 * @extends Roo.util.Observable
23449 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23450 * This class also supports single and multi selection modes. <br>
23451 * Create a data model bound view:
23453 var store = new Roo.data.Store(...);
23455 var view = new Roo.View({
23457 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23459 singleSelect: true,
23460 selectedClass: "ydataview-selected",
23464 // listen for node click?
23465 view.on("click", function(vw, index, node, e){
23466 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23470 dataModel.load("foobar.xml");
23472 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23474 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23475 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23477 * Note: old style constructor is still suported (container, template, config)
23480 * Create a new View
23481 * @param {Object} config The config object
23484 Roo.View = function(config, depreciated_tpl, depreciated_config){
23486 if (typeof(depreciated_tpl) == 'undefined') {
23487 // new way.. - universal constructor.
23488 Roo.apply(this, config);
23489 this.el = Roo.get(this.el);
23492 this.el = Roo.get(config);
23493 this.tpl = depreciated_tpl;
23494 Roo.apply(this, depreciated_config);
23498 if(typeof(this.tpl) == "string"){
23499 this.tpl = new Roo.Template(this.tpl);
23501 // support xtype ctors..
23502 this.tpl = new Roo.factory(this.tpl, Roo);
23506 this.tpl.compile();
23513 * @event beforeclick
23514 * Fires before a click is processed. Returns false to cancel the default action.
23515 * @param {Roo.View} this
23516 * @param {Number} index The index of the target node
23517 * @param {HTMLElement} node The target node
23518 * @param {Roo.EventObject} e The raw event object
23520 "beforeclick" : true,
23523 * Fires when a template node is clicked.
23524 * @param {Roo.View} this
23525 * @param {Number} index The index of the target node
23526 * @param {HTMLElement} node The target node
23527 * @param {Roo.EventObject} e The raw event object
23532 * Fires when a template node is double clicked.
23533 * @param {Roo.View} this
23534 * @param {Number} index The index of the target node
23535 * @param {HTMLElement} node The target node
23536 * @param {Roo.EventObject} e The raw event object
23540 * @event contextmenu
23541 * Fires when a template node is right clicked.
23542 * @param {Roo.View} this
23543 * @param {Number} index The index of the target node
23544 * @param {HTMLElement} node The target node
23545 * @param {Roo.EventObject} e The raw event object
23547 "contextmenu" : true,
23549 * @event selectionchange
23550 * Fires when the selected nodes change.
23551 * @param {Roo.View} this
23552 * @param {Array} selections Array of the selected nodes
23554 "selectionchange" : true,
23557 * @event beforeselect
23558 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23559 * @param {Roo.View} this
23560 * @param {HTMLElement} node The node to be selected
23561 * @param {Array} selections Array of currently selected nodes
23563 "beforeselect" : true
23567 "click": this.onClick,
23568 "dblclick": this.onDblClick,
23569 "contextmenu": this.onContextMenu,
23573 this.selections = [];
23575 this.cmp = new Roo.CompositeElementLite([]);
23577 this.store = Roo.factory(this.store, Roo.data);
23578 this.setStore(this.store, true);
23580 Roo.View.superclass.constructor.call(this);
23583 Roo.extend(Roo.View, Roo.util.Observable, {
23586 * @cfg {Roo.data.Store} store Data store to load data from.
23591 * @cfg {String|Roo.Element} el The container element.
23596 * @cfg {String|Roo.Template} tpl The template used by this View
23601 * @cfg {String} selectedClass The css class to add to selected nodes
23603 selectedClass : "x-view-selected",
23605 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23609 * @cfg {Boolean} multiSelect Allow multiple selection
23612 multiSelect : false,
23614 * @cfg {Boolean} singleSelect Allow single selection
23616 singleSelect: false,
23619 * Returns the element this view is bound to.
23620 * @return {Roo.Element}
23622 getEl : function(){
23627 * Refreshes the view.
23629 refresh : function(){
23631 this.clearSelections();
23632 this.el.update("");
23634 var records = this.store.getRange();
23635 if(records.length < 1){
23636 this.el.update(this.emptyText);
23639 for(var i = 0, len = records.length; i < len; i++){
23640 var data = this.prepareData(records[i].data, i, records[i]);
23641 html[html.length] = t.apply(data);
23643 this.el.update(html.join(""));
23644 this.nodes = this.el.dom.childNodes;
23645 this.updateIndexes(0);
23649 * Function to override to reformat the data that is sent to
23650 * the template for each node.
23651 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23652 * a JSON object for an UpdateManager bound view).
23654 prepareData : function(data){
23658 onUpdate : function(ds, record){
23659 this.clearSelections();
23660 var index = this.store.indexOf(record);
23661 var n = this.nodes[index];
23662 this.tpl.insertBefore(n, this.prepareData(record.data));
23663 n.parentNode.removeChild(n);
23664 this.updateIndexes(index, index);
23667 onAdd : function(ds, records, index){
23668 this.clearSelections();
23669 if(this.nodes.length == 0){
23673 var n = this.nodes[index];
23674 for(var i = 0, len = records.length; i < len; i++){
23675 var d = this.prepareData(records[i].data);
23677 this.tpl.insertBefore(n, d);
23679 this.tpl.append(this.el, d);
23682 this.updateIndexes(index);
23685 onRemove : function(ds, record, index){
23686 this.clearSelections();
23687 this.el.dom.removeChild(this.nodes[index]);
23688 this.updateIndexes(index);
23692 * Refresh an individual node.
23693 * @param {Number} index
23695 refreshNode : function(index){
23696 this.onUpdate(this.store, this.store.getAt(index));
23699 updateIndexes : function(startIndex, endIndex){
23700 var ns = this.nodes;
23701 startIndex = startIndex || 0;
23702 endIndex = endIndex || ns.length - 1;
23703 for(var i = startIndex; i <= endIndex; i++){
23704 ns[i].nodeIndex = i;
23709 * Changes the data store this view uses and refresh the view.
23710 * @param {Store} store
23712 setStore : function(store, initial){
23713 if(!initial && this.store){
23714 this.store.un("datachanged", this.refresh);
23715 this.store.un("add", this.onAdd);
23716 this.store.un("remove", this.onRemove);
23717 this.store.un("update", this.onUpdate);
23718 this.store.un("clear", this.refresh);
23722 store.on("datachanged", this.refresh, this);
23723 store.on("add", this.onAdd, this);
23724 store.on("remove", this.onRemove, this);
23725 store.on("update", this.onUpdate, this);
23726 store.on("clear", this.refresh, this);
23735 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23736 * @param {HTMLElement} node
23737 * @return {HTMLElement} The template node
23739 findItemFromChild : function(node){
23740 var el = this.el.dom;
23741 if(!node || node.parentNode == el){
23744 var p = node.parentNode;
23745 while(p && p != el){
23746 if(p.parentNode == el){
23755 onClick : function(e){
23756 var item = this.findItemFromChild(e.getTarget());
23758 var index = this.indexOf(item);
23759 if(this.onItemClick(item, index, e) !== false){
23760 this.fireEvent("click", this, index, item, e);
23763 this.clearSelections();
23768 onContextMenu : function(e){
23769 var item = this.findItemFromChild(e.getTarget());
23771 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23776 onDblClick : function(e){
23777 var item = this.findItemFromChild(e.getTarget());
23779 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23783 onItemClick : function(item, index, e){
23784 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23787 if(this.multiSelect || this.singleSelect){
23788 if(this.multiSelect && e.shiftKey && this.lastSelection){
23789 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23791 this.select(item, this.multiSelect && e.ctrlKey);
23792 this.lastSelection = item;
23794 e.preventDefault();
23800 * Get the number of selected nodes.
23803 getSelectionCount : function(){
23804 return this.selections.length;
23808 * Get the currently selected nodes.
23809 * @return {Array} An array of HTMLElements
23811 getSelectedNodes : function(){
23812 return this.selections;
23816 * Get the indexes of the selected nodes.
23819 getSelectedIndexes : function(){
23820 var indexes = [], s = this.selections;
23821 for(var i = 0, len = s.length; i < len; i++){
23822 indexes.push(s[i].nodeIndex);
23828 * Clear all selections
23829 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23831 clearSelections : function(suppressEvent){
23832 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23833 this.cmp.elements = this.selections;
23834 this.cmp.removeClass(this.selectedClass);
23835 this.selections = [];
23836 if(!suppressEvent){
23837 this.fireEvent("selectionchange", this, this.selections);
23843 * Returns true if the passed node is selected
23844 * @param {HTMLElement/Number} node The node or node index
23845 * @return {Boolean}
23847 isSelected : function(node){
23848 var s = this.selections;
23852 node = this.getNode(node);
23853 return s.indexOf(node) !== -1;
23858 * @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
23859 * @param {Boolean} keepExisting (optional) true to keep existing selections
23860 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23862 select : function(nodeInfo, keepExisting, suppressEvent){
23863 if(nodeInfo instanceof Array){
23865 this.clearSelections(true);
23867 for(var i = 0, len = nodeInfo.length; i < len; i++){
23868 this.select(nodeInfo[i], true, true);
23871 var node = this.getNode(nodeInfo);
23872 if(node && !this.isSelected(node)){
23874 this.clearSelections(true);
23876 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23877 Roo.fly(node).addClass(this.selectedClass);
23878 this.selections.push(node);
23879 if(!suppressEvent){
23880 this.fireEvent("selectionchange", this, this.selections);
23888 * Gets a template node.
23889 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23890 * @return {HTMLElement} The node or null if it wasn't found
23892 getNode : function(nodeInfo){
23893 if(typeof nodeInfo == "string"){
23894 return document.getElementById(nodeInfo);
23895 }else if(typeof nodeInfo == "number"){
23896 return this.nodes[nodeInfo];
23902 * Gets a range template nodes.
23903 * @param {Number} startIndex
23904 * @param {Number} endIndex
23905 * @return {Array} An array of nodes
23907 getNodes : function(start, end){
23908 var ns = this.nodes;
23909 start = start || 0;
23910 end = typeof end == "undefined" ? ns.length - 1 : end;
23913 for(var i = start; i <= end; i++){
23917 for(var i = start; i >= end; i--){
23925 * Finds the index of the passed node
23926 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23927 * @return {Number} The index of the node or -1
23929 indexOf : function(node){
23930 node = this.getNode(node);
23931 if(typeof node.nodeIndex == "number"){
23932 return node.nodeIndex;
23934 var ns = this.nodes;
23935 for(var i = 0, len = ns.length; i < len; i++){
23945 * Ext JS Library 1.1.1
23946 * Copyright(c) 2006-2007, Ext JS, LLC.
23948 * Originally Released Under LGPL - original licence link has changed is not relivant.
23951 * <script type="text/javascript">
23955 * @class Roo.JsonView
23956 * @extends Roo.View
23957 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
23959 var view = new Roo.JsonView({
23960 container: "my-element",
23961 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
23966 // listen for node click?
23967 view.on("click", function(vw, index, node, e){
23968 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23971 // direct load of JSON data
23972 view.load("foobar.php");
23974 // Example from my blog list
23975 var tpl = new Roo.Template(
23976 '<div class="entry">' +
23977 '<a class="entry-title" href="{link}">{title}</a>' +
23978 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
23979 "</div><hr />"
23982 var moreView = new Roo.JsonView({
23983 container : "entry-list",
23987 moreView.on("beforerender", this.sortEntries, this);
23989 url: "/blog/get-posts.php",
23990 params: "allposts=true",
23991 text: "Loading Blog Entries..."
23995 * Note: old code is supported with arguments : (container, template, config)
23999 * Create a new JsonView
24001 * @param {Object} config The config object
24004 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24007 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24009 var um = this.el.getUpdateManager();
24010 um.setRenderer(this);
24011 um.on("update", this.onLoad, this);
24012 um.on("failure", this.onLoadException, this);
24015 * @event beforerender
24016 * Fires before rendering of the downloaded JSON data.
24017 * @param {Roo.JsonView} this
24018 * @param {Object} data The JSON data loaded
24022 * Fires when data is loaded.
24023 * @param {Roo.JsonView} this
24024 * @param {Object} data The JSON data loaded
24025 * @param {Object} response The raw Connect response object
24028 * @event loadexception
24029 * Fires when loading fails.
24030 * @param {Roo.JsonView} this
24031 * @param {Object} response The raw Connect response object
24034 'beforerender' : true,
24036 'loadexception' : true
24039 Roo.extend(Roo.JsonView, Roo.View, {
24041 * @type {String} The root property in the loaded JSON object that contains the data
24046 * Refreshes the view.
24048 refresh : function(){
24049 this.clearSelections();
24050 this.el.update("");
24052 var o = this.jsonData;
24053 if(o && o.length > 0){
24054 for(var i = 0, len = o.length; i < len; i++){
24055 var data = this.prepareData(o[i], i, o);
24056 html[html.length] = this.tpl.apply(data);
24059 html.push(this.emptyText);
24061 this.el.update(html.join(""));
24062 this.nodes = this.el.dom.childNodes;
24063 this.updateIndexes(0);
24067 * 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.
24068 * @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:
24071 url: "your-url.php",
24072 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24073 callback: yourFunction,
24074 scope: yourObject, //(optional scope)
24077 text: "Loading...",
24082 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24083 * 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.
24084 * @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}
24085 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24086 * @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.
24089 var um = this.el.getUpdateManager();
24090 um.update.apply(um, arguments);
24093 render : function(el, response){
24094 this.clearSelections();
24095 this.el.update("");
24098 o = Roo.util.JSON.decode(response.responseText);
24101 o = o[this.jsonRoot];
24106 * The current JSON data or null
24109 this.beforeRender();
24114 * Get the number of records in the current JSON dataset
24117 getCount : function(){
24118 return this.jsonData ? this.jsonData.length : 0;
24122 * Returns the JSON object for the specified node(s)
24123 * @param {HTMLElement/Array} node The node or an array of nodes
24124 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24125 * you get the JSON object for the node
24127 getNodeData : function(node){
24128 if(node instanceof Array){
24130 for(var i = 0, len = node.length; i < len; i++){
24131 data.push(this.getNodeData(node[i]));
24135 return this.jsonData[this.indexOf(node)] || null;
24138 beforeRender : function(){
24139 this.snapshot = this.jsonData;
24141 this.sort.apply(this, this.sortInfo);
24143 this.fireEvent("beforerender", this, this.jsonData);
24146 onLoad : function(el, o){
24147 this.fireEvent("load", this, this.jsonData, o);
24150 onLoadException : function(el, o){
24151 this.fireEvent("loadexception", this, o);
24155 * Filter the data by a specific property.
24156 * @param {String} property A property on your JSON objects
24157 * @param {String/RegExp} value Either string that the property values
24158 * should start with, or a RegExp to test against the property
24160 filter : function(property, value){
24163 var ss = this.snapshot;
24164 if(typeof value == "string"){
24165 var vlen = value.length;
24167 this.clearFilter();
24170 value = value.toLowerCase();
24171 for(var i = 0, len = ss.length; i < len; i++){
24173 if(o[property].substr(0, vlen).toLowerCase() == value){
24177 } else if(value.exec){ // regex?
24178 for(var i = 0, len = ss.length; i < len; i++){
24180 if(value.test(o[property])){
24187 this.jsonData = data;
24193 * Filter by a function. The passed function will be called with each
24194 * object in the current dataset. If the function returns true the value is kept,
24195 * otherwise it is filtered.
24196 * @param {Function} fn
24197 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24199 filterBy : function(fn, scope){
24202 var ss = this.snapshot;
24203 for(var i = 0, len = ss.length; i < len; i++){
24205 if(fn.call(scope || this, o)){
24209 this.jsonData = data;
24215 * Clears the current filter.
24217 clearFilter : function(){
24218 if(this.snapshot && this.jsonData != this.snapshot){
24219 this.jsonData = this.snapshot;
24226 * Sorts the data for this view and refreshes it.
24227 * @param {String} property A property on your JSON objects to sort on
24228 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24229 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24231 sort : function(property, dir, sortType){
24232 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24235 var dsc = dir && dir.toLowerCase() == "desc";
24236 var f = function(o1, o2){
24237 var v1 = sortType ? sortType(o1[p]) : o1[p];
24238 var v2 = sortType ? sortType(o2[p]) : o2[p];
24241 return dsc ? +1 : -1;
24242 } else if(v1 > v2){
24243 return dsc ? -1 : +1;
24248 this.jsonData.sort(f);
24250 if(this.jsonData != this.snapshot){
24251 this.snapshot.sort(f);
24257 * Ext JS Library 1.1.1
24258 * Copyright(c) 2006-2007, Ext JS, LLC.
24260 * Originally Released Under LGPL - original licence link has changed is not relivant.
24263 * <script type="text/javascript">
24268 * @class Roo.ColorPalette
24269 * @extends Roo.Component
24270 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24271 * Here's an example of typical usage:
24273 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24274 cp.render('my-div');
24276 cp.on('select', function(palette, selColor){
24277 // do something with selColor
24281 * Create a new ColorPalette
24282 * @param {Object} config The config object
24284 Roo.ColorPalette = function(config){
24285 Roo.ColorPalette.superclass.constructor.call(this, config);
24289 * Fires when a color is selected
24290 * @param {ColorPalette} this
24291 * @param {String} color The 6-digit color hex code (without the # symbol)
24297 this.on("select", this.handler, this.scope, true);
24300 Roo.extend(Roo.ColorPalette, Roo.Component, {
24302 * @cfg {String} itemCls
24303 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24305 itemCls : "x-color-palette",
24307 * @cfg {String} value
24308 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24309 * the hex codes are case-sensitive.
24312 clickEvent:'click',
24314 ctype: "Roo.ColorPalette",
24317 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24319 allowReselect : false,
24322 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24323 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24324 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24325 * of colors with the width setting until the box is symmetrical.</p>
24326 * <p>You can override individual colors if needed:</p>
24328 var cp = new Roo.ColorPalette();
24329 cp.colors[0] = "FF0000"; // change the first box to red
24332 Or you can provide a custom array of your own for complete control:
24334 var cp = new Roo.ColorPalette();
24335 cp.colors = ["000000", "993300", "333300"];
24340 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24341 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24342 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24343 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24344 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24348 onRender : function(container, position){
24349 var t = new Roo.MasterTemplate(
24350 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24352 var c = this.colors;
24353 for(var i = 0, len = c.length; i < len; i++){
24356 var el = document.createElement("div");
24357 el.className = this.itemCls;
24359 container.dom.insertBefore(el, position);
24360 this.el = Roo.get(el);
24361 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24362 if(this.clickEvent != 'click'){
24363 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24368 afterRender : function(){
24369 Roo.ColorPalette.superclass.afterRender.call(this);
24371 var s = this.value;
24378 handleClick : function(e, t){
24379 e.preventDefault();
24380 if(!this.disabled){
24381 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24382 this.select(c.toUpperCase());
24387 * Selects the specified color in the palette (fires the select event)
24388 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24390 select : function(color){
24391 color = color.replace("#", "");
24392 if(color != this.value || this.allowReselect){
24395 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24397 el.child("a.color-"+color).addClass("x-color-palette-sel");
24398 this.value = color;
24399 this.fireEvent("select", this, color);
24404 * Ext JS Library 1.1.1
24405 * Copyright(c) 2006-2007, Ext JS, LLC.
24407 * Originally Released Under LGPL - original licence link has changed is not relivant.
24410 * <script type="text/javascript">
24414 * @class Roo.DatePicker
24415 * @extends Roo.Component
24416 * Simple date picker class.
24418 * Create a new DatePicker
24419 * @param {Object} config The config object
24421 Roo.DatePicker = function(config){
24422 Roo.DatePicker.superclass.constructor.call(this, config);
24424 this.value = config && config.value ?
24425 config.value.clearTime() : new Date().clearTime();
24430 * Fires when a date is selected
24431 * @param {DatePicker} this
24432 * @param {Date} date The selected date
24438 this.on("select", this.handler, this.scope || this);
24440 // build the disabledDatesRE
24441 if(!this.disabledDatesRE && this.disabledDates){
24442 var dd = this.disabledDates;
24444 for(var i = 0; i < dd.length; i++){
24446 if(i != dd.length-1) re += "|";
24448 this.disabledDatesRE = new RegExp(re + ")");
24452 Roo.extend(Roo.DatePicker, Roo.Component, {
24454 * @cfg {String} todayText
24455 * The text to display on the button that selects the current date (defaults to "Today")
24457 todayText : "Today",
24459 * @cfg {String} okText
24460 * The text to display on the ok button
24462 okText : " OK ", //   to give the user extra clicking room
24464 * @cfg {String} cancelText
24465 * The text to display on the cancel button
24467 cancelText : "Cancel",
24469 * @cfg {String} todayTip
24470 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24472 todayTip : "{0} (Spacebar)",
24474 * @cfg {Date} minDate
24475 * Minimum allowable date (JavaScript date object, defaults to null)
24479 * @cfg {Date} maxDate
24480 * Maximum allowable date (JavaScript date object, defaults to null)
24484 * @cfg {String} minText
24485 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24487 minText : "This date is before the minimum date",
24489 * @cfg {String} maxText
24490 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24492 maxText : "This date is after the maximum date",
24494 * @cfg {String} format
24495 * The default date format string which can be overriden for localization support. The format must be
24496 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24500 * @cfg {Array} disabledDays
24501 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24503 disabledDays : null,
24505 * @cfg {String} disabledDaysText
24506 * The tooltip to display when the date falls on a disabled day (defaults to "")
24508 disabledDaysText : "",
24510 * @cfg {RegExp} disabledDatesRE
24511 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24513 disabledDatesRE : null,
24515 * @cfg {String} disabledDatesText
24516 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24518 disabledDatesText : "",
24520 * @cfg {Boolean} constrainToViewport
24521 * True to constrain the date picker to the viewport (defaults to true)
24523 constrainToViewport : true,
24525 * @cfg {Array} monthNames
24526 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24528 monthNames : Date.monthNames,
24530 * @cfg {Array} dayNames
24531 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24533 dayNames : Date.dayNames,
24535 * @cfg {String} nextText
24536 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24538 nextText: 'Next Month (Control+Right)',
24540 * @cfg {String} prevText
24541 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24543 prevText: 'Previous Month (Control+Left)',
24545 * @cfg {String} monthYearText
24546 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24548 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24550 * @cfg {Number} startDay
24551 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24555 * @cfg {Bool} showClear
24556 * Show a clear button (usefull for date form elements that can be blank.)
24562 * Sets the value of the date field
24563 * @param {Date} value The date to set
24565 setValue : function(value){
24566 var old = this.value;
24567 this.value = value.clearTime(true);
24569 this.update(this.value);
24574 * Gets the current selected value of the date field
24575 * @return {Date} The selected date
24577 getValue : function(){
24582 focus : function(){
24584 this.update(this.activeDate);
24589 onRender : function(container, position){
24591 '<table cellspacing="0">',
24592 '<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>',
24593 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24594 var dn = this.dayNames;
24595 for(var i = 0; i < 7; i++){
24596 var d = this.startDay+i;
24600 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24602 m[m.length] = "</tr></thead><tbody><tr>";
24603 for(var i = 0; i < 42; i++) {
24604 if(i % 7 == 0 && i != 0){
24605 m[m.length] = "</tr><tr>";
24607 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24609 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24610 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24612 var el = document.createElement("div");
24613 el.className = "x-date-picker";
24614 el.innerHTML = m.join("");
24616 container.dom.insertBefore(el, position);
24618 this.el = Roo.get(el);
24619 this.eventEl = Roo.get(el.firstChild);
24621 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24622 handler: this.showPrevMonth,
24624 preventDefault:true,
24628 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24629 handler: this.showNextMonth,
24631 preventDefault:true,
24635 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24637 this.monthPicker = this.el.down('div.x-date-mp');
24638 this.monthPicker.enableDisplayMode('block');
24640 var kn = new Roo.KeyNav(this.eventEl, {
24641 "left" : function(e){
24643 this.showPrevMonth() :
24644 this.update(this.activeDate.add("d", -1));
24647 "right" : function(e){
24649 this.showNextMonth() :
24650 this.update(this.activeDate.add("d", 1));
24653 "up" : function(e){
24655 this.showNextYear() :
24656 this.update(this.activeDate.add("d", -7));
24659 "down" : function(e){
24661 this.showPrevYear() :
24662 this.update(this.activeDate.add("d", 7));
24665 "pageUp" : function(e){
24666 this.showNextMonth();
24669 "pageDown" : function(e){
24670 this.showPrevMonth();
24673 "enter" : function(e){
24674 e.stopPropagation();
24681 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24683 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24685 this.el.unselectable();
24687 this.cells = this.el.select("table.x-date-inner tbody td");
24688 this.textNodes = this.el.query("table.x-date-inner tbody span");
24690 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24692 tooltip: this.monthYearText
24695 this.mbtn.on('click', this.showMonthPicker, this);
24696 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24699 var today = (new Date()).dateFormat(this.format);
24701 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24702 if (this.showClear) {
24703 baseTb.add( new Roo.Toolbar.Fill());
24706 text: String.format(this.todayText, today),
24707 tooltip: String.format(this.todayTip, today),
24708 handler: this.selectToday,
24712 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24715 if (this.showClear) {
24717 baseTb.add( new Roo.Toolbar.Fill());
24720 cls: 'x-btn-icon x-btn-clear',
24721 handler: function() {
24723 this.fireEvent("select", this, '');
24733 this.update(this.value);
24736 createMonthPicker : function(){
24737 if(!this.monthPicker.dom.firstChild){
24738 var buf = ['<table border="0" cellspacing="0">'];
24739 for(var i = 0; i < 6; i++){
24741 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24742 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24744 '<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>' :
24745 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24749 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24751 '</button><button type="button" class="x-date-mp-cancel">',
24753 '</button></td></tr>',
24756 this.monthPicker.update(buf.join(''));
24757 this.monthPicker.on('click', this.onMonthClick, this);
24758 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24760 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24761 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24763 this.mpMonths.each(function(m, a, i){
24766 m.dom.xmonth = 5 + Math.round(i * .5);
24768 m.dom.xmonth = Math.round((i-1) * .5);
24774 showMonthPicker : function(){
24775 this.createMonthPicker();
24776 var size = this.el.getSize();
24777 this.monthPicker.setSize(size);
24778 this.monthPicker.child('table').setSize(size);
24780 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24781 this.updateMPMonth(this.mpSelMonth);
24782 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24783 this.updateMPYear(this.mpSelYear);
24785 this.monthPicker.slideIn('t', {duration:.2});
24788 updateMPYear : function(y){
24790 var ys = this.mpYears.elements;
24791 for(var i = 1; i <= 10; i++){
24792 var td = ys[i-1], y2;
24794 y2 = y + Math.round(i * .5);
24795 td.firstChild.innerHTML = y2;
24798 y2 = y - (5-Math.round(i * .5));
24799 td.firstChild.innerHTML = y2;
24802 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24806 updateMPMonth : function(sm){
24807 this.mpMonths.each(function(m, a, i){
24808 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24812 selectMPMonth: function(m){
24816 onMonthClick : function(e, t){
24818 var el = new Roo.Element(t), pn;
24819 if(el.is('button.x-date-mp-cancel')){
24820 this.hideMonthPicker();
24822 else if(el.is('button.x-date-mp-ok')){
24823 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24824 this.hideMonthPicker();
24826 else if(pn = el.up('td.x-date-mp-month', 2)){
24827 this.mpMonths.removeClass('x-date-mp-sel');
24828 pn.addClass('x-date-mp-sel');
24829 this.mpSelMonth = pn.dom.xmonth;
24831 else if(pn = el.up('td.x-date-mp-year', 2)){
24832 this.mpYears.removeClass('x-date-mp-sel');
24833 pn.addClass('x-date-mp-sel');
24834 this.mpSelYear = pn.dom.xyear;
24836 else if(el.is('a.x-date-mp-prev')){
24837 this.updateMPYear(this.mpyear-10);
24839 else if(el.is('a.x-date-mp-next')){
24840 this.updateMPYear(this.mpyear+10);
24844 onMonthDblClick : function(e, t){
24846 var el = new Roo.Element(t), pn;
24847 if(pn = el.up('td.x-date-mp-month', 2)){
24848 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24849 this.hideMonthPicker();
24851 else if(pn = el.up('td.x-date-mp-year', 2)){
24852 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24853 this.hideMonthPicker();
24857 hideMonthPicker : function(disableAnim){
24858 if(this.monthPicker){
24859 if(disableAnim === true){
24860 this.monthPicker.hide();
24862 this.monthPicker.slideOut('t', {duration:.2});
24868 showPrevMonth : function(e){
24869 this.update(this.activeDate.add("mo", -1));
24873 showNextMonth : function(e){
24874 this.update(this.activeDate.add("mo", 1));
24878 showPrevYear : function(){
24879 this.update(this.activeDate.add("y", -1));
24883 showNextYear : function(){
24884 this.update(this.activeDate.add("y", 1));
24888 handleMouseWheel : function(e){
24889 var delta = e.getWheelDelta();
24891 this.showPrevMonth();
24893 } else if(delta < 0){
24894 this.showNextMonth();
24900 handleDateClick : function(e, t){
24902 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24903 this.setValue(new Date(t.dateValue));
24904 this.fireEvent("select", this, this.value);
24909 selectToday : function(){
24910 this.setValue(new Date().clearTime());
24911 this.fireEvent("select", this, this.value);
24915 update : function(date){
24916 var vd = this.activeDate;
24917 this.activeDate = date;
24919 var t = date.getTime();
24920 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
24921 this.cells.removeClass("x-date-selected");
24922 this.cells.each(function(c){
24923 if(c.dom.firstChild.dateValue == t){
24924 c.addClass("x-date-selected");
24925 setTimeout(function(){
24926 try{c.dom.firstChild.focus();}catch(e){}
24934 var days = date.getDaysInMonth();
24935 var firstOfMonth = date.getFirstDateOfMonth();
24936 var startingPos = firstOfMonth.getDay()-this.startDay;
24938 if(startingPos <= this.startDay){
24942 var pm = date.add("mo", -1);
24943 var prevStart = pm.getDaysInMonth()-startingPos;
24945 var cells = this.cells.elements;
24946 var textEls = this.textNodes;
24947 days += startingPos;
24949 // convert everything to numbers so it's fast
24950 var day = 86400000;
24951 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
24952 var today = new Date().clearTime().getTime();
24953 var sel = date.clearTime().getTime();
24954 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
24955 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
24956 var ddMatch = this.disabledDatesRE;
24957 var ddText = this.disabledDatesText;
24958 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
24959 var ddaysText = this.disabledDaysText;
24960 var format = this.format;
24962 var setCellClass = function(cal, cell){
24964 var t = d.getTime();
24965 cell.firstChild.dateValue = t;
24967 cell.className += " x-date-today";
24968 cell.title = cal.todayText;
24971 cell.className += " x-date-selected";
24972 setTimeout(function(){
24973 try{cell.firstChild.focus();}catch(e){}
24978 cell.className = " x-date-disabled";
24979 cell.title = cal.minText;
24983 cell.className = " x-date-disabled";
24984 cell.title = cal.maxText;
24988 if(ddays.indexOf(d.getDay()) != -1){
24989 cell.title = ddaysText;
24990 cell.className = " x-date-disabled";
24993 if(ddMatch && format){
24994 var fvalue = d.dateFormat(format);
24995 if(ddMatch.test(fvalue)){
24996 cell.title = ddText.replace("%0", fvalue);
24997 cell.className = " x-date-disabled";
25003 for(; i < startingPos; i++) {
25004 textEls[i].innerHTML = (++prevStart);
25005 d.setDate(d.getDate()+1);
25006 cells[i].className = "x-date-prevday";
25007 setCellClass(this, cells[i]);
25009 for(; i < days; i++){
25010 intDay = i - startingPos + 1;
25011 textEls[i].innerHTML = (intDay);
25012 d.setDate(d.getDate()+1);
25013 cells[i].className = "x-date-active";
25014 setCellClass(this, cells[i]);
25017 for(; i < 42; i++) {
25018 textEls[i].innerHTML = (++extraDays);
25019 d.setDate(d.getDate()+1);
25020 cells[i].className = "x-date-nextday";
25021 setCellClass(this, cells[i]);
25024 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25026 if(!this.internalRender){
25027 var main = this.el.dom.firstChild;
25028 var w = main.offsetWidth;
25029 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25030 Roo.fly(main).setWidth(w);
25031 this.internalRender = true;
25032 // opera does not respect the auto grow header center column
25033 // then, after it gets a width opera refuses to recalculate
25034 // without a second pass
25035 if(Roo.isOpera && !this.secondPass){
25036 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25037 this.secondPass = true;
25038 this.update.defer(10, this, [date]);
25044 * Ext JS Library 1.1.1
25045 * Copyright(c) 2006-2007, Ext JS, LLC.
25047 * Originally Released Under LGPL - original licence link has changed is not relivant.
25050 * <script type="text/javascript">
25053 * @class Roo.TabPanel
25054 * @extends Roo.util.Observable
25055 * A lightweight tab container.
25059 // basic tabs 1, built from existing content
25060 var tabs = new Roo.TabPanel("tabs1");
25061 tabs.addTab("script", "View Script");
25062 tabs.addTab("markup", "View Markup");
25063 tabs.activate("script");
25065 // more advanced tabs, built from javascript
25066 var jtabs = new Roo.TabPanel("jtabs");
25067 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25069 // set up the UpdateManager
25070 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25071 var updater = tab2.getUpdateManager();
25072 updater.setDefaultUrl("ajax1.htm");
25073 tab2.on('activate', updater.refresh, updater, true);
25075 // Use setUrl for Ajax loading
25076 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25077 tab3.setUrl("ajax2.htm", null, true);
25080 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25083 jtabs.activate("jtabs-1");
25086 * Create a new TabPanel.
25087 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25088 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25090 Roo.TabPanel = function(container, config){
25092 * The container element for this TabPanel.
25093 * @type Roo.Element
25095 this.el = Roo.get(container, true);
25097 if(typeof config == "boolean"){
25098 this.tabPosition = config ? "bottom" : "top";
25100 Roo.apply(this, config);
25103 if(this.tabPosition == "bottom"){
25104 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25105 this.el.addClass("x-tabs-bottom");
25107 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25108 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25109 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25111 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25113 if(this.tabPosition != "bottom"){
25114 /** The body element that contains {@link Roo.TabPanelItem} bodies.
25115 * @type Roo.Element
25117 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25118 this.el.addClass("x-tabs-top");
25122 this.bodyEl.setStyle("position", "relative");
25124 this.active = null;
25125 this.activateDelegate = this.activate.createDelegate(this);
25130 * Fires when the active tab changes
25131 * @param {Roo.TabPanel} this
25132 * @param {Roo.TabPanelItem} activePanel The new active tab
25136 * @event beforetabchange
25137 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25138 * @param {Roo.TabPanel} this
25139 * @param {Object} e Set cancel to true on this object to cancel the tab change
25140 * @param {Roo.TabPanelItem} tab The tab being changed to
25142 "beforetabchange" : true
25145 Roo.EventManager.onWindowResize(this.onResize, this);
25146 this.cpad = this.el.getPadding("lr");
25147 this.hiddenCount = 0;
25149 Roo.TabPanel.superclass.constructor.call(this);
25152 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25154 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25156 tabPosition : "top",
25158 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25160 currentTabWidth : 0,
25162 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25166 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25170 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25172 preferredTabWidth : 175,
25174 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25176 resizeTabs : false,
25178 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25180 monitorResize : true,
25183 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25184 * @param {String} id The id of the div to use <b>or create</b>
25185 * @param {String} text The text for the tab
25186 * @param {String} content (optional) Content to put in the TabPanelItem body
25187 * @param {Boolean} closable (optional) True to create a close icon on the tab
25188 * @return {Roo.TabPanelItem} The created TabPanelItem
25190 addTab : function(id, text, content, closable){
25191 var item = new Roo.TabPanelItem(this, id, text, closable);
25192 this.addTabItem(item);
25194 item.setContent(content);
25200 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25201 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25202 * @return {Roo.TabPanelItem}
25204 getTab : function(id){
25205 return this.items[id];
25209 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25210 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25212 hideTab : function(id){
25213 var t = this.items[id];
25216 this.hiddenCount++;
25217 this.autoSizeTabs();
25222 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25223 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25225 unhideTab : function(id){
25226 var t = this.items[id];
25228 t.setHidden(false);
25229 this.hiddenCount--;
25230 this.autoSizeTabs();
25235 * Adds an existing {@link Roo.TabPanelItem}.
25236 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25238 addTabItem : function(item){
25239 this.items[item.id] = item;
25240 this.items.push(item);
25241 if(this.resizeTabs){
25242 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25243 this.autoSizeTabs();
25250 * Removes a {@link Roo.TabPanelItem}.
25251 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25253 removeTab : function(id){
25254 var items = this.items;
25255 var tab = items[id];
25256 if(!tab) { return; }
25257 var index = items.indexOf(tab);
25258 if(this.active == tab && items.length > 1){
25259 var newTab = this.getNextAvailable(index);
25264 this.stripEl.dom.removeChild(tab.pnode.dom);
25265 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25266 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25268 items.splice(index, 1);
25269 delete this.items[tab.id];
25270 tab.fireEvent("close", tab);
25271 tab.purgeListeners();
25272 this.autoSizeTabs();
25275 getNextAvailable : function(start){
25276 var items = this.items;
25278 // look for a next tab that will slide over to
25279 // replace the one being removed
25280 while(index < items.length){
25281 var item = items[++index];
25282 if(item && !item.isHidden()){
25286 // if one isn't found select the previous tab (on the left)
25289 var item = items[--index];
25290 if(item && !item.isHidden()){
25298 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25299 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25301 disableTab : function(id){
25302 var tab = this.items[id];
25303 if(tab && this.active != tab){
25309 * Enables a {@link Roo.TabPanelItem} that is disabled.
25310 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25312 enableTab : function(id){
25313 var tab = this.items[id];
25318 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25319 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25320 * @return {Roo.TabPanelItem} The TabPanelItem.
25322 activate : function(id){
25323 var tab = this.items[id];
25327 if(tab == this.active || tab.disabled){
25331 this.fireEvent("beforetabchange", this, e, tab);
25332 if(e.cancel !== true && !tab.disabled){
25334 this.active.hide();
25336 this.active = this.items[id];
25337 this.active.show();
25338 this.fireEvent("tabchange", this, this.active);
25344 * Gets the active {@link Roo.TabPanelItem}.
25345 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25347 getActiveTab : function(){
25348 return this.active;
25352 * Updates the tab body element to fit the height of the container element
25353 * for overflow scrolling
25354 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25356 syncHeight : function(targetHeight){
25357 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25358 var bm = this.bodyEl.getMargins();
25359 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25360 this.bodyEl.setHeight(newHeight);
25364 onResize : function(){
25365 if(this.monitorResize){
25366 this.autoSizeTabs();
25371 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25373 beginUpdate : function(){
25374 this.updating = true;
25378 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25380 endUpdate : function(){
25381 this.updating = false;
25382 this.autoSizeTabs();
25386 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25388 autoSizeTabs : function(){
25389 var count = this.items.length;
25390 var vcount = count - this.hiddenCount;
25391 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25392 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25393 var availWidth = Math.floor(w / vcount);
25394 var b = this.stripBody;
25395 if(b.getWidth() > w){
25396 var tabs = this.items;
25397 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25398 if(availWidth < this.minTabWidth){
25399 /*if(!this.sleft){ // incomplete scrolling code
25400 this.createScrollButtons();
25403 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25406 if(this.currentTabWidth < this.preferredTabWidth){
25407 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25413 * Returns the number of tabs in this TabPanel.
25416 getCount : function(){
25417 return this.items.length;
25421 * Resizes all the tabs to the passed width
25422 * @param {Number} The new width
25424 setTabWidth : function(width){
25425 this.currentTabWidth = width;
25426 for(var i = 0, len = this.items.length; i < len; i++) {
25427 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25432 * Destroys this TabPanel
25433 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25435 destroy : function(removeEl){
25436 Roo.EventManager.removeResizeListener(this.onResize, this);
25437 for(var i = 0, len = this.items.length; i < len; i++){
25438 this.items[i].purgeListeners();
25440 if(removeEl === true){
25441 this.el.update("");
25448 * @class Roo.TabPanelItem
25449 * @extends Roo.util.Observable
25450 * Represents an individual item (tab plus body) in a TabPanel.
25451 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25452 * @param {String} id The id of this TabPanelItem
25453 * @param {String} text The text for the tab of this TabPanelItem
25454 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25456 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25458 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25459 * @type Roo.TabPanel
25461 this.tabPanel = tabPanel;
25463 * The id for this TabPanelItem
25468 this.disabled = false;
25472 this.loaded = false;
25473 this.closable = closable;
25476 * The body element for this TabPanelItem.
25477 * @type Roo.Element
25479 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25480 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25481 this.bodyEl.setStyle("display", "block");
25482 this.bodyEl.setStyle("zoom", "1");
25485 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25487 this.el = Roo.get(els.el, true);
25488 this.inner = Roo.get(els.inner, true);
25489 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25490 this.pnode = Roo.get(els.el.parentNode, true);
25491 this.el.on("mousedown", this.onTabMouseDown, this);
25492 this.el.on("click", this.onTabClick, this);
25495 var c = Roo.get(els.close, true);
25496 c.dom.title = this.closeText;
25497 c.addClassOnOver("close-over");
25498 c.on("click", this.closeClick, this);
25504 * Fires when this tab becomes the active tab.
25505 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25506 * @param {Roo.TabPanelItem} this
25510 * @event beforeclose
25511 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25512 * @param {Roo.TabPanelItem} this
25513 * @param {Object} e Set cancel to true on this object to cancel the close.
25515 "beforeclose": true,
25518 * Fires when this tab is closed.
25519 * @param {Roo.TabPanelItem} this
25523 * @event deactivate
25524 * Fires when this tab is no longer the active tab.
25525 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25526 * @param {Roo.TabPanelItem} this
25528 "deactivate" : true
25530 this.hidden = false;
25532 Roo.TabPanelItem.superclass.constructor.call(this);
25535 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25536 purgeListeners : function(){
25537 Roo.util.Observable.prototype.purgeListeners.call(this);
25538 this.el.removeAllListeners();
25541 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25544 this.pnode.addClass("on");
25547 this.tabPanel.stripWrap.repaint();
25549 this.fireEvent("activate", this.tabPanel, this);
25553 * Returns true if this tab is the active tab.
25554 * @return {Boolean}
25556 isActive : function(){
25557 return this.tabPanel.getActiveTab() == this;
25561 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25564 this.pnode.removeClass("on");
25566 this.fireEvent("deactivate", this.tabPanel, this);
25569 hideAction : function(){
25570 this.bodyEl.hide();
25571 this.bodyEl.setStyle("position", "absolute");
25572 this.bodyEl.setLeft("-20000px");
25573 this.bodyEl.setTop("-20000px");
25576 showAction : function(){
25577 this.bodyEl.setStyle("position", "relative");
25578 this.bodyEl.setTop("");
25579 this.bodyEl.setLeft("");
25580 this.bodyEl.show();
25584 * Set the tooltip for the tab.
25585 * @param {String} tooltip The tab's tooltip
25587 setTooltip : function(text){
25588 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25589 this.textEl.dom.qtip = text;
25590 this.textEl.dom.removeAttribute('title');
25592 this.textEl.dom.title = text;
25596 onTabClick : function(e){
25597 e.preventDefault();
25598 this.tabPanel.activate(this.id);
25601 onTabMouseDown : function(e){
25602 e.preventDefault();
25603 this.tabPanel.activate(this.id);
25606 getWidth : function(){
25607 return this.inner.getWidth();
25610 setWidth : function(width){
25611 var iwidth = width - this.pnode.getPadding("lr");
25612 this.inner.setWidth(iwidth);
25613 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25614 this.pnode.setWidth(width);
25618 * Show or hide the tab
25619 * @param {Boolean} hidden True to hide or false to show.
25621 setHidden : function(hidden){
25622 this.hidden = hidden;
25623 this.pnode.setStyle("display", hidden ? "none" : "");
25627 * Returns true if this tab is "hidden"
25628 * @return {Boolean}
25630 isHidden : function(){
25631 return this.hidden;
25635 * Returns the text for this tab
25638 getText : function(){
25642 autoSize : function(){
25643 //this.el.beginMeasure();
25644 this.textEl.setWidth(1);
25645 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25646 //this.el.endMeasure();
25650 * Sets the text for the tab (Note: this also sets the tooltip text)
25651 * @param {String} text The tab's text and tooltip
25653 setText : function(text){
25655 this.textEl.update(text);
25656 this.setTooltip(text);
25657 if(!this.tabPanel.resizeTabs){
25662 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25664 activate : function(){
25665 this.tabPanel.activate(this.id);
25669 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25671 disable : function(){
25672 if(this.tabPanel.active != this){
25673 this.disabled = true;
25674 this.pnode.addClass("disabled");
25679 * Enables this TabPanelItem if it was previously disabled.
25681 enable : function(){
25682 this.disabled = false;
25683 this.pnode.removeClass("disabled");
25687 * Sets the content for this TabPanelItem.
25688 * @param {String} content The content
25689 * @param {Boolean} loadScripts true to look for and load scripts
25691 setContent : function(content, loadScripts){
25692 this.bodyEl.update(content, loadScripts);
25696 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25697 * @return {Roo.UpdateManager} The UpdateManager
25699 getUpdateManager : function(){
25700 return this.bodyEl.getUpdateManager();
25704 * Set a URL to be used to load the content for this TabPanelItem.
25705 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25706 * @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)
25707 * @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)
25708 * @return {Roo.UpdateManager} The UpdateManager
25710 setUrl : function(url, params, loadOnce){
25711 if(this.refreshDelegate){
25712 this.un('activate', this.refreshDelegate);
25714 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25715 this.on("activate", this.refreshDelegate);
25716 return this.bodyEl.getUpdateManager();
25720 _handleRefresh : function(url, params, loadOnce){
25721 if(!loadOnce || !this.loaded){
25722 var updater = this.bodyEl.getUpdateManager();
25723 updater.update(url, params, this._setLoaded.createDelegate(this));
25728 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25729 * Will fail silently if the setUrl method has not been called.
25730 * This does not activate the panel, just updates its content.
25732 refresh : function(){
25733 if(this.refreshDelegate){
25734 this.loaded = false;
25735 this.refreshDelegate();
25740 _setLoaded : function(){
25741 this.loaded = true;
25745 closeClick : function(e){
25748 this.fireEvent("beforeclose", this, o);
25749 if(o.cancel !== true){
25750 this.tabPanel.removeTab(this.id);
25754 * The text displayed in the tooltip for the close icon.
25757 closeText : "Close this tab"
25761 Roo.TabPanel.prototype.createStrip = function(container){
25762 var strip = document.createElement("div");
25763 strip.className = "x-tabs-wrap";
25764 container.appendChild(strip);
25768 Roo.TabPanel.prototype.createStripList = function(strip){
25769 // div wrapper for retard IE
25770 strip.innerHTML = '<div class="x-tabs-strip-wrap"><table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
25771 return strip.firstChild.firstChild.firstChild.firstChild;
25774 Roo.TabPanel.prototype.createBody = function(container){
25775 var body = document.createElement("div");
25776 Roo.id(body, "tab-body");
25777 Roo.fly(body).addClass("x-tabs-body");
25778 container.appendChild(body);
25782 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25783 var body = Roo.getDom(id);
25785 body = document.createElement("div");
25788 Roo.fly(body).addClass("x-tabs-item-body");
25789 bodyEl.insertBefore(body, bodyEl.firstChild);
25793 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25794 var td = document.createElement("td");
25795 stripEl.appendChild(td);
25797 td.className = "x-tabs-closable";
25798 if(!this.closeTpl){
25799 this.closeTpl = new Roo.Template(
25800 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25801 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25802 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25805 var el = this.closeTpl.overwrite(td, {"text": text});
25806 var close = el.getElementsByTagName("div")[0];
25807 var inner = el.getElementsByTagName("em")[0];
25808 return {"el": el, "close": close, "inner": inner};
25811 this.tabTpl = new Roo.Template(
25812 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25813 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25816 var el = this.tabTpl.overwrite(td, {"text": text});
25817 var inner = el.getElementsByTagName("em")[0];
25818 return {"el": el, "inner": inner};
25822 * Ext JS Library 1.1.1
25823 * Copyright(c) 2006-2007, Ext JS, LLC.
25825 * Originally Released Under LGPL - original licence link has changed is not relivant.
25828 * <script type="text/javascript">
25832 * @class Roo.Button
25833 * @extends Roo.util.Observable
25834 * Simple Button class
25835 * @cfg {String} text The button text
25836 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25837 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25838 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25839 * @cfg {Object} scope The scope of the handler
25840 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25841 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25842 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25843 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25844 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25845 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25846 applies if enableToggle = true)
25847 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25848 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25849 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25851 * Create a new button
25852 * @param {Object} config The config object
25854 Roo.Button = function(renderTo, config)
25858 renderTo = config.renderTo || false;
25861 Roo.apply(this, config);
25865 * Fires when this button is clicked
25866 * @param {Button} this
25867 * @param {EventObject} e The click event
25872 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25873 * @param {Button} this
25874 * @param {Boolean} pressed
25879 * Fires when the mouse hovers over the button
25880 * @param {Button} this
25881 * @param {Event} e The event object
25883 'mouseover' : true,
25886 * Fires when the mouse exits the button
25887 * @param {Button} this
25888 * @param {Event} e The event object
25893 * Fires when the button is rendered
25894 * @param {Button} this
25899 this.menu = Roo.menu.MenuMgr.get(this.menu);
25901 // register listeners first!! - so render can be captured..
25902 Roo.util.Observable.call(this);
25904 this.render(renderTo);
25910 Roo.extend(Roo.Button, Roo.util.Observable, {
25916 * Read-only. True if this button is hidden
25921 * Read-only. True if this button is disabled
25926 * Read-only. True if this button is pressed (only if enableToggle = true)
25932 * @cfg {Number} tabIndex
25933 * The DOM tabIndex for this button (defaults to undefined)
25935 tabIndex : undefined,
25938 * @cfg {Boolean} enableToggle
25939 * True to enable pressed/not pressed toggling (defaults to false)
25941 enableToggle: false,
25943 * @cfg {Mixed} menu
25944 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
25948 * @cfg {String} menuAlign
25949 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
25951 menuAlign : "tl-bl?",
25954 * @cfg {String} iconCls
25955 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
25957 iconCls : undefined,
25959 * @cfg {String} type
25960 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
25965 menuClassTarget: 'tr',
25968 * @cfg {String} clickEvent
25969 * The type of event to map to the button's event handler (defaults to 'click')
25971 clickEvent : 'click',
25974 * @cfg {Boolean} handleMouseEvents
25975 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
25977 handleMouseEvents : true,
25980 * @cfg {String} tooltipType
25981 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
25983 tooltipType : 'qtip',
25986 * @cfg {String} cls
25987 * A CSS class to apply to the button's main element.
25991 * @cfg {Roo.Template} template (Optional)
25992 * An {@link Roo.Template} with which to create the Button's main element. This Template must
25993 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
25994 * require code modifications if required elements (e.g. a button) aren't present.
25998 render : function(renderTo){
26000 if(this.hideParent){
26001 this.parentEl = Roo.get(renderTo);
26003 if(!this.dhconfig){
26004 if(!this.template){
26005 if(!Roo.Button.buttonTemplate){
26006 // hideous table template
26007 Roo.Button.buttonTemplate = new Roo.Template(
26008 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26009 '<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>',
26010 "</tr></tbody></table>");
26012 this.template = Roo.Button.buttonTemplate;
26014 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26015 var btnEl = btn.child("button:first");
26016 btnEl.on('focus', this.onFocus, this);
26017 btnEl.on('blur', this.onBlur, this);
26019 btn.addClass(this.cls);
26022 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26025 btnEl.addClass(this.iconCls);
26027 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26030 if(this.tabIndex !== undefined){
26031 btnEl.dom.tabIndex = this.tabIndex;
26034 if(typeof this.tooltip == 'object'){
26035 Roo.QuickTips.tips(Roo.apply({
26039 btnEl.dom[this.tooltipType] = this.tooltip;
26043 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26047 this.el.dom.id = this.el.id = this.id;
26050 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26051 this.menu.on("show", this.onMenuShow, this);
26052 this.menu.on("hide", this.onMenuHide, this);
26054 btn.addClass("x-btn");
26055 if(Roo.isIE && !Roo.isIE7){
26056 this.autoWidth.defer(1, this);
26060 if(this.handleMouseEvents){
26061 btn.on("mouseover", this.onMouseOver, this);
26062 btn.on("mouseout", this.onMouseOut, this);
26063 btn.on("mousedown", this.onMouseDown, this);
26065 btn.on(this.clickEvent, this.onClick, this);
26066 //btn.on("mouseup", this.onMouseUp, this);
26073 Roo.ButtonToggleMgr.register(this);
26075 this.el.addClass("x-btn-pressed");
26078 var repeater = new Roo.util.ClickRepeater(btn,
26079 typeof this.repeat == "object" ? this.repeat : {}
26081 repeater.on("click", this.onClick, this);
26084 this.fireEvent('render', this);
26088 * Returns the button's underlying element
26089 * @return {Roo.Element} The element
26091 getEl : function(){
26096 * Destroys this Button and removes any listeners.
26098 destroy : function(){
26099 Roo.ButtonToggleMgr.unregister(this);
26100 this.el.removeAllListeners();
26101 this.purgeListeners();
26106 autoWidth : function(){
26108 this.el.setWidth("auto");
26109 if(Roo.isIE7 && Roo.isStrict){
26110 var ib = this.el.child('button');
26111 if(ib && ib.getWidth() > 20){
26113 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26118 this.el.beginMeasure();
26120 if(this.el.getWidth() < this.minWidth){
26121 this.el.setWidth(this.minWidth);
26124 this.el.endMeasure();
26131 * Assigns this button's click handler
26132 * @param {Function} handler The function to call when the button is clicked
26133 * @param {Object} scope (optional) Scope for the function passed in
26135 setHandler : function(handler, scope){
26136 this.handler = handler;
26137 this.scope = scope;
26141 * Sets this button's text
26142 * @param {String} text The button text
26144 setText : function(text){
26147 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26153 * Gets the text for this button
26154 * @return {String} The button text
26156 getText : function(){
26164 this.hidden = false;
26166 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26174 this.hidden = true;
26176 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26181 * Convenience function for boolean show/hide
26182 * @param {Boolean} visible True to show, false to hide
26184 setVisible: function(visible){
26193 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26194 * @param {Boolean} state (optional) Force a particular state
26196 toggle : function(state){
26197 state = state === undefined ? !this.pressed : state;
26198 if(state != this.pressed){
26200 this.el.addClass("x-btn-pressed");
26201 this.pressed = true;
26202 this.fireEvent("toggle", this, true);
26204 this.el.removeClass("x-btn-pressed");
26205 this.pressed = false;
26206 this.fireEvent("toggle", this, false);
26208 if(this.toggleHandler){
26209 this.toggleHandler.call(this.scope || this, this, state);
26217 focus : function(){
26218 this.el.child('button:first').focus();
26222 * Disable this button
26224 disable : function(){
26226 this.el.addClass("x-btn-disabled");
26228 this.disabled = true;
26232 * Enable this button
26234 enable : function(){
26236 this.el.removeClass("x-btn-disabled");
26238 this.disabled = false;
26242 * Convenience function for boolean enable/disable
26243 * @param {Boolean} enabled True to enable, false to disable
26245 setDisabled : function(v){
26246 this[v !== true ? "enable" : "disable"]();
26250 onClick : function(e){
26252 e.preventDefault();
26257 if(!this.disabled){
26258 if(this.enableToggle){
26261 if(this.menu && !this.menu.isVisible()){
26262 this.menu.show(this.el, this.menuAlign);
26264 this.fireEvent("click", this, e);
26266 this.el.removeClass("x-btn-over");
26267 this.handler.call(this.scope || this, this, e);
26272 onMouseOver : function(e){
26273 if(!this.disabled){
26274 this.el.addClass("x-btn-over");
26275 this.fireEvent('mouseover', this, e);
26279 onMouseOut : function(e){
26280 if(!e.within(this.el, true)){
26281 this.el.removeClass("x-btn-over");
26282 this.fireEvent('mouseout', this, e);
26286 onFocus : function(e){
26287 if(!this.disabled){
26288 this.el.addClass("x-btn-focus");
26292 onBlur : function(e){
26293 this.el.removeClass("x-btn-focus");
26296 onMouseDown : function(e){
26297 if(!this.disabled && e.button == 0){
26298 this.el.addClass("x-btn-click");
26299 Roo.get(document).on('mouseup', this.onMouseUp, this);
26303 onMouseUp : function(e){
26305 this.el.removeClass("x-btn-click");
26306 Roo.get(document).un('mouseup', this.onMouseUp, this);
26310 onMenuShow : function(e){
26311 this.el.addClass("x-btn-menu-active");
26314 onMenuHide : function(e){
26315 this.el.removeClass("x-btn-menu-active");
26319 // Private utility class used by Button
26320 Roo.ButtonToggleMgr = function(){
26323 function toggleGroup(btn, state){
26325 var g = groups[btn.toggleGroup];
26326 for(var i = 0, l = g.length; i < l; i++){
26328 g[i].toggle(false);
26335 register : function(btn){
26336 if(!btn.toggleGroup){
26339 var g = groups[btn.toggleGroup];
26341 g = groups[btn.toggleGroup] = [];
26344 btn.on("toggle", toggleGroup);
26347 unregister : function(btn){
26348 if(!btn.toggleGroup){
26351 var g = groups[btn.toggleGroup];
26354 btn.un("toggle", toggleGroup);
26360 * Ext JS Library 1.1.1
26361 * Copyright(c) 2006-2007, Ext JS, LLC.
26363 * Originally Released Under LGPL - original licence link has changed is not relivant.
26366 * <script type="text/javascript">
26370 * @class Roo.SplitButton
26371 * @extends Roo.Button
26372 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26373 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26374 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26375 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26376 * @cfg {String} arrowTooltip The title attribute of the arrow
26378 * Create a new menu button
26379 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26380 * @param {Object} config The config object
26382 Roo.SplitButton = function(renderTo, config){
26383 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26385 * @event arrowclick
26386 * Fires when this button's arrow is clicked
26387 * @param {SplitButton} this
26388 * @param {EventObject} e The click event
26390 this.addEvents({"arrowclick":true});
26393 Roo.extend(Roo.SplitButton, Roo.Button, {
26394 render : function(renderTo){
26395 // this is one sweet looking template!
26396 var tpl = new Roo.Template(
26397 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26398 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26399 '<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>',
26400 "</tbody></table></td><td>",
26401 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26402 '<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>',
26403 "</tbody></table></td></tr></table>"
26405 var btn = tpl.append(renderTo, [this.text, this.type], true);
26406 var btnEl = btn.child("button");
26408 btn.addClass(this.cls);
26411 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26414 btnEl.addClass(this.iconCls);
26416 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26420 if(this.handleMouseEvents){
26421 btn.on("mouseover", this.onMouseOver, this);
26422 btn.on("mouseout", this.onMouseOut, this);
26423 btn.on("mousedown", this.onMouseDown, this);
26424 btn.on("mouseup", this.onMouseUp, this);
26426 btn.on(this.clickEvent, this.onClick, this);
26428 if(typeof this.tooltip == 'object'){
26429 Roo.QuickTips.tips(Roo.apply({
26433 btnEl.dom[this.tooltipType] = this.tooltip;
26436 if(this.arrowTooltip){
26437 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26446 this.el.addClass("x-btn-pressed");
26448 if(Roo.isIE && !Roo.isIE7){
26449 this.autoWidth.defer(1, this);
26454 this.menu.on("show", this.onMenuShow, this);
26455 this.menu.on("hide", this.onMenuHide, this);
26457 this.fireEvent('render', this);
26461 autoWidth : function(){
26463 var tbl = this.el.child("table:first");
26464 var tbl2 = this.el.child("table:last");
26465 this.el.setWidth("auto");
26466 tbl.setWidth("auto");
26467 if(Roo.isIE7 && Roo.isStrict){
26468 var ib = this.el.child('button:first');
26469 if(ib && ib.getWidth() > 20){
26471 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26476 this.el.beginMeasure();
26478 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26479 tbl.setWidth(this.minWidth-tbl2.getWidth());
26482 this.el.endMeasure();
26485 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26489 * Sets this button's click handler
26490 * @param {Function} handler The function to call when the button is clicked
26491 * @param {Object} scope (optional) Scope for the function passed above
26493 setHandler : function(handler, scope){
26494 this.handler = handler;
26495 this.scope = scope;
26499 * Sets this button's arrow click handler
26500 * @param {Function} handler The function to call when the arrow is clicked
26501 * @param {Object} scope (optional) Scope for the function passed above
26503 setArrowHandler : function(handler, scope){
26504 this.arrowHandler = handler;
26505 this.scope = scope;
26511 focus : function(){
26513 this.el.child("button:first").focus();
26518 onClick : function(e){
26519 e.preventDefault();
26520 if(!this.disabled){
26521 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26522 if(this.menu && !this.menu.isVisible()){
26523 this.menu.show(this.el, this.menuAlign);
26525 this.fireEvent("arrowclick", this, e);
26526 if(this.arrowHandler){
26527 this.arrowHandler.call(this.scope || this, this, e);
26530 this.fireEvent("click", this, e);
26532 this.handler.call(this.scope || this, this, e);
26538 onMouseDown : function(e){
26539 if(!this.disabled){
26540 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26544 onMouseUp : function(e){
26545 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26550 // backwards compat
26551 Roo.MenuButton = Roo.SplitButton;/*
26553 * Ext JS Library 1.1.1
26554 * Copyright(c) 2006-2007, Ext JS, LLC.
26556 * Originally Released Under LGPL - original licence link has changed is not relivant.
26559 * <script type="text/javascript">
26563 * @class Roo.Toolbar
26564 * Basic Toolbar class.
26566 * Creates a new Toolbar
26567 * @param {Object} config The config object
26569 Roo.Toolbar = function(container, buttons, config)
26571 /// old consturctor format still supported..
26572 if(container instanceof Array){ // omit the container for later rendering
26573 buttons = container;
26577 if (typeof(container) == 'object' && container.xtype) {
26578 config = container;
26579 container = config.container;
26580 buttons = config.buttons; // not really - use items!!
26583 if (config && config.items) {
26584 xitems = config.items;
26585 delete config.items;
26587 Roo.apply(this, config);
26588 this.buttons = buttons;
26591 this.render(container);
26593 Roo.each(xitems, function(b) {
26599 Roo.Toolbar.prototype = {
26601 * @cfg {Roo.data.Store} items
26602 * array of button configs or elements to add
26606 * @cfg {String/HTMLElement/Element} container
26607 * The id or element that will contain the toolbar
26610 render : function(ct){
26611 this.el = Roo.get(ct);
26613 this.el.addClass(this.cls);
26615 // using a table allows for vertical alignment
26616 // 100% width is needed by Safari...
26617 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26618 this.tr = this.el.child("tr", true);
26620 this.items = new Roo.util.MixedCollection(false, function(o){
26621 return o.id || ("item" + (++autoId));
26624 this.add.apply(this, this.buttons);
26625 delete this.buttons;
26630 * Adds element(s) to the toolbar -- this function takes a variable number of
26631 * arguments of mixed type and adds them to the toolbar.
26632 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26634 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26635 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26636 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26637 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26638 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26639 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26640 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26641 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26642 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26644 * @param {Mixed} arg2
26645 * @param {Mixed} etc.
26648 var a = arguments, l = a.length;
26649 for(var i = 0; i < l; i++){
26654 _add : function(el) {
26657 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26660 if (el.applyTo){ // some kind of form field
26661 return this.addField(el);
26663 if (el.render){ // some kind of Toolbar.Item
26664 return this.addItem(el);
26666 if (typeof el == "string"){ // string
26667 if(el == "separator" || el == "-"){
26668 return this.addSeparator();
26671 return this.addSpacer();
26674 return this.addFill();
26676 return this.addText(el);
26679 if(el.tagName){ // element
26680 return this.addElement(el);
26682 if(typeof el == "object"){ // must be button config?
26683 return this.addButton(el);
26685 // and now what?!?!
26691 * Add an Xtype element
26692 * @param {Object} xtype Xtype Object
26693 * @return {Object} created Object
26695 addxtype : function(e){
26696 return this.add(e);
26700 * Returns the Element for this toolbar.
26701 * @return {Roo.Element}
26703 getEl : function(){
26709 * @return {Roo.Toolbar.Item} The separator item
26711 addSeparator : function(){
26712 return this.addItem(new Roo.Toolbar.Separator());
26716 * Adds a spacer element
26717 * @return {Roo.Toolbar.Spacer} The spacer item
26719 addSpacer : function(){
26720 return this.addItem(new Roo.Toolbar.Spacer());
26724 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26725 * @return {Roo.Toolbar.Fill} The fill item
26727 addFill : function(){
26728 return this.addItem(new Roo.Toolbar.Fill());
26732 * Adds any standard HTML element to the toolbar
26733 * @param {String/HTMLElement/Element} el The element or id of the element to add
26734 * @return {Roo.Toolbar.Item} The element's item
26736 addElement : function(el){
26737 return this.addItem(new Roo.Toolbar.Item(el));
26740 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26741 * @type Roo.util.MixedCollection
26746 * Adds any Toolbar.Item or subclass
26747 * @param {Roo.Toolbar.Item} item
26748 * @return {Roo.Toolbar.Item} The item
26750 addItem : function(item){
26751 var td = this.nextBlock();
26753 this.items.add(item);
26758 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26759 * @param {Object/Array} config A button config or array of configs
26760 * @return {Roo.Toolbar.Button/Array}
26762 addButton : function(config){
26763 if(config instanceof Array){
26765 for(var i = 0, len = config.length; i < len; i++) {
26766 buttons.push(this.addButton(config[i]));
26771 if(!(config instanceof Roo.Toolbar.Button)){
26773 new Roo.Toolbar.SplitButton(config) :
26774 new Roo.Toolbar.Button(config);
26776 var td = this.nextBlock();
26783 * Adds text to the toolbar
26784 * @param {String} text The text to add
26785 * @return {Roo.Toolbar.Item} The element's item
26787 addText : function(text){
26788 return this.addItem(new Roo.Toolbar.TextItem(text));
26792 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26793 * @param {Number} index The index where the item is to be inserted
26794 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26795 * @return {Roo.Toolbar.Button/Item}
26797 insertButton : function(index, item){
26798 if(item instanceof Array){
26800 for(var i = 0, len = item.length; i < len; i++) {
26801 buttons.push(this.insertButton(index + i, item[i]));
26805 if (!(item instanceof Roo.Toolbar.Button)){
26806 item = new Roo.Toolbar.Button(item);
26808 var td = document.createElement("td");
26809 this.tr.insertBefore(td, this.tr.childNodes[index]);
26811 this.items.insert(index, item);
26816 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26817 * @param {Object} config
26818 * @return {Roo.Toolbar.Item} The element's item
26820 addDom : function(config, returnEl){
26821 var td = this.nextBlock();
26822 Roo.DomHelper.overwrite(td, config);
26823 var ti = new Roo.Toolbar.Item(td.firstChild);
26825 this.items.add(ti);
26830 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26831 * @type Roo.util.MixedCollection
26836 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26837 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26838 * @param {Roo.form.Field} field
26839 * @return {Roo.ToolbarItem}
26843 addField : function(field) {
26844 if (!this.fields) {
26846 this.fields = new Roo.util.MixedCollection(false, function(o){
26847 return o.id || ("item" + (++autoId));
26852 var td = this.nextBlock();
26854 var ti = new Roo.Toolbar.Item(td.firstChild);
26856 this.items.add(ti);
26857 this.fields.add(field);
26868 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26869 this.el.child('div').hide();
26877 this.el.child('div').show();
26881 nextBlock : function(){
26882 var td = document.createElement("td");
26883 this.tr.appendChild(td);
26888 destroy : function(){
26889 if(this.items){ // rendered?
26890 Roo.destroy.apply(Roo, this.items.items);
26892 if(this.fields){ // rendered?
26893 Roo.destroy.apply(Roo, this.fields.items);
26895 Roo.Element.uncache(this.el, this.tr);
26900 * @class Roo.Toolbar.Item
26901 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26903 * Creates a new Item
26904 * @param {HTMLElement} el
26906 Roo.Toolbar.Item = function(el){
26907 this.el = Roo.getDom(el);
26908 this.id = Roo.id(this.el);
26909 this.hidden = false;
26912 Roo.Toolbar.Item.prototype = {
26915 * Get this item's HTML Element
26916 * @return {HTMLElement}
26918 getEl : function(){
26923 render : function(td){
26925 td.appendChild(this.el);
26929 * Removes and destroys this item.
26931 destroy : function(){
26932 this.td.parentNode.removeChild(this.td);
26939 this.hidden = false;
26940 this.td.style.display = "";
26947 this.hidden = true;
26948 this.td.style.display = "none";
26952 * Convenience function for boolean show/hide.
26953 * @param {Boolean} visible true to show/false to hide
26955 setVisible: function(visible){
26964 * Try to focus this item.
26966 focus : function(){
26967 Roo.fly(this.el).focus();
26971 * Disables this item.
26973 disable : function(){
26974 Roo.fly(this.td).addClass("x-item-disabled");
26975 this.disabled = true;
26976 this.el.disabled = true;
26980 * Enables this item.
26982 enable : function(){
26983 Roo.fly(this.td).removeClass("x-item-disabled");
26984 this.disabled = false;
26985 this.el.disabled = false;
26991 * @class Roo.Toolbar.Separator
26992 * @extends Roo.Toolbar.Item
26993 * A simple toolbar separator class
26995 * Creates a new Separator
26997 Roo.Toolbar.Separator = function(){
26998 var s = document.createElement("span");
26999 s.className = "ytb-sep";
27000 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27002 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27003 enable:Roo.emptyFn,
27004 disable:Roo.emptyFn,
27009 * @class Roo.Toolbar.Spacer
27010 * @extends Roo.Toolbar.Item
27011 * A simple element that adds extra horizontal space to a toolbar.
27013 * Creates a new Spacer
27015 Roo.Toolbar.Spacer = function(){
27016 var s = document.createElement("div");
27017 s.className = "ytb-spacer";
27018 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27020 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27021 enable:Roo.emptyFn,
27022 disable:Roo.emptyFn,
27027 * @class Roo.Toolbar.Fill
27028 * @extends Roo.Toolbar.Spacer
27029 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27031 * Creates a new Spacer
27033 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27035 render : function(td){
27036 td.style.width = '100%';
27037 Roo.Toolbar.Fill.superclass.render.call(this, td);
27042 * @class Roo.Toolbar.TextItem
27043 * @extends Roo.Toolbar.Item
27044 * A simple class that renders text directly into a toolbar.
27046 * Creates a new TextItem
27047 * @param {String} text
27049 Roo.Toolbar.TextItem = function(text){
27050 if (typeof(text) == 'object') {
27053 var s = document.createElement("span");
27054 s.className = "ytb-text";
27055 s.innerHTML = text;
27056 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27058 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27059 enable:Roo.emptyFn,
27060 disable:Roo.emptyFn,
27065 * @class Roo.Toolbar.Button
27066 * @extends Roo.Button
27067 * A button that renders into a toolbar.
27069 * Creates a new Button
27070 * @param {Object} config A standard {@link Roo.Button} config object
27072 Roo.Toolbar.Button = function(config){
27073 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27075 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27076 render : function(td){
27078 Roo.Toolbar.Button.superclass.render.call(this, td);
27082 * Removes and destroys this button
27084 destroy : function(){
27085 Roo.Toolbar.Button.superclass.destroy.call(this);
27086 this.td.parentNode.removeChild(this.td);
27090 * Shows this button
27093 this.hidden = false;
27094 this.td.style.display = "";
27098 * Hides this button
27101 this.hidden = true;
27102 this.td.style.display = "none";
27106 * Disables this item
27108 disable : function(){
27109 Roo.fly(this.td).addClass("x-item-disabled");
27110 this.disabled = true;
27114 * Enables this item
27116 enable : function(){
27117 Roo.fly(this.td).removeClass("x-item-disabled");
27118 this.disabled = false;
27121 // backwards compat
27122 Roo.ToolbarButton = Roo.Toolbar.Button;
27125 * @class Roo.Toolbar.SplitButton
27126 * @extends Roo.SplitButton
27127 * A menu button that renders into a toolbar.
27129 * Creates a new SplitButton
27130 * @param {Object} config A standard {@link Roo.SplitButton} config object
27132 Roo.Toolbar.SplitButton = function(config){
27133 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27135 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27136 render : function(td){
27138 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27142 * Removes and destroys this button
27144 destroy : function(){
27145 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27146 this.td.parentNode.removeChild(this.td);
27150 * Shows this button
27153 this.hidden = false;
27154 this.td.style.display = "";
27158 * Hides this button
27161 this.hidden = true;
27162 this.td.style.display = "none";
27166 // backwards compat
27167 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27169 * Ext JS Library 1.1.1
27170 * Copyright(c) 2006-2007, Ext JS, LLC.
27172 * Originally Released Under LGPL - original licence link has changed is not relivant.
27175 * <script type="text/javascript">
27179 * @class Roo.PagingToolbar
27180 * @extends Roo.Toolbar
27181 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27183 * Create a new PagingToolbar
27184 * @param {Object} config The config object
27186 Roo.PagingToolbar = function(el, ds, config)
27188 // old args format still supported... - xtype is prefered..
27189 if (typeof(el) == 'object' && el.xtype) {
27190 // created from xtype...
27192 ds = el.dataSource;
27193 el = config.container;
27196 if (config.items) {
27197 items = config.items;
27201 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27204 this.renderButtons(this.el);
27207 // supprot items array.
27209 Roo.each(items, function(e) {
27210 this.add(Roo.factory(e));
27215 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27217 * @cfg {Roo.data.Store} dataSource
27218 * The underlying data store providing the paged data
27221 * @cfg {String/HTMLElement/Element} container
27222 * container The id or element that will contain the toolbar
27225 * @cfg {Boolean} displayInfo
27226 * True to display the displayMsg (defaults to false)
27229 * @cfg {Number} pageSize
27230 * The number of records to display per page (defaults to 20)
27234 * @cfg {String} displayMsg
27235 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27237 displayMsg : 'Displaying {0} - {1} of {2}',
27239 * @cfg {String} emptyMsg
27240 * The message to display when no records are found (defaults to "No data to display")
27242 emptyMsg : 'No data to display',
27244 * Customizable piece of the default paging text (defaults to "Page")
27247 beforePageText : "Page",
27249 * Customizable piece of the default paging text (defaults to "of %0")
27252 afterPageText : "of {0}",
27254 * Customizable piece of the default paging text (defaults to "First Page")
27257 firstText : "First Page",
27259 * Customizable piece of the default paging text (defaults to "Previous Page")
27262 prevText : "Previous Page",
27264 * Customizable piece of the default paging text (defaults to "Next Page")
27267 nextText : "Next Page",
27269 * Customizable piece of the default paging text (defaults to "Last Page")
27272 lastText : "Last Page",
27274 * Customizable piece of the default paging text (defaults to "Refresh")
27277 refreshText : "Refresh",
27280 renderButtons : function(el){
27281 Roo.PagingToolbar.superclass.render.call(this, el);
27282 this.first = this.addButton({
27283 tooltip: this.firstText,
27284 cls: "x-btn-icon x-grid-page-first",
27286 handler: this.onClick.createDelegate(this, ["first"])
27288 this.prev = this.addButton({
27289 tooltip: this.prevText,
27290 cls: "x-btn-icon x-grid-page-prev",
27292 handler: this.onClick.createDelegate(this, ["prev"])
27294 //this.addSeparator();
27295 this.add(this.beforePageText);
27296 this.field = Roo.get(this.addDom({
27301 cls: "x-grid-page-number"
27303 this.field.on("keydown", this.onPagingKeydown, this);
27304 this.field.on("focus", function(){this.dom.select();});
27305 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27306 this.field.setHeight(18);
27307 //this.addSeparator();
27308 this.next = this.addButton({
27309 tooltip: this.nextText,
27310 cls: "x-btn-icon x-grid-page-next",
27312 handler: this.onClick.createDelegate(this, ["next"])
27314 this.last = this.addButton({
27315 tooltip: this.lastText,
27316 cls: "x-btn-icon x-grid-page-last",
27318 handler: this.onClick.createDelegate(this, ["last"])
27320 //this.addSeparator();
27321 this.loading = this.addButton({
27322 tooltip: this.refreshText,
27323 cls: "x-btn-icon x-grid-loading",
27324 handler: this.onClick.createDelegate(this, ["refresh"])
27327 if(this.displayInfo){
27328 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27333 updateInfo : function(){
27334 if(this.displayEl){
27335 var count = this.ds.getCount();
27336 var msg = count == 0 ?
27340 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27342 this.displayEl.update(msg);
27347 onLoad : function(ds, r, o){
27348 this.cursor = o.params ? o.params.start : 0;
27349 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27351 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27352 this.field.dom.value = ap;
27353 this.first.setDisabled(ap == 1);
27354 this.prev.setDisabled(ap == 1);
27355 this.next.setDisabled(ap == ps);
27356 this.last.setDisabled(ap == ps);
27357 this.loading.enable();
27362 getPageData : function(){
27363 var total = this.ds.getTotalCount();
27366 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27367 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27372 onLoadError : function(){
27373 this.loading.enable();
27377 onPagingKeydown : function(e){
27378 var k = e.getKey();
27379 var d = this.getPageData();
27381 var v = this.field.dom.value, pageNum;
27382 if(!v || isNaN(pageNum = parseInt(v, 10))){
27383 this.field.dom.value = d.activePage;
27386 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27387 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27390 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))
27392 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27393 this.field.dom.value = pageNum;
27394 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27397 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27399 var v = this.field.dom.value, pageNum;
27400 var increment = (e.shiftKey) ? 10 : 1;
27401 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27403 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27404 this.field.dom.value = d.activePage;
27407 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27409 this.field.dom.value = parseInt(v, 10) + increment;
27410 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27411 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27418 beforeLoad : function(){
27420 this.loading.disable();
27425 onClick : function(which){
27429 ds.load({params:{start: 0, limit: this.pageSize}});
27432 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27435 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27438 var total = ds.getTotalCount();
27439 var extra = total % this.pageSize;
27440 var lastStart = extra ? (total - extra) : total-this.pageSize;
27441 ds.load({params:{start: lastStart, limit: this.pageSize}});
27444 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27450 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27451 * @param {Roo.data.Store} store The data store to unbind
27453 unbind : function(ds){
27454 ds.un("beforeload", this.beforeLoad, this);
27455 ds.un("load", this.onLoad, this);
27456 ds.un("loadexception", this.onLoadError, this);
27457 ds.un("remove", this.updateInfo, this);
27458 ds.un("add", this.updateInfo, this);
27459 this.ds = undefined;
27463 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27464 * @param {Roo.data.Store} store The data store to bind
27466 bind : function(ds){
27467 ds.on("beforeload", this.beforeLoad, this);
27468 ds.on("load", this.onLoad, this);
27469 ds.on("loadexception", this.onLoadError, this);
27470 ds.on("remove", this.updateInfo, this);
27471 ds.on("add", this.updateInfo, this);
27476 * Ext JS Library 1.1.1
27477 * Copyright(c) 2006-2007, Ext JS, LLC.
27479 * Originally Released Under LGPL - original licence link has changed is not relivant.
27482 * <script type="text/javascript">
27486 * @class Roo.Resizable
27487 * @extends Roo.util.Observable
27488 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27489 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27490 * 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
27491 * the element will be wrapped for you automatically.</p>
27492 * <p>Here is the list of valid resize handles:</p>
27495 ------ -------------------
27504 'hd' horizontal drag
27507 * <p>Here's an example showing the creation of a typical Resizable:</p>
27509 var resizer = new Roo.Resizable("element-id", {
27517 resizer.on("resize", myHandler);
27519 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27520 * resizer.east.setDisplayed(false);</p>
27521 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27522 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27523 * resize operation's new size (defaults to [0, 0])
27524 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27525 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27526 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27527 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27528 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27529 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27530 * @cfg {Number} width The width of the element in pixels (defaults to null)
27531 * @cfg {Number} height The height of the element in pixels (defaults to null)
27532 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27533 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27534 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27535 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27536 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27537 * in favor of the handles config option (defaults to false)
27538 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27539 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27540 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27541 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27542 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27543 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27544 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27545 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27546 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27547 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27548 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27550 * Create a new resizable component
27551 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27552 * @param {Object} config configuration options
27554 Roo.Resizable = function(el, config)
27556 this.el = Roo.get(el);
27558 if(config && config.wrap){
27559 config.resizeChild = this.el;
27560 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27561 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27562 this.el.setStyle("overflow", "hidden");
27563 this.el.setPositioning(config.resizeChild.getPositioning());
27564 config.resizeChild.clearPositioning();
27565 if(!config.width || !config.height){
27566 var csize = config.resizeChild.getSize();
27567 this.el.setSize(csize.width, csize.height);
27569 if(config.pinned && !config.adjustments){
27570 config.adjustments = "auto";
27574 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27575 this.proxy.unselectable();
27576 this.proxy.enableDisplayMode('block');
27578 Roo.apply(this, config);
27581 this.disableTrackOver = true;
27582 this.el.addClass("x-resizable-pinned");
27584 // if the element isn't positioned, make it relative
27585 var position = this.el.getStyle("position");
27586 if(position != "absolute" && position != "fixed"){
27587 this.el.setStyle("position", "relative");
27589 if(!this.handles){ // no handles passed, must be legacy style
27590 this.handles = 's,e,se';
27591 if(this.multiDirectional){
27592 this.handles += ',n,w';
27595 if(this.handles == "all"){
27596 this.handles = "n s e w ne nw se sw";
27598 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27599 var ps = Roo.Resizable.positions;
27600 for(var i = 0, len = hs.length; i < len; i++){
27601 if(hs[i] && ps[hs[i]]){
27602 var pos = ps[hs[i]];
27603 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27607 this.corner = this.southeast;
27609 // updateBox = the box can move..
27610 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27611 this.updateBox = true;
27614 this.activeHandle = null;
27616 if(this.resizeChild){
27617 if(typeof this.resizeChild == "boolean"){
27618 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27620 this.resizeChild = Roo.get(this.resizeChild, true);
27624 if(this.adjustments == "auto"){
27625 var rc = this.resizeChild;
27626 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27627 if(rc && (hw || hn)){
27628 rc.position("relative");
27629 rc.setLeft(hw ? hw.el.getWidth() : 0);
27630 rc.setTop(hn ? hn.el.getHeight() : 0);
27632 this.adjustments = [
27633 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27634 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27638 if(this.draggable){
27639 this.dd = this.dynamic ?
27640 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27641 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27647 * @event beforeresize
27648 * Fired before resize is allowed. Set enabled to false to cancel resize.
27649 * @param {Roo.Resizable} this
27650 * @param {Roo.EventObject} e The mousedown event
27652 "beforeresize" : true,
27655 * Fired after a resize.
27656 * @param {Roo.Resizable} this
27657 * @param {Number} width The new width
27658 * @param {Number} height The new height
27659 * @param {Roo.EventObject} e The mouseup event
27664 if(this.width !== null && this.height !== null){
27665 this.resizeTo(this.width, this.height);
27667 this.updateChildSize();
27670 this.el.dom.style.zoom = 1;
27672 Roo.Resizable.superclass.constructor.call(this);
27675 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27676 resizeChild : false,
27677 adjustments : [0, 0],
27687 multiDirectional : false,
27688 disableTrackOver : false,
27689 easing : 'easeOutStrong',
27690 widthIncrement : 0,
27691 heightIncrement : 0,
27695 preserveRatio : false,
27696 transparent: false,
27702 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27704 constrainTo: undefined,
27706 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27708 resizeRegion: undefined,
27712 * Perform a manual resize
27713 * @param {Number} width
27714 * @param {Number} height
27716 resizeTo : function(width, height){
27717 this.el.setSize(width, height);
27718 this.updateChildSize();
27719 this.fireEvent("resize", this, width, height, null);
27723 startSizing : function(e, handle){
27724 this.fireEvent("beforeresize", this, e);
27725 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27728 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27729 this.overlay.unselectable();
27730 this.overlay.enableDisplayMode("block");
27731 this.overlay.on("mousemove", this.onMouseMove, this);
27732 this.overlay.on("mouseup", this.onMouseUp, this);
27734 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27736 this.resizing = true;
27737 this.startBox = this.el.getBox();
27738 this.startPoint = e.getXY();
27739 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27740 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27742 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27743 this.overlay.show();
27745 if(this.constrainTo) {
27746 var ct = Roo.get(this.constrainTo);
27747 this.resizeRegion = ct.getRegion().adjust(
27748 ct.getFrameWidth('t'),
27749 ct.getFrameWidth('l'),
27750 -ct.getFrameWidth('b'),
27751 -ct.getFrameWidth('r')
27755 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27757 this.proxy.setBox(this.startBox);
27759 this.proxy.setStyle('visibility', 'visible');
27765 onMouseDown : function(handle, e){
27768 this.activeHandle = handle;
27769 this.startSizing(e, handle);
27774 onMouseUp : function(e){
27775 var size = this.resizeElement();
27776 this.resizing = false;
27778 this.overlay.hide();
27780 this.fireEvent("resize", this, size.width, size.height, e);
27784 updateChildSize : function(){
27785 if(this.resizeChild){
27787 var child = this.resizeChild;
27788 var adj = this.adjustments;
27789 if(el.dom.offsetWidth){
27790 var b = el.getSize(true);
27791 child.setSize(b.width+adj[0], b.height+adj[1]);
27793 // Second call here for IE
27794 // The first call enables instant resizing and
27795 // the second call corrects scroll bars if they
27798 setTimeout(function(){
27799 if(el.dom.offsetWidth){
27800 var b = el.getSize(true);
27801 child.setSize(b.width+adj[0], b.height+adj[1]);
27809 snap : function(value, inc, min){
27810 if(!inc || !value) return value;
27811 var newValue = value;
27812 var m = value % inc;
27815 newValue = value + (inc-m);
27817 newValue = value - m;
27820 return Math.max(min, newValue);
27824 resizeElement : function(){
27825 var box = this.proxy.getBox();
27826 if(this.updateBox){
27827 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27829 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27831 this.updateChildSize();
27839 constrain : function(v, diff, m, mx){
27842 }else if(v - diff > mx){
27849 onMouseMove : function(e){
27851 try{// try catch so if something goes wrong the user doesn't get hung
27853 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27857 //var curXY = this.startPoint;
27858 var curSize = this.curSize || this.startBox;
27859 var x = this.startBox.x, y = this.startBox.y;
27860 var ox = x, oy = y;
27861 var w = curSize.width, h = curSize.height;
27862 var ow = w, oh = h;
27863 var mw = this.minWidth, mh = this.minHeight;
27864 var mxw = this.maxWidth, mxh = this.maxHeight;
27865 var wi = this.widthIncrement;
27866 var hi = this.heightIncrement;
27868 var eventXY = e.getXY();
27869 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27870 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27872 var pos = this.activeHandle.position;
27877 w = Math.min(Math.max(mw, w), mxw);
27882 h = Math.min(Math.max(mh, h), mxh);
27887 w = Math.min(Math.max(mw, w), mxw);
27888 h = Math.min(Math.max(mh, h), mxh);
27891 diffY = this.constrain(h, diffY, mh, mxh);
27898 var adiffX = Math.abs(diffX);
27899 var sub = (adiffX % wi); // how much
27900 if (sub > (wi/2)) { // far enough to snap
27901 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
27903 // remove difference..
27904 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
27908 x = Math.max(this.minX, x);
27911 diffX = this.constrain(w, diffX, mw, mxw);
27917 w = Math.min(Math.max(mw, w), mxw);
27918 diffY = this.constrain(h, diffY, mh, mxh);
27923 diffX = this.constrain(w, diffX, mw, mxw);
27924 diffY = this.constrain(h, diffY, mh, mxh);
27931 diffX = this.constrain(w, diffX, mw, mxw);
27933 h = Math.min(Math.max(mh, h), mxh);
27939 var sw = this.snap(w, wi, mw);
27940 var sh = this.snap(h, hi, mh);
27941 if(sw != w || sh != h){
27964 if(this.preserveRatio){
27969 h = Math.min(Math.max(mh, h), mxh);
27974 w = Math.min(Math.max(mw, w), mxw);
27979 w = Math.min(Math.max(mw, w), mxw);
27985 w = Math.min(Math.max(mw, w), mxw);
27991 h = Math.min(Math.max(mh, h), mxh);
27999 h = Math.min(Math.max(mh, h), mxh);
28009 h = Math.min(Math.max(mh, h), mxh);
28017 if (pos == 'hdrag') {
28020 this.proxy.setBounds(x, y, w, h);
28022 this.resizeElement();
28029 handleOver : function(){
28031 this.el.addClass("x-resizable-over");
28036 handleOut : function(){
28037 if(!this.resizing){
28038 this.el.removeClass("x-resizable-over");
28043 * Returns the element this component is bound to.
28044 * @return {Roo.Element}
28046 getEl : function(){
28051 * Returns the resizeChild element (or null).
28052 * @return {Roo.Element}
28054 getResizeChild : function(){
28055 return this.resizeChild;
28059 * Destroys this resizable. If the element was wrapped and
28060 * removeEl is not true then the element remains.
28061 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28063 destroy : function(removeEl){
28064 this.proxy.remove();
28066 this.overlay.removeAllListeners();
28067 this.overlay.remove();
28069 var ps = Roo.Resizable.positions;
28071 if(typeof ps[k] != "function" && this[ps[k]]){
28072 var h = this[ps[k]];
28073 h.el.removeAllListeners();
28078 this.el.update("");
28085 // hash to map config positions to true positions
28086 Roo.Resizable.positions = {
28087 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28092 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28094 // only initialize the template if resizable is used
28095 var tpl = Roo.DomHelper.createTemplate(
28096 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28099 Roo.Resizable.Handle.prototype.tpl = tpl;
28101 this.position = pos;
28103 // show north drag fro topdra
28104 var handlepos = pos == 'hdrag' ? 'north' : pos;
28106 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28107 if (pos == 'hdrag') {
28108 this.el.setStyle('cursor', 'pointer');
28110 this.el.unselectable();
28112 this.el.setOpacity(0);
28114 this.el.on("mousedown", this.onMouseDown, this);
28115 if(!disableTrackOver){
28116 this.el.on("mouseover", this.onMouseOver, this);
28117 this.el.on("mouseout", this.onMouseOut, this);
28122 Roo.Resizable.Handle.prototype = {
28123 afterResize : function(rz){
28127 onMouseDown : function(e){
28128 this.rz.onMouseDown(this, e);
28131 onMouseOver : function(e){
28132 this.rz.handleOver(this, e);
28135 onMouseOut : function(e){
28136 this.rz.handleOut(this, e);
28140 * Ext JS Library 1.1.1
28141 * Copyright(c) 2006-2007, Ext JS, LLC.
28143 * Originally Released Under LGPL - original licence link has changed is not relivant.
28146 * <script type="text/javascript">
28150 * @class Roo.Editor
28151 * @extends Roo.Component
28152 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28154 * Create a new Editor
28155 * @param {Roo.form.Field} field The Field object (or descendant)
28156 * @param {Object} config The config object
28158 Roo.Editor = function(field, config){
28159 Roo.Editor.superclass.constructor.call(this, config);
28160 this.field = field;
28163 * @event beforestartedit
28164 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28165 * false from the handler of this event.
28166 * @param {Editor} this
28167 * @param {Roo.Element} boundEl The underlying element bound to this editor
28168 * @param {Mixed} value The field value being set
28170 "beforestartedit" : true,
28173 * Fires when this editor is displayed
28174 * @param {Roo.Element} boundEl The underlying element bound to this editor
28175 * @param {Mixed} value The starting field value
28177 "startedit" : true,
28179 * @event beforecomplete
28180 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28181 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28182 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28183 * event will not fire since no edit actually occurred.
28184 * @param {Editor} this
28185 * @param {Mixed} value The current field value
28186 * @param {Mixed} startValue The original field value
28188 "beforecomplete" : true,
28191 * Fires after editing is complete and any changed value has been written to the underlying field.
28192 * @param {Editor} this
28193 * @param {Mixed} value The current field value
28194 * @param {Mixed} startValue The original field value
28198 * @event specialkey
28199 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28200 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28201 * @param {Roo.form.Field} this
28202 * @param {Roo.EventObject} e The event object
28204 "specialkey" : true
28208 Roo.extend(Roo.Editor, Roo.Component, {
28210 * @cfg {Boolean/String} autosize
28211 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28212 * or "height" to adopt the height only (defaults to false)
28215 * @cfg {Boolean} revertInvalid
28216 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28217 * validation fails (defaults to true)
28220 * @cfg {Boolean} ignoreNoChange
28221 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28222 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28223 * will never be ignored.
28226 * @cfg {Boolean} hideEl
28227 * False to keep the bound element visible while the editor is displayed (defaults to true)
28230 * @cfg {Mixed} value
28231 * The data value of the underlying field (defaults to "")
28235 * @cfg {String} alignment
28236 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28240 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28241 * for bottom-right shadow (defaults to "frame")
28245 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28249 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28251 completeOnEnter : false,
28253 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28255 cancelOnEsc : false,
28257 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28262 onRender : function(ct, position){
28263 this.el = new Roo.Layer({
28264 shadow: this.shadow,
28270 constrain: this.constrain
28272 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28273 if(this.field.msgTarget != 'title'){
28274 this.field.msgTarget = 'qtip';
28276 this.field.render(this.el);
28278 this.field.el.dom.setAttribute('autocomplete', 'off');
28280 this.field.on("specialkey", this.onSpecialKey, this);
28281 if(this.swallowKeys){
28282 this.field.el.swallowEvent(['keydown','keypress']);
28285 this.field.on("blur", this.onBlur, this);
28286 if(this.field.grow){
28287 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28291 onSpecialKey : function(field, e){
28292 //Roo.log('editor onSpecialKey');
28293 if(this.completeOnEnter && e.getKey() == e.ENTER){
28295 this.completeEdit();
28296 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
28299 this.fireEvent('specialkey', field, e);
28304 * Starts the editing process and shows the editor.
28305 * @param {String/HTMLElement/Element} el The element to edit
28306 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28307 * to the innerHTML of el.
28309 startEdit : function(el, value){
28311 this.completeEdit();
28313 this.boundEl = Roo.get(el);
28314 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28315 if(!this.rendered){
28316 this.render(this.parentEl || document.body);
28318 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28321 this.startValue = v;
28322 this.field.setValue(v);
28324 var sz = this.boundEl.getSize();
28325 switch(this.autoSize){
28327 this.setSize(sz.width, "");
28330 this.setSize("", sz.height);
28333 this.setSize(sz.width, sz.height);
28336 this.el.alignTo(this.boundEl, this.alignment);
28337 this.editing = true;
28339 Roo.QuickTips.disable();
28345 * Sets the height and width of this editor.
28346 * @param {Number} width The new width
28347 * @param {Number} height The new height
28349 setSize : function(w, h){
28350 this.field.setSize(w, h);
28357 * Realigns the editor to the bound field based on the current alignment config value.
28359 realign : function(){
28360 this.el.alignTo(this.boundEl, this.alignment);
28364 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28365 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28367 completeEdit : function(remainVisible){
28371 var v = this.getValue();
28372 if(this.revertInvalid !== false && !this.field.isValid()){
28373 v = this.startValue;
28374 this.cancelEdit(true);
28376 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28377 this.editing = false;
28381 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28382 this.editing = false;
28383 if(this.updateEl && this.boundEl){
28384 this.boundEl.update(v);
28386 if(remainVisible !== true){
28389 this.fireEvent("complete", this, v, this.startValue);
28394 onShow : function(){
28396 if(this.hideEl !== false){
28397 this.boundEl.hide();
28400 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28401 this.fixIEFocus = true;
28402 this.deferredFocus.defer(50, this);
28404 this.field.focus();
28406 this.fireEvent("startedit", this.boundEl, this.startValue);
28409 deferredFocus : function(){
28411 this.field.focus();
28416 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28417 * reverted to the original starting value.
28418 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28419 * cancel (defaults to false)
28421 cancelEdit : function(remainVisible){
28423 this.setValue(this.startValue);
28424 if(remainVisible !== true){
28431 onBlur : function(){
28432 if(this.allowBlur !== true && this.editing){
28433 this.completeEdit();
28438 onHide : function(){
28440 this.completeEdit();
28444 if(this.field.collapse){
28445 this.field.collapse();
28448 if(this.hideEl !== false){
28449 this.boundEl.show();
28452 Roo.QuickTips.enable();
28457 * Sets the data value of the editor
28458 * @param {Mixed} value Any valid value supported by the underlying field
28460 setValue : function(v){
28461 this.field.setValue(v);
28465 * Gets the data value of the editor
28466 * @return {Mixed} The data value
28468 getValue : function(){
28469 return this.field.getValue();
28473 * Ext JS Library 1.1.1
28474 * Copyright(c) 2006-2007, Ext JS, LLC.
28476 * Originally Released Under LGPL - original licence link has changed is not relivant.
28479 * <script type="text/javascript">
28483 * @class Roo.BasicDialog
28484 * @extends Roo.util.Observable
28485 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28487 var dlg = new Roo.BasicDialog("my-dlg", {
28496 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28497 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28498 dlg.addButton('Cancel', dlg.hide, dlg);
28501 <b>A Dialog should always be a direct child of the body element.</b>
28502 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28503 * @cfg {String} title Default text to display in the title bar (defaults to null)
28504 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28505 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28506 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28507 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28508 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28509 * (defaults to null with no animation)
28510 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28511 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28512 * property for valid values (defaults to 'all')
28513 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28514 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28515 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28516 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28517 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28518 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28519 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28520 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28521 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28522 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28523 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28524 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28525 * draggable = true (defaults to false)
28526 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28527 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28528 * shadow (defaults to false)
28529 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28530 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28531 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28532 * @cfg {Array} buttons Array of buttons
28533 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28535 * Create a new BasicDialog.
28536 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28537 * @param {Object} config Configuration options
28539 Roo.BasicDialog = function(el, config){
28540 this.el = Roo.get(el);
28541 var dh = Roo.DomHelper;
28542 if(!this.el && config && config.autoCreate){
28543 if(typeof config.autoCreate == "object"){
28544 if(!config.autoCreate.id){
28545 config.autoCreate.id = el;
28547 this.el = dh.append(document.body,
28548 config.autoCreate, true);
28550 this.el = dh.append(document.body,
28551 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28555 el.setDisplayed(true);
28556 el.hide = this.hideAction;
28558 el.addClass("x-dlg");
28560 Roo.apply(this, config);
28562 this.proxy = el.createProxy("x-dlg-proxy");
28563 this.proxy.hide = this.hideAction;
28564 this.proxy.setOpacity(.5);
28568 el.setWidth(config.width);
28571 el.setHeight(config.height);
28573 this.size = el.getSize();
28574 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28575 this.xy = [config.x,config.y];
28577 this.xy = el.getCenterXY(true);
28579 /** The header element @type Roo.Element */
28580 this.header = el.child("> .x-dlg-hd");
28581 /** The body element @type Roo.Element */
28582 this.body = el.child("> .x-dlg-bd");
28583 /** The footer element @type Roo.Element */
28584 this.footer = el.child("> .x-dlg-ft");
28587 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28590 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28593 this.header.unselectable();
28595 this.header.update(this.title);
28597 // this element allows the dialog to be focused for keyboard event
28598 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28599 this.focusEl.swallowEvent("click", true);
28601 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28603 // wrap the body and footer for special rendering
28604 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28606 this.bwrap.dom.appendChild(this.footer.dom);
28609 this.bg = this.el.createChild({
28610 tag: "div", cls:"x-dlg-bg",
28611 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28613 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28616 if(this.autoScroll !== false && !this.autoTabs){
28617 this.body.setStyle("overflow", "auto");
28620 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28622 if(this.closable !== false){
28623 this.el.addClass("x-dlg-closable");
28624 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28625 this.close.on("click", this.closeClick, this);
28626 this.close.addClassOnOver("x-dlg-close-over");
28628 if(this.collapsible !== false){
28629 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28630 this.collapseBtn.on("click", this.collapseClick, this);
28631 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28632 this.header.on("dblclick", this.collapseClick, this);
28634 if(this.resizable !== false){
28635 this.el.addClass("x-dlg-resizable");
28636 this.resizer = new Roo.Resizable(el, {
28637 minWidth: this.minWidth || 80,
28638 minHeight:this.minHeight || 80,
28639 handles: this.resizeHandles || "all",
28642 this.resizer.on("beforeresize", this.beforeResize, this);
28643 this.resizer.on("resize", this.onResize, this);
28645 if(this.draggable !== false){
28646 el.addClass("x-dlg-draggable");
28647 if (!this.proxyDrag) {
28648 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28651 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28653 dd.setHandleElId(this.header.id);
28654 dd.endDrag = this.endMove.createDelegate(this);
28655 dd.startDrag = this.startMove.createDelegate(this);
28656 dd.onDrag = this.onDrag.createDelegate(this);
28661 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28662 this.mask.enableDisplayMode("block");
28664 this.el.addClass("x-dlg-modal");
28667 this.shadow = new Roo.Shadow({
28668 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28669 offset : this.shadowOffset
28672 this.shadowOffset = 0;
28674 if(Roo.useShims && this.shim !== false){
28675 this.shim = this.el.createShim();
28676 this.shim.hide = this.hideAction;
28684 if (this.buttons) {
28685 var bts= this.buttons;
28687 Roo.each(bts, function(b) {
28696 * Fires when a key is pressed
28697 * @param {Roo.BasicDialog} this
28698 * @param {Roo.EventObject} e
28703 * Fires when this dialog is moved by the user.
28704 * @param {Roo.BasicDialog} this
28705 * @param {Number} x The new page X
28706 * @param {Number} y The new page Y
28711 * Fires when this dialog is resized by the user.
28712 * @param {Roo.BasicDialog} this
28713 * @param {Number} width The new width
28714 * @param {Number} height The new height
28718 * @event beforehide
28719 * Fires before this dialog is hidden.
28720 * @param {Roo.BasicDialog} this
28722 "beforehide" : true,
28725 * Fires when this dialog is hidden.
28726 * @param {Roo.BasicDialog} this
28730 * @event beforeshow
28731 * Fires before this dialog is shown.
28732 * @param {Roo.BasicDialog} this
28734 "beforeshow" : true,
28737 * Fires when this dialog is shown.
28738 * @param {Roo.BasicDialog} this
28742 el.on("keydown", this.onKeyDown, this);
28743 el.on("mousedown", this.toFront, this);
28744 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28746 Roo.DialogManager.register(this);
28747 Roo.BasicDialog.superclass.constructor.call(this);
28750 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28751 shadowOffset: Roo.isIE ? 6 : 5,
28754 minButtonWidth: 75,
28755 defaultButton: null,
28756 buttonAlign: "right",
28761 * Sets the dialog title text
28762 * @param {String} text The title text to display
28763 * @return {Roo.BasicDialog} this
28765 setTitle : function(text){
28766 this.header.update(text);
28771 closeClick : function(){
28776 collapseClick : function(){
28777 this[this.collapsed ? "expand" : "collapse"]();
28781 * Collapses the dialog to its minimized state (only the title bar is visible).
28782 * Equivalent to the user clicking the collapse dialog button.
28784 collapse : function(){
28785 if(!this.collapsed){
28786 this.collapsed = true;
28787 this.el.addClass("x-dlg-collapsed");
28788 this.restoreHeight = this.el.getHeight();
28789 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28794 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28795 * clicking the expand dialog button.
28797 expand : function(){
28798 if(this.collapsed){
28799 this.collapsed = false;
28800 this.el.removeClass("x-dlg-collapsed");
28801 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28806 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28807 * @return {Roo.TabPanel} The tabs component
28809 initTabs : function(){
28810 var tabs = this.getTabs();
28811 while(tabs.getTab(0)){
28814 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28816 tabs.addTab(Roo.id(dom), dom.title);
28824 beforeResize : function(){
28825 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28829 onResize : function(){
28830 this.refreshSize();
28831 this.syncBodyHeight();
28832 this.adjustAssets();
28834 this.fireEvent("resize", this, this.size.width, this.size.height);
28838 onKeyDown : function(e){
28839 if(this.isVisible()){
28840 this.fireEvent("keydown", this, e);
28845 * Resizes the dialog.
28846 * @param {Number} width
28847 * @param {Number} height
28848 * @return {Roo.BasicDialog} this
28850 resizeTo : function(width, height){
28851 this.el.setSize(width, height);
28852 this.size = {width: width, height: height};
28853 this.syncBodyHeight();
28854 if(this.fixedcenter){
28857 if(this.isVisible()){
28858 this.constrainXY();
28859 this.adjustAssets();
28861 this.fireEvent("resize", this, width, height);
28867 * Resizes the dialog to fit the specified content size.
28868 * @param {Number} width
28869 * @param {Number} height
28870 * @return {Roo.BasicDialog} this
28872 setContentSize : function(w, h){
28873 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28874 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28875 //if(!this.el.isBorderBox()){
28876 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28877 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28880 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28881 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28883 this.resizeTo(w, h);
28888 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28889 * executed in response to a particular key being pressed while the dialog is active.
28890 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28891 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28892 * @param {Function} fn The function to call
28893 * @param {Object} scope (optional) The scope of the function
28894 * @return {Roo.BasicDialog} this
28896 addKeyListener : function(key, fn, scope){
28897 var keyCode, shift, ctrl, alt;
28898 if(typeof key == "object" && !(key instanceof Array)){
28899 keyCode = key["key"];
28900 shift = key["shift"];
28901 ctrl = key["ctrl"];
28906 var handler = function(dlg, e){
28907 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
28908 var k = e.getKey();
28909 if(keyCode instanceof Array){
28910 for(var i = 0, len = keyCode.length; i < len; i++){
28911 if(keyCode[i] == k){
28912 fn.call(scope || window, dlg, k, e);
28918 fn.call(scope || window, dlg, k, e);
28923 this.on("keydown", handler);
28928 * Returns the TabPanel component (creates it if it doesn't exist).
28929 * Note: If you wish to simply check for the existence of tabs without creating them,
28930 * check for a null 'tabs' property.
28931 * @return {Roo.TabPanel} The tabs component
28933 getTabs : function(){
28935 this.el.addClass("x-dlg-auto-tabs");
28936 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
28937 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
28943 * Adds a button to the footer section of the dialog.
28944 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28945 * object or a valid Roo.DomHelper element config
28946 * @param {Function} handler The function called when the button is clicked
28947 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
28948 * @return {Roo.Button} The new button
28950 addButton : function(config, handler, scope){
28951 var dh = Roo.DomHelper;
28953 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
28955 if(!this.btnContainer){
28956 var tb = this.footer.createChild({
28958 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
28959 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28961 this.btnContainer = tb.firstChild.firstChild.firstChild;
28966 minWidth: this.minButtonWidth,
28969 if(typeof config == "string"){
28970 bconfig.text = config;
28973 bconfig.dhconfig = config;
28975 Roo.apply(bconfig, config);
28979 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
28980 bconfig.position = Math.max(0, bconfig.position);
28981 fc = this.btnContainer.childNodes[bconfig.position];
28984 var btn = new Roo.Button(
28986 this.btnContainer.insertBefore(document.createElement("td"),fc)
28987 : this.btnContainer.appendChild(document.createElement("td")),
28988 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
28991 this.syncBodyHeight();
28994 * Array of all the buttons that have been added to this dialog via addButton
28999 this.buttons.push(btn);
29004 * Sets the default button to be focused when the dialog is displayed.
29005 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29006 * @return {Roo.BasicDialog} this
29008 setDefaultButton : function(btn){
29009 this.defaultButton = btn;
29014 getHeaderFooterHeight : function(safe){
29017 height += this.header.getHeight();
29020 var fm = this.footer.getMargins();
29021 height += (this.footer.getHeight()+fm.top+fm.bottom);
29023 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29024 height += this.centerBg.getPadding("tb");
29029 syncBodyHeight : function(){
29030 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29031 var height = this.size.height - this.getHeaderFooterHeight(false);
29032 bd.setHeight(height-bd.getMargins("tb"));
29033 var hh = this.header.getHeight();
29034 var h = this.size.height-hh;
29036 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29037 bw.setHeight(h-cb.getPadding("tb"));
29038 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29039 bd.setWidth(bw.getWidth(true));
29041 this.tabs.syncHeight();
29043 this.tabs.el.repaint();
29049 * Restores the previous state of the dialog if Roo.state is configured.
29050 * @return {Roo.BasicDialog} this
29052 restoreState : function(){
29053 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29054 if(box && box.width){
29055 this.xy = [box.x, box.y];
29056 this.resizeTo(box.width, box.height);
29062 beforeShow : function(){
29064 if(this.fixedcenter){
29065 this.xy = this.el.getCenterXY(true);
29068 Roo.get(document.body).addClass("x-body-masked");
29069 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29072 this.constrainXY();
29076 animShow : function(){
29077 var b = Roo.get(this.animateTarget).getBox();
29078 this.proxy.setSize(b.width, b.height);
29079 this.proxy.setLocation(b.x, b.y);
29081 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29082 true, .35, this.showEl.createDelegate(this));
29086 * Shows the dialog.
29087 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29088 * @return {Roo.BasicDialog} this
29090 show : function(animateTarget){
29091 if (this.fireEvent("beforeshow", this) === false){
29094 if(this.syncHeightBeforeShow){
29095 this.syncBodyHeight();
29096 }else if(this.firstShow){
29097 this.firstShow = false;
29098 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29100 this.animateTarget = animateTarget || this.animateTarget;
29101 if(!this.el.isVisible()){
29103 if(this.animateTarget && Roo.get(this.animateTarget)){
29113 showEl : function(){
29115 this.el.setXY(this.xy);
29117 this.adjustAssets(true);
29120 // IE peekaboo bug - fix found by Dave Fenwick
29124 this.fireEvent("show", this);
29128 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29129 * dialog itself will receive focus.
29131 focus : function(){
29132 if(this.defaultButton){
29133 this.defaultButton.focus();
29135 this.focusEl.focus();
29140 constrainXY : function(){
29141 if(this.constraintoviewport !== false){
29142 if(!this.viewSize){
29143 if(this.container){
29144 var s = this.container.getSize();
29145 this.viewSize = [s.width, s.height];
29147 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29150 var s = Roo.get(this.container||document).getScroll();
29152 var x = this.xy[0], y = this.xy[1];
29153 var w = this.size.width, h = this.size.height;
29154 var vw = this.viewSize[0], vh = this.viewSize[1];
29155 // only move it if it needs it
29157 // first validate right/bottom
29158 if(x + w > vw+s.left){
29162 if(y + h > vh+s.top){
29166 // then make sure top/left isn't negative
29178 if(this.isVisible()){
29179 this.el.setLocation(x, y);
29180 this.adjustAssets();
29187 onDrag : function(){
29188 if(!this.proxyDrag){
29189 this.xy = this.el.getXY();
29190 this.adjustAssets();
29195 adjustAssets : function(doShow){
29196 var x = this.xy[0], y = this.xy[1];
29197 var w = this.size.width, h = this.size.height;
29198 if(doShow === true){
29200 this.shadow.show(this.el);
29206 if(this.shadow && this.shadow.isVisible()){
29207 this.shadow.show(this.el);
29209 if(this.shim && this.shim.isVisible()){
29210 this.shim.setBounds(x, y, w, h);
29215 adjustViewport : function(w, h){
29217 w = Roo.lib.Dom.getViewWidth();
29218 h = Roo.lib.Dom.getViewHeight();
29221 this.viewSize = [w, h];
29222 if(this.modal && this.mask.isVisible()){
29223 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29224 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29226 if(this.isVisible()){
29227 this.constrainXY();
29232 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29233 * shadow, proxy, mask, etc.) Also removes all event listeners.
29234 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29236 destroy : function(removeEl){
29237 if(this.isVisible()){
29238 this.animateTarget = null;
29241 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29243 this.tabs.destroy(removeEl);
29256 for(var i = 0, len = this.buttons.length; i < len; i++){
29257 this.buttons[i].destroy();
29260 this.el.removeAllListeners();
29261 if(removeEl === true){
29262 this.el.update("");
29265 Roo.DialogManager.unregister(this);
29269 startMove : function(){
29270 if(this.proxyDrag){
29273 if(this.constraintoviewport !== false){
29274 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29279 endMove : function(){
29280 if(!this.proxyDrag){
29281 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29283 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29286 this.refreshSize();
29287 this.adjustAssets();
29289 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29293 * Brings this dialog to the front of any other visible dialogs
29294 * @return {Roo.BasicDialog} this
29296 toFront : function(){
29297 Roo.DialogManager.bringToFront(this);
29302 * Sends this dialog to the back (under) of any other visible dialogs
29303 * @return {Roo.BasicDialog} this
29305 toBack : function(){
29306 Roo.DialogManager.sendToBack(this);
29311 * Centers this dialog in the viewport
29312 * @return {Roo.BasicDialog} this
29314 center : function(){
29315 var xy = this.el.getCenterXY(true);
29316 this.moveTo(xy[0], xy[1]);
29321 * Moves the dialog's top-left corner to the specified point
29322 * @param {Number} x
29323 * @param {Number} y
29324 * @return {Roo.BasicDialog} this
29326 moveTo : function(x, y){
29328 if(this.isVisible()){
29329 this.el.setXY(this.xy);
29330 this.adjustAssets();
29336 * Aligns the dialog to the specified element
29337 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29338 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29339 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29340 * @return {Roo.BasicDialog} this
29342 alignTo : function(element, position, offsets){
29343 this.xy = this.el.getAlignToXY(element, position, offsets);
29344 if(this.isVisible()){
29345 this.el.setXY(this.xy);
29346 this.adjustAssets();
29352 * Anchors an element to another element and realigns it when the window is resized.
29353 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29354 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29355 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29356 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29357 * is a number, it is used as the buffer delay (defaults to 50ms).
29358 * @return {Roo.BasicDialog} this
29360 anchorTo : function(el, alignment, offsets, monitorScroll){
29361 var action = function(){
29362 this.alignTo(el, alignment, offsets);
29364 Roo.EventManager.onWindowResize(action, this);
29365 var tm = typeof monitorScroll;
29366 if(tm != 'undefined'){
29367 Roo.EventManager.on(window, 'scroll', action, this,
29368 {buffer: tm == 'number' ? monitorScroll : 50});
29375 * Returns true if the dialog is visible
29376 * @return {Boolean}
29378 isVisible : function(){
29379 return this.el.isVisible();
29383 animHide : function(callback){
29384 var b = Roo.get(this.animateTarget).getBox();
29386 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29388 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29389 this.hideEl.createDelegate(this, [callback]));
29393 * Hides the dialog.
29394 * @param {Function} callback (optional) Function to call when the dialog is hidden
29395 * @return {Roo.BasicDialog} this
29397 hide : function(callback){
29398 if (this.fireEvent("beforehide", this) === false){
29402 this.shadow.hide();
29407 // sometimes animateTarget seems to get set.. causing problems...
29408 // this just double checks..
29409 if(this.animateTarget && Roo.get(this.animateTarget)) {
29410 this.animHide(callback);
29413 this.hideEl(callback);
29419 hideEl : function(callback){
29423 Roo.get(document.body).removeClass("x-body-masked");
29425 this.fireEvent("hide", this);
29426 if(typeof callback == "function"){
29432 hideAction : function(){
29433 this.setLeft("-10000px");
29434 this.setTop("-10000px");
29435 this.setStyle("visibility", "hidden");
29439 refreshSize : function(){
29440 this.size = this.el.getSize();
29441 this.xy = this.el.getXY();
29442 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29446 // z-index is managed by the DialogManager and may be overwritten at any time
29447 setZIndex : function(index){
29449 this.mask.setStyle("z-index", index);
29452 this.shim.setStyle("z-index", ++index);
29455 this.shadow.setZIndex(++index);
29457 this.el.setStyle("z-index", ++index);
29459 this.proxy.setStyle("z-index", ++index);
29462 this.resizer.proxy.setStyle("z-index", ++index);
29465 this.lastZIndex = index;
29469 * Returns the element for this dialog
29470 * @return {Roo.Element} The underlying dialog Element
29472 getEl : function(){
29478 * @class Roo.DialogManager
29479 * Provides global access to BasicDialogs that have been created and
29480 * support for z-indexing (layering) multiple open dialogs.
29482 Roo.DialogManager = function(){
29484 var accessList = [];
29488 var sortDialogs = function(d1, d2){
29489 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29493 var orderDialogs = function(){
29494 accessList.sort(sortDialogs);
29495 var seed = Roo.DialogManager.zseed;
29496 for(var i = 0, len = accessList.length; i < len; i++){
29497 var dlg = accessList[i];
29499 dlg.setZIndex(seed + (i*10));
29506 * The starting z-index for BasicDialogs (defaults to 9000)
29507 * @type Number The z-index value
29512 register : function(dlg){
29513 list[dlg.id] = dlg;
29514 accessList.push(dlg);
29518 unregister : function(dlg){
29519 delete list[dlg.id];
29522 if(!accessList.indexOf){
29523 for( i = 0, len = accessList.length; i < len; i++){
29524 if(accessList[i] == dlg){
29525 accessList.splice(i, 1);
29530 i = accessList.indexOf(dlg);
29532 accessList.splice(i, 1);
29538 * Gets a registered dialog by id
29539 * @param {String/Object} id The id of the dialog or a dialog
29540 * @return {Roo.BasicDialog} this
29542 get : function(id){
29543 return typeof id == "object" ? id : list[id];
29547 * Brings the specified dialog to the front
29548 * @param {String/Object} dlg The id of the dialog or a dialog
29549 * @return {Roo.BasicDialog} this
29551 bringToFront : function(dlg){
29552 dlg = this.get(dlg);
29555 dlg._lastAccess = new Date().getTime();
29562 * Sends the specified dialog to the back
29563 * @param {String/Object} dlg The id of the dialog or a dialog
29564 * @return {Roo.BasicDialog} this
29566 sendToBack : function(dlg){
29567 dlg = this.get(dlg);
29568 dlg._lastAccess = -(new Date().getTime());
29574 * Hides all dialogs
29576 hideAll : function(){
29577 for(var id in list){
29578 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29587 * @class Roo.LayoutDialog
29588 * @extends Roo.BasicDialog
29589 * Dialog which provides adjustments for working with a layout in a Dialog.
29590 * Add your necessary layout config options to the dialog's config.<br>
29591 * Example usage (including a nested layout):
29594 dialog = new Roo.LayoutDialog("download-dlg", {
29603 // layout config merges with the dialog config
29605 tabPosition: "top",
29606 alwaysShowTabs: true
29609 dialog.addKeyListener(27, dialog.hide, dialog);
29610 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29611 dialog.addButton("Build It!", this.getDownload, this);
29613 // we can even add nested layouts
29614 var innerLayout = new Roo.BorderLayout("dl-inner", {
29624 innerLayout.beginUpdate();
29625 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29626 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29627 innerLayout.endUpdate(true);
29629 var layout = dialog.getLayout();
29630 layout.beginUpdate();
29631 layout.add("center", new Roo.ContentPanel("standard-panel",
29632 {title: "Download the Source", fitToFrame:true}));
29633 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29634 {title: "Build your own roo.js"}));
29635 layout.getRegion("center").showPanel(sp);
29636 layout.endUpdate();
29640 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29641 * @param {Object} config configuration options
29643 Roo.LayoutDialog = function(el, cfg){
29646 if (typeof(cfg) == 'undefined') {
29647 config = Roo.apply({}, el);
29648 // not sure why we use documentElement here.. - it should always be body.
29649 // IE7 borks horribly if we use documentElement.
29650 el = Roo.get( Roo.isIE ? (document.body || document.documentElement) : (document.documentElement || document.body) ).createChild();
29651 //config.autoCreate = true;
29655 config.autoTabs = false;
29656 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29657 this.body.setStyle({overflow:"hidden", position:"relative"});
29658 this.layout = new Roo.BorderLayout(this.body.dom, config);
29659 this.layout.monitorWindowResize = false;
29660 this.el.addClass("x-dlg-auto-layout");
29661 // fix case when center region overwrites center function
29662 this.center = Roo.BasicDialog.prototype.center;
29663 this.on("show", this.layout.layout, this.layout, true);
29664 if (config.items) {
29665 var xitems = config.items;
29666 delete config.items;
29667 Roo.each(xitems, this.addxtype, this);
29672 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29674 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29677 endUpdate : function(){
29678 this.layout.endUpdate();
29682 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29685 beginUpdate : function(){
29686 this.layout.beginUpdate();
29690 * Get the BorderLayout for this dialog
29691 * @return {Roo.BorderLayout}
29693 getLayout : function(){
29694 return this.layout;
29697 showEl : function(){
29698 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29700 this.layout.layout();
29705 // Use the syncHeightBeforeShow config option to control this automatically
29706 syncBodyHeight : function(){
29707 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29708 if(this.layout){this.layout.layout();}
29712 * Add an xtype element (actually adds to the layout.)
29713 * @return {Object} xdata xtype object data.
29716 addxtype : function(c) {
29717 return this.layout.addxtype(c);
29721 * Ext JS Library 1.1.1
29722 * Copyright(c) 2006-2007, Ext JS, LLC.
29724 * Originally Released Under LGPL - original licence link has changed is not relivant.
29727 * <script type="text/javascript">
29731 * @class Roo.MessageBox
29732 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29736 Roo.Msg.alert('Status', 'Changes saved successfully.');
29738 // Prompt for user data:
29739 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29741 // process text value...
29745 // Show a dialog using config options:
29747 title:'Save Changes?',
29748 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29749 buttons: Roo.Msg.YESNOCANCEL,
29756 Roo.MessageBox = function(){
29757 var dlg, opt, mask, waitTimer;
29758 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29759 var buttons, activeTextEl, bwidth;
29762 var handleButton = function(button){
29764 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29768 var handleHide = function(){
29769 if(opt && opt.cls){
29770 dlg.el.removeClass(opt.cls);
29773 Roo.TaskMgr.stop(waitTimer);
29779 var updateButtons = function(b){
29782 buttons["ok"].hide();
29783 buttons["cancel"].hide();
29784 buttons["yes"].hide();
29785 buttons["no"].hide();
29786 dlg.footer.dom.style.display = 'none';
29789 dlg.footer.dom.style.display = '';
29790 for(var k in buttons){
29791 if(typeof buttons[k] != "function"){
29794 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29795 width += buttons[k].el.getWidth()+15;
29805 var handleEsc = function(d, k, e){
29806 if(opt && opt.closable !== false){
29816 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29817 * @return {Roo.BasicDialog} The BasicDialog element
29819 getDialog : function(){
29821 dlg = new Roo.BasicDialog("x-msg-box", {
29826 constraintoviewport:false,
29828 collapsible : false,
29831 width:400, height:100,
29832 buttonAlign:"center",
29833 closeClick : function(){
29834 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29835 handleButton("no");
29837 handleButton("cancel");
29841 dlg.on("hide", handleHide);
29843 dlg.addKeyListener(27, handleEsc);
29845 var bt = this.buttonText;
29846 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29847 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29848 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29849 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29850 bodyEl = dlg.body.createChild({
29852 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>'
29854 msgEl = bodyEl.dom.firstChild;
29855 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29856 textboxEl.enableDisplayMode();
29857 textboxEl.addKeyListener([10,13], function(){
29858 if(dlg.isVisible() && opt && opt.buttons){
29859 if(opt.buttons.ok){
29860 handleButton("ok");
29861 }else if(opt.buttons.yes){
29862 handleButton("yes");
29866 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29867 textareaEl.enableDisplayMode();
29868 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29869 progressEl.enableDisplayMode();
29870 var pf = progressEl.dom.firstChild;
29872 pp = Roo.get(pf.firstChild);
29873 pp.setHeight(pf.offsetHeight);
29881 * Updates the message box body text
29882 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29883 * the XHTML-compliant non-breaking space character '&#160;')
29884 * @return {Roo.MessageBox} This message box
29886 updateText : function(text){
29887 if(!dlg.isVisible() && !opt.width){
29888 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29890 msgEl.innerHTML = text || ' ';
29891 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29892 Math.max(opt.minWidth || this.minWidth, bwidth));
29894 activeTextEl.setWidth(w);
29896 if(dlg.isVisible()){
29897 dlg.fixedcenter = false;
29899 dlg.setContentSize(w, bodyEl.getHeight());
29900 if(dlg.isVisible()){
29901 dlg.fixedcenter = true;
29907 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
29908 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
29909 * @param {Number} value Any number between 0 and 1 (e.g., .5)
29910 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
29911 * @return {Roo.MessageBox} This message box
29913 updateProgress : function(value, text){
29915 this.updateText(text);
29917 if (pp) { // weird bug on my firefox - for some reason this is not defined
29918 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
29924 * Returns true if the message box is currently displayed
29925 * @return {Boolean} True if the message box is visible, else false
29927 isVisible : function(){
29928 return dlg && dlg.isVisible();
29932 * Hides the message box if it is displayed
29935 if(this.isVisible()){
29941 * Displays a new message box, or reinitializes an existing message box, based on the config options
29942 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
29943 * The following config object properties are supported:
29945 Property Type Description
29946 ---------- --------------- ------------------------------------------------------------------------------------
29947 animEl String/Element An id or Element from which the message box should animate as it opens and
29948 closes (defaults to undefined)
29949 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
29950 cancel:'Bar'}), or false to not show any buttons (defaults to false)
29951 closable Boolean False to hide the top-right close button (defaults to true). Note that
29952 progress and wait dialogs will ignore this property and always hide the
29953 close button as they can only be closed programmatically.
29954 cls String A custom CSS class to apply to the message box element
29955 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
29956 displayed (defaults to 75)
29957 fn Function A callback function to execute after closing the dialog. The arguments to the
29958 function will be btn (the name of the button that was clicked, if applicable,
29959 e.g. "ok"), and text (the value of the active text field, if applicable).
29960 Progress and wait dialogs will ignore this option since they do not respond to
29961 user actions and can only be closed programmatically, so any required function
29962 should be called by the same code after it closes the dialog.
29963 icon String A CSS class that provides a background image to be used as an icon for
29964 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
29965 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
29966 minWidth Number The minimum width in pixels of the message box (defaults to 100)
29967 modal Boolean False to allow user interaction with the page while the message box is
29968 displayed (defaults to true)
29969 msg String A string that will replace the existing message box body text (defaults
29970 to the XHTML-compliant non-breaking space character ' ')
29971 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
29972 progress Boolean True to display a progress bar (defaults to false)
29973 progressText String The text to display inside the progress bar if progress = true (defaults to '')
29974 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
29975 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
29976 title String The title text
29977 value String The string value to set into the active textbox element if displayed
29978 wait Boolean True to display a progress bar (defaults to false)
29979 width Number The width of the dialog in pixels
29986 msg: 'Please enter your address:',
29988 buttons: Roo.MessageBox.OKCANCEL,
29991 animEl: 'addAddressBtn'
29994 * @param {Object} config Configuration options
29995 * @return {Roo.MessageBox} This message box
29997 show : function(options){
29998 if(this.isVisible()){
30001 var d = this.getDialog();
30003 d.setTitle(opt.title || " ");
30004 d.close.setDisplayed(opt.closable !== false);
30005 activeTextEl = textboxEl;
30006 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30011 textareaEl.setHeight(typeof opt.multiline == "number" ?
30012 opt.multiline : this.defaultTextHeight);
30013 activeTextEl = textareaEl;
30022 progressEl.setDisplayed(opt.progress === true);
30023 this.updateProgress(0);
30024 activeTextEl.dom.value = opt.value || "";
30026 dlg.setDefaultButton(activeTextEl);
30028 var bs = opt.buttons;
30031 db = buttons["ok"];
30032 }else if(bs && bs.yes){
30033 db = buttons["yes"];
30035 dlg.setDefaultButton(db);
30037 bwidth = updateButtons(opt.buttons);
30038 this.updateText(opt.msg);
30040 d.el.addClass(opt.cls);
30042 d.proxyDrag = opt.proxyDrag === true;
30043 d.modal = opt.modal !== false;
30044 d.mask = opt.modal !== false ? mask : false;
30045 if(!d.isVisible()){
30046 // force it to the end of the z-index stack so it gets a cursor in FF
30047 document.body.appendChild(dlg.el.dom);
30048 d.animateTarget = null;
30049 d.show(options.animEl);
30055 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30056 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30057 * and closing the message box when the process is complete.
30058 * @param {String} title The title bar text
30059 * @param {String} msg The message box body text
30060 * @return {Roo.MessageBox} This message box
30062 progress : function(title, msg){
30069 minWidth: this.minProgressWidth,
30076 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30077 * If a callback function is passed it will be called after the user clicks the button, and the
30078 * id of the button that was clicked will be passed as the only parameter to the callback
30079 * (could also be the top-right close button).
30080 * @param {String} title The title bar text
30081 * @param {String} msg The message box body text
30082 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30083 * @param {Object} scope (optional) The scope of the callback function
30084 * @return {Roo.MessageBox} This message box
30086 alert : function(title, msg, fn, scope){
30099 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30100 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30101 * You are responsible for closing the message box when the process is complete.
30102 * @param {String} msg The message box body text
30103 * @param {String} title (optional) The title bar text
30104 * @return {Roo.MessageBox} This message box
30106 wait : function(msg, title){
30117 waitTimer = Roo.TaskMgr.start({
30119 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30127 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30128 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30129 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30130 * @param {String} title The title bar text
30131 * @param {String} msg The message box body text
30132 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30133 * @param {Object} scope (optional) The scope of the callback function
30134 * @return {Roo.MessageBox} This message box
30136 confirm : function(title, msg, fn, scope){
30140 buttons: this.YESNO,
30149 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30150 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30151 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30152 * (could also be the top-right close button) and the text that was entered will be passed as the two
30153 * parameters to the callback.
30154 * @param {String} title The title bar text
30155 * @param {String} msg The message box body text
30156 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30157 * @param {Object} scope (optional) The scope of the callback function
30158 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30159 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30160 * @return {Roo.MessageBox} This message box
30162 prompt : function(title, msg, fn, scope, multiline){
30166 buttons: this.OKCANCEL,
30171 multiline: multiline,
30178 * Button config that displays a single OK button
30183 * Button config that displays Yes and No buttons
30186 YESNO : {yes:true, no:true},
30188 * Button config that displays OK and Cancel buttons
30191 OKCANCEL : {ok:true, cancel:true},
30193 * Button config that displays Yes, No and Cancel buttons
30196 YESNOCANCEL : {yes:true, no:true, cancel:true},
30199 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30202 defaultTextHeight : 75,
30204 * The maximum width in pixels of the message box (defaults to 600)
30209 * The minimum width in pixels of the message box (defaults to 100)
30214 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30215 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30218 minProgressWidth : 250,
30220 * An object containing the default button text strings that can be overriden for localized language support.
30221 * Supported properties are: ok, cancel, yes and no.
30222 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30235 * Shorthand for {@link Roo.MessageBox}
30237 Roo.Msg = Roo.MessageBox;/*
30239 * Ext JS Library 1.1.1
30240 * Copyright(c) 2006-2007, Ext JS, LLC.
30242 * Originally Released Under LGPL - original licence link has changed is not relivant.
30245 * <script type="text/javascript">
30248 * @class Roo.QuickTips
30249 * Provides attractive and customizable tooltips for any element.
30252 Roo.QuickTips = function(){
30253 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30254 var ce, bd, xy, dd;
30255 var visible = false, disabled = true, inited = false;
30256 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30258 var onOver = function(e){
30262 var t = e.getTarget();
30263 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30266 if(ce && t == ce.el){
30267 clearTimeout(hideProc);
30270 if(t && tagEls[t.id]){
30271 tagEls[t.id].el = t;
30272 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30275 var ttp, et = Roo.fly(t);
30276 var ns = cfg.namespace;
30277 if(tm.interceptTitles && t.title){
30280 t.removeAttribute("title");
30281 e.preventDefault();
30283 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30286 showProc = show.defer(tm.showDelay, tm, [{
30289 width: et.getAttributeNS(ns, cfg.width),
30290 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30291 title: et.getAttributeNS(ns, cfg.title),
30292 cls: et.getAttributeNS(ns, cfg.cls)
30297 var onOut = function(e){
30298 clearTimeout(showProc);
30299 var t = e.getTarget();
30300 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30301 hideProc = setTimeout(hide, tm.hideDelay);
30305 var onMove = function(e){
30311 if(tm.trackMouse && ce){
30316 var onDown = function(e){
30317 clearTimeout(showProc);
30318 clearTimeout(hideProc);
30320 if(tm.hideOnClick){
30323 tm.enable.defer(100, tm);
30328 var getPad = function(){
30329 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30332 var show = function(o){
30336 clearTimeout(dismissProc);
30338 if(removeCls){ // in case manually hidden
30339 el.removeClass(removeCls);
30343 el.addClass(ce.cls);
30344 removeCls = ce.cls;
30347 tipTitle.update(ce.title);
30350 tipTitle.update('');
30353 el.dom.style.width = tm.maxWidth+'px';
30354 //tipBody.dom.style.width = '';
30355 tipBodyText.update(o.text);
30356 var p = getPad(), w = ce.width;
30358 var td = tipBodyText.dom;
30359 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30360 if(aw > tm.maxWidth){
30362 }else if(aw < tm.minWidth){
30368 //tipBody.setWidth(w);
30369 el.setWidth(parseInt(w, 10) + p);
30370 if(ce.autoHide === false){
30371 close.setDisplayed(true);
30376 close.setDisplayed(false);
30382 el.avoidY = xy[1]-18;
30387 el.setStyle("visibility", "visible");
30388 el.fadeIn({callback: afterShow});
30394 var afterShow = function(){
30398 if(tm.autoDismiss && ce.autoHide !== false){
30399 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30404 var hide = function(noanim){
30405 clearTimeout(dismissProc);
30406 clearTimeout(hideProc);
30408 if(el.isVisible()){
30410 if(noanim !== true && tm.animate){
30411 el.fadeOut({callback: afterHide});
30418 var afterHide = function(){
30421 el.removeClass(removeCls);
30428 * @cfg {Number} minWidth
30429 * The minimum width of the quick tip (defaults to 40)
30433 * @cfg {Number} maxWidth
30434 * The maximum width of the quick tip (defaults to 300)
30438 * @cfg {Boolean} interceptTitles
30439 * True to automatically use the element's DOM title value if available (defaults to false)
30441 interceptTitles : false,
30443 * @cfg {Boolean} trackMouse
30444 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30446 trackMouse : false,
30448 * @cfg {Boolean} hideOnClick
30449 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30451 hideOnClick : true,
30453 * @cfg {Number} showDelay
30454 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30458 * @cfg {Number} hideDelay
30459 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30463 * @cfg {Boolean} autoHide
30464 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30465 * Used in conjunction with hideDelay.
30470 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30471 * (defaults to true). Used in conjunction with autoDismissDelay.
30473 autoDismiss : true,
30476 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30478 autoDismissDelay : 5000,
30480 * @cfg {Boolean} animate
30481 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30486 * @cfg {String} title
30487 * Title text to display (defaults to ''). This can be any valid HTML markup.
30491 * @cfg {String} text
30492 * Body text to display (defaults to ''). This can be any valid HTML markup.
30496 * @cfg {String} cls
30497 * A CSS class to apply to the base quick tip element (defaults to '').
30501 * @cfg {Number} width
30502 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30503 * minWidth or maxWidth.
30508 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30509 * or display QuickTips in a page.
30512 tm = Roo.QuickTips;
30513 cfg = tm.tagConfig;
30515 if(!Roo.isReady){ // allow calling of init() before onReady
30516 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30519 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30520 el.fxDefaults = {stopFx: true};
30521 // maximum custom styling
30522 //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>');
30523 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>');
30524 tipTitle = el.child('h3');
30525 tipTitle.enableDisplayMode("block");
30526 tipBody = el.child('div.x-tip-bd');
30527 tipBodyText = el.child('div.x-tip-bd-inner');
30528 //bdLeft = el.child('div.x-tip-bd-left');
30529 //bdRight = el.child('div.x-tip-bd-right');
30530 close = el.child('div.x-tip-close');
30531 close.enableDisplayMode("block");
30532 close.on("click", hide);
30533 var d = Roo.get(document);
30534 d.on("mousedown", onDown);
30535 d.on("mouseover", onOver);
30536 d.on("mouseout", onOut);
30537 d.on("mousemove", onMove);
30538 esc = d.addKeyListener(27, hide);
30541 dd = el.initDD("default", null, {
30542 onDrag : function(){
30546 dd.setHandleElId(tipTitle.id);
30555 * Configures a new quick tip instance and assigns it to a target element. The following config options
30558 Property Type Description
30559 ---------- --------------------- ------------------------------------------------------------------------
30560 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30562 * @param {Object} config The config object
30564 register : function(config){
30565 var cs = config instanceof Array ? config : arguments;
30566 for(var i = 0, len = cs.length; i < len; i++) {
30568 var target = c.target;
30570 if(target instanceof Array){
30571 for(var j = 0, jlen = target.length; j < jlen; j++){
30572 tagEls[target[j]] = c;
30575 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30582 * Removes this quick tip from its element and destroys it.
30583 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30585 unregister : function(el){
30586 delete tagEls[Roo.id(el)];
30590 * Enable this quick tip.
30592 enable : function(){
30593 if(inited && disabled){
30595 if(locks.length < 1){
30602 * Disable this quick tip.
30604 disable : function(){
30606 clearTimeout(showProc);
30607 clearTimeout(hideProc);
30608 clearTimeout(dismissProc);
30616 * Returns true if the quick tip is enabled, else false.
30618 isEnabled : function(){
30625 attribute : "qtip",
30635 // backwards compat
30636 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30638 * Ext JS Library 1.1.1
30639 * Copyright(c) 2006-2007, Ext JS, LLC.
30641 * Originally Released Under LGPL - original licence link has changed is not relivant.
30644 * <script type="text/javascript">
30649 * @class Roo.tree.TreePanel
30650 * @extends Roo.data.Tree
30652 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30653 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30654 * @cfg {Boolean} enableDD true to enable drag and drop
30655 * @cfg {Boolean} enableDrag true to enable just drag
30656 * @cfg {Boolean} enableDrop true to enable just drop
30657 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30658 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30659 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30660 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30661 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30662 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30663 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30664 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30665 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30666 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30667 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30668 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30669 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30670 * @cfg {Function} renderer 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>
30671 * @cfg {Function} rendererTip 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>
30674 * @param {String/HTMLElement/Element} el The container element
30675 * @param {Object} config
30677 Roo.tree.TreePanel = function(el, config){
30679 var loader = false;
30681 root = config.root;
30682 delete config.root;
30684 if (config.loader) {
30685 loader = config.loader;
30686 delete config.loader;
30689 Roo.apply(this, config);
30690 Roo.tree.TreePanel.superclass.constructor.call(this);
30691 this.el = Roo.get(el);
30692 this.el.addClass('x-tree');
30693 //console.log(root);
30695 this.setRootNode( Roo.factory(root, Roo.tree));
30698 this.loader = Roo.factory(loader, Roo.tree);
30701 * Read-only. The id of the container element becomes this TreePanel's id.
30703 this.id = this.el.id;
30706 * @event beforeload
30707 * Fires before a node is loaded, return false to cancel
30708 * @param {Node} node The node being loaded
30710 "beforeload" : true,
30713 * Fires when a node is loaded
30714 * @param {Node} node The node that was loaded
30718 * @event textchange
30719 * Fires when the text for a node is changed
30720 * @param {Node} node The node
30721 * @param {String} text The new text
30722 * @param {String} oldText The old text
30724 "textchange" : true,
30726 * @event beforeexpand
30727 * Fires before a node is expanded, return false to cancel.
30728 * @param {Node} node The node
30729 * @param {Boolean} deep
30730 * @param {Boolean} anim
30732 "beforeexpand" : true,
30734 * @event beforecollapse
30735 * Fires before a node is collapsed, return false to cancel.
30736 * @param {Node} node The node
30737 * @param {Boolean} deep
30738 * @param {Boolean} anim
30740 "beforecollapse" : true,
30743 * Fires when a node is expanded
30744 * @param {Node} node The node
30748 * @event disabledchange
30749 * Fires when the disabled status of a node changes
30750 * @param {Node} node The node
30751 * @param {Boolean} disabled
30753 "disabledchange" : true,
30756 * Fires when a node is collapsed
30757 * @param {Node} node The node
30761 * @event beforeclick
30762 * Fires before click processing on a node. Return false to cancel the default action.
30763 * @param {Node} node The node
30764 * @param {Roo.EventObject} e The event object
30766 "beforeclick":true,
30768 * @event checkchange
30769 * Fires when a node with a checkbox's checked property changes
30770 * @param {Node} this This node
30771 * @param {Boolean} checked
30773 "checkchange":true,
30776 * Fires when a node is clicked
30777 * @param {Node} node The node
30778 * @param {Roo.EventObject} e The event object
30783 * Fires when a node is double clicked
30784 * @param {Node} node The node
30785 * @param {Roo.EventObject} e The event object
30789 * @event contextmenu
30790 * Fires when a node is right clicked
30791 * @param {Node} node The node
30792 * @param {Roo.EventObject} e The event object
30794 "contextmenu":true,
30796 * @event beforechildrenrendered
30797 * Fires right before the child nodes for a node are rendered
30798 * @param {Node} node The node
30800 "beforechildrenrendered":true,
30803 * Fires when a node starts being dragged
30804 * @param {Roo.tree.TreePanel} this
30805 * @param {Roo.tree.TreeNode} node
30806 * @param {event} e The raw browser event
30808 "startdrag" : true,
30811 * Fires when a drag operation is complete
30812 * @param {Roo.tree.TreePanel} this
30813 * @param {Roo.tree.TreeNode} node
30814 * @param {event} e The raw browser event
30819 * Fires when a dragged node is dropped on a valid DD target
30820 * @param {Roo.tree.TreePanel} this
30821 * @param {Roo.tree.TreeNode} node
30822 * @param {DD} dd The dd it was dropped on
30823 * @param {event} e The raw browser event
30827 * @event beforenodedrop
30828 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30829 * passed to handlers has the following properties:<br />
30830 * <ul style="padding:5px;padding-left:16px;">
30831 * <li>tree - The TreePanel</li>
30832 * <li>target - The node being targeted for the drop</li>
30833 * <li>data - The drag data from the drag source</li>
30834 * <li>point - The point of the drop - append, above or below</li>
30835 * <li>source - The drag source</li>
30836 * <li>rawEvent - Raw mouse event</li>
30837 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30838 * to be inserted by setting them on this object.</li>
30839 * <li>cancel - Set this to true to cancel the drop.</li>
30841 * @param {Object} dropEvent
30843 "beforenodedrop" : true,
30846 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30847 * passed to handlers has the following properties:<br />
30848 * <ul style="padding:5px;padding-left:16px;">
30849 * <li>tree - The TreePanel</li>
30850 * <li>target - The node being targeted for the drop</li>
30851 * <li>data - The drag data from the drag source</li>
30852 * <li>point - The point of the drop - append, above or below</li>
30853 * <li>source - The drag source</li>
30854 * <li>rawEvent - Raw mouse event</li>
30855 * <li>dropNode - Dropped node(s).</li>
30857 * @param {Object} dropEvent
30861 * @event nodedragover
30862 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30863 * passed to handlers has the following properties:<br />
30864 * <ul style="padding:5px;padding-left:16px;">
30865 * <li>tree - The TreePanel</li>
30866 * <li>target - The node being targeted for the drop</li>
30867 * <li>data - The drag data from the drag source</li>
30868 * <li>point - The point of the drop - append, above or below</li>
30869 * <li>source - The drag source</li>
30870 * <li>rawEvent - Raw mouse event</li>
30871 * <li>dropNode - Drop node(s) provided by the source.</li>
30872 * <li>cancel - Set this to true to signal drop not allowed.</li>
30874 * @param {Object} dragOverEvent
30876 "nodedragover" : true
30879 if(this.singleExpand){
30880 this.on("beforeexpand", this.restrictExpand, this);
30883 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30884 rootVisible : true,
30885 animate: Roo.enableFx,
30888 hlDrop : Roo.enableFx,
30892 rendererTip: false,
30894 restrictExpand : function(node){
30895 var p = node.parentNode;
30897 if(p.expandedChild && p.expandedChild.parentNode == p){
30898 p.expandedChild.collapse();
30900 p.expandedChild = node;
30904 // private override
30905 setRootNode : function(node){
30906 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
30907 if(!this.rootVisible){
30908 node.ui = new Roo.tree.RootTreeNodeUI(node);
30914 * Returns the container element for this TreePanel
30916 getEl : function(){
30921 * Returns the default TreeLoader for this TreePanel
30923 getLoader : function(){
30924 return this.loader;
30930 expandAll : function(){
30931 this.root.expand(true);
30935 * Collapse all nodes
30937 collapseAll : function(){
30938 this.root.collapse(true);
30942 * Returns the selection model used by this TreePanel
30944 getSelectionModel : function(){
30945 if(!this.selModel){
30946 this.selModel = new Roo.tree.DefaultSelectionModel();
30948 return this.selModel;
30952 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
30953 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
30954 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
30957 getChecked : function(a, startNode){
30958 startNode = startNode || this.root;
30960 var f = function(){
30961 if(this.attributes.checked){
30962 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
30965 startNode.cascade(f);
30970 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30971 * @param {String} path
30972 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30973 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
30974 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
30976 expandPath : function(path, attr, callback){
30977 attr = attr || "id";
30978 var keys = path.split(this.pathSeparator);
30979 var curNode = this.root;
30980 if(curNode.attributes[attr] != keys[1]){ // invalid root
30982 callback(false, null);
30987 var f = function(){
30988 if(++index == keys.length){
30990 callback(true, curNode);
30994 var c = curNode.findChild(attr, keys[index]);
30997 callback(false, curNode);
31002 c.expand(false, false, f);
31004 curNode.expand(false, false, f);
31008 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31009 * @param {String} path
31010 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31011 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31012 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31014 selectPath : function(path, attr, callback){
31015 attr = attr || "id";
31016 var keys = path.split(this.pathSeparator);
31017 var v = keys.pop();
31018 if(keys.length > 0){
31019 var f = function(success, node){
31020 if(success && node){
31021 var n = node.findChild(attr, v);
31027 }else if(callback){
31028 callback(false, n);
31032 callback(false, n);
31036 this.expandPath(keys.join(this.pathSeparator), attr, f);
31038 this.root.select();
31040 callback(true, this.root);
31045 getTreeEl : function(){
31050 * Trigger rendering of this TreePanel
31052 render : function(){
31053 if (this.innerCt) {
31054 return this; // stop it rendering more than once!!
31057 this.innerCt = this.el.createChild({tag:"ul",
31058 cls:"x-tree-root-ct " +
31059 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31061 if(this.containerScroll){
31062 Roo.dd.ScrollManager.register(this.el);
31064 if((this.enableDD || this.enableDrop) && !this.dropZone){
31066 * The dropZone used by this tree if drop is enabled
31067 * @type Roo.tree.TreeDropZone
31069 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31070 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31073 if((this.enableDD || this.enableDrag) && !this.dragZone){
31075 * The dragZone used by this tree if drag is enabled
31076 * @type Roo.tree.TreeDragZone
31078 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31079 ddGroup: this.ddGroup || "TreeDD",
31080 scroll: this.ddScroll
31083 this.getSelectionModel().init(this);
31085 console.log("ROOT not set in tree");
31088 this.root.render();
31089 if(!this.rootVisible){
31090 this.root.renderChildren();
31096 * Ext JS Library 1.1.1
31097 * Copyright(c) 2006-2007, Ext JS, LLC.
31099 * Originally Released Under LGPL - original licence link has changed is not relivant.
31102 * <script type="text/javascript">
31107 * @class Roo.tree.DefaultSelectionModel
31108 * @extends Roo.util.Observable
31109 * The default single selection for a TreePanel.
31111 Roo.tree.DefaultSelectionModel = function(){
31112 this.selNode = null;
31116 * @event selectionchange
31117 * Fires when the selected node changes
31118 * @param {DefaultSelectionModel} this
31119 * @param {TreeNode} node the new selection
31121 "selectionchange" : true,
31124 * @event beforeselect
31125 * Fires before the selected node changes, return false to cancel the change
31126 * @param {DefaultSelectionModel} this
31127 * @param {TreeNode} node the new selection
31128 * @param {TreeNode} node the old selection
31130 "beforeselect" : true
31134 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31135 init : function(tree){
31137 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31138 tree.on("click", this.onNodeClick, this);
31141 onNodeClick : function(node, e){
31142 if (e.ctrlKey && this.selNode == node) {
31143 this.unselect(node);
31151 * @param {TreeNode} node The node to select
31152 * @return {TreeNode} The selected node
31154 select : function(node){
31155 var last = this.selNode;
31156 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31158 last.ui.onSelectedChange(false);
31160 this.selNode = node;
31161 node.ui.onSelectedChange(true);
31162 this.fireEvent("selectionchange", this, node, last);
31169 * @param {TreeNode} node The node to unselect
31171 unselect : function(node){
31172 if(this.selNode == node){
31173 this.clearSelections();
31178 * Clear all selections
31180 clearSelections : function(){
31181 var n = this.selNode;
31183 n.ui.onSelectedChange(false);
31184 this.selNode = null;
31185 this.fireEvent("selectionchange", this, null);
31191 * Get the selected node
31192 * @return {TreeNode} The selected node
31194 getSelectedNode : function(){
31195 return this.selNode;
31199 * Returns true if the node is selected
31200 * @param {TreeNode} node The node to check
31201 * @return {Boolean}
31203 isSelected : function(node){
31204 return this.selNode == node;
31208 * Selects the node above the selected node in the tree, intelligently walking the nodes
31209 * @return TreeNode The new selection
31211 selectPrevious : function(){
31212 var s = this.selNode || this.lastSelNode;
31216 var ps = s.previousSibling;
31218 if(!ps.isExpanded() || ps.childNodes.length < 1){
31219 return this.select(ps);
31221 var lc = ps.lastChild;
31222 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31225 return this.select(lc);
31227 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31228 return this.select(s.parentNode);
31234 * Selects the node above the selected node in the tree, intelligently walking the nodes
31235 * @return TreeNode The new selection
31237 selectNext : function(){
31238 var s = this.selNode || this.lastSelNode;
31242 if(s.firstChild && s.isExpanded()){
31243 return this.select(s.firstChild);
31244 }else if(s.nextSibling){
31245 return this.select(s.nextSibling);
31246 }else if(s.parentNode){
31248 s.parentNode.bubble(function(){
31249 if(this.nextSibling){
31250 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31259 onKeyDown : function(e){
31260 var s = this.selNode || this.lastSelNode;
31261 // undesirable, but required
31266 var k = e.getKey();
31274 this.selectPrevious();
31277 e.preventDefault();
31278 if(s.hasChildNodes()){
31279 if(!s.isExpanded()){
31281 }else if(s.firstChild){
31282 this.select(s.firstChild, e);
31287 e.preventDefault();
31288 if(s.hasChildNodes() && s.isExpanded()){
31290 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31291 this.select(s.parentNode, e);
31299 * @class Roo.tree.MultiSelectionModel
31300 * @extends Roo.util.Observable
31301 * Multi selection for a TreePanel.
31303 Roo.tree.MultiSelectionModel = function(){
31304 this.selNodes = [];
31308 * @event selectionchange
31309 * Fires when the selected nodes change
31310 * @param {MultiSelectionModel} this
31311 * @param {Array} nodes Array of the selected nodes
31313 "selectionchange" : true
31317 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31318 init : function(tree){
31320 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31321 tree.on("click", this.onNodeClick, this);
31324 onNodeClick : function(node, e){
31325 this.select(node, e, e.ctrlKey);
31330 * @param {TreeNode} node The node to select
31331 * @param {EventObject} e (optional) An event associated with the selection
31332 * @param {Boolean} keepExisting True to retain existing selections
31333 * @return {TreeNode} The selected node
31335 select : function(node, e, keepExisting){
31336 if(keepExisting !== true){
31337 this.clearSelections(true);
31339 if(this.isSelected(node)){
31340 this.lastSelNode = node;
31343 this.selNodes.push(node);
31344 this.selMap[node.id] = node;
31345 this.lastSelNode = node;
31346 node.ui.onSelectedChange(true);
31347 this.fireEvent("selectionchange", this, this.selNodes);
31353 * @param {TreeNode} node The node to unselect
31355 unselect : function(node){
31356 if(this.selMap[node.id]){
31357 node.ui.onSelectedChange(false);
31358 var sn = this.selNodes;
31361 index = sn.indexOf(node);
31363 for(var i = 0, len = sn.length; i < len; i++){
31371 this.selNodes.splice(index, 1);
31373 delete this.selMap[node.id];
31374 this.fireEvent("selectionchange", this, this.selNodes);
31379 * Clear all selections
31381 clearSelections : function(suppressEvent){
31382 var sn = this.selNodes;
31384 for(var i = 0, len = sn.length; i < len; i++){
31385 sn[i].ui.onSelectedChange(false);
31387 this.selNodes = [];
31389 if(suppressEvent !== true){
31390 this.fireEvent("selectionchange", this, this.selNodes);
31396 * Returns true if the node is selected
31397 * @param {TreeNode} node The node to check
31398 * @return {Boolean}
31400 isSelected : function(node){
31401 return this.selMap[node.id] ? true : false;
31405 * Returns an array of the selected nodes
31408 getSelectedNodes : function(){
31409 return this.selNodes;
31412 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31414 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31416 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31419 * Ext JS Library 1.1.1
31420 * Copyright(c) 2006-2007, Ext JS, LLC.
31422 * Originally Released Under LGPL - original licence link has changed is not relivant.
31425 * <script type="text/javascript">
31429 * @class Roo.tree.TreeNode
31430 * @extends Roo.data.Node
31431 * @cfg {String} text The text for this node
31432 * @cfg {Boolean} expanded true to start the node expanded
31433 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31434 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31435 * @cfg {Boolean} disabled true to start the node disabled
31436 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31437 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31438 * @cfg {String} cls A css class to be added to the node
31439 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31440 * @cfg {String} href URL of the link used for the node (defaults to #)
31441 * @cfg {String} hrefTarget target frame for the link
31442 * @cfg {String} qtip An Ext QuickTip for the node
31443 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31444 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31445 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31446 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31447 * (defaults to undefined with no checkbox rendered)
31449 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31451 Roo.tree.TreeNode = function(attributes){
31452 attributes = attributes || {};
31453 if(typeof attributes == "string"){
31454 attributes = {text: attributes};
31456 this.childrenRendered = false;
31457 this.rendered = false;
31458 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31459 this.expanded = attributes.expanded === true;
31460 this.isTarget = attributes.isTarget !== false;
31461 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31462 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31465 * Read-only. The text for this node. To change it use setText().
31468 this.text = attributes.text;
31470 * True if this node is disabled.
31473 this.disabled = attributes.disabled === true;
31477 * @event textchange
31478 * Fires when the text for this node is changed
31479 * @param {Node} this This node
31480 * @param {String} text The new text
31481 * @param {String} oldText The old text
31483 "textchange" : true,
31485 * @event beforeexpand
31486 * Fires before this node is expanded, return false to cancel.
31487 * @param {Node} this This node
31488 * @param {Boolean} deep
31489 * @param {Boolean} anim
31491 "beforeexpand" : true,
31493 * @event beforecollapse
31494 * Fires before this node is collapsed, return false to cancel.
31495 * @param {Node} this This node
31496 * @param {Boolean} deep
31497 * @param {Boolean} anim
31499 "beforecollapse" : true,
31502 * Fires when this node is expanded
31503 * @param {Node} this This node
31507 * @event disabledchange
31508 * Fires when the disabled status of this node changes
31509 * @param {Node} this This node
31510 * @param {Boolean} disabled
31512 "disabledchange" : true,
31515 * Fires when this node is collapsed
31516 * @param {Node} this This node
31520 * @event beforeclick
31521 * Fires before click processing. Return false to cancel the default action.
31522 * @param {Node} this This node
31523 * @param {Roo.EventObject} e The event object
31525 "beforeclick":true,
31527 * @event checkchange
31528 * Fires when a node with a checkbox's checked property changes
31529 * @param {Node} this This node
31530 * @param {Boolean} checked
31532 "checkchange":true,
31535 * Fires when this node is clicked
31536 * @param {Node} this This node
31537 * @param {Roo.EventObject} e The event object
31542 * Fires when this node is double clicked
31543 * @param {Node} this This node
31544 * @param {Roo.EventObject} e The event object
31548 * @event contextmenu
31549 * Fires when this node is right clicked
31550 * @param {Node} this This node
31551 * @param {Roo.EventObject} e The event object
31553 "contextmenu":true,
31555 * @event beforechildrenrendered
31556 * Fires right before the child nodes for this node are rendered
31557 * @param {Node} this This node
31559 "beforechildrenrendered":true
31562 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31565 * Read-only. The UI for this node
31568 this.ui = new uiClass(this);
31570 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31571 preventHScroll: true,
31573 * Returns true if this node is expanded
31574 * @return {Boolean}
31576 isExpanded : function(){
31577 return this.expanded;
31581 * Returns the UI object for this node
31582 * @return {TreeNodeUI}
31584 getUI : function(){
31588 // private override
31589 setFirstChild : function(node){
31590 var of = this.firstChild;
31591 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31592 if(this.childrenRendered && of && node != of){
31593 of.renderIndent(true, true);
31596 this.renderIndent(true, true);
31600 // private override
31601 setLastChild : function(node){
31602 var ol = this.lastChild;
31603 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31604 if(this.childrenRendered && ol && node != ol){
31605 ol.renderIndent(true, true);
31608 this.renderIndent(true, true);
31612 // these methods are overridden to provide lazy rendering support
31613 // private override
31614 appendChild : function(){
31615 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31616 if(node && this.childrenRendered){
31619 this.ui.updateExpandIcon();
31623 // private override
31624 removeChild : function(node){
31625 this.ownerTree.getSelectionModel().unselect(node);
31626 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31627 // if it's been rendered remove dom node
31628 if(this.childrenRendered){
31631 if(this.childNodes.length < 1){
31632 this.collapse(false, false);
31634 this.ui.updateExpandIcon();
31636 if(!this.firstChild) {
31637 this.childrenRendered = false;
31642 // private override
31643 insertBefore : function(node, refNode){
31644 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31645 if(newNode && refNode && this.childrenRendered){
31648 this.ui.updateExpandIcon();
31653 * Sets the text for this node
31654 * @param {String} text
31656 setText : function(text){
31657 var oldText = this.text;
31659 this.attributes.text = text;
31660 if(this.rendered){ // event without subscribing
31661 this.ui.onTextChange(this, text, oldText);
31663 this.fireEvent("textchange", this, text, oldText);
31667 * Triggers selection of this node
31669 select : function(){
31670 this.getOwnerTree().getSelectionModel().select(this);
31674 * Triggers deselection of this node
31676 unselect : function(){
31677 this.getOwnerTree().getSelectionModel().unselect(this);
31681 * Returns true if this node is selected
31682 * @return {Boolean}
31684 isSelected : function(){
31685 return this.getOwnerTree().getSelectionModel().isSelected(this);
31689 * Expand this node.
31690 * @param {Boolean} deep (optional) True to expand all children as well
31691 * @param {Boolean} anim (optional) false to cancel the default animation
31692 * @param {Function} callback (optional) A callback to be called when
31693 * expanding this node completes (does not wait for deep expand to complete).
31694 * Called with 1 parameter, this node.
31696 expand : function(deep, anim, callback){
31697 if(!this.expanded){
31698 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31701 if(!this.childrenRendered){
31702 this.renderChildren();
31704 this.expanded = true;
31705 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31706 this.ui.animExpand(function(){
31707 this.fireEvent("expand", this);
31708 if(typeof callback == "function"){
31712 this.expandChildNodes(true);
31714 }.createDelegate(this));
31718 this.fireEvent("expand", this);
31719 if(typeof callback == "function"){
31724 if(typeof callback == "function"){
31729 this.expandChildNodes(true);
31733 isHiddenRoot : function(){
31734 return this.isRoot && !this.getOwnerTree().rootVisible;
31738 * Collapse this node.
31739 * @param {Boolean} deep (optional) True to collapse all children as well
31740 * @param {Boolean} anim (optional) false to cancel the default animation
31742 collapse : function(deep, anim){
31743 if(this.expanded && !this.isHiddenRoot()){
31744 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31747 this.expanded = false;
31748 if((this.getOwnerTree().animate && anim !== false) || anim){
31749 this.ui.animCollapse(function(){
31750 this.fireEvent("collapse", this);
31752 this.collapseChildNodes(true);
31754 }.createDelegate(this));
31757 this.ui.collapse();
31758 this.fireEvent("collapse", this);
31762 var cs = this.childNodes;
31763 for(var i = 0, len = cs.length; i < len; i++) {
31764 cs[i].collapse(true, false);
31770 delayedExpand : function(delay){
31771 if(!this.expandProcId){
31772 this.expandProcId = this.expand.defer(delay, this);
31777 cancelExpand : function(){
31778 if(this.expandProcId){
31779 clearTimeout(this.expandProcId);
31781 this.expandProcId = false;
31785 * Toggles expanded/collapsed state of the node
31787 toggle : function(){
31796 * Ensures all parent nodes are expanded
31798 ensureVisible : function(callback){
31799 var tree = this.getOwnerTree();
31800 tree.expandPath(this.parentNode.getPath(), false, function(){
31801 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31802 Roo.callback(callback);
31803 }.createDelegate(this));
31807 * Expand all child nodes
31808 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31810 expandChildNodes : function(deep){
31811 var cs = this.childNodes;
31812 for(var i = 0, len = cs.length; i < len; i++) {
31813 cs[i].expand(deep);
31818 * Collapse all child nodes
31819 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31821 collapseChildNodes : function(deep){
31822 var cs = this.childNodes;
31823 for(var i = 0, len = cs.length; i < len; i++) {
31824 cs[i].collapse(deep);
31829 * Disables this node
31831 disable : function(){
31832 this.disabled = true;
31834 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31835 this.ui.onDisableChange(this, true);
31837 this.fireEvent("disabledchange", this, true);
31841 * Enables this node
31843 enable : function(){
31844 this.disabled = false;
31845 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31846 this.ui.onDisableChange(this, false);
31848 this.fireEvent("disabledchange", this, false);
31852 renderChildren : function(suppressEvent){
31853 if(suppressEvent !== false){
31854 this.fireEvent("beforechildrenrendered", this);
31856 var cs = this.childNodes;
31857 for(var i = 0, len = cs.length; i < len; i++){
31858 cs[i].render(true);
31860 this.childrenRendered = true;
31864 sort : function(fn, scope){
31865 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31866 if(this.childrenRendered){
31867 var cs = this.childNodes;
31868 for(var i = 0, len = cs.length; i < len; i++){
31869 cs[i].render(true);
31875 render : function(bulkRender){
31876 this.ui.render(bulkRender);
31877 if(!this.rendered){
31878 this.rendered = true;
31880 this.expanded = false;
31881 this.expand(false, false);
31887 renderIndent : function(deep, refresh){
31889 this.ui.childIndent = null;
31891 this.ui.renderIndent();
31892 if(deep === true && this.childrenRendered){
31893 var cs = this.childNodes;
31894 for(var i = 0, len = cs.length; i < len; i++){
31895 cs[i].renderIndent(true, refresh);
31901 * Ext JS Library 1.1.1
31902 * Copyright(c) 2006-2007, Ext JS, LLC.
31904 * Originally Released Under LGPL - original licence link has changed is not relivant.
31907 * <script type="text/javascript">
31911 * @class Roo.tree.AsyncTreeNode
31912 * @extends Roo.tree.TreeNode
31913 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
31915 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31917 Roo.tree.AsyncTreeNode = function(config){
31918 this.loaded = false;
31919 this.loading = false;
31920 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
31922 * @event beforeload
31923 * Fires before this node is loaded, return false to cancel
31924 * @param {Node} this This node
31926 this.addEvents({'beforeload':true, 'load': true});
31929 * Fires when this node is loaded
31930 * @param {Node} this This node
31933 * The loader used by this node (defaults to using the tree's defined loader)
31938 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
31939 expand : function(deep, anim, callback){
31940 if(this.loading){ // if an async load is already running, waiting til it's done
31942 var f = function(){
31943 if(!this.loading){ // done loading
31944 clearInterval(timer);
31945 this.expand(deep, anim, callback);
31947 }.createDelegate(this);
31948 timer = setInterval(f, 200);
31952 if(this.fireEvent("beforeload", this) === false){
31955 this.loading = true;
31956 this.ui.beforeLoad(this);
31957 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
31959 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
31963 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
31967 * Returns true if this node is currently loading
31968 * @return {Boolean}
31970 isLoading : function(){
31971 return this.loading;
31974 loadComplete : function(deep, anim, callback){
31975 this.loading = false;
31976 this.loaded = true;
31977 this.ui.afterLoad(this);
31978 this.fireEvent("load", this);
31979 this.expand(deep, anim, callback);
31983 * Returns true if this node has been loaded
31984 * @return {Boolean}
31986 isLoaded : function(){
31987 return this.loaded;
31990 hasChildNodes : function(){
31991 if(!this.isLeaf() && !this.loaded){
31994 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
31999 * Trigger a reload for this node
32000 * @param {Function} callback
32002 reload : function(callback){
32003 this.collapse(false, false);
32004 while(this.firstChild){
32005 this.removeChild(this.firstChild);
32007 this.childrenRendered = false;
32008 this.loaded = false;
32009 if(this.isHiddenRoot()){
32010 this.expanded = false;
32012 this.expand(false, false, callback);
32016 * Ext JS Library 1.1.1
32017 * Copyright(c) 2006-2007, Ext JS, LLC.
32019 * Originally Released Under LGPL - original licence link has changed is not relivant.
32022 * <script type="text/javascript">
32026 * @class Roo.tree.TreeNodeUI
32028 * @param {Object} node The node to render
32029 * The TreeNode UI implementation is separate from the
32030 * tree implementation. Unless you are customizing the tree UI,
32031 * you should never have to use this directly.
32033 Roo.tree.TreeNodeUI = function(node){
32035 this.rendered = false;
32036 this.animating = false;
32037 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32040 Roo.tree.TreeNodeUI.prototype = {
32041 removeChild : function(node){
32043 this.ctNode.removeChild(node.ui.getEl());
32047 beforeLoad : function(){
32048 this.addClass("x-tree-node-loading");
32051 afterLoad : function(){
32052 this.removeClass("x-tree-node-loading");
32055 onTextChange : function(node, text, oldText){
32057 this.textNode.innerHTML = text;
32061 onDisableChange : function(node, state){
32062 this.disabled = state;
32064 this.addClass("x-tree-node-disabled");
32066 this.removeClass("x-tree-node-disabled");
32070 onSelectedChange : function(state){
32073 this.addClass("x-tree-selected");
32076 this.removeClass("x-tree-selected");
32080 onMove : function(tree, node, oldParent, newParent, index, refNode){
32081 this.childIndent = null;
32083 var targetNode = newParent.ui.getContainer();
32084 if(!targetNode){//target not rendered
32085 this.holder = document.createElement("div");
32086 this.holder.appendChild(this.wrap);
32089 var insertBefore = refNode ? refNode.ui.getEl() : null;
32091 targetNode.insertBefore(this.wrap, insertBefore);
32093 targetNode.appendChild(this.wrap);
32095 this.node.renderIndent(true);
32099 addClass : function(cls){
32101 Roo.fly(this.elNode).addClass(cls);
32105 removeClass : function(cls){
32107 Roo.fly(this.elNode).removeClass(cls);
32111 remove : function(){
32113 this.holder = document.createElement("div");
32114 this.holder.appendChild(this.wrap);
32118 fireEvent : function(){
32119 return this.node.fireEvent.apply(this.node, arguments);
32122 initEvents : function(){
32123 this.node.on("move", this.onMove, this);
32124 var E = Roo.EventManager;
32125 var a = this.anchor;
32127 var el = Roo.fly(a, '_treeui');
32129 if(Roo.isOpera){ // opera render bug ignores the CSS
32130 el.setStyle("text-decoration", "none");
32133 el.on("click", this.onClick, this);
32134 el.on("dblclick", this.onDblClick, this);
32137 Roo.EventManager.on(this.checkbox,
32138 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32141 el.on("contextmenu", this.onContextMenu, this);
32143 var icon = Roo.fly(this.iconNode);
32144 icon.on("click", this.onClick, this);
32145 icon.on("dblclick", this.onDblClick, this);
32146 icon.on("contextmenu", this.onContextMenu, this);
32147 E.on(this.ecNode, "click", this.ecClick, this, true);
32149 if(this.node.disabled){
32150 this.addClass("x-tree-node-disabled");
32152 if(this.node.hidden){
32153 this.addClass("x-tree-node-disabled");
32155 var ot = this.node.getOwnerTree();
32156 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32157 if(dd && (!this.node.isRoot || ot.rootVisible)){
32158 Roo.dd.Registry.register(this.elNode, {
32160 handles: this.getDDHandles(),
32166 getDDHandles : function(){
32167 return [this.iconNode, this.textNode];
32172 this.wrap.style.display = "none";
32178 this.wrap.style.display = "";
32182 onContextMenu : function(e){
32183 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32184 e.preventDefault();
32186 this.fireEvent("contextmenu", this.node, e);
32190 onClick : function(e){
32195 if(this.fireEvent("beforeclick", this.node, e) !== false){
32196 if(!this.disabled && this.node.attributes.href){
32197 this.fireEvent("click", this.node, e);
32200 e.preventDefault();
32205 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32206 this.node.toggle();
32209 this.fireEvent("click", this.node, e);
32215 onDblClick : function(e){
32216 e.preventDefault();
32221 this.toggleCheck();
32223 if(!this.animating && this.node.hasChildNodes()){
32224 this.node.toggle();
32226 this.fireEvent("dblclick", this.node, e);
32229 onCheckChange : function(){
32230 var checked = this.checkbox.checked;
32231 this.node.attributes.checked = checked;
32232 this.fireEvent('checkchange', this.node, checked);
32235 ecClick : function(e){
32236 if(!this.animating && this.node.hasChildNodes()){
32237 this.node.toggle();
32241 startDrop : function(){
32242 this.dropping = true;
32245 // delayed drop so the click event doesn't get fired on a drop
32246 endDrop : function(){
32247 setTimeout(function(){
32248 this.dropping = false;
32249 }.createDelegate(this), 50);
32252 expand : function(){
32253 this.updateExpandIcon();
32254 this.ctNode.style.display = "";
32257 focus : function(){
32258 if(!this.node.preventHScroll){
32259 try{this.anchor.focus();
32261 }else if(!Roo.isIE){
32263 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32264 var l = noscroll.scrollLeft;
32265 this.anchor.focus();
32266 noscroll.scrollLeft = l;
32271 toggleCheck : function(value){
32272 var cb = this.checkbox;
32274 cb.checked = (value === undefined ? !cb.checked : value);
32280 this.anchor.blur();
32284 animExpand : function(callback){
32285 var ct = Roo.get(this.ctNode);
32287 if(!this.node.hasChildNodes()){
32288 this.updateExpandIcon();
32289 this.ctNode.style.display = "";
32290 Roo.callback(callback);
32293 this.animating = true;
32294 this.updateExpandIcon();
32297 callback : function(){
32298 this.animating = false;
32299 Roo.callback(callback);
32302 duration: this.node.ownerTree.duration || .25
32306 highlight : function(){
32307 var tree = this.node.getOwnerTree();
32308 Roo.fly(this.wrap).highlight(
32309 tree.hlColor || "C3DAF9",
32310 {endColor: tree.hlBaseColor}
32314 collapse : function(){
32315 this.updateExpandIcon();
32316 this.ctNode.style.display = "none";
32319 animCollapse : function(callback){
32320 var ct = Roo.get(this.ctNode);
32321 ct.enableDisplayMode('block');
32324 this.animating = true;
32325 this.updateExpandIcon();
32328 callback : function(){
32329 this.animating = false;
32330 Roo.callback(callback);
32333 duration: this.node.ownerTree.duration || .25
32337 getContainer : function(){
32338 return this.ctNode;
32341 getEl : function(){
32345 appendDDGhost : function(ghostNode){
32346 ghostNode.appendChild(this.elNode.cloneNode(true));
32349 getDDRepairXY : function(){
32350 return Roo.lib.Dom.getXY(this.iconNode);
32353 onRender : function(){
32357 render : function(bulkRender){
32358 var n = this.node, a = n.attributes;
32359 var targetNode = n.parentNode ?
32360 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32362 if(!this.rendered){
32363 this.rendered = true;
32365 this.renderElements(n, a, targetNode, bulkRender);
32368 if(this.textNode.setAttributeNS){
32369 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32371 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32374 this.textNode.setAttribute("ext:qtip", a.qtip);
32376 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32379 }else if(a.qtipCfg){
32380 a.qtipCfg.target = Roo.id(this.textNode);
32381 Roo.QuickTips.register(a.qtipCfg);
32384 if(!this.node.expanded){
32385 this.updateExpandIcon();
32388 if(bulkRender === true) {
32389 targetNode.appendChild(this.wrap);
32394 renderElements : function(n, a, targetNode, bulkRender){
32395 // add some indent caching, this helps performance when rendering a large tree
32396 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32397 var t = n.getOwnerTree();
32398 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32399 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32400 var cb = typeof a.checked == 'boolean';
32401 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32402 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32403 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32404 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32405 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32406 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32407 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32408 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32409 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32410 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32413 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32414 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32415 n.nextSibling.ui.getEl(), buf.join(""));
32417 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32420 this.elNode = this.wrap.childNodes[0];
32421 this.ctNode = this.wrap.childNodes[1];
32422 var cs = this.elNode.childNodes;
32423 this.indentNode = cs[0];
32424 this.ecNode = cs[1];
32425 this.iconNode = cs[2];
32428 this.checkbox = cs[3];
32431 this.anchor = cs[index];
32432 this.textNode = cs[index].firstChild;
32435 getAnchor : function(){
32436 return this.anchor;
32439 getTextEl : function(){
32440 return this.textNode;
32443 getIconEl : function(){
32444 return this.iconNode;
32447 isChecked : function(){
32448 return this.checkbox ? this.checkbox.checked : false;
32451 updateExpandIcon : function(){
32453 var n = this.node, c1, c2;
32454 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32455 var hasChild = n.hasChildNodes();
32459 c1 = "x-tree-node-collapsed";
32460 c2 = "x-tree-node-expanded";
32463 c1 = "x-tree-node-expanded";
32464 c2 = "x-tree-node-collapsed";
32467 this.removeClass("x-tree-node-leaf");
32468 this.wasLeaf = false;
32470 if(this.c1 != c1 || this.c2 != c2){
32471 Roo.fly(this.elNode).replaceClass(c1, c2);
32472 this.c1 = c1; this.c2 = c2;
32476 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32479 this.wasLeaf = true;
32482 var ecc = "x-tree-ec-icon "+cls;
32483 if(this.ecc != ecc){
32484 this.ecNode.className = ecc;
32490 getChildIndent : function(){
32491 if(!this.childIndent){
32495 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32497 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32499 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32504 this.childIndent = buf.join("");
32506 return this.childIndent;
32509 renderIndent : function(){
32512 var p = this.node.parentNode;
32514 indent = p.ui.getChildIndent();
32516 if(this.indentMarkup != indent){ // don't rerender if not required
32517 this.indentNode.innerHTML = indent;
32518 this.indentMarkup = indent;
32520 this.updateExpandIcon();
32525 Roo.tree.RootTreeNodeUI = function(){
32526 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32528 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32529 render : function(){
32530 if(!this.rendered){
32531 var targetNode = this.node.ownerTree.innerCt.dom;
32532 this.node.expanded = true;
32533 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32534 this.wrap = this.ctNode = targetNode.firstChild;
32537 collapse : function(){
32539 expand : function(){
32543 * Ext JS Library 1.1.1
32544 * Copyright(c) 2006-2007, Ext JS, LLC.
32546 * Originally Released Under LGPL - original licence link has changed is not relivant.
32549 * <script type="text/javascript">
32552 * @class Roo.tree.TreeLoader
32553 * @extends Roo.util.Observable
32554 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32555 * nodes from a specified URL. The response must be a javascript Array definition
32556 * who's elements are node definition objects. eg:
32558 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32559 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32562 * A server request is sent, and child nodes are loaded only when a node is expanded.
32563 * The loading node's id is passed to the server under the parameter name "node" to
32564 * enable the server to produce the correct child nodes.
32566 * To pass extra parameters, an event handler may be attached to the "beforeload"
32567 * event, and the parameters specified in the TreeLoader's baseParams property:
32569 myTreeLoader.on("beforeload", function(treeLoader, node) {
32570 this.baseParams.category = node.attributes.category;
32573 * This would pass an HTTP parameter called "category" to the server containing
32574 * the value of the Node's "category" attribute.
32576 * Creates a new Treeloader.
32577 * @param {Object} config A config object containing config properties.
32579 Roo.tree.TreeLoader = function(config){
32580 this.baseParams = {};
32581 this.requestMethod = "POST";
32582 Roo.apply(this, config);
32587 * @event beforeload
32588 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32589 * @param {Object} This TreeLoader object.
32590 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32591 * @param {Object} callback The callback function specified in the {@link #load} call.
32596 * Fires when the node has been successfuly loaded.
32597 * @param {Object} This TreeLoader object.
32598 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32599 * @param {Object} response The response object containing the data from the server.
32603 * @event loadexception
32604 * Fires if the network request failed.
32605 * @param {Object} This TreeLoader object.
32606 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32607 * @param {Object} response The response object containing the data from the server.
32609 loadexception : true,
32612 * Fires before a node is created, enabling you to return custom Node types
32613 * @param {Object} This TreeLoader object.
32614 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32619 Roo.tree.TreeLoader.superclass.constructor.call(this);
32622 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32624 * @cfg {String} dataUrl The URL from which to request a Json string which
32625 * specifies an array of node definition object representing the child nodes
32629 * @cfg {Object} baseParams (optional) An object containing properties which
32630 * specify HTTP parameters to be passed to each request for child nodes.
32633 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32634 * created by this loader. If the attributes sent by the server have an attribute in this object,
32635 * they take priority.
32638 * @cfg {Object} uiProviders (optional) An object containing properties which
32640 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32641 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32642 * <i>uiProvider</i> attribute of a returned child node is a string rather
32643 * than a reference to a TreeNodeUI implementation, this that string value
32644 * is used as a property name in the uiProviders object. You can define the provider named
32645 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32650 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32651 * child nodes before loading.
32653 clearOnLoad : true,
32656 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32657 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32658 * Grid query { data : [ .....] }
32663 * @cfg {String} queryParam (optional)
32664 * Name of the query as it will be passed on the querystring (defaults to 'node')
32665 * eg. the request will be ?node=[id]
32672 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32673 * This is called automatically when a node is expanded, but may be used to reload
32674 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32675 * @param {Roo.tree.TreeNode} node
32676 * @param {Function} callback
32678 load : function(node, callback){
32679 if(this.clearOnLoad){
32680 while(node.firstChild){
32681 node.removeChild(node.firstChild);
32684 if(node.attributes.children){ // preloaded json children
32685 var cs = node.attributes.children;
32686 for(var i = 0, len = cs.length; i < len; i++){
32687 node.appendChild(this.createNode(cs[i]));
32689 if(typeof callback == "function"){
32692 }else if(this.dataUrl){
32693 this.requestData(node, callback);
32697 getParams: function(node){
32698 var buf = [], bp = this.baseParams;
32699 for(var key in bp){
32700 if(typeof bp[key] != "function"){
32701 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32704 var n = this.queryParam === false ? 'node' : this.queryParam;
32705 buf.push(n + "=", encodeURIComponent(node.id));
32706 return buf.join("");
32709 requestData : function(node, callback){
32710 if(this.fireEvent("beforeload", this, node, callback) !== false){
32711 this.transId = Roo.Ajax.request({
32712 method:this.requestMethod,
32713 url: this.dataUrl||this.url,
32714 success: this.handleResponse,
32715 failure: this.handleFailure,
32717 argument: {callback: callback, node: node},
32718 params: this.getParams(node)
32721 // if the load is cancelled, make sure we notify
32722 // the node that we are done
32723 if(typeof callback == "function"){
32729 isLoading : function(){
32730 return this.transId ? true : false;
32733 abort : function(){
32734 if(this.isLoading()){
32735 Roo.Ajax.abort(this.transId);
32740 createNode : function(attr){
32741 // apply baseAttrs, nice idea Corey!
32742 if(this.baseAttrs){
32743 Roo.applyIf(attr, this.baseAttrs);
32745 if(this.applyLoader !== false){
32746 attr.loader = this;
32748 // uiProvider = depreciated..
32750 if(typeof(attr.uiProvider) == 'string'){
32751 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32752 /** eval:var:attr */ eval(attr.uiProvider);
32754 if(typeof(this.uiProviders['default']) != 'undefined') {
32755 attr.uiProvider = this.uiProviders['default'];
32758 this.fireEvent('create', this, attr);
32760 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32762 new Roo.tree.TreeNode(attr) :
32763 new Roo.tree.AsyncTreeNode(attr));
32766 processResponse : function(response, node, callback){
32767 var json = response.responseText;
32770 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32771 if (this.root !== false) {
32775 for(var i = 0, len = o.length; i < len; i++){
32776 var n = this.createNode(o[i]);
32778 node.appendChild(n);
32781 if(typeof callback == "function"){
32782 callback(this, node);
32785 this.handleFailure(response);
32789 handleResponse : function(response){
32790 this.transId = false;
32791 var a = response.argument;
32792 this.processResponse(response, a.node, a.callback);
32793 this.fireEvent("load", this, a.node, response);
32796 handleFailure : function(response){
32797 this.transId = false;
32798 var a = response.argument;
32799 this.fireEvent("loadexception", this, a.node, response);
32800 if(typeof a.callback == "function"){
32801 a.callback(this, a.node);
32806 * Ext JS Library 1.1.1
32807 * Copyright(c) 2006-2007, Ext JS, LLC.
32809 * Originally Released Under LGPL - original licence link has changed is not relivant.
32812 * <script type="text/javascript">
32816 * @class Roo.tree.TreeFilter
32817 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32818 * @param {TreePanel} tree
32819 * @param {Object} config (optional)
32821 Roo.tree.TreeFilter = function(tree, config){
32823 this.filtered = {};
32824 Roo.apply(this, config);
32827 Roo.tree.TreeFilter.prototype = {
32834 * Filter the data by a specific attribute.
32835 * @param {String/RegExp} value Either string that the attribute value
32836 * should start with or a RegExp to test against the attribute
32837 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32838 * @param {TreeNode} startNode (optional) The node to start the filter at.
32840 filter : function(value, attr, startNode){
32841 attr = attr || "text";
32843 if(typeof value == "string"){
32844 var vlen = value.length;
32845 // auto clear empty filter
32846 if(vlen == 0 && this.clearBlank){
32850 value = value.toLowerCase();
32852 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32854 }else if(value.exec){ // regex?
32856 return value.test(n.attributes[attr]);
32859 throw 'Illegal filter type, must be string or regex';
32861 this.filterBy(f, null, startNode);
32865 * Filter by a function. The passed function will be called with each
32866 * node in the tree (or from the startNode). If the function returns true, the node is kept
32867 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32868 * @param {Function} fn The filter function
32869 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32871 filterBy : function(fn, scope, startNode){
32872 startNode = startNode || this.tree.root;
32873 if(this.autoClear){
32876 var af = this.filtered, rv = this.reverse;
32877 var f = function(n){
32878 if(n == startNode){
32884 var m = fn.call(scope || n, n);
32892 startNode.cascade(f);
32895 if(typeof id != "function"){
32897 if(n && n.parentNode){
32898 n.parentNode.removeChild(n);
32906 * Clears the current filter. Note: with the "remove" option
32907 * set a filter cannot be cleared.
32909 clear : function(){
32911 var af = this.filtered;
32913 if(typeof id != "function"){
32920 this.filtered = {};
32925 * Ext JS Library 1.1.1
32926 * Copyright(c) 2006-2007, Ext JS, LLC.
32928 * Originally Released Under LGPL - original licence link has changed is not relivant.
32931 * <script type="text/javascript">
32936 * @class Roo.tree.TreeSorter
32937 * Provides sorting of nodes in a TreePanel
32939 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
32940 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
32941 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
32942 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
32943 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
32944 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
32946 * @param {TreePanel} tree
32947 * @param {Object} config
32949 Roo.tree.TreeSorter = function(tree, config){
32950 Roo.apply(this, config);
32951 tree.on("beforechildrenrendered", this.doSort, this);
32952 tree.on("append", this.updateSort, this);
32953 tree.on("insert", this.updateSort, this);
32955 var dsc = this.dir && this.dir.toLowerCase() == "desc";
32956 var p = this.property || "text";
32957 var sortType = this.sortType;
32958 var fs = this.folderSort;
32959 var cs = this.caseSensitive === true;
32960 var leafAttr = this.leafAttr || 'leaf';
32962 this.sortFn = function(n1, n2){
32964 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
32967 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
32971 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
32972 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
32974 return dsc ? +1 : -1;
32976 return dsc ? -1 : +1;
32983 Roo.tree.TreeSorter.prototype = {
32984 doSort : function(node){
32985 node.sort(this.sortFn);
32988 compareNodes : function(n1, n2){
32989 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
32992 updateSort : function(tree, node){
32993 if(node.childrenRendered){
32994 this.doSort.defer(1, this, [node]);
32999 * Ext JS Library 1.1.1
33000 * Copyright(c) 2006-2007, Ext JS, LLC.
33002 * Originally Released Under LGPL - original licence link has changed is not relivant.
33005 * <script type="text/javascript">
33008 if(Roo.dd.DropZone){
33010 Roo.tree.TreeDropZone = function(tree, config){
33011 this.allowParentInsert = false;
33012 this.allowContainerDrop = false;
33013 this.appendOnly = false;
33014 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33016 this.lastInsertClass = "x-tree-no-status";
33017 this.dragOverData = {};
33020 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33021 ddGroup : "TreeDD",
33023 expandDelay : 1000,
33025 expandNode : function(node){
33026 if(node.hasChildNodes() && !node.isExpanded()){
33027 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33031 queueExpand : function(node){
33032 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33035 cancelExpand : function(){
33036 if(this.expandProcId){
33037 clearTimeout(this.expandProcId);
33038 this.expandProcId = false;
33042 isValidDropPoint : function(n, pt, dd, e, data){
33043 if(!n || !data){ return false; }
33044 var targetNode = n.node;
33045 var dropNode = data.node;
33046 // default drop rules
33047 if(!(targetNode && targetNode.isTarget && pt)){
33050 if(pt == "append" && targetNode.allowChildren === false){
33053 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33056 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33059 // reuse the object
33060 var overEvent = this.dragOverData;
33061 overEvent.tree = this.tree;
33062 overEvent.target = targetNode;
33063 overEvent.data = data;
33064 overEvent.point = pt;
33065 overEvent.source = dd;
33066 overEvent.rawEvent = e;
33067 overEvent.dropNode = dropNode;
33068 overEvent.cancel = false;
33069 var result = this.tree.fireEvent("nodedragover", overEvent);
33070 return overEvent.cancel === false && result !== false;
33073 getDropPoint : function(e, n, dd){
33076 return tn.allowChildren !== false ? "append" : false; // always append for root
33078 var dragEl = n.ddel;
33079 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33080 var y = Roo.lib.Event.getPageY(e);
33081 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33083 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33084 var noAppend = tn.allowChildren === false;
33085 if(this.appendOnly || tn.parentNode.allowChildren === false){
33086 return noAppend ? false : "append";
33088 var noBelow = false;
33089 if(!this.allowParentInsert){
33090 noBelow = tn.hasChildNodes() && tn.isExpanded();
33092 var q = (b - t) / (noAppend ? 2 : 3);
33093 if(y >= t && y < (t + q)){
33095 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33102 onNodeEnter : function(n, dd, e, data){
33103 this.cancelExpand();
33106 onNodeOver : function(n, dd, e, data){
33107 var pt = this.getDropPoint(e, n, dd);
33110 // auto node expand check
33111 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33112 this.queueExpand(node);
33113 }else if(pt != "append"){
33114 this.cancelExpand();
33117 // set the insert point style on the target node
33118 var returnCls = this.dropNotAllowed;
33119 if(this.isValidDropPoint(n, pt, dd, e, data)){
33124 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33125 cls = "x-tree-drag-insert-above";
33126 }else if(pt == "below"){
33127 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33128 cls = "x-tree-drag-insert-below";
33130 returnCls = "x-tree-drop-ok-append";
33131 cls = "x-tree-drag-append";
33133 if(this.lastInsertClass != cls){
33134 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33135 this.lastInsertClass = cls;
33142 onNodeOut : function(n, dd, e, data){
33143 this.cancelExpand();
33144 this.removeDropIndicators(n);
33147 onNodeDrop : function(n, dd, e, data){
33148 var point = this.getDropPoint(e, n, dd);
33149 var targetNode = n.node;
33150 targetNode.ui.startDrop();
33151 if(!this.isValidDropPoint(n, point, dd, e, data)){
33152 targetNode.ui.endDrop();
33155 // first try to find the drop node
33156 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33159 target: targetNode,
33164 dropNode: dropNode,
33167 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33168 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33169 targetNode.ui.endDrop();
33172 // allow target changing
33173 targetNode = dropEvent.target;
33174 if(point == "append" && !targetNode.isExpanded()){
33175 targetNode.expand(false, null, function(){
33176 this.completeDrop(dropEvent);
33177 }.createDelegate(this));
33179 this.completeDrop(dropEvent);
33184 completeDrop : function(de){
33185 var ns = de.dropNode, p = de.point, t = de.target;
33186 if(!(ns instanceof Array)){
33190 for(var i = 0, len = ns.length; i < len; i++){
33193 t.parentNode.insertBefore(n, t);
33194 }else if(p == "below"){
33195 t.parentNode.insertBefore(n, t.nextSibling);
33201 if(this.tree.hlDrop){
33205 this.tree.fireEvent("nodedrop", de);
33208 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33209 if(this.tree.hlDrop){
33210 dropNode.ui.focus();
33211 dropNode.ui.highlight();
33213 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33216 getTree : function(){
33220 removeDropIndicators : function(n){
33223 Roo.fly(el).removeClass([
33224 "x-tree-drag-insert-above",
33225 "x-tree-drag-insert-below",
33226 "x-tree-drag-append"]);
33227 this.lastInsertClass = "_noclass";
33231 beforeDragDrop : function(target, e, id){
33232 this.cancelExpand();
33236 afterRepair : function(data){
33237 if(data && Roo.enableFx){
33238 data.node.ui.highlight();
33247 * Ext JS Library 1.1.1
33248 * Copyright(c) 2006-2007, Ext JS, LLC.
33250 * Originally Released Under LGPL - original licence link has changed is not relivant.
33253 * <script type="text/javascript">
33257 if(Roo.dd.DragZone){
33258 Roo.tree.TreeDragZone = function(tree, config){
33259 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33263 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33264 ddGroup : "TreeDD",
33266 onBeforeDrag : function(data, e){
33268 return n && n.draggable && !n.disabled;
33271 onInitDrag : function(e){
33272 var data = this.dragData;
33273 this.tree.getSelectionModel().select(data.node);
33274 this.proxy.update("");
33275 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33276 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33279 getRepairXY : function(e, data){
33280 return data.node.ui.getDDRepairXY();
33283 onEndDrag : function(data, e){
33284 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33287 onValidDrop : function(dd, e, id){
33288 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33292 beforeInvalidDrop : function(e, id){
33293 // this scrolls the original position back into view
33294 var sm = this.tree.getSelectionModel();
33295 sm.clearSelections();
33296 sm.select(this.dragData.node);
33301 * Ext JS Library 1.1.1
33302 * Copyright(c) 2006-2007, Ext JS, LLC.
33304 * Originally Released Under LGPL - original licence link has changed is not relivant.
33307 * <script type="text/javascript">
33310 * @class Roo.tree.TreeEditor
33311 * @extends Roo.Editor
33312 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33313 * as the editor field.
33315 * @param {TreePanel} tree
33316 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33318 Roo.tree.TreeEditor = function(tree, config){
33319 config = config || {};
33320 var field = config.events ? config : new Roo.form.TextField(config);
33321 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33325 tree.on('beforeclick', this.beforeNodeClick, this);
33326 tree.getTreeEl().on('mousedown', this.hide, this);
33327 this.on('complete', this.updateNode, this);
33328 this.on('beforestartedit', this.fitToTree, this);
33329 this.on('startedit', this.bindScroll, this, {delay:10});
33330 this.on('specialkey', this.onSpecialKey, this);
33333 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33335 * @cfg {String} alignment
33336 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33342 * @cfg {Boolean} hideEl
33343 * True to hide the bound element while the editor is displayed (defaults to false)
33347 * @cfg {String} cls
33348 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33350 cls: "x-small-editor x-tree-editor",
33352 * @cfg {Boolean} shim
33353 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33359 * @cfg {Number} maxWidth
33360 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33361 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33362 * scroll and client offsets into account prior to each edit.
33369 fitToTree : function(ed, el){
33370 var td = this.tree.getTreeEl().dom, nd = el.dom;
33371 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33372 td.scrollLeft = nd.offsetLeft;
33376 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33377 this.setSize(w, '');
33381 triggerEdit : function(node){
33382 this.completeEdit();
33383 this.editNode = node;
33384 this.startEdit(node.ui.textNode, node.text);
33388 bindScroll : function(){
33389 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33393 beforeNodeClick : function(node, e){
33394 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33395 this.lastClick = new Date();
33396 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33398 this.triggerEdit(node);
33404 updateNode : function(ed, value){
33405 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33406 this.editNode.setText(value);
33410 onHide : function(){
33411 Roo.tree.TreeEditor.superclass.onHide.call(this);
33413 this.editNode.ui.focus();
33418 onSpecialKey : function(field, e){
33419 var k = e.getKey();
33423 }else if(k == e.ENTER && !e.hasModifier()){
33425 this.completeEdit();
33428 });//<Script type="text/javascript">
33431 * Ext JS Library 1.1.1
33432 * Copyright(c) 2006-2007, Ext JS, LLC.
33434 * Originally Released Under LGPL - original licence link has changed is not relivant.
33437 * <script type="text/javascript">
33441 * Not documented??? - probably should be...
33444 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33445 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33447 renderElements : function(n, a, targetNode, bulkRender){
33448 //consel.log("renderElements?");
33449 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33451 var t = n.getOwnerTree();
33452 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33454 var cols = t.columns;
33455 var bw = t.borderWidth;
33457 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33458 var cb = typeof a.checked == "boolean";
33459 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33460 var colcls = 'x-t-' + tid + '-c0';
33462 '<li class="x-tree-node">',
33465 '<div class="x-tree-node-el ', a.cls,'">',
33467 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33470 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33471 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33472 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33473 (a.icon ? ' x-tree-node-inline-icon' : ''),
33474 (a.iconCls ? ' '+a.iconCls : ''),
33475 '" unselectable="on" />',
33476 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33477 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33479 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33480 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33481 '<span unselectable="on" qtip="' + tx + '">',
33485 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33486 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33488 for(var i = 1, len = cols.length; i < len; i++){
33490 colcls = 'x-t-' + tid + '-c' +i;
33491 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33492 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33493 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33499 '<div class="x-clear"></div></div>',
33500 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33503 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33504 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33505 n.nextSibling.ui.getEl(), buf.join(""));
33507 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33509 var el = this.wrap.firstChild;
33511 this.elNode = el.firstChild;
33512 this.ranchor = el.childNodes[1];
33513 this.ctNode = this.wrap.childNodes[1];
33514 var cs = el.firstChild.childNodes;
33515 this.indentNode = cs[0];
33516 this.ecNode = cs[1];
33517 this.iconNode = cs[2];
33520 this.checkbox = cs[3];
33523 this.anchor = cs[index];
33525 this.textNode = cs[index].firstChild;
33527 //el.on("click", this.onClick, this);
33528 //el.on("dblclick", this.onDblClick, this);
33531 // console.log(this);
33533 initEvents : function(){
33534 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33537 var a = this.ranchor;
33539 var el = Roo.get(a);
33541 if(Roo.isOpera){ // opera render bug ignores the CSS
33542 el.setStyle("text-decoration", "none");
33545 el.on("click", this.onClick, this);
33546 el.on("dblclick", this.onDblClick, this);
33547 el.on("contextmenu", this.onContextMenu, this);
33551 /*onSelectedChange : function(state){
33554 this.addClass("x-tree-selected");
33557 this.removeClass("x-tree-selected");
33560 addClass : function(cls){
33562 Roo.fly(this.elRow).addClass(cls);
33568 removeClass : function(cls){
33570 Roo.fly(this.elRow).removeClass(cls);
33576 });//<Script type="text/javascript">
33580 * Ext JS Library 1.1.1
33581 * Copyright(c) 2006-2007, Ext JS, LLC.
33583 * Originally Released Under LGPL - original licence link has changed is not relivant.
33586 * <script type="text/javascript">
33591 * @class Roo.tree.ColumnTree
33592 * @extends Roo.data.TreePanel
33593 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33594 * @cfg {int} borderWidth compined right/left border allowance
33596 * @param {String/HTMLElement/Element} el The container element
33597 * @param {Object} config
33599 Roo.tree.ColumnTree = function(el, config)
33601 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33605 * Fire this event on a container when it resizes
33606 * @param {int} w Width
33607 * @param {int} h Height
33611 this.on('resize', this.onResize, this);
33614 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33618 borderWidth: Roo.isBorderBox ? 0 : 2,
33621 render : function(){
33622 // add the header.....
33624 Roo.tree.ColumnTree.superclass.render.apply(this);
33626 this.el.addClass('x-column-tree');
33628 this.headers = this.el.createChild(
33629 {cls:'x-tree-headers'},this.innerCt.dom);
33631 var cols = this.columns, c;
33632 var totalWidth = 0;
33634 var len = cols.length;
33635 for(var i = 0; i < len; i++){
33637 totalWidth += c.width;
33638 this.headEls.push(this.headers.createChild({
33639 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33641 cls:'x-tree-hd-text',
33644 style:'width:'+(c.width-this.borderWidth)+'px;'
33647 this.headers.createChild({cls:'x-clear'});
33648 // prevent floats from wrapping when clipped
33649 this.headers.setWidth(totalWidth);
33650 //this.innerCt.setWidth(totalWidth);
33651 this.innerCt.setStyle({ overflow: 'auto' });
33652 this.onResize(this.width, this.height);
33656 onResize : function(w,h)
33661 this.innerCt.setWidth(this.width);
33662 this.innerCt.setHeight(this.height-20);
33665 var cols = this.columns, c;
33666 var totalWidth = 0;
33668 var len = cols.length;
33669 for(var i = 0; i < len; i++){
33671 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33672 // it's the expander..
33673 expEl = this.headEls[i];
33676 totalWidth += c.width;
33680 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33682 this.headers.setWidth(w-20);
33691 * Ext JS Library 1.1.1
33692 * Copyright(c) 2006-2007, Ext JS, LLC.
33694 * Originally Released Under LGPL - original licence link has changed is not relivant.
33697 * <script type="text/javascript">
33701 * @class Roo.menu.Menu
33702 * @extends Roo.util.Observable
33703 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33704 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33706 * Creates a new Menu
33707 * @param {Object} config Configuration options
33709 Roo.menu.Menu = function(config){
33710 Roo.apply(this, config);
33711 this.id = this.id || Roo.id();
33714 * @event beforeshow
33715 * Fires before this menu is displayed
33716 * @param {Roo.menu.Menu} this
33720 * @event beforehide
33721 * Fires before this menu is hidden
33722 * @param {Roo.menu.Menu} this
33727 * Fires after this menu is displayed
33728 * @param {Roo.menu.Menu} this
33733 * Fires after this menu is hidden
33734 * @param {Roo.menu.Menu} this
33739 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33740 * @param {Roo.menu.Menu} this
33741 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33742 * @param {Roo.EventObject} e
33747 * Fires when the mouse is hovering over this menu
33748 * @param {Roo.menu.Menu} this
33749 * @param {Roo.EventObject} e
33750 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33755 * Fires when the mouse exits this menu
33756 * @param {Roo.menu.Menu} this
33757 * @param {Roo.EventObject} e
33758 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33763 * Fires when a menu item contained in this menu is clicked
33764 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33765 * @param {Roo.EventObject} e
33769 if (this.registerMenu) {
33770 Roo.menu.MenuMgr.register(this);
33773 var mis = this.items;
33774 this.items = new Roo.util.MixedCollection();
33776 this.add.apply(this, mis);
33780 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33782 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33786 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33787 * for bottom-right shadow (defaults to "sides")
33791 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33792 * this menu (defaults to "tl-tr?")
33794 subMenuAlign : "tl-tr?",
33796 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33797 * relative to its element of origin (defaults to "tl-bl?")
33799 defaultAlign : "tl-bl?",
33801 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33803 allowOtherMenus : false,
33805 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33807 registerMenu : true,
33812 render : function(){
33816 var el = this.el = new Roo.Layer({
33818 shadow:this.shadow,
33820 parentEl: this.parentEl || document.body,
33824 this.keyNav = new Roo.menu.MenuNav(this);
33827 el.addClass("x-menu-plain");
33830 el.addClass(this.cls);
33832 // generic focus element
33833 this.focusEl = el.createChild({
33834 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33836 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33837 ul.on("click", this.onClick, this);
33838 ul.on("mouseover", this.onMouseOver, this);
33839 ul.on("mouseout", this.onMouseOut, this);
33840 this.items.each(function(item){
33841 var li = document.createElement("li");
33842 li.className = "x-menu-list-item";
33843 ul.dom.appendChild(li);
33844 item.render(li, this);
33851 autoWidth : function(){
33852 var el = this.el, ul = this.ul;
33856 var w = this.width;
33859 }else if(Roo.isIE){
33860 el.setWidth(this.minWidth);
33861 var t = el.dom.offsetWidth; // force recalc
33862 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33867 delayAutoWidth : function(){
33870 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33872 this.awTask.delay(20);
33877 findTargetItem : function(e){
33878 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33879 if(t && t.menuItemId){
33880 return this.items.get(t.menuItemId);
33885 onClick : function(e){
33887 if(t = this.findTargetItem(e)){
33889 this.fireEvent("click", this, t, e);
33894 setActiveItem : function(item, autoExpand){
33895 if(item != this.activeItem){
33896 if(this.activeItem){
33897 this.activeItem.deactivate();
33899 this.activeItem = item;
33900 item.activate(autoExpand);
33901 }else if(autoExpand){
33907 tryActivate : function(start, step){
33908 var items = this.items;
33909 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
33910 var item = items.get(i);
33911 if(!item.disabled && item.canActivate){
33912 this.setActiveItem(item, false);
33920 onMouseOver : function(e){
33922 if(t = this.findTargetItem(e)){
33923 if(t.canActivate && !t.disabled){
33924 this.setActiveItem(t, true);
33927 this.fireEvent("mouseover", this, e, t);
33931 onMouseOut : function(e){
33933 if(t = this.findTargetItem(e)){
33934 if(t == this.activeItem && t.shouldDeactivate(e)){
33935 this.activeItem.deactivate();
33936 delete this.activeItem;
33939 this.fireEvent("mouseout", this, e, t);
33943 * Read-only. Returns true if the menu is currently displayed, else false.
33946 isVisible : function(){
33947 return this.el && !this.hidden;
33951 * Displays this menu relative to another element
33952 * @param {String/HTMLElement/Roo.Element} element The element to align to
33953 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
33954 * the element (defaults to this.defaultAlign)
33955 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33957 show : function(el, pos, parentMenu){
33958 this.parentMenu = parentMenu;
33962 this.fireEvent("beforeshow", this);
33963 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
33967 * Displays this menu at a specific xy position
33968 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
33969 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33971 showAt : function(xy, parentMenu, /* private: */_e){
33972 this.parentMenu = parentMenu;
33977 this.fireEvent("beforeshow", this);
33978 xy = this.el.adjustForConstraints(xy);
33982 this.hidden = false;
33984 this.fireEvent("show", this);
33987 focus : function(){
33989 this.doFocus.defer(50, this);
33993 doFocus : function(){
33995 this.focusEl.focus();
34000 * Hides this menu and optionally all parent menus
34001 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34003 hide : function(deep){
34004 if(this.el && this.isVisible()){
34005 this.fireEvent("beforehide", this);
34006 if(this.activeItem){
34007 this.activeItem.deactivate();
34008 this.activeItem = null;
34011 this.hidden = true;
34012 this.fireEvent("hide", this);
34014 if(deep === true && this.parentMenu){
34015 this.parentMenu.hide(true);
34020 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34021 * Any of the following are valid:
34023 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34024 * <li>An HTMLElement object which will be converted to a menu item</li>
34025 * <li>A menu item config object that will be created as a new menu item</li>
34026 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34027 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34032 var menu = new Roo.menu.Menu();
34034 // Create a menu item to add by reference
34035 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34037 // Add a bunch of items at once using different methods.
34038 // Only the last item added will be returned.
34039 var item = menu.add(
34040 menuItem, // add existing item by ref
34041 'Dynamic Item', // new TextItem
34042 '-', // new separator
34043 { text: 'Config Item' } // new item by config
34046 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34047 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34050 var a = arguments, l = a.length, item;
34051 for(var i = 0; i < l; i++){
34053 if ((typeof(el) == "object") && el.xtype && el.xns) {
34054 el = Roo.factory(el, Roo.menu);
34057 if(el.render){ // some kind of Item
34058 item = this.addItem(el);
34059 }else if(typeof el == "string"){ // string
34060 if(el == "separator" || el == "-"){
34061 item = this.addSeparator();
34063 item = this.addText(el);
34065 }else if(el.tagName || el.el){ // element
34066 item = this.addElement(el);
34067 }else if(typeof el == "object"){ // must be menu item config?
34068 item = this.addMenuItem(el);
34075 * Returns this menu's underlying {@link Roo.Element} object
34076 * @return {Roo.Element} The element
34078 getEl : function(){
34086 * Adds a separator bar to the menu
34087 * @return {Roo.menu.Item} The menu item that was added
34089 addSeparator : function(){
34090 return this.addItem(new Roo.menu.Separator());
34094 * Adds an {@link Roo.Element} object to the menu
34095 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34096 * @return {Roo.menu.Item} The menu item that was added
34098 addElement : function(el){
34099 return this.addItem(new Roo.menu.BaseItem(el));
34103 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34104 * @param {Roo.menu.Item} item The menu item to add
34105 * @return {Roo.menu.Item} The menu item that was added
34107 addItem : function(item){
34108 this.items.add(item);
34110 var li = document.createElement("li");
34111 li.className = "x-menu-list-item";
34112 this.ul.dom.appendChild(li);
34113 item.render(li, this);
34114 this.delayAutoWidth();
34120 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34121 * @param {Object} config A MenuItem config object
34122 * @return {Roo.menu.Item} The menu item that was added
34124 addMenuItem : function(config){
34125 if(!(config instanceof Roo.menu.Item)){
34126 if(typeof config.checked == "boolean"){ // must be check menu item config?
34127 config = new Roo.menu.CheckItem(config);
34129 config = new Roo.menu.Item(config);
34132 return this.addItem(config);
34136 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34137 * @param {String} text The text to display in the menu item
34138 * @return {Roo.menu.Item} The menu item that was added
34140 addText : function(text){
34141 return this.addItem(new Roo.menu.TextItem({ text : text }));
34145 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34146 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34147 * @param {Roo.menu.Item} item The menu item to add
34148 * @return {Roo.menu.Item} The menu item that was added
34150 insert : function(index, item){
34151 this.items.insert(index, item);
34153 var li = document.createElement("li");
34154 li.className = "x-menu-list-item";
34155 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34156 item.render(li, this);
34157 this.delayAutoWidth();
34163 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34164 * @param {Roo.menu.Item} item The menu item to remove
34166 remove : function(item){
34167 this.items.removeKey(item.id);
34172 * Removes and destroys all items in the menu
34174 removeAll : function(){
34176 while(f = this.items.first()){
34182 // MenuNav is a private utility class used internally by the Menu
34183 Roo.menu.MenuNav = function(menu){
34184 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34185 this.scope = this.menu = menu;
34188 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34189 doRelay : function(e, h){
34190 var k = e.getKey();
34191 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34192 this.menu.tryActivate(0, 1);
34195 return h.call(this.scope || this, e, this.menu);
34198 up : function(e, m){
34199 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34200 m.tryActivate(m.items.length-1, -1);
34204 down : function(e, m){
34205 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34206 m.tryActivate(0, 1);
34210 right : function(e, m){
34212 m.activeItem.expandMenu(true);
34216 left : function(e, m){
34218 if(m.parentMenu && m.parentMenu.activeItem){
34219 m.parentMenu.activeItem.activate();
34223 enter : function(e, m){
34225 e.stopPropagation();
34226 m.activeItem.onClick(e);
34227 m.fireEvent("click", this, m.activeItem);
34233 * Ext JS Library 1.1.1
34234 * Copyright(c) 2006-2007, Ext JS, LLC.
34236 * Originally Released Under LGPL - original licence link has changed is not relivant.
34239 * <script type="text/javascript">
34243 * @class Roo.menu.MenuMgr
34244 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34247 Roo.menu.MenuMgr = function(){
34248 var menus, active, groups = {}, attached = false, lastShow = new Date();
34250 // private - called when first menu is created
34253 active = new Roo.util.MixedCollection();
34254 Roo.get(document).addKeyListener(27, function(){
34255 if(active.length > 0){
34262 function hideAll(){
34263 if(active && active.length > 0){
34264 var c = active.clone();
34265 c.each(function(m){
34272 function onHide(m){
34274 if(active.length < 1){
34275 Roo.get(document).un("mousedown", onMouseDown);
34281 function onShow(m){
34282 var last = active.last();
34283 lastShow = new Date();
34286 Roo.get(document).on("mousedown", onMouseDown);
34290 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34291 m.parentMenu.activeChild = m;
34292 }else if(last && last.isVisible()){
34293 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34298 function onBeforeHide(m){
34300 m.activeChild.hide();
34302 if(m.autoHideTimer){
34303 clearTimeout(m.autoHideTimer);
34304 delete m.autoHideTimer;
34309 function onBeforeShow(m){
34310 var pm = m.parentMenu;
34311 if(!pm && !m.allowOtherMenus){
34313 }else if(pm && pm.activeChild && active != m){
34314 pm.activeChild.hide();
34319 function onMouseDown(e){
34320 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34326 function onBeforeCheck(mi, state){
34328 var g = groups[mi.group];
34329 for(var i = 0, l = g.length; i < l; i++){
34331 g[i].setChecked(false);
34340 * Hides all menus that are currently visible
34342 hideAll : function(){
34347 register : function(menu){
34351 menus[menu.id] = menu;
34352 menu.on("beforehide", onBeforeHide);
34353 menu.on("hide", onHide);
34354 menu.on("beforeshow", onBeforeShow);
34355 menu.on("show", onShow);
34356 var g = menu.group;
34357 if(g && menu.events["checkchange"]){
34361 groups[g].push(menu);
34362 menu.on("checkchange", onCheck);
34367 * Returns a {@link Roo.menu.Menu} object
34368 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34369 * be used to generate and return a new Menu instance.
34371 get : function(menu){
34372 if(typeof menu == "string"){ // menu id
34373 return menus[menu];
34374 }else if(menu.events){ // menu instance
34376 }else if(typeof menu.length == 'number'){ // array of menu items?
34377 return new Roo.menu.Menu({items:menu});
34378 }else{ // otherwise, must be a config
34379 return new Roo.menu.Menu(menu);
34384 unregister : function(menu){
34385 delete menus[menu.id];
34386 menu.un("beforehide", onBeforeHide);
34387 menu.un("hide", onHide);
34388 menu.un("beforeshow", onBeforeShow);
34389 menu.un("show", onShow);
34390 var g = menu.group;
34391 if(g && menu.events["checkchange"]){
34392 groups[g].remove(menu);
34393 menu.un("checkchange", onCheck);
34398 registerCheckable : function(menuItem){
34399 var g = menuItem.group;
34404 groups[g].push(menuItem);
34405 menuItem.on("beforecheckchange", onBeforeCheck);
34410 unregisterCheckable : function(menuItem){
34411 var g = menuItem.group;
34413 groups[g].remove(menuItem);
34414 menuItem.un("beforecheckchange", onBeforeCheck);
34420 * Ext JS Library 1.1.1
34421 * Copyright(c) 2006-2007, Ext JS, LLC.
34423 * Originally Released Under LGPL - original licence link has changed is not relivant.
34426 * <script type="text/javascript">
34431 * @class Roo.menu.BaseItem
34432 * @extends Roo.Component
34433 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34434 * management and base configuration options shared by all menu components.
34436 * Creates a new BaseItem
34437 * @param {Object} config Configuration options
34439 Roo.menu.BaseItem = function(config){
34440 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34445 * Fires when this item is clicked
34446 * @param {Roo.menu.BaseItem} this
34447 * @param {Roo.EventObject} e
34452 * Fires when this item is activated
34453 * @param {Roo.menu.BaseItem} this
34457 * @event deactivate
34458 * Fires when this item is deactivated
34459 * @param {Roo.menu.BaseItem} this
34465 this.on("click", this.handler, this.scope, true);
34469 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34471 * @cfg {Function} handler
34472 * A function that will handle the click event of this menu item (defaults to undefined)
34475 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34477 canActivate : false,
34479 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34481 activeClass : "x-menu-item-active",
34483 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34485 hideOnClick : true,
34487 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34492 ctype: "Roo.menu.BaseItem",
34495 actionMode : "container",
34498 render : function(container, parentMenu){
34499 this.parentMenu = parentMenu;
34500 Roo.menu.BaseItem.superclass.render.call(this, container);
34501 this.container.menuItemId = this.id;
34505 onRender : function(container, position){
34506 this.el = Roo.get(this.el);
34507 container.dom.appendChild(this.el.dom);
34511 onClick : function(e){
34512 if(!this.disabled && this.fireEvent("click", this, e) !== false
34513 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34514 this.handleClick(e);
34521 activate : function(){
34525 var li = this.container;
34526 li.addClass(this.activeClass);
34527 this.region = li.getRegion().adjust(2, 2, -2, -2);
34528 this.fireEvent("activate", this);
34533 deactivate : function(){
34534 this.container.removeClass(this.activeClass);
34535 this.fireEvent("deactivate", this);
34539 shouldDeactivate : function(e){
34540 return !this.region || !this.region.contains(e.getPoint());
34544 handleClick : function(e){
34545 if(this.hideOnClick){
34546 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34551 expandMenu : function(autoActivate){
34556 hideMenu : function(){
34561 * Ext JS Library 1.1.1
34562 * Copyright(c) 2006-2007, Ext JS, LLC.
34564 * Originally Released Under LGPL - original licence link has changed is not relivant.
34567 * <script type="text/javascript">
34571 * @class Roo.menu.Adapter
34572 * @extends Roo.menu.BaseItem
34573 * 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.
34574 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34576 * Creates a new Adapter
34577 * @param {Object} config Configuration options
34579 Roo.menu.Adapter = function(component, config){
34580 Roo.menu.Adapter.superclass.constructor.call(this, config);
34581 this.component = component;
34583 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34585 canActivate : true,
34588 onRender : function(container, position){
34589 this.component.render(container);
34590 this.el = this.component.getEl();
34594 activate : function(){
34598 this.component.focus();
34599 this.fireEvent("activate", this);
34604 deactivate : function(){
34605 this.fireEvent("deactivate", this);
34609 disable : function(){
34610 this.component.disable();
34611 Roo.menu.Adapter.superclass.disable.call(this);
34615 enable : function(){
34616 this.component.enable();
34617 Roo.menu.Adapter.superclass.enable.call(this);
34621 * Ext JS Library 1.1.1
34622 * Copyright(c) 2006-2007, Ext JS, LLC.
34624 * Originally Released Under LGPL - original licence link has changed is not relivant.
34627 * <script type="text/javascript">
34631 * @class Roo.menu.TextItem
34632 * @extends Roo.menu.BaseItem
34633 * Adds a static text string to a menu, usually used as either a heading or group separator.
34634 * Note: old style constructor with text is still supported.
34637 * Creates a new TextItem
34638 * @param {Object} cfg Configuration
34640 Roo.menu.TextItem = function(cfg){
34641 if (typeof(cfg) == 'string') {
34644 Roo.apply(this,cfg);
34647 Roo.menu.TextItem.superclass.constructor.call(this);
34650 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34652 * @cfg {Boolean} text Text to show on item.
34657 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34659 hideOnClick : false,
34661 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34663 itemCls : "x-menu-text",
34666 onRender : function(){
34667 var s = document.createElement("span");
34668 s.className = this.itemCls;
34669 s.innerHTML = this.text;
34671 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34675 * Ext JS Library 1.1.1
34676 * Copyright(c) 2006-2007, Ext JS, LLC.
34678 * Originally Released Under LGPL - original licence link has changed is not relivant.
34681 * <script type="text/javascript">
34685 * @class Roo.menu.Separator
34686 * @extends Roo.menu.BaseItem
34687 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34688 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34690 * @param {Object} config Configuration options
34692 Roo.menu.Separator = function(config){
34693 Roo.menu.Separator.superclass.constructor.call(this, config);
34696 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34698 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34700 itemCls : "x-menu-sep",
34702 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34704 hideOnClick : false,
34707 onRender : function(li){
34708 var s = document.createElement("span");
34709 s.className = this.itemCls;
34710 s.innerHTML = " ";
34712 li.addClass("x-menu-sep-li");
34713 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34717 * Ext JS Library 1.1.1
34718 * Copyright(c) 2006-2007, Ext JS, LLC.
34720 * Originally Released Under LGPL - original licence link has changed is not relivant.
34723 * <script type="text/javascript">
34726 * @class Roo.menu.Item
34727 * @extends Roo.menu.BaseItem
34728 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34729 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34730 * activation and click handling.
34732 * Creates a new Item
34733 * @param {Object} config Configuration options
34735 Roo.menu.Item = function(config){
34736 Roo.menu.Item.superclass.constructor.call(this, config);
34738 this.menu = Roo.menu.MenuMgr.get(this.menu);
34741 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34744 * @cfg {String} text
34745 * The text to show on the menu item.
34749 * @cfg {String} HTML to render in menu
34750 * The text to show on the menu item (HTML version).
34754 * @cfg {String} icon
34755 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34759 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34761 itemCls : "x-menu-item",
34763 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34765 canActivate : true,
34767 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34770 // doc'd in BaseItem
34774 ctype: "Roo.menu.Item",
34777 onRender : function(container, position){
34778 var el = document.createElement("a");
34779 el.hideFocus = true;
34780 el.unselectable = "on";
34781 el.href = this.href || "#";
34782 if(this.hrefTarget){
34783 el.target = this.hrefTarget;
34785 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34787 var html = this.html.length ? this.html : String.format('{0}',this.text);
34789 el.innerHTML = String.format(
34790 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
34791 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
34793 Roo.menu.Item.superclass.onRender.call(this, container, position);
34797 * Sets the text to display in this menu item
34798 * @param {String} text The text to display
34799 * @param {Boolean} isHTML true to indicate text is pure html.
34801 setText : function(text, isHTML){
34809 var html = this.html.length ? this.html : String.format('{0}',this.text);
34811 this.el.update(String.format(
34812 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
34813 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34814 this.parentMenu.autoWidth();
34819 handleClick : function(e){
34820 if(!this.href){ // if no link defined, stop the event automatically
34823 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34827 activate : function(autoExpand){
34828 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34838 shouldDeactivate : function(e){
34839 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34840 if(this.menu && this.menu.isVisible()){
34841 return !this.menu.getEl().getRegion().contains(e.getPoint());
34849 deactivate : function(){
34850 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34855 expandMenu : function(autoActivate){
34856 if(!this.disabled && this.menu){
34857 clearTimeout(this.hideTimer);
34858 delete this.hideTimer;
34859 if(!this.menu.isVisible() && !this.showTimer){
34860 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34861 }else if (this.menu.isVisible() && autoActivate){
34862 this.menu.tryActivate(0, 1);
34868 deferExpand : function(autoActivate){
34869 delete this.showTimer;
34870 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34872 this.menu.tryActivate(0, 1);
34877 hideMenu : function(){
34878 clearTimeout(this.showTimer);
34879 delete this.showTimer;
34880 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34881 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34886 deferHide : function(){
34887 delete this.hideTimer;
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">
34902 * @class Roo.menu.CheckItem
34903 * @extends Roo.menu.Item
34904 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
34906 * Creates a new CheckItem
34907 * @param {Object} config Configuration options
34909 Roo.menu.CheckItem = function(config){
34910 Roo.menu.CheckItem.superclass.constructor.call(this, config);
34913 * @event beforecheckchange
34914 * Fires before the checked value is set, providing an opportunity to cancel if needed
34915 * @param {Roo.menu.CheckItem} this
34916 * @param {Boolean} checked The new checked value that will be set
34918 "beforecheckchange" : true,
34920 * @event checkchange
34921 * Fires after the checked value has been set
34922 * @param {Roo.menu.CheckItem} this
34923 * @param {Boolean} checked The checked value that was set
34925 "checkchange" : true
34927 if(this.checkHandler){
34928 this.on('checkchange', this.checkHandler, this.scope);
34931 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
34933 * @cfg {String} group
34934 * All check items with the same group name will automatically be grouped into a single-select
34935 * radio button group (defaults to '')
34938 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
34940 itemCls : "x-menu-item x-menu-check-item",
34942 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
34944 groupClass : "x-menu-group-item",
34947 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
34948 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
34949 * initialized with checked = true will be rendered as checked.
34954 ctype: "Roo.menu.CheckItem",
34957 onRender : function(c){
34958 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
34960 this.el.addClass(this.groupClass);
34962 Roo.menu.MenuMgr.registerCheckable(this);
34964 this.checked = false;
34965 this.setChecked(true, true);
34970 destroy : function(){
34972 Roo.menu.MenuMgr.unregisterCheckable(this);
34974 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
34978 * Set the checked state of this item
34979 * @param {Boolean} checked The new checked value
34980 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
34982 setChecked : function(state, suppressEvent){
34983 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
34984 if(this.container){
34985 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
34987 this.checked = state;
34988 if(suppressEvent !== true){
34989 this.fireEvent("checkchange", this, state);
34995 handleClick : function(e){
34996 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
34997 this.setChecked(!this.checked);
34999 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35003 * Ext JS Library 1.1.1
35004 * Copyright(c) 2006-2007, Ext JS, LLC.
35006 * Originally Released Under LGPL - original licence link has changed is not relivant.
35009 * <script type="text/javascript">
35013 * @class Roo.menu.DateItem
35014 * @extends Roo.menu.Adapter
35015 * A menu item that wraps the {@link Roo.DatPicker} component.
35017 * Creates a new DateItem
35018 * @param {Object} config Configuration options
35020 Roo.menu.DateItem = function(config){
35021 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35022 /** The Roo.DatePicker object @type Roo.DatePicker */
35023 this.picker = this.component;
35024 this.addEvents({select: true});
35026 this.picker.on("render", function(picker){
35027 picker.getEl().swallowEvent("click");
35028 picker.container.addClass("x-menu-date-item");
35031 this.picker.on("select", this.onSelect, this);
35034 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35036 onSelect : function(picker, date){
35037 this.fireEvent("select", this, date, picker);
35038 Roo.menu.DateItem.superclass.handleClick.call(this);
35042 * Ext JS Library 1.1.1
35043 * Copyright(c) 2006-2007, Ext JS, LLC.
35045 * Originally Released Under LGPL - original licence link has changed is not relivant.
35048 * <script type="text/javascript">
35052 * @class Roo.menu.ColorItem
35053 * @extends Roo.menu.Adapter
35054 * A menu item that wraps the {@link Roo.ColorPalette} component.
35056 * Creates a new ColorItem
35057 * @param {Object} config Configuration options
35059 Roo.menu.ColorItem = function(config){
35060 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35061 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35062 this.palette = this.component;
35063 this.relayEvents(this.palette, ["select"]);
35064 if(this.selectHandler){
35065 this.on('select', this.selectHandler, this.scope);
35068 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35070 * Ext JS Library 1.1.1
35071 * Copyright(c) 2006-2007, Ext JS, LLC.
35073 * Originally Released Under LGPL - original licence link has changed is not relivant.
35076 * <script type="text/javascript">
35081 * @class Roo.menu.DateMenu
35082 * @extends Roo.menu.Menu
35083 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35085 * Creates a new DateMenu
35086 * @param {Object} config Configuration options
35088 Roo.menu.DateMenu = function(config){
35089 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35091 var di = new Roo.menu.DateItem(config);
35094 * The {@link Roo.DatePicker} instance for this DateMenu
35097 this.picker = di.picker;
35100 * @param {DatePicker} picker
35101 * @param {Date} date
35103 this.relayEvents(di, ["select"]);
35105 this.on('beforeshow', function(){
35107 this.picker.hideMonthPicker(true);
35111 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35115 * Ext JS Library 1.1.1
35116 * Copyright(c) 2006-2007, Ext JS, LLC.
35118 * Originally Released Under LGPL - original licence link has changed is not relivant.
35121 * <script type="text/javascript">
35126 * @class Roo.menu.ColorMenu
35127 * @extends Roo.menu.Menu
35128 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35130 * Creates a new ColorMenu
35131 * @param {Object} config Configuration options
35133 Roo.menu.ColorMenu = function(config){
35134 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35136 var ci = new Roo.menu.ColorItem(config);
35139 * The {@link Roo.ColorPalette} instance for this ColorMenu
35140 * @type ColorPalette
35142 this.palette = ci.palette;
35145 * @param {ColorPalette} palette
35146 * @param {String} color
35148 this.relayEvents(ci, ["select"]);
35150 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35152 * Ext JS Library 1.1.1
35153 * Copyright(c) 2006-2007, Ext JS, LLC.
35155 * Originally Released Under LGPL - original licence link has changed is not relivant.
35158 * <script type="text/javascript">
35162 * @class Roo.form.Field
35163 * @extends Roo.BoxComponent
35164 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35166 * Creates a new Field
35167 * @param {Object} config Configuration options
35169 Roo.form.Field = function(config){
35170 Roo.form.Field.superclass.constructor.call(this, config);
35173 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35175 * @cfg {String} fieldLabel Label to use when rendering a form.
35178 * @cfg {String} qtip Mouse over tip
35182 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35184 invalidClass : "x-form-invalid",
35186 * @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")
35188 invalidText : "The value in this field is invalid",
35190 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35192 focusClass : "x-form-focus",
35194 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35195 automatic validation (defaults to "keyup").
35197 validationEvent : "keyup",
35199 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35201 validateOnBlur : true,
35203 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35205 validationDelay : 250,
35207 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35208 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35210 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35212 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35214 fieldClass : "x-form-field",
35216 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35219 ----------- ----------------------------------------------------------------------
35220 qtip Display a quick tip when the user hovers over the field
35221 title Display a default browser title attribute popup
35222 under Add a block div beneath the field containing the error text
35223 side Add an error icon to the right of the field with a popup on hover
35224 [element id] Add the error text directly to the innerHTML of the specified element
35227 msgTarget : 'qtip',
35229 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35234 * @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.
35239 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35244 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35246 inputType : undefined,
35249 * @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).
35251 tabIndex : undefined,
35254 isFormField : true,
35259 * @property {Roo.Element} fieldEl
35260 * Element Containing the rendered Field (with label etc.)
35263 * @cfg {Mixed} value A value to initialize this field with.
35268 * @cfg {String} name The field's HTML name attribute.
35271 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35275 initComponent : function(){
35276 Roo.form.Field.superclass.initComponent.call(this);
35280 * Fires when this field receives input focus.
35281 * @param {Roo.form.Field} this
35286 * Fires when this field loses input focus.
35287 * @param {Roo.form.Field} this
35291 * @event specialkey
35292 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35293 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35294 * @param {Roo.form.Field} this
35295 * @param {Roo.EventObject} e The event object
35300 * Fires just before the field blurs if the field value has changed.
35301 * @param {Roo.form.Field} this
35302 * @param {Mixed} newValue The new value
35303 * @param {Mixed} oldValue The original value
35308 * Fires after the field has been marked as invalid.
35309 * @param {Roo.form.Field} this
35310 * @param {String} msg The validation message
35315 * Fires after the field has been validated with no errors.
35316 * @param {Roo.form.Field} this
35321 * Fires after the key up
35322 * @param {Roo.form.Field} this
35323 * @param {Roo.EventObject} e The event Object
35330 * Returns the name attribute of the field if available
35331 * @return {String} name The field name
35333 getName: function(){
35334 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35338 onRender : function(ct, position){
35339 Roo.form.Field.superclass.onRender.call(this, ct, position);
35341 var cfg = this.getAutoCreate();
35343 cfg.name = this.name || this.id;
35345 if(this.inputType){
35346 cfg.type = this.inputType;
35348 this.el = ct.createChild(cfg, position);
35350 var type = this.el.dom.type;
35352 if(type == 'password'){
35355 this.el.addClass('x-form-'+type);
35358 this.el.dom.readOnly = true;
35360 if(this.tabIndex !== undefined){
35361 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35364 this.el.addClass([this.fieldClass, this.cls]);
35369 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35370 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35371 * @return {Roo.form.Field} this
35373 applyTo : function(target){
35374 this.allowDomMove = false;
35375 this.el = Roo.get(target);
35376 this.render(this.el.dom.parentNode);
35381 initValue : function(){
35382 if(this.value !== undefined){
35383 this.setValue(this.value);
35384 }else if(this.el.dom.value.length > 0){
35385 this.setValue(this.el.dom.value);
35390 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35392 isDirty : function() {
35393 if(this.disabled) {
35396 return String(this.getValue()) !== String(this.originalValue);
35400 afterRender : function(){
35401 Roo.form.Field.superclass.afterRender.call(this);
35406 fireKey : function(e){
35407 //Roo.log('field ' + e.getKey());
35408 if(e.isNavKeyPress()){
35409 this.fireEvent("specialkey", this, e);
35414 * Resets the current field value to the originally loaded value and clears any validation messages
35416 reset : function(){
35417 this.setValue(this.originalValue);
35418 this.clearInvalid();
35422 initEvents : function(){
35423 // safari killled keypress - so keydown is now used..
35424 this.el.on("keydown" , this.fireKey, this);
35425 this.el.on("focus", this.onFocus, this);
35426 this.el.on("blur", this.onBlur, this);
35427 this.el.relayEvent('keyup', this);
35429 // reference to original value for reset
35430 this.originalValue = this.getValue();
35434 onFocus : function(){
35435 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35436 this.el.addClass(this.focusClass);
35438 if(!this.hasFocus){
35439 this.hasFocus = true;
35440 this.startValue = this.getValue();
35441 this.fireEvent("focus", this);
35445 beforeBlur : Roo.emptyFn,
35448 onBlur : function(){
35450 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35451 this.el.removeClass(this.focusClass);
35453 this.hasFocus = false;
35454 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35457 var v = this.getValue();
35458 if(String(v) !== String(this.startValue)){
35459 this.fireEvent('change', this, v, this.startValue);
35461 this.fireEvent("blur", this);
35465 * Returns whether or not the field value is currently valid
35466 * @param {Boolean} preventMark True to disable marking the field invalid
35467 * @return {Boolean} True if the value is valid, else false
35469 isValid : function(preventMark){
35473 var restore = this.preventMark;
35474 this.preventMark = preventMark === true;
35475 var v = this.validateValue(this.processValue(this.getRawValue()));
35476 this.preventMark = restore;
35481 * Validates the field value
35482 * @return {Boolean} True if the value is valid, else false
35484 validate : function(){
35485 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35486 this.clearInvalid();
35492 processValue : function(value){
35497 // Subclasses should provide the validation implementation by overriding this
35498 validateValue : function(value){
35503 * Mark this field as invalid
35504 * @param {String} msg The validation message
35506 markInvalid : function(msg){
35507 if(!this.rendered || this.preventMark){ // not rendered
35510 this.el.addClass(this.invalidClass);
35511 msg = msg || this.invalidText;
35512 switch(this.msgTarget){
35514 this.el.dom.qtip = msg;
35515 this.el.dom.qclass = 'x-form-invalid-tip';
35516 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35517 Roo.QuickTips.enable();
35521 this.el.dom.title = msg;
35525 var elp = this.el.findParent('.x-form-element', 5, true);
35526 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35527 this.errorEl.setWidth(elp.getWidth(true)-20);
35529 this.errorEl.update(msg);
35530 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35533 if(!this.errorIcon){
35534 var elp = this.el.findParent('.x-form-element', 5, true);
35535 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35537 this.alignErrorIcon();
35538 this.errorIcon.dom.qtip = msg;
35539 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35540 this.errorIcon.show();
35541 this.on('resize', this.alignErrorIcon, this);
35544 var t = Roo.getDom(this.msgTarget);
35546 t.style.display = this.msgDisplay;
35549 this.fireEvent('invalid', this, msg);
35553 alignErrorIcon : function(){
35554 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35558 * Clear any invalid styles/messages for this field
35560 clearInvalid : function(){
35561 if(!this.rendered || this.preventMark){ // not rendered
35564 this.el.removeClass(this.invalidClass);
35565 switch(this.msgTarget){
35567 this.el.dom.qtip = '';
35570 this.el.dom.title = '';
35574 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35578 if(this.errorIcon){
35579 this.errorIcon.dom.qtip = '';
35580 this.errorIcon.hide();
35581 this.un('resize', this.alignErrorIcon, this);
35585 var t = Roo.getDom(this.msgTarget);
35587 t.style.display = 'none';
35590 this.fireEvent('valid', this);
35594 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35595 * @return {Mixed} value The field value
35597 getRawValue : function(){
35598 var v = this.el.getValue();
35599 if(v === this.emptyText){
35606 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35607 * @return {Mixed} value The field value
35609 getValue : function(){
35610 var v = this.el.getValue();
35611 if(v === this.emptyText || v === undefined){
35618 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35619 * @param {Mixed} value The value to set
35621 setRawValue : function(v){
35622 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35626 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35627 * @param {Mixed} value The value to set
35629 setValue : function(v){
35632 this.el.dom.value = (v === null || v === undefined ? '' : v);
35637 adjustSize : function(w, h){
35638 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35639 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35643 adjustWidth : function(tag, w){
35644 tag = tag.toLowerCase();
35645 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35646 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35647 if(tag == 'input'){
35650 if(tag = 'textarea'){
35653 }else if(Roo.isOpera){
35654 if(tag == 'input'){
35657 if(tag = 'textarea'){
35667 // anything other than normal should be considered experimental
35668 Roo.form.Field.msgFx = {
35670 show: function(msgEl, f){
35671 msgEl.setDisplayed('block');
35674 hide : function(msgEl, f){
35675 msgEl.setDisplayed(false).update('');
35680 show: function(msgEl, f){
35681 msgEl.slideIn('t', {stopFx:true});
35684 hide : function(msgEl, f){
35685 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35690 show: function(msgEl, f){
35691 msgEl.fixDisplay();
35692 msgEl.alignTo(f.el, 'tl-tr');
35693 msgEl.slideIn('l', {stopFx:true});
35696 hide : function(msgEl, f){
35697 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35702 * Ext JS Library 1.1.1
35703 * Copyright(c) 2006-2007, Ext JS, LLC.
35705 * Originally Released Under LGPL - original licence link has changed is not relivant.
35708 * <script type="text/javascript">
35713 * @class Roo.form.TextField
35714 * @extends Roo.form.Field
35715 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35716 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35718 * Creates a new TextField
35719 * @param {Object} config Configuration options
35721 Roo.form.TextField = function(config){
35722 Roo.form.TextField.superclass.constructor.call(this, config);
35726 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35727 * according to the default logic, but this event provides a hook for the developer to apply additional
35728 * logic at runtime to resize the field if needed.
35729 * @param {Roo.form.Field} this This text field
35730 * @param {Number} width The new field width
35736 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35738 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35742 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35746 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35750 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35754 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35758 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35760 disableKeyFilter : false,
35762 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35766 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35770 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35772 maxLength : Number.MAX_VALUE,
35774 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35776 minLengthText : "The minimum length for this field is {0}",
35778 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35780 maxLengthText : "The maximum length for this field is {0}",
35782 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35784 selectOnFocus : false,
35786 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35788 blankText : "This field is required",
35790 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35791 * If available, this function will be called only after the basic validators all return true, and will be passed the
35792 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35796 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35797 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35798 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35802 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35806 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35810 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35811 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35813 emptyClass : 'x-form-empty-field',
35816 initEvents : function(){
35817 Roo.form.TextField.superclass.initEvents.call(this);
35818 if(this.validationEvent == 'keyup'){
35819 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35820 this.el.on('keyup', this.filterValidation, this);
35822 else if(this.validationEvent !== false){
35823 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35825 if(this.selectOnFocus || this.emptyText){
35826 this.on("focus", this.preFocus, this);
35827 if(this.emptyText){
35828 this.on('blur', this.postBlur, this);
35829 this.applyEmptyText();
35832 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35833 this.el.on("keypress", this.filterKeys, this);
35836 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35837 this.el.on("click", this.autoSize, this);
35841 processValue : function(value){
35842 if(this.stripCharsRe){
35843 var newValue = value.replace(this.stripCharsRe, '');
35844 if(newValue !== value){
35845 this.setRawValue(newValue);
35852 filterValidation : function(e){
35853 if(!e.isNavKeyPress()){
35854 this.validationTask.delay(this.validationDelay);
35859 onKeyUp : function(e){
35860 if(!e.isNavKeyPress()){
35866 * Resets the current field value to the originally-loaded value and clears any validation messages.
35867 * Also adds emptyText and emptyClass if the original value was blank.
35869 reset : function(){
35870 Roo.form.TextField.superclass.reset.call(this);
35871 this.applyEmptyText();
35874 applyEmptyText : function(){
35875 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35876 this.setRawValue(this.emptyText);
35877 this.el.addClass(this.emptyClass);
35882 preFocus : function(){
35883 if(this.emptyText){
35884 if(this.el.dom.value == this.emptyText){
35885 this.setRawValue('');
35887 this.el.removeClass(this.emptyClass);
35889 if(this.selectOnFocus){
35890 this.el.dom.select();
35895 postBlur : function(){
35896 this.applyEmptyText();
35900 filterKeys : function(e){
35901 var k = e.getKey();
35902 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
35905 var c = e.getCharCode(), cc = String.fromCharCode(c);
35906 if(Roo.isIE && (e.isSpecialKey() || !cc)){
35909 if(!this.maskRe.test(cc)){
35914 setValue : function(v){
35915 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
35916 this.el.removeClass(this.emptyClass);
35918 Roo.form.TextField.superclass.setValue.apply(this, arguments);
35919 this.applyEmptyText();
35924 * Validates a value according to the field's validation rules and marks the field as invalid
35925 * if the validation fails
35926 * @param {Mixed} value The value to validate
35927 * @return {Boolean} True if the value is valid, else false
35929 validateValue : function(value){
35930 if(value.length < 1 || value === this.emptyText){ // if it's blank
35931 if(this.allowBlank){
35932 this.clearInvalid();
35935 this.markInvalid(this.blankText);
35939 if(value.length < this.minLength){
35940 this.markInvalid(String.format(this.minLengthText, this.minLength));
35943 if(value.length > this.maxLength){
35944 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
35948 var vt = Roo.form.VTypes;
35949 if(!vt[this.vtype](value, this)){
35950 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
35954 if(typeof this.validator == "function"){
35955 var msg = this.validator(value);
35957 this.markInvalid(msg);
35961 if(this.regex && !this.regex.test(value)){
35962 this.markInvalid(this.regexText);
35969 * Selects text in this field
35970 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
35971 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
35973 selectText : function(start, end){
35974 var v = this.getRawValue();
35976 start = start === undefined ? 0 : start;
35977 end = end === undefined ? v.length : end;
35978 var d = this.el.dom;
35979 if(d.setSelectionRange){
35980 d.setSelectionRange(start, end);
35981 }else if(d.createTextRange){
35982 var range = d.createTextRange();
35983 range.moveStart("character", start);
35984 range.moveEnd("character", v.length-end);
35991 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
35992 * This only takes effect if grow = true, and fires the autosize event.
35994 autoSize : function(){
35995 if(!this.grow || !this.rendered){
35999 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36002 var v = el.dom.value;
36003 var d = document.createElement('div');
36004 d.appendChild(document.createTextNode(v));
36008 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36009 this.el.setWidth(w);
36010 this.fireEvent("autosize", this, w);
36014 * Ext JS Library 1.1.1
36015 * Copyright(c) 2006-2007, Ext JS, LLC.
36017 * Originally Released Under LGPL - original licence link has changed is not relivant.
36020 * <script type="text/javascript">
36024 * @class Roo.form.Hidden
36025 * @extends Roo.form.TextField
36026 * Simple Hidden element used on forms
36028 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36031 * Creates a new Hidden form element.
36032 * @param {Object} config Configuration options
36037 // easy hidden field...
36038 Roo.form.Hidden = function(config){
36039 Roo.form.Hidden.superclass.constructor.call(this, config);
36042 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36044 inputType: 'hidden',
36047 labelSeparator: '',
36049 itemCls : 'x-form-item-display-none'
36057 * Ext JS Library 1.1.1
36058 * Copyright(c) 2006-2007, Ext JS, LLC.
36060 * Originally Released Under LGPL - original licence link has changed is not relivant.
36063 * <script type="text/javascript">
36067 * @class Roo.form.TriggerField
36068 * @extends Roo.form.TextField
36069 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36070 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36071 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36072 * for which you can provide a custom implementation. For example:
36074 var trigger = new Roo.form.TriggerField();
36075 trigger.onTriggerClick = myTriggerFn;
36076 trigger.applyTo('my-field');
36079 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36080 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36081 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36082 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36084 * Create a new TriggerField.
36085 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36086 * to the base TextField)
36088 Roo.form.TriggerField = function(config){
36089 this.mimicing = false;
36090 Roo.form.TriggerField.superclass.constructor.call(this, config);
36093 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36095 * @cfg {String} triggerClass A CSS class to apply to the trigger
36098 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36099 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36101 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36103 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36107 /** @cfg {Boolean} grow @hide */
36108 /** @cfg {Number} growMin @hide */
36109 /** @cfg {Number} growMax @hide */
36115 autoSize: Roo.emptyFn,
36119 deferHeight : true,
36122 actionMode : 'wrap',
36124 onResize : function(w, h){
36125 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36126 if(typeof w == 'number'){
36127 var x = w - this.trigger.getWidth();
36128 this.el.setWidth(this.adjustWidth('input', x));
36129 this.trigger.setStyle('left', x+'px');
36134 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36137 getResizeEl : function(){
36142 getPositionEl : function(){
36147 alignErrorIcon : function(){
36148 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36152 onRender : function(ct, position){
36153 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36154 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36155 this.trigger = this.wrap.createChild(this.triggerConfig ||
36156 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36157 if(this.hideTrigger){
36158 this.trigger.setDisplayed(false);
36160 this.initTrigger();
36162 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36167 initTrigger : function(){
36168 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36169 this.trigger.addClassOnOver('x-form-trigger-over');
36170 this.trigger.addClassOnClick('x-form-trigger-click');
36174 onDestroy : function(){
36176 this.trigger.removeAllListeners();
36177 this.trigger.remove();
36180 this.wrap.remove();
36182 Roo.form.TriggerField.superclass.onDestroy.call(this);
36186 onFocus : function(){
36187 Roo.form.TriggerField.superclass.onFocus.call(this);
36188 if(!this.mimicing){
36189 this.wrap.addClass('x-trigger-wrap-focus');
36190 this.mimicing = true;
36191 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36192 if(this.monitorTab){
36193 this.el.on("keydown", this.checkTab, this);
36199 checkTab : function(e){
36200 if(e.getKey() == e.TAB){
36201 this.triggerBlur();
36206 onBlur : function(){
36211 mimicBlur : function(e, t){
36212 if(!this.wrap.contains(t) && this.validateBlur()){
36213 this.triggerBlur();
36218 triggerBlur : function(){
36219 this.mimicing = false;
36220 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36221 if(this.monitorTab){
36222 this.el.un("keydown", this.checkTab, this);
36224 this.wrap.removeClass('x-trigger-wrap-focus');
36225 Roo.form.TriggerField.superclass.onBlur.call(this);
36229 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36230 validateBlur : function(e, t){
36235 onDisable : function(){
36236 Roo.form.TriggerField.superclass.onDisable.call(this);
36238 this.wrap.addClass('x-item-disabled');
36243 onEnable : function(){
36244 Roo.form.TriggerField.superclass.onEnable.call(this);
36246 this.wrap.removeClass('x-item-disabled');
36251 onShow : function(){
36252 var ae = this.getActionEl();
36255 ae.dom.style.display = '';
36256 ae.dom.style.visibility = 'visible';
36262 onHide : function(){
36263 var ae = this.getActionEl();
36264 ae.dom.style.display = 'none';
36268 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36269 * by an implementing function.
36271 * @param {EventObject} e
36273 onTriggerClick : Roo.emptyFn
36276 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36277 // to be extended by an implementing class. For an example of implementing this class, see the custom
36278 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36279 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36280 initComponent : function(){
36281 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36283 this.triggerConfig = {
36284 tag:'span', cls:'x-form-twin-triggers', cn:[
36285 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36286 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36290 getTrigger : function(index){
36291 return this.triggers[index];
36294 initTrigger : function(){
36295 var ts = this.trigger.select('.x-form-trigger', true);
36296 this.wrap.setStyle('overflow', 'hidden');
36297 var triggerField = this;
36298 ts.each(function(t, all, index){
36299 t.hide = function(){
36300 var w = triggerField.wrap.getWidth();
36301 this.dom.style.display = 'none';
36302 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36304 t.show = function(){
36305 var w = triggerField.wrap.getWidth();
36306 this.dom.style.display = '';
36307 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36309 var triggerIndex = 'Trigger'+(index+1);
36311 if(this['hide'+triggerIndex]){
36312 t.dom.style.display = 'none';
36314 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36315 t.addClassOnOver('x-form-trigger-over');
36316 t.addClassOnClick('x-form-trigger-click');
36318 this.triggers = ts.elements;
36321 onTrigger1Click : Roo.emptyFn,
36322 onTrigger2Click : Roo.emptyFn
36325 * Ext JS Library 1.1.1
36326 * Copyright(c) 2006-2007, Ext JS, LLC.
36328 * Originally Released Under LGPL - original licence link has changed is not relivant.
36331 * <script type="text/javascript">
36335 * @class Roo.form.TextArea
36336 * @extends Roo.form.TextField
36337 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36338 * support for auto-sizing.
36340 * Creates a new TextArea
36341 * @param {Object} config Configuration options
36343 Roo.form.TextArea = function(config){
36344 Roo.form.TextArea.superclass.constructor.call(this, config);
36345 // these are provided exchanges for backwards compat
36346 // minHeight/maxHeight were replaced by growMin/growMax to be
36347 // compatible with TextField growing config values
36348 if(this.minHeight !== undefined){
36349 this.growMin = this.minHeight;
36351 if(this.maxHeight !== undefined){
36352 this.growMax = this.maxHeight;
36356 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36358 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36362 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36366 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36367 * in the field (equivalent to setting overflow: hidden, defaults to false)
36369 preventScrollbars: false,
36371 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36372 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36376 onRender : function(ct, position){
36378 this.defaultAutoCreate = {
36380 style:"width:300px;height:60px;",
36381 autocomplete: "off"
36384 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36386 this.textSizeEl = Roo.DomHelper.append(document.body, {
36387 tag: "pre", cls: "x-form-grow-sizer"
36389 if(this.preventScrollbars){
36390 this.el.setStyle("overflow", "hidden");
36392 this.el.setHeight(this.growMin);
36396 onDestroy : function(){
36397 if(this.textSizeEl){
36398 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36400 Roo.form.TextArea.superclass.onDestroy.call(this);
36404 onKeyUp : function(e){
36405 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36411 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36412 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36414 autoSize : function(){
36415 if(!this.grow || !this.textSizeEl){
36419 var v = el.dom.value;
36420 var ts = this.textSizeEl;
36423 ts.appendChild(document.createTextNode(v));
36426 Roo.fly(ts).setWidth(this.el.getWidth());
36428 v = "  ";
36431 v = v.replace(/\n/g, '<p> </p>');
36433 v += " \n ";
36436 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36437 if(h != this.lastHeight){
36438 this.lastHeight = h;
36439 this.el.setHeight(h);
36440 this.fireEvent("autosize", this, h);
36445 * Ext JS Library 1.1.1
36446 * Copyright(c) 2006-2007, Ext JS, LLC.
36448 * Originally Released Under LGPL - original licence link has changed is not relivant.
36451 * <script type="text/javascript">
36456 * @class Roo.form.NumberField
36457 * @extends Roo.form.TextField
36458 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36460 * Creates a new NumberField
36461 * @param {Object} config Configuration options
36463 Roo.form.NumberField = function(config){
36464 Roo.form.NumberField.superclass.constructor.call(this, config);
36467 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36469 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36471 fieldClass: "x-form-field x-form-num-field",
36473 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36475 allowDecimals : true,
36477 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36479 decimalSeparator : ".",
36481 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36483 decimalPrecision : 2,
36485 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36487 allowNegative : true,
36489 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36491 minValue : Number.NEGATIVE_INFINITY,
36493 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36495 maxValue : Number.MAX_VALUE,
36497 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36499 minText : "The minimum value for this field is {0}",
36501 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36503 maxText : "The maximum value for this field is {0}",
36505 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36506 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36508 nanText : "{0} is not a valid number",
36511 initEvents : function(){
36512 Roo.form.NumberField.superclass.initEvents.call(this);
36513 var allowed = "0123456789";
36514 if(this.allowDecimals){
36515 allowed += this.decimalSeparator;
36517 if(this.allowNegative){
36520 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36521 var keyPress = function(e){
36522 var k = e.getKey();
36523 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36526 var c = e.getCharCode();
36527 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36531 this.el.on("keypress", keyPress, this);
36535 validateValue : function(value){
36536 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36539 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36542 var num = this.parseValue(value);
36544 this.markInvalid(String.format(this.nanText, value));
36547 if(num < this.minValue){
36548 this.markInvalid(String.format(this.minText, this.minValue));
36551 if(num > this.maxValue){
36552 this.markInvalid(String.format(this.maxText, this.maxValue));
36558 getValue : function(){
36559 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36563 parseValue : function(value){
36564 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36565 return isNaN(value) ? '' : value;
36569 fixPrecision : function(value){
36570 var nan = isNaN(value);
36571 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36572 return nan ? '' : value;
36574 return parseFloat(value).toFixed(this.decimalPrecision);
36577 setValue : function(v){
36578 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36582 decimalPrecisionFcn : function(v){
36583 return Math.floor(v);
36586 beforeBlur : function(){
36587 var v = this.parseValue(this.getRawValue());
36589 this.setValue(this.fixPrecision(v));
36594 * Ext JS Library 1.1.1
36595 * Copyright(c) 2006-2007, Ext JS, LLC.
36597 * Originally Released Under LGPL - original licence link has changed is not relivant.
36600 * <script type="text/javascript">
36604 * @class Roo.form.DateField
36605 * @extends Roo.form.TriggerField
36606 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36608 * Create a new DateField
36609 * @param {Object} config
36611 Roo.form.DateField = function(config){
36612 Roo.form.DateField.superclass.constructor.call(this, config);
36618 * Fires when a date is selected
36619 * @param {Roo.form.DateField} combo This combo box
36620 * @param {Date} date The date selected
36627 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36628 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36629 this.ddMatch = null;
36630 if(this.disabledDates){
36631 var dd = this.disabledDates;
36633 for(var i = 0; i < dd.length; i++){
36635 if(i != dd.length-1) re += "|";
36637 this.ddMatch = new RegExp(re + ")");
36641 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36643 * @cfg {String} format
36644 * The default date format string which can be overriden for localization support. The format must be
36645 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36649 * @cfg {String} altFormats
36650 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36651 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36653 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36655 * @cfg {Array} disabledDays
36656 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36658 disabledDays : null,
36660 * @cfg {String} disabledDaysText
36661 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36663 disabledDaysText : "Disabled",
36665 * @cfg {Array} disabledDates
36666 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36667 * expression so they are very powerful. Some examples:
36669 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36670 * <li>["03/08", "09/16"] would disable those days for every year</li>
36671 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36672 * <li>["03/../2006"] would disable every day in March 2006</li>
36673 * <li>["^03"] would disable every day in every March</li>
36675 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36676 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36678 disabledDates : null,
36680 * @cfg {String} disabledDatesText
36681 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36683 disabledDatesText : "Disabled",
36685 * @cfg {Date/String} minValue
36686 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36687 * valid format (defaults to null).
36691 * @cfg {Date/String} maxValue
36692 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36693 * valid format (defaults to null).
36697 * @cfg {String} minText
36698 * The error text to display when the date in the cell is before minValue (defaults to
36699 * 'The date in this field must be after {minValue}').
36701 minText : "The date in this field must be equal to or after {0}",
36703 * @cfg {String} maxText
36704 * The error text to display when the date in the cell is after maxValue (defaults to
36705 * 'The date in this field must be before {maxValue}').
36707 maxText : "The date in this field must be equal to or before {0}",
36709 * @cfg {String} invalidText
36710 * The error text to display when the date in the field is invalid (defaults to
36711 * '{value} is not a valid date - it must be in the format {format}').
36713 invalidText : "{0} is not a valid date - it must be in the format {1}",
36715 * @cfg {String} triggerClass
36716 * An additional CSS class used to style the trigger button. The trigger will always get the
36717 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36718 * which displays a calendar icon).
36720 triggerClass : 'x-form-date-trigger',
36724 * @cfg {bool} useIso
36725 * if enabled, then the date field will use a hidden field to store the
36726 * real value as iso formated date. default (false)
36730 * @cfg {String/Object} autoCreate
36731 * A DomHelper element spec, or true for a default element spec (defaults to
36732 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36735 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36738 hiddenField: false,
36740 onRender : function(ct, position)
36742 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36744 this.el.dom.removeAttribute('name');
36745 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36747 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36748 // prevent input submission
36749 this.hiddenName = this.name;
36756 validateValue : function(value)
36758 value = this.formatDate(value);
36759 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36762 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36765 var svalue = value;
36766 value = this.parseDate(value);
36768 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36771 var time = value.getTime();
36772 if(this.minValue && time < this.minValue.getTime()){
36773 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36776 if(this.maxValue && time > this.maxValue.getTime()){
36777 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36780 if(this.disabledDays){
36781 var day = value.getDay();
36782 for(var i = 0; i < this.disabledDays.length; i++) {
36783 if(day === this.disabledDays[i]){
36784 this.markInvalid(this.disabledDaysText);
36789 var fvalue = this.formatDate(value);
36790 if(this.ddMatch && this.ddMatch.test(fvalue)){
36791 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36798 // Provides logic to override the default TriggerField.validateBlur which just returns true
36799 validateBlur : function(){
36800 return !this.menu || !this.menu.isVisible();
36804 * Returns the current date value of the date field.
36805 * @return {Date} The date value
36807 getValue : function(){
36809 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36813 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36814 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36815 * (the default format used is "m/d/y").
36818 //All of these calls set the same date value (May 4, 2006)
36820 //Pass a date object:
36821 var dt = new Date('5/4/06');
36822 dateField.setValue(dt);
36824 //Pass a date string (default format):
36825 dateField.setValue('5/4/06');
36827 //Pass a date string (custom format):
36828 dateField.format = 'Y-m-d';
36829 dateField.setValue('2006-5-4');
36831 * @param {String/Date} date The date or valid date string
36833 setValue : function(date){
36834 if (this.hiddenField) {
36835 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36837 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36841 parseDate : function(value){
36842 if(!value || value instanceof Date){
36845 var v = Date.parseDate(value, this.format);
36846 if(!v && this.altFormats){
36847 if(!this.altFormatsArray){
36848 this.altFormatsArray = this.altFormats.split("|");
36850 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36851 v = Date.parseDate(value, this.altFormatsArray[i]);
36858 formatDate : function(date, fmt){
36859 return (!date || !(date instanceof Date)) ?
36860 date : date.dateFormat(fmt || this.format);
36865 select: function(m, d){
36867 this.fireEvent('select', this, d);
36869 show : function(){ // retain focus styling
36873 this.focus.defer(10, this);
36874 var ml = this.menuListeners;
36875 this.menu.un("select", ml.select, this);
36876 this.menu.un("show", ml.show, this);
36877 this.menu.un("hide", ml.hide, this);
36882 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36883 onTriggerClick : function(){
36887 if(this.menu == null){
36888 this.menu = new Roo.menu.DateMenu();
36890 Roo.apply(this.menu.picker, {
36891 showClear: this.allowBlank,
36892 minDate : this.minValue,
36893 maxDate : this.maxValue,
36894 disabledDatesRE : this.ddMatch,
36895 disabledDatesText : this.disabledDatesText,
36896 disabledDays : this.disabledDays,
36897 disabledDaysText : this.disabledDaysText,
36898 format : this.format,
36899 minText : String.format(this.minText, this.formatDate(this.minValue)),
36900 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
36902 this.menu.on(Roo.apply({}, this.menuListeners, {
36905 this.menu.picker.setValue(this.getValue() || new Date());
36906 this.menu.show(this.el, "tl-bl?");
36909 beforeBlur : function(){
36910 var v = this.parseDate(this.getRawValue());
36916 /** @cfg {Boolean} grow @hide */
36917 /** @cfg {Number} growMin @hide */
36918 /** @cfg {Number} growMax @hide */
36925 * Ext JS Library 1.1.1
36926 * Copyright(c) 2006-2007, Ext JS, LLC.
36928 * Originally Released Under LGPL - original licence link has changed is not relivant.
36931 * <script type="text/javascript">
36936 * @class Roo.form.ComboBox
36937 * @extends Roo.form.TriggerField
36938 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
36940 * Create a new ComboBox.
36941 * @param {Object} config Configuration options
36943 Roo.form.ComboBox = function(config){
36944 Roo.form.ComboBox.superclass.constructor.call(this, config);
36948 * Fires when the dropdown list is expanded
36949 * @param {Roo.form.ComboBox} combo This combo box
36954 * Fires when the dropdown list is collapsed
36955 * @param {Roo.form.ComboBox} combo This combo box
36959 * @event beforeselect
36960 * Fires before a list item is selected. Return false to cancel the selection.
36961 * @param {Roo.form.ComboBox} combo This combo box
36962 * @param {Roo.data.Record} record The data record returned from the underlying store
36963 * @param {Number} index The index of the selected item in the dropdown list
36965 'beforeselect' : true,
36968 * Fires when a list item is selected
36969 * @param {Roo.form.ComboBox} combo This combo box
36970 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
36971 * @param {Number} index The index of the selected item in the dropdown list
36975 * @event beforequery
36976 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
36977 * The event object passed has these properties:
36978 * @param {Roo.form.ComboBox} combo This combo box
36979 * @param {String} query The query
36980 * @param {Boolean} forceAll true to force "all" query
36981 * @param {Boolean} cancel true to cancel the query
36982 * @param {Object} e The query event object
36984 'beforequery': true,
36987 * Fires when the 'add' icon is pressed (add a listener to enable add button)
36988 * @param {Roo.form.ComboBox} combo This combo box
36993 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
36994 * @param {Roo.form.ComboBox} combo This combo box
36995 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37001 if(this.transform){
37002 this.allowDomMove = false;
37003 var s = Roo.getDom(this.transform);
37004 if(!this.hiddenName){
37005 this.hiddenName = s.name;
37008 this.mode = 'local';
37009 var d = [], opts = s.options;
37010 for(var i = 0, len = opts.length;i < len; i++){
37012 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37014 this.value = value;
37016 d.push([value, o.text]);
37018 this.store = new Roo.data.SimpleStore({
37020 fields: ['value', 'text'],
37023 this.valueField = 'value';
37024 this.displayField = 'text';
37026 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37027 if(!this.lazyRender){
37028 this.target = true;
37029 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37030 s.parentNode.removeChild(s); // remove it
37031 this.render(this.el.parentNode);
37033 s.parentNode.removeChild(s); // remove it
37038 this.store = Roo.factory(this.store, Roo.data);
37041 this.selectedIndex = -1;
37042 if(this.mode == 'local'){
37043 if(config.queryDelay === undefined){
37044 this.queryDelay = 10;
37046 if(config.minChars === undefined){
37052 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37054 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37057 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37058 * rendering into an Roo.Editor, defaults to false)
37061 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37062 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37065 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37068 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37069 * the dropdown list (defaults to undefined, with no header element)
37073 * @cfg {String/Roo.Template} tpl The template to use to render the output
37077 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37079 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37081 listWidth: undefined,
37083 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37084 * mode = 'remote' or 'text' if mode = 'local')
37086 displayField: undefined,
37088 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37089 * mode = 'remote' or 'value' if mode = 'local').
37090 * Note: use of a valueField requires the user make a selection
37091 * in order for a value to be mapped.
37093 valueField: undefined,
37095 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37096 * field's data value (defaults to the underlying DOM element's name)
37098 hiddenName: undefined,
37100 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37104 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37106 selectedClass: 'x-combo-selected',
37108 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37109 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37110 * which displays a downward arrow icon).
37112 triggerClass : 'x-form-arrow-trigger',
37114 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37118 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37119 * anchor positions (defaults to 'tl-bl')
37121 listAlign: 'tl-bl?',
37123 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37127 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37128 * query specified by the allQuery config option (defaults to 'query')
37130 triggerAction: 'query',
37132 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37133 * (defaults to 4, does not apply if editable = false)
37137 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37138 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37142 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37143 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37147 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37148 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37152 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37153 * when editable = true (defaults to false)
37155 selectOnFocus:false,
37157 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37159 queryParam: 'query',
37161 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37162 * when mode = 'remote' (defaults to 'Loading...')
37164 loadingText: 'Loading...',
37166 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37170 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37174 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37175 * traditional select (defaults to true)
37179 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37183 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37187 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37188 * listWidth has a higher value)
37192 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37193 * allow the user to set arbitrary text into the field (defaults to false)
37195 forceSelection:false,
37197 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37198 * if typeAhead = true (defaults to 250)
37200 typeAheadDelay : 250,
37202 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37203 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37205 valueNotFoundText : undefined,
37207 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37209 blockFocus : false,
37212 * @cfg {Boolean} disableClear Disable showing of clear button.
37214 disableClear : false,
37216 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37218 alwaysQuery : false,
37226 onRender : function(ct, position){
37227 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37228 if(this.hiddenName){
37229 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37231 this.hiddenField.value =
37232 this.hiddenValue !== undefined ? this.hiddenValue :
37233 this.value !== undefined ? this.value : '';
37235 // prevent input submission
37236 this.el.dom.removeAttribute('name');
37239 this.el.dom.setAttribute('autocomplete', 'off');
37242 var cls = 'x-combo-list';
37244 this.list = new Roo.Layer({
37245 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37248 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37249 this.list.setWidth(lw);
37250 this.list.swallowEvent('mousewheel');
37251 this.assetHeight = 0;
37254 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37255 this.assetHeight += this.header.getHeight();
37258 this.innerList = this.list.createChild({cls:cls+'-inner'});
37259 this.innerList.on('mouseover', this.onViewOver, this);
37260 this.innerList.on('mousemove', this.onViewMove, this);
37261 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37263 if(this.allowBlank && !this.pageSize && !this.disableClear){
37264 this.footer = this.list.createChild({cls:cls+'-ft'});
37265 this.pageTb = new Roo.Toolbar(this.footer);
37269 this.footer = this.list.createChild({cls:cls+'-ft'});
37270 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37271 {pageSize: this.pageSize});
37275 if (this.pageTb && this.allowBlank && !this.disableClear) {
37277 this.pageTb.add(new Roo.Toolbar.Fill(), {
37278 cls: 'x-btn-icon x-btn-clear',
37280 handler: function()
37283 _this.clearValue();
37284 _this.onSelect(false, -1);
37289 this.assetHeight += this.footer.getHeight();
37294 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37297 this.view = new Roo.View(this.innerList, this.tpl, {
37298 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37301 this.view.on('click', this.onViewClick, this);
37303 this.store.on('beforeload', this.onBeforeLoad, this);
37304 this.store.on('load', this.onLoad, this);
37305 this.store.on('loadexception', this.collapse, this);
37307 if(this.resizable){
37308 this.resizer = new Roo.Resizable(this.list, {
37309 pinned:true, handles:'se'
37311 this.resizer.on('resize', function(r, w, h){
37312 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37313 this.listWidth = w;
37314 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37315 this.restrictHeight();
37317 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37319 if(!this.editable){
37320 this.editable = true;
37321 this.setEditable(false);
37325 if (typeof(this.events.add.listeners) != 'undefined') {
37327 this.addicon = this.wrap.createChild(
37328 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37330 this.addicon.on('click', function(e) {
37331 this.fireEvent('add', this);
37334 if (typeof(this.events.edit.listeners) != 'undefined') {
37336 this.editicon = this.wrap.createChild(
37337 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37338 if (this.addicon) {
37339 this.editicon.setStyle('margin-left', '40px');
37341 this.editicon.on('click', function(e) {
37343 // we fire even if inothing is selected..
37344 this.fireEvent('edit', this, this.lastData );
37354 initEvents : function(){
37355 Roo.form.ComboBox.superclass.initEvents.call(this);
37357 this.keyNav = new Roo.KeyNav(this.el, {
37358 "up" : function(e){
37359 this.inKeyMode = true;
37363 "down" : function(e){
37364 if(!this.isExpanded()){
37365 this.onTriggerClick();
37367 this.inKeyMode = true;
37372 "enter" : function(e){
37373 this.onViewClick();
37377 "esc" : function(e){
37381 "tab" : function(e){
37382 this.onViewClick(false);
37388 doRelay : function(foo, bar, hname){
37389 if(hname == 'down' || this.scope.isExpanded()){
37390 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37397 this.queryDelay = Math.max(this.queryDelay || 10,
37398 this.mode == 'local' ? 10 : 250);
37399 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37400 if(this.typeAhead){
37401 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37403 if(this.editable !== false){
37404 this.el.on("keyup", this.onKeyUp, this);
37406 if(this.forceSelection){
37407 this.on('blur', this.doForce, this);
37411 onDestroy : function(){
37413 this.view.setStore(null);
37414 this.view.el.removeAllListeners();
37415 this.view.el.remove();
37416 this.view.purgeListeners();
37419 this.list.destroy();
37422 this.store.un('beforeload', this.onBeforeLoad, this);
37423 this.store.un('load', this.onLoad, this);
37424 this.store.un('loadexception', this.collapse, this);
37426 Roo.form.ComboBox.superclass.onDestroy.call(this);
37430 fireKey : function(e){
37431 if(e.isNavKeyPress() && !this.list.isVisible()){
37432 this.fireEvent("specialkey", this, e);
37437 onResize: function(w, h){
37438 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37440 if(typeof w != 'number'){
37441 // we do not handle it!?!?
37444 var tw = this.trigger.getWidth();
37445 tw += this.addicon ? this.addicon.getWidth() : 0;
37446 tw += this.editicon ? this.editicon.getWidth() : 0;
37448 this.el.setWidth( this.adjustWidth('input', x));
37450 this.trigger.setStyle('left', x+'px');
37452 if(this.list && this.listWidth === undefined){
37453 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37454 this.list.setWidth(lw);
37455 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37463 * Allow or prevent the user from directly editing the field text. If false is passed,
37464 * the user will only be able to select from the items defined in the dropdown list. This method
37465 * is the runtime equivalent of setting the 'editable' config option at config time.
37466 * @param {Boolean} value True to allow the user to directly edit the field text
37468 setEditable : function(value){
37469 if(value == this.editable){
37472 this.editable = value;
37474 this.el.dom.setAttribute('readOnly', true);
37475 this.el.on('mousedown', this.onTriggerClick, this);
37476 this.el.addClass('x-combo-noedit');
37478 this.el.dom.setAttribute('readOnly', false);
37479 this.el.un('mousedown', this.onTriggerClick, this);
37480 this.el.removeClass('x-combo-noedit');
37485 onBeforeLoad : function(){
37486 if(!this.hasFocus){
37489 this.innerList.update(this.loadingText ?
37490 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37491 this.restrictHeight();
37492 this.selectedIndex = -1;
37496 onLoad : function(){
37497 if(!this.hasFocus){
37500 if(this.store.getCount() > 0){
37502 this.restrictHeight();
37503 if(this.lastQuery == this.allQuery){
37505 this.el.dom.select();
37507 if(!this.selectByValue(this.value, true)){
37508 this.select(0, true);
37512 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37513 this.taTask.delay(this.typeAheadDelay);
37517 this.onEmptyResults();
37523 onTypeAhead : function(){
37524 if(this.store.getCount() > 0){
37525 var r = this.store.getAt(0);
37526 var newValue = r.data[this.displayField];
37527 var len = newValue.length;
37528 var selStart = this.getRawValue().length;
37529 if(selStart != len){
37530 this.setRawValue(newValue);
37531 this.selectText(selStart, newValue.length);
37537 onSelect : function(record, index){
37538 if(this.fireEvent('beforeselect', this, record, index) !== false){
37539 this.setFromData(index > -1 ? record.data : false);
37541 this.fireEvent('select', this, record, index);
37546 * Returns the currently selected field value or empty string if no value is set.
37547 * @return {String} value The selected value
37549 getValue : function(){
37550 if(this.valueField){
37551 return typeof this.value != 'undefined' ? this.value : '';
37553 return Roo.form.ComboBox.superclass.getValue.call(this);
37558 * Clears any text/value currently set in the field
37560 clearValue : function(){
37561 if(this.hiddenField){
37562 this.hiddenField.value = '';
37565 this.setRawValue('');
37566 this.lastSelectionText = '';
37567 this.applyEmptyText();
37571 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37572 * will be displayed in the field. If the value does not match the data value of an existing item,
37573 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37574 * Otherwise the field will be blank (although the value will still be set).
37575 * @param {String} value The value to match
37577 setValue : function(v){
37579 if(this.valueField){
37580 var r = this.findRecord(this.valueField, v);
37582 text = r.data[this.displayField];
37583 }else if(this.valueNotFoundText !== undefined){
37584 text = this.valueNotFoundText;
37587 this.lastSelectionText = text;
37588 if(this.hiddenField){
37589 this.hiddenField.value = v;
37591 Roo.form.ComboBox.superclass.setValue.call(this, text);
37595 * @property {Object} the last set data for the element
37600 * Sets the value of the field based on a object which is related to the record format for the store.
37601 * @param {Object} value the value to set as. or false on reset?
37603 setFromData : function(o){
37604 var dv = ''; // display value
37605 var vv = ''; // value value..
37607 if (this.displayField) {
37608 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37610 // this is an error condition!!!
37611 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37614 if(this.valueField){
37615 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37617 if(this.hiddenField){
37618 this.hiddenField.value = vv;
37620 this.lastSelectionText = dv;
37621 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37625 // no hidden field.. - we store the value in 'value', but still display
37626 // display field!!!!
37627 this.lastSelectionText = dv;
37628 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37634 reset : function(){
37635 // overridden so that last data is reset..
37636 this.setValue(this.originalValue);
37637 this.clearInvalid();
37638 this.lastData = false;
37641 findRecord : function(prop, value){
37643 if(this.store.getCount() > 0){
37644 this.store.each(function(r){
37645 if(r.data[prop] == value){
37655 onViewMove : function(e, t){
37656 this.inKeyMode = false;
37660 onViewOver : function(e, t){
37661 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37664 var item = this.view.findItemFromChild(t);
37666 var index = this.view.indexOf(item);
37667 this.select(index, false);
37672 onViewClick : function(doFocus){
37673 var index = this.view.getSelectedIndexes()[0];
37674 var r = this.store.getAt(index);
37676 this.onSelect(r, index);
37678 if(doFocus !== false && !this.blockFocus){
37684 restrictHeight : function(){
37685 this.innerList.dom.style.height = '';
37686 var inner = this.innerList.dom;
37687 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37688 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37689 this.list.beginUpdate();
37690 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37691 this.list.alignTo(this.el, this.listAlign);
37692 this.list.endUpdate();
37696 onEmptyResults : function(){
37701 * Returns true if the dropdown list is expanded, else false.
37703 isExpanded : function(){
37704 return this.list.isVisible();
37708 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37709 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37710 * @param {String} value The data value of the item to select
37711 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37712 * selected item if it is not currently in view (defaults to true)
37713 * @return {Boolean} True if the value matched an item in the list, else false
37715 selectByValue : function(v, scrollIntoView){
37716 if(v !== undefined && v !== null){
37717 var r = this.findRecord(this.valueField || this.displayField, v);
37719 this.select(this.store.indexOf(r), scrollIntoView);
37727 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37728 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37729 * @param {Number} index The zero-based index of the list item to select
37730 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37731 * selected item if it is not currently in view (defaults to true)
37733 select : function(index, scrollIntoView){
37734 this.selectedIndex = index;
37735 this.view.select(index);
37736 if(scrollIntoView !== false){
37737 var el = this.view.getNode(index);
37739 this.innerList.scrollChildIntoView(el, false);
37745 selectNext : function(){
37746 var ct = this.store.getCount();
37748 if(this.selectedIndex == -1){
37750 }else if(this.selectedIndex < ct-1){
37751 this.select(this.selectedIndex+1);
37757 selectPrev : function(){
37758 var ct = this.store.getCount();
37760 if(this.selectedIndex == -1){
37762 }else if(this.selectedIndex != 0){
37763 this.select(this.selectedIndex-1);
37769 onKeyUp : function(e){
37770 if(this.editable !== false && !e.isSpecialKey()){
37771 this.lastKey = e.getKey();
37772 this.dqTask.delay(this.queryDelay);
37777 validateBlur : function(){
37778 return !this.list || !this.list.isVisible();
37782 initQuery : function(){
37783 this.doQuery(this.getRawValue());
37787 doForce : function(){
37788 if(this.el.dom.value.length > 0){
37789 this.el.dom.value =
37790 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37791 this.applyEmptyText();
37796 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37797 * query allowing the query action to be canceled if needed.
37798 * @param {String} query The SQL query to execute
37799 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37800 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37801 * saved in the current store (defaults to false)
37803 doQuery : function(q, forceAll){
37804 if(q === undefined || q === null){
37809 forceAll: forceAll,
37813 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37817 forceAll = qe.forceAll;
37818 if(forceAll === true || (q.length >= this.minChars)){
37819 if(this.lastQuery != q || this.alwaysQuery){
37820 this.lastQuery = q;
37821 if(this.mode == 'local'){
37822 this.selectedIndex = -1;
37824 this.store.clearFilter();
37826 this.store.filter(this.displayField, q);
37830 this.store.baseParams[this.queryParam] = q;
37832 params: this.getParams(q)
37837 this.selectedIndex = -1;
37844 getParams : function(q){
37846 //p[this.queryParam] = q;
37849 p.limit = this.pageSize;
37855 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37857 collapse : function(){
37858 if(!this.isExpanded()){
37862 Roo.get(document).un('mousedown', this.collapseIf, this);
37863 Roo.get(document).un('mousewheel', this.collapseIf, this);
37864 if (!this.editable) {
37865 Roo.get(document).un('keydown', this.listKeyPress, this);
37867 this.fireEvent('collapse', this);
37871 collapseIf : function(e){
37872 if(!e.within(this.wrap) && !e.within(this.list)){
37878 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37880 expand : function(){
37881 if(this.isExpanded() || !this.hasFocus){
37884 this.list.alignTo(this.el, this.listAlign);
37886 Roo.get(document).on('mousedown', this.collapseIf, this);
37887 Roo.get(document).on('mousewheel', this.collapseIf, this);
37888 if (!this.editable) {
37889 Roo.get(document).on('keydown', this.listKeyPress, this);
37892 this.fireEvent('expand', this);
37896 // Implements the default empty TriggerField.onTriggerClick function
37897 onTriggerClick : function(){
37901 if(this.isExpanded()){
37903 if (!this.blockFocus) {
37908 this.hasFocus = true;
37909 if(this.triggerAction == 'all') {
37910 this.doQuery(this.allQuery, true);
37912 this.doQuery(this.getRawValue());
37914 if (!this.blockFocus) {
37919 listKeyPress : function(e)
37921 //Roo.log('listkeypress');
37922 // scroll to first matching element based on key pres..
37923 if (e.isSpecialKey()) {
37926 var k = String.fromCharCode(e.getKey()).toUpperCase();
37929 var csel = this.view.getSelectedNodes();
37930 var cselitem = false;
37932 var ix = this.view.indexOf(csel[0]);
37933 cselitem = this.store.getAt(ix);
37934 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
37940 this.store.each(function(v) {
37942 // start at existing selection.
37943 if (cselitem.id == v.id) {
37949 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
37950 match = this.store.indexOf(v);
37955 if (match === false) {
37956 return true; // no more action?
37959 this.view.select(match);
37960 var sn = Roo.get(this.view.getSelectedNodes()[0])
37961 sn.scrollIntoView(sn.dom.parentNode, false);
37965 * @cfg {Boolean} grow
37969 * @cfg {Number} growMin
37973 * @cfg {Number} growMax
37982 * Ext JS Library 1.1.1
37983 * Copyright(c) 2006-2007, Ext JS, LLC.
37985 * Originally Released Under LGPL - original licence link has changed is not relivant.
37988 * <script type="text/javascript">
37991 * @class Roo.form.Checkbox
37992 * @extends Roo.form.Field
37993 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
37995 * Creates a new Checkbox
37996 * @param {Object} config Configuration options
37998 Roo.form.Checkbox = function(config){
37999 Roo.form.Checkbox.superclass.constructor.call(this, config);
38003 * Fires when the checkbox is checked or unchecked.
38004 * @param {Roo.form.Checkbox} this This checkbox
38005 * @param {Boolean} checked The new checked value
38011 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38013 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38015 focusClass : undefined,
38017 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38019 fieldClass: "x-form-field",
38021 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38025 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38026 * {tag: "input", type: "checkbox", autocomplete: "off"})
38028 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38030 * @cfg {String} boxLabel The text that appears beside the checkbox
38034 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38038 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38040 valueOff: '0', // value when not checked..
38042 actionMode : 'viewEl',
38045 itemCls : 'x-menu-check-item x-form-item',
38046 groupClass : 'x-menu-group-item',
38047 inputType : 'hidden',
38050 inSetChecked: false, // check that we are not calling self...
38052 inputElement: false, // real input element?
38053 basedOn: false, // ????
38055 isFormField: true, // not sure where this is needed!!!!
38057 onResize : function(){
38058 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38059 if(!this.boxLabel){
38060 this.el.alignTo(this.wrap, 'c-c');
38064 initEvents : function(){
38065 Roo.form.Checkbox.superclass.initEvents.call(this);
38066 this.el.on("click", this.onClick, this);
38067 this.el.on("change", this.onClick, this);
38071 getResizeEl : function(){
38075 getPositionEl : function(){
38080 onRender : function(ct, position){
38081 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38083 if(this.inputValue !== undefined){
38084 this.el.dom.value = this.inputValue;
38087 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38088 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38089 var viewEl = this.wrap.createChild({
38090 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38091 this.viewEl = viewEl;
38092 this.wrap.on('click', this.onClick, this);
38094 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38095 this.el.on('propertychange', this.setFromHidden, this); //ie
38100 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38101 // viewEl.on('click', this.onClick, this);
38103 //if(this.checked){
38104 this.setChecked(this.checked);
38106 //this.checked = this.el.dom;
38112 initValue : Roo.emptyFn,
38115 * Returns the checked state of the checkbox.
38116 * @return {Boolean} True if checked, else false
38118 getValue : function(){
38120 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38122 return this.valueOff;
38127 onClick : function(){
38128 this.setChecked(!this.checked);
38130 //if(this.el.dom.checked != this.checked){
38131 // this.setValue(this.el.dom.checked);
38136 * Sets the checked state of the checkbox.
38137 * On is always based on a string comparison between inputValue and the param.
38138 * @param {Boolean/String} value - the value to set
38139 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38141 setValue : function(v,suppressEvent){
38144 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38145 //if(this.el && this.el.dom){
38146 // this.el.dom.checked = this.checked;
38147 // this.el.dom.defaultChecked = this.checked;
38149 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38150 //this.fireEvent("check", this, this.checked);
38153 setChecked : function(state,suppressEvent)
38155 if (this.inSetChecked) {
38156 this.checked = state;
38162 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38164 this.checked = state;
38165 if(suppressEvent !== true){
38166 this.fireEvent('check', this, state);
38168 this.inSetChecked = true;
38169 this.el.dom.value = state ? this.inputValue : this.valueOff;
38170 this.inSetChecked = false;
38173 // handle setting of hidden value by some other method!!?!?
38174 setFromHidden: function()
38179 //console.log("SET FROM HIDDEN");
38180 //alert('setFrom hidden');
38181 this.setValue(this.el.dom.value);
38184 onDestroy : function()
38187 Roo.get(this.viewEl).remove();
38190 Roo.form.Checkbox.superclass.onDestroy.call(this);
38195 * Ext JS Library 1.1.1
38196 * Copyright(c) 2006-2007, Ext JS, LLC.
38198 * Originally Released Under LGPL - original licence link has changed is not relivant.
38201 * <script type="text/javascript">
38205 * @class Roo.form.Radio
38206 * @extends Roo.form.Checkbox
38207 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38208 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38210 * Creates a new Radio
38211 * @param {Object} config Configuration options
38213 Roo.form.Radio = function(){
38214 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38216 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38217 inputType: 'radio',
38220 * If this radio is part of a group, it will return the selected value
38223 getGroupValue : function(){
38224 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38226 });//<script type="text/javascript">
38229 * Ext JS Library 1.1.1
38230 * Copyright(c) 2006-2007, Ext JS, LLC.
38231 * licensing@extjs.com
38233 * http://www.extjs.com/license
38239 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38240 * - IE ? - no idea how much works there.
38248 * @class Ext.form.HtmlEditor
38249 * @extends Ext.form.Field
38250 * Provides a lightweight HTML Editor component.
38251 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38253 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38254 * supported by this editor.</b><br/><br/>
38255 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38256 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38258 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38260 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38264 * @cfg {String} createLinkText The default text for the create link prompt
38266 createLinkText : 'Please enter the URL for the link:',
38268 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38270 defaultLinkValue : 'http:/'+'/',
38276 // private properties
38277 validationEvent : false,
38279 initialized : false,
38281 sourceEditMode : false,
38282 onFocus : Roo.emptyFn,
38284 hideMode:'offsets',
38285 defaultAutoCreate : {
38287 style:"width:500px;height:300px;",
38288 autocomplete: "off"
38292 initComponent : function(){
38295 * @event initialize
38296 * Fires when the editor is fully initialized (including the iframe)
38297 * @param {HtmlEditor} this
38302 * Fires when the editor is first receives the focus. Any insertion must wait
38303 * until after this event.
38304 * @param {HtmlEditor} this
38308 * @event beforesync
38309 * Fires before the textarea is updated with content from the editor iframe. Return false
38310 * to cancel the sync.
38311 * @param {HtmlEditor} this
38312 * @param {String} html
38316 * @event beforepush
38317 * Fires before the iframe editor is updated with content from the textarea. Return false
38318 * to cancel the push.
38319 * @param {HtmlEditor} this
38320 * @param {String} html
38325 * Fires when the textarea is updated with content from the editor iframe.
38326 * @param {HtmlEditor} this
38327 * @param {String} html
38332 * Fires when the iframe editor is updated with content from the textarea.
38333 * @param {HtmlEditor} this
38334 * @param {String} html
38338 * @event editmodechange
38339 * Fires when the editor switches edit modes
38340 * @param {HtmlEditor} this
38341 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38343 editmodechange: true,
38345 * @event editorevent
38346 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38347 * @param {HtmlEditor} this
38354 * Protected method that will not generally be called directly. It
38355 * is called when the editor creates its toolbar. Override this method if you need to
38356 * add custom toolbar buttons.
38357 * @param {HtmlEditor} editor
38359 createToolbar : function(editor){
38360 if (!editor.toolbars || !editor.toolbars.length) {
38361 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38364 for (var i =0 ; i < editor.toolbars.length;i++) {
38365 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38366 editor.toolbars[i].init(editor);
38373 * Protected method that will not generally be called directly. It
38374 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38375 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38377 getDocMarkup : function(){
38378 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
38382 onRender : function(ct, position){
38383 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38384 this.el.dom.style.border = '0 none';
38385 this.el.dom.setAttribute('tabIndex', -1);
38386 this.el.addClass('x-hidden');
38387 if(Roo.isIE){ // fix IE 1px bogus margin
38388 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38390 this.wrap = this.el.wrap({
38391 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38394 this.frameId = Roo.id();
38395 this.createToolbar(this);
38402 var iframe = this.wrap.createChild({
38405 name: this.frameId,
38406 frameBorder : 'no',
38407 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38410 // console.log(iframe);
38411 //this.wrap.dom.appendChild(iframe);
38413 this.iframe = iframe.dom;
38415 this.assignDocWin();
38417 this.doc.designMode = 'on';
38420 this.doc.write(this.getDocMarkup());
38424 var task = { // must defer to wait for browser to be ready
38426 //console.log("run task?" + this.doc.readyState);
38427 this.assignDocWin();
38428 if(this.doc.body || this.doc.readyState == 'complete'){
38430 this.doc.designMode="on";
38434 Roo.TaskMgr.stop(task);
38435 this.initEditor.defer(10, this);
38442 Roo.TaskMgr.start(task);
38445 this.setSize(this.el.getSize());
38450 onResize : function(w, h){
38451 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38452 if(this.el && this.iframe){
38453 if(typeof w == 'number'){
38454 var aw = w - this.wrap.getFrameWidth('lr');
38455 this.el.setWidth(this.adjustWidth('textarea', aw));
38456 this.iframe.style.width = aw + 'px';
38458 if(typeof h == 'number'){
38460 for (var i =0; i < this.toolbars.length;i++) {
38461 // fixme - ask toolbars for heights?
38462 tbh += this.toolbars[i].tb.el.getHeight();
38468 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38469 this.el.setHeight(this.adjustWidth('textarea', ah));
38470 this.iframe.style.height = ah + 'px';
38472 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38479 * Toggles the editor between standard and source edit mode.
38480 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38482 toggleSourceEdit : function(sourceEditMode){
38484 this.sourceEditMode = sourceEditMode === true;
38486 if(this.sourceEditMode){
38489 this.iframe.className = 'x-hidden';
38490 this.el.removeClass('x-hidden');
38491 this.el.dom.removeAttribute('tabIndex');
38496 this.iframe.className = '';
38497 this.el.addClass('x-hidden');
38498 this.el.dom.setAttribute('tabIndex', -1);
38501 this.setSize(this.wrap.getSize());
38502 this.fireEvent('editmodechange', this, this.sourceEditMode);
38505 // private used internally
38506 createLink : function(){
38507 var url = prompt(this.createLinkText, this.defaultLinkValue);
38508 if(url && url != 'http:/'+'/'){
38509 this.relayCmd('createlink', url);
38513 // private (for BoxComponent)
38514 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38516 // private (for BoxComponent)
38517 getResizeEl : function(){
38521 // private (for BoxComponent)
38522 getPositionEl : function(){
38527 initEvents : function(){
38528 this.originalValue = this.getValue();
38532 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38535 markInvalid : Roo.emptyFn,
38537 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38540 clearInvalid : Roo.emptyFn,
38542 setValue : function(v){
38543 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38548 * Protected method that will not generally be called directly. If you need/want
38549 * custom HTML cleanup, this is the method you should override.
38550 * @param {String} html The HTML to be cleaned
38551 * return {String} The cleaned HTML
38553 cleanHtml : function(html){
38554 html = String(html);
38555 if(html.length > 5){
38556 if(Roo.isSafari){ // strip safari nonsense
38557 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38560 if(html == ' '){
38567 * Protected method that will not generally be called directly. Syncs the contents
38568 * of the editor iframe with the textarea.
38570 syncValue : function(){
38571 if(this.initialized){
38572 var bd = (this.doc.body || this.doc.documentElement);
38573 var html = bd.innerHTML;
38575 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38576 var m = bs.match(/text-align:(.*?);/i);
38578 html = '<div style="'+m[0]+'">' + html + '</div>';
38581 html = this.cleanHtml(html);
38582 if(this.fireEvent('beforesync', this, html) !== false){
38583 this.el.dom.value = html;
38584 this.fireEvent('sync', this, html);
38590 * Protected method that will not generally be called directly. Pushes the value of the textarea
38591 * into the iframe editor.
38593 pushValue : function(){
38594 if(this.initialized){
38595 var v = this.el.dom.value;
38599 if(this.fireEvent('beforepush', this, v) !== false){
38600 (this.doc.body || this.doc.documentElement).innerHTML = v;
38601 this.fireEvent('push', this, v);
38607 deferFocus : function(){
38608 this.focus.defer(10, this);
38612 focus : function(){
38613 if(this.win && !this.sourceEditMode){
38620 assignDocWin: function()
38622 var iframe = this.iframe;
38625 this.doc = iframe.contentWindow.document;
38626 this.win = iframe.contentWindow;
38628 if (!Roo.get(this.frameId)) {
38631 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38632 this.win = Roo.get(this.frameId).dom.contentWindow;
38637 initEditor : function(){
38638 //console.log("INIT EDITOR");
38639 this.assignDocWin();
38643 this.doc.designMode="on";
38645 this.doc.write(this.getDocMarkup());
38648 var dbody = (this.doc.body || this.doc.documentElement);
38649 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38650 // this copies styles from the containing element into thsi one..
38651 // not sure why we need all of this..
38652 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38653 ss['background-attachment'] = 'fixed'; // w3c
38654 dbody.bgProperties = 'fixed'; // ie
38655 Roo.DomHelper.applyStyles(dbody, ss);
38656 Roo.EventManager.on(this.doc, {
38657 'mousedown': this.onEditorEvent,
38658 'dblclick': this.onEditorEvent,
38659 'click': this.onEditorEvent,
38660 'keyup': this.onEditorEvent,
38665 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
38667 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38668 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38670 this.initialized = true;
38672 this.fireEvent('initialize', this);
38677 onDestroy : function(){
38683 for (var i =0; i < this.toolbars.length;i++) {
38684 // fixme - ask toolbars for heights?
38685 this.toolbars[i].onDestroy();
38688 this.wrap.dom.innerHTML = '';
38689 this.wrap.remove();
38694 onFirstFocus : function(){
38696 this.assignDocWin();
38699 this.activated = true;
38700 for (var i =0; i < this.toolbars.length;i++) {
38701 this.toolbars[i].onFirstFocus();
38704 if(Roo.isGecko){ // prevent silly gecko errors
38706 var s = this.win.getSelection();
38707 if(!s.focusNode || s.focusNode.nodeType != 3){
38708 var r = s.getRangeAt(0);
38709 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38714 this.execCmd('useCSS', true);
38715 this.execCmd('styleWithCSS', false);
38718 this.fireEvent('activate', this);
38722 adjustFont: function(btn){
38723 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38724 //if(Roo.isSafari){ // safari
38727 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38728 if(Roo.isSafari){ // safari
38729 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38730 v = (v < 10) ? 10 : v;
38731 v = (v > 48) ? 48 : v;
38732 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38737 v = Math.max(1, v+adjust);
38739 this.execCmd('FontSize', v );
38742 onEditorEvent : function(e){
38743 this.fireEvent('editorevent', this, e);
38744 // this.updateToolbar();
38748 insertTag : function(tg)
38750 // could be a bit smarter... -> wrap the current selected tRoo..
38752 this.execCmd("formatblock", tg);
38756 insertText : function(txt)
38760 range = this.createRange();
38761 range.deleteContents();
38762 //alert(Sender.getAttribute('label'));
38764 range.insertNode(this.doc.createTextNode(txt));
38768 relayBtnCmd : function(btn){
38769 this.relayCmd(btn.cmd);
38773 * Executes a Midas editor command on the editor document and performs necessary focus and
38774 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38775 * @param {String} cmd The Midas command
38776 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38778 relayCmd : function(cmd, value){
38780 this.execCmd(cmd, value);
38781 this.fireEvent('editorevent', this);
38782 //this.updateToolbar();
38787 * Executes a Midas editor command directly on the editor document.
38788 * For visual commands, you should use {@link #relayCmd} instead.
38789 * <b>This should only be called after the editor is initialized.</b>
38790 * @param {String} cmd The Midas command
38791 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38793 execCmd : function(cmd, value){
38794 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38800 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38802 * @param {String} text
38804 insertAtCursor : function(text){
38805 if(!this.activated){
38810 var r = this.doc.selection.createRange();
38817 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
38819 this.execCmd('InsertHTML', text);
38824 mozKeyPress : function(e){
38826 var c = e.getCharCode(), cmd;
38829 c = String.fromCharCode(c).toLowerCase();
38840 this.cleanUpPaste.defer(100, this);
38848 e.preventDefault();
38856 fixKeys : function(){ // load time branching for fastest keydown performance
38858 return function(e){
38859 var k = e.getKey(), r;
38862 r = this.doc.selection.createRange();
38865 r.pasteHTML('    ');
38872 r = this.doc.selection.createRange();
38874 var target = r.parentElement();
38875 if(!target || target.tagName.toLowerCase() != 'li'){
38877 r.pasteHTML('<br />');
38883 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38884 this.cleanUpPaste.defer(100, this);
38890 }else if(Roo.isOpera){
38891 return function(e){
38892 var k = e.getKey();
38896 this.execCmd('InsertHTML','    ');
38899 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38900 this.cleanUpPaste.defer(100, this);
38905 }else if(Roo.isSafari){
38906 return function(e){
38907 var k = e.getKey();
38911 this.execCmd('InsertText','\t');
38915 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38916 this.cleanUpPaste.defer(100, this);
38924 getAllAncestors: function()
38926 var p = this.getSelectedNode();
38929 a.push(p); // push blank onto stack..
38930 p = this.getParentElement();
38934 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
38938 a.push(this.doc.body);
38942 lastSelNode : false,
38945 getSelection : function()
38947 this.assignDocWin();
38948 return Roo.isIE ? this.doc.selection : this.win.getSelection();
38951 getSelectedNode: function()
38953 // this may only work on Gecko!!!
38955 // should we cache this!!!!
38960 var range = this.createRange(this.getSelection());
38963 var parent = range.parentElement();
38965 var testRange = range.duplicate();
38966 testRange.moveToElementText(parent);
38967 if (testRange.inRange(range)) {
38970 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
38973 parent = parent.parentElement;
38979 var ar = range.endContainer.childNodes;
38981 ar = range.commonAncestorContainer.childNodes;
38982 //alert(ar.length);
38985 var other_nodes = [];
38986 var has_other_nodes = false;
38987 for (var i=0;i<ar.length;i++) {
38988 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
38991 // fullly contained node.
38993 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
38998 // probably selected..
38999 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39000 other_nodes.push(ar[i]);
39003 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39008 has_other_nodes = true;
39010 if (!nodes.length && other_nodes.length) {
39011 nodes= other_nodes;
39013 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39019 createRange: function(sel)
39021 // this has strange effects when using with
39022 // top toolbar - not sure if it's a great idea.
39023 //this.editor.contentWindow.focus();
39024 if (typeof sel != "undefined") {
39026 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39028 return this.doc.createRange();
39031 return this.doc.createRange();
39034 getParentElement: function()
39037 this.assignDocWin();
39038 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39040 var range = this.createRange(sel);
39043 var p = range.commonAncestorContainer;
39044 while (p.nodeType == 3) { // text node
39056 // BC Hacks - cause I cant work out what i was trying to do..
39057 rangeIntersectsNode : function(range, node)
39059 var nodeRange = node.ownerDocument.createRange();
39061 nodeRange.selectNode(node);
39064 nodeRange.selectNodeContents(node);
39067 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
39068 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
39070 rangeCompareNode : function(range, node) {
39071 var nodeRange = node.ownerDocument.createRange();
39073 nodeRange.selectNode(node);
39075 nodeRange.selectNodeContents(node);
39077 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
39078 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
39080 if (nodeIsBefore && !nodeIsAfter)
39082 if (!nodeIsBefore && nodeIsAfter)
39084 if (nodeIsBefore && nodeIsAfter)
39090 // private? - in a new class?
39091 cleanUpPaste : function()
39093 // cleans up the whole document..
39094 // console.log('cleanuppaste');
39095 this.cleanUpChildren(this.doc.body)
39099 cleanUpChildren : function (n)
39101 if (!n.childNodes.length) {
39104 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39105 this.cleanUpChild(n.childNodes[i]);
39112 cleanUpChild : function (node)
39114 //console.log(node);
39115 if (node.nodeName == "#text") {
39116 // clean up silly Windows -- stuff?
39119 if (node.nodeName == "#comment") {
39120 node.parentNode.removeChild(node);
39121 // clean up silly Windows -- stuff?
39125 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39127 node.parentNode.removeChild(node);
39131 if (!node.attributes || !node.attributes.length) {
39132 this.cleanUpChildren(node);
39136 function cleanAttr(n,v)
39139 if (v.match(/^\./) || v.match(/^\//)) {
39142 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39145 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39146 node.removeAttribute(n);
39150 function cleanStyle(n,v)
39152 if (v.match(/expression/)) { //XSS?? should we even bother..
39153 node.removeAttribute(n);
39158 var parts = v.split(/;/);
39159 Roo.each(parts, function(p) {
39160 p = p.replace(/\s+/g,'');
39164 var l = p.split(':').shift().replace(/\s+/g,'');
39166 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39167 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39168 node.removeAttribute(n);
39177 for (var i = node.attributes.length-1; i > -1 ; i--) {
39178 var a = node.attributes[i];
39180 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39181 node.removeAttribute(a.name);
39184 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39185 cleanAttr(a.name,a.value); // fixme..
39188 if (a.name == 'style') {
39189 cleanStyle(a.name,a.value);
39191 /// clean up MS crap..
39192 if (a.name == 'class') {
39193 if (a.value.match(/^Mso/)) {
39194 node.className = '';
39204 this.cleanUpChildren(node);
39210 // hide stuff that is not compatible
39224 * @event specialkey
39228 * @cfg {String} fieldClass @hide
39231 * @cfg {String} focusClass @hide
39234 * @cfg {String} autoCreate @hide
39237 * @cfg {String} inputType @hide
39240 * @cfg {String} invalidClass @hide
39243 * @cfg {String} invalidText @hide
39246 * @cfg {String} msgFx @hide
39249 * @cfg {String} validateOnBlur @hide
39253 Roo.form.HtmlEditor.white = [
39254 'area', 'br', 'img', 'input', 'hr', 'wbr',
39256 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39257 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39258 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39259 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39260 'table', 'ul', 'xmp',
39262 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39265 'dir', 'menu', 'ol', 'ul', 'dl',
39271 Roo.form.HtmlEditor.black = [
39272 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39274 'base', 'basefont', 'bgsound', 'blink', 'body',
39275 'frame', 'frameset', 'head', 'html', 'ilayer',
39276 'iframe', 'layer', 'link', 'meta', 'object',
39277 'script', 'style' ,'title', 'xml' // clean later..
39279 Roo.form.HtmlEditor.clean = [
39280 'script', 'style', 'title', 'xml'
39285 Roo.form.HtmlEditor.ablack = [
39289 Roo.form.HtmlEditor.aclean = [
39290 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39294 Roo.form.HtmlEditor.pwhite= [
39295 'http', 'https', 'mailto'
39298 Roo.form.HtmlEditor.cwhite= [
39303 // <script type="text/javascript">
39306 * Ext JS Library 1.1.1
39307 * Copyright(c) 2006-2007, Ext JS, LLC.
39313 * @class Roo.form.HtmlEditorToolbar1
39318 new Roo.form.HtmlEditor({
39321 new Roo.form.HtmlEditorToolbar1({
39322 disable : { fonts: 1 , format: 1, ..., ... , ...],
39328 * @cfg {Object} disable List of elements to disable..
39329 * @cfg {Array} btns List of additional buttons.
39333 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39336 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39339 Roo.apply(this, config);
39340 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39341 // dont call parent... till later.
39344 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39352 * @cfg {Object} disable List of toolbar elements to disable
39357 * @cfg {Array} fontFamilies An array of available font families
39375 // "á" , ?? a acute?
39380 "°" // , // degrees
39382 // "é" , // e ecute
39383 // "ú" , // u ecute?
39386 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39387 "input:submit", "input:button", "select", "textarea", "label" ],
39390 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39392 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39395 * @cfg {String} defaultFont default font to use.
39397 defaultFont: 'tahoma',
39399 fontSelect : false,
39402 formatCombo : false,
39404 init : function(editor)
39406 this.editor = editor;
39409 var fid = editor.frameId;
39411 function btn(id, toggle, handler){
39412 var xid = fid + '-'+ id ;
39416 cls : 'x-btn-icon x-edit-'+id,
39417 enableToggle:toggle !== false,
39418 scope: editor, // was editor...
39419 handler:handler||editor.relayBtnCmd,
39420 clickEvent:'mousedown',
39421 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39428 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
39430 // stop form submits
39431 tb.el.on('click', function(e){
39432 e.preventDefault(); // what does this do?
39435 if(!this.disable.font && !Roo.isSafari){
39436 /* why no safari for fonts
39437 editor.fontSelect = tb.el.createChild({
39440 cls:'x-font-select',
39441 html: editor.createFontOptions()
39443 editor.fontSelect.on('change', function(){
39444 var font = editor.fontSelect.dom.value;
39445 editor.relayCmd('fontname', font);
39446 editor.deferFocus();
39449 editor.fontSelect.dom,
39454 if(!this.disable.formats){
39455 this.formatCombo = new Roo.form.ComboBox({
39456 store: new Roo.data.SimpleStore({
39459 data : this.formats // from states.js
39462 //autoCreate : {tag: "div", size: "20"},
39463 displayField:'tag',
39467 triggerAction: 'all',
39468 emptyText:'Add tag',
39469 selectOnFocus:true,
39472 'select': function(c, r, i) {
39473 editor.insertTag(r.get('tag'));
39479 tb.addField(this.formatCombo);
39483 if(!this.disable.format){
39490 if(!this.disable.fontSize){
39495 btn('increasefontsize', false, editor.adjustFont),
39496 btn('decreasefontsize', false, editor.adjustFont)
39501 if(this.disable.colors){
39504 id:editor.frameId +'-forecolor',
39505 cls:'x-btn-icon x-edit-forecolor',
39506 clickEvent:'mousedown',
39507 tooltip: this.buttonTips['forecolor'] || undefined,
39509 menu : new Roo.menu.ColorMenu({
39510 allowReselect: true,
39511 focus: Roo.emptyFn,
39514 selectHandler: function(cp, color){
39515 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
39516 editor.deferFocus();
39519 clickEvent:'mousedown'
39522 id:editor.frameId +'backcolor',
39523 cls:'x-btn-icon x-edit-backcolor',
39524 clickEvent:'mousedown',
39525 tooltip: this.buttonTips['backcolor'] || undefined,
39527 menu : new Roo.menu.ColorMenu({
39528 focus: Roo.emptyFn,
39531 allowReselect: true,
39532 selectHandler: function(cp, color){
39534 editor.execCmd('useCSS', false);
39535 editor.execCmd('hilitecolor', color);
39536 editor.execCmd('useCSS', true);
39537 editor.deferFocus();
39539 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
39540 Roo.isSafari || Roo.isIE ? '#'+color : color);
39541 editor.deferFocus();
39545 clickEvent:'mousedown'
39550 // now add all the items...
39553 if(!this.disable.alignments){
39556 btn('justifyleft'),
39557 btn('justifycenter'),
39558 btn('justifyright')
39562 //if(!Roo.isSafari){
39563 if(!this.disable.links){
39566 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
39570 if(!this.disable.lists){
39573 btn('insertorderedlist'),
39574 btn('insertunorderedlist')
39577 if(!this.disable.sourceEdit){
39580 btn('sourceedit', true, function(btn){
39581 this.toggleSourceEdit(btn.pressed);
39588 // special menu.. - needs to be tidied up..
39589 if (!this.disable.special) {
39592 cls: 'x-edit-none',
39597 for (var i =0; i < this.specialChars.length; i++) {
39598 smenu.menu.items.push({
39600 html: this.specialChars[i],
39601 handler: function(a,b) {
39602 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
39615 for(var i =0; i< this.btns.length;i++) {
39616 var b = this.btns[i];
39617 b.cls = 'x-edit-none';
39626 // disable everything...
39628 this.tb.items.each(function(item){
39629 if(item.id != editor.frameId+ '-sourceedit'){
39633 this.rendered = true;
39635 // the all the btns;
39636 editor.on('editorevent', this.updateToolbar, this);
39637 // other toolbars need to implement this..
39638 //editor.on('editmodechange', this.updateToolbar, this);
39644 * Protected method that will not generally be called directly. It triggers
39645 * a toolbar update by reading the markup state of the current selection in the editor.
39647 updateToolbar: function(){
39649 if(!this.editor.activated){
39650 this.editor.onFirstFocus();
39654 var btns = this.tb.items.map,
39655 doc = this.editor.doc,
39656 frameId = this.editor.frameId;
39658 if(!this.disable.font && !Roo.isSafari){
39660 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39661 if(name != this.fontSelect.dom.value){
39662 this.fontSelect.dom.value = name;
39666 if(!this.disable.format){
39667 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39668 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39669 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39671 if(!this.disable.alignments){
39672 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39673 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39674 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39676 if(!Roo.isSafari && !this.disable.lists){
39677 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39678 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39681 var ans = this.editor.getAllAncestors();
39682 if (this.formatCombo) {
39685 var store = this.formatCombo.store;
39686 this.formatCombo.setValue("");
39687 for (var i =0; i < ans.length;i++) {
39688 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
39690 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39698 // hides menus... - so this cant be on a menu...
39699 Roo.menu.MenuMgr.hideAll();
39701 //this.editorsyncValue();
39705 createFontOptions : function(){
39706 var buf = [], fs = this.fontFamilies, ff, lc;
39707 for(var i = 0, len = fs.length; i< len; i++){
39709 lc = ff.toLowerCase();
39711 '<option value="',lc,'" style="font-family:',ff,';"',
39712 (this.defaultFont == lc ? ' selected="true">' : '>'),
39717 return buf.join('');
39720 toggleSourceEdit : function(sourceEditMode){
39721 if(sourceEditMode === undefined){
39722 sourceEditMode = !this.sourceEditMode;
39724 this.sourceEditMode = sourceEditMode === true;
39725 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39726 // just toggle the button?
39727 if(btn.pressed !== this.editor.sourceEditMode){
39728 btn.toggle(this.editor.sourceEditMode);
39732 if(this.sourceEditMode){
39733 this.tb.items.each(function(item){
39734 if(item.cmd != 'sourceedit'){
39740 if(this.initialized){
39741 this.tb.items.each(function(item){
39747 // tell the editor that it's been pressed..
39748 this.editor.toggleSourceEdit(sourceEditMode);
39752 * Object collection of toolbar tooltips for the buttons in the editor. The key
39753 * is the command id associated with that button and the value is a valid QuickTips object.
39758 title: 'Bold (Ctrl+B)',
39759 text: 'Make the selected text bold.',
39760 cls: 'x-html-editor-tip'
39763 title: 'Italic (Ctrl+I)',
39764 text: 'Make the selected text italic.',
39765 cls: 'x-html-editor-tip'
39773 title: 'Bold (Ctrl+B)',
39774 text: 'Make the selected text bold.',
39775 cls: 'x-html-editor-tip'
39778 title: 'Italic (Ctrl+I)',
39779 text: 'Make the selected text italic.',
39780 cls: 'x-html-editor-tip'
39783 title: 'Underline (Ctrl+U)',
39784 text: 'Underline the selected text.',
39785 cls: 'x-html-editor-tip'
39787 increasefontsize : {
39788 title: 'Grow Text',
39789 text: 'Increase the font size.',
39790 cls: 'x-html-editor-tip'
39792 decreasefontsize : {
39793 title: 'Shrink Text',
39794 text: 'Decrease the font size.',
39795 cls: 'x-html-editor-tip'
39798 title: 'Text Highlight Color',
39799 text: 'Change the background color of the selected text.',
39800 cls: 'x-html-editor-tip'
39803 title: 'Font Color',
39804 text: 'Change the color of the selected text.',
39805 cls: 'x-html-editor-tip'
39808 title: 'Align Text Left',
39809 text: 'Align text to the left.',
39810 cls: 'x-html-editor-tip'
39813 title: 'Center Text',
39814 text: 'Center text in the editor.',
39815 cls: 'x-html-editor-tip'
39818 title: 'Align Text Right',
39819 text: 'Align text to the right.',
39820 cls: 'x-html-editor-tip'
39822 insertunorderedlist : {
39823 title: 'Bullet List',
39824 text: 'Start a bulleted list.',
39825 cls: 'x-html-editor-tip'
39827 insertorderedlist : {
39828 title: 'Numbered List',
39829 text: 'Start a numbered list.',
39830 cls: 'x-html-editor-tip'
39833 title: 'Hyperlink',
39834 text: 'Make the selected text a hyperlink.',
39835 cls: 'x-html-editor-tip'
39838 title: 'Source Edit',
39839 text: 'Switch to source editing mode.',
39840 cls: 'x-html-editor-tip'
39844 onDestroy : function(){
39847 this.tb.items.each(function(item){
39849 item.menu.removeAll();
39851 item.menu.el.destroy();
39859 onFirstFocus: function() {
39860 this.tb.items.each(function(item){
39869 // <script type="text/javascript">
39872 * Ext JS Library 1.1.1
39873 * Copyright(c) 2006-2007, Ext JS, LLC.
39880 * @class Roo.form.HtmlEditor.ToolbarContext
39885 new Roo.form.HtmlEditor({
39888 new Roo.form.HtmlEditor.ToolbarStandard(),
39889 new Roo.form.HtmlEditor.ToolbarContext()
39894 * @config : {Object} disable List of elements to disable.. (not done yet.)
39899 Roo.form.HtmlEditor.ToolbarContext = function(config)
39902 Roo.apply(this, config);
39903 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39904 // dont call parent... till later.
39906 Roo.form.HtmlEditor.ToolbarContext.types = {
39918 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
39980 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
39985 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40049 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40057 * @cfg {Object} disable List of toolbar elements to disable
40066 init : function(editor)
40068 this.editor = editor;
40071 var fid = editor.frameId;
40073 function btn(id, toggle, handler){
40074 var xid = fid + '-'+ id ;
40078 cls : 'x-btn-icon x-edit-'+id,
40079 enableToggle:toggle !== false,
40080 scope: editor, // was editor...
40081 handler:handler||editor.relayBtnCmd,
40082 clickEvent:'mousedown',
40083 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40087 // create a new element.
40088 var wdiv = editor.wrap.createChild({
40090 }, editor.wrap.dom.firstChild.nextSibling, true);
40092 // can we do this more than once??
40094 // stop form submits
40097 // disable everything...
40098 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40099 this.toolbars = {};
40101 for (var i in ty) {
40103 this.toolbars[i] = this.buildToolbar(ty[i],i);
40105 this.tb = this.toolbars.BODY;
40109 this.rendered = true;
40111 // the all the btns;
40112 editor.on('editorevent', this.updateToolbar, this);
40113 // other toolbars need to implement this..
40114 //editor.on('editmodechange', this.updateToolbar, this);
40120 * Protected method that will not generally be called directly. It triggers
40121 * a toolbar update by reading the markup state of the current selection in the editor.
40123 updateToolbar: function(){
40125 if(!this.editor.activated){
40126 this.editor.onFirstFocus();
40131 var ans = this.editor.getAllAncestors();
40134 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40135 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40136 sel = sel ? sel : this.editor.doc.body;
40137 sel = sel.tagName.length ? sel : this.editor.doc.body;
40138 var tn = sel.tagName.toUpperCase();
40139 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40140 tn = sel.tagName.toUpperCase();
40141 if (this.tb.name == tn) {
40142 return; // no change
40145 ///console.log("show: " + tn);
40146 this.tb = this.toolbars[tn];
40148 this.tb.fields.each(function(e) {
40149 e.setValue(sel.getAttribute(e.name));
40151 this.tb.selectedNode = sel;
40154 Roo.menu.MenuMgr.hideAll();
40156 //this.editorsyncValue();
40161 onDestroy : function(){
40164 this.tb.items.each(function(item){
40166 item.menu.removeAll();
40168 item.menu.el.destroy();
40176 onFirstFocus: function() {
40177 // need to do this for all the toolbars..
40178 this.tb.items.each(function(item){
40182 buildToolbar: function(tlist, nm)
40184 var editor = this.editor;
40185 // create a new element.
40186 var wdiv = editor.wrap.createChild({
40188 }, editor.wrap.dom.firstChild.nextSibling, true);
40191 var tb = new Roo.Toolbar(wdiv);
40192 tb.add(nm+ ": ");
40193 for (var i in tlist) {
40194 var item = tlist[i];
40195 tb.add(item.title + ": ");
40200 tb.addField( new Roo.form.ComboBox({
40201 store: new Roo.data.SimpleStore({
40204 data : item.opts // from states.js
40207 displayField:'val',
40211 triggerAction: 'all',
40212 emptyText:'Select',
40213 selectOnFocus:true,
40214 width: item.width ? item.width : 130,
40216 'select': function(c, r, i) {
40217 tb.selectedNode.setAttribute(c.name, r.get('val'));
40228 tb.addField( new Roo.form.TextField({
40231 //allowBlank:false,
40236 tb.addField( new Roo.form.TextField({
40242 'change' : function(f, nv, ov) {
40243 tb.selectedNode.setAttribute(f.name, nv);
40249 tb.el.on('click', function(e){
40250 e.preventDefault(); // what does this do?
40252 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40255 // dont need to disable them... as they will get hidden
40272 * Ext JS Library 1.1.1
40273 * Copyright(c) 2006-2007, Ext JS, LLC.
40275 * Originally Released Under LGPL - original licence link has changed is not relivant.
40278 * <script type="text/javascript">
40282 * @class Roo.form.BasicForm
40283 * @extends Roo.util.Observable
40284 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
40286 * @param {String/HTMLElement/Roo.Element} el The form element or its id
40287 * @param {Object} config Configuration options
40289 Roo.form.BasicForm = function(el, config){
40290 this.allItems = [];
40291 this.childForms = [];
40292 Roo.apply(this, config);
40294 * The Roo.form.Field items in this form.
40295 * @type MixedCollection
40299 this.items = new Roo.util.MixedCollection(false, function(o){
40300 return o.id || (o.id = Roo.id());
40304 * @event beforeaction
40305 * Fires before any action is performed. Return false to cancel the action.
40306 * @param {Form} this
40307 * @param {Action} action The action to be performed
40309 beforeaction: true,
40311 * @event actionfailed
40312 * Fires when an action fails.
40313 * @param {Form} this
40314 * @param {Action} action The action that failed
40316 actionfailed : true,
40318 * @event actioncomplete
40319 * Fires when an action is completed.
40320 * @param {Form} this
40321 * @param {Action} action The action that completed
40323 actioncomplete : true
40328 Roo.form.BasicForm.superclass.constructor.call(this);
40331 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
40333 * @cfg {String} method
40334 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
40337 * @cfg {DataReader} reader
40338 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
40339 * This is optional as there is built-in support for processing JSON.
40342 * @cfg {DataReader} errorReader
40343 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
40344 * This is completely optional as there is built-in support for processing JSON.
40347 * @cfg {String} url
40348 * The URL to use for form actions if one isn't supplied in the action options.
40351 * @cfg {Boolean} fileUpload
40352 * Set to true if this form is a file upload.
40355 * @cfg {Object} baseParams
40356 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
40359 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
40364 activeAction : null,
40367 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
40368 * or setValues() data instead of when the form was first created.
40370 trackResetOnLoad : false,
40374 * childForms - used for multi-tab forms
40377 childForms : false,
40380 * allItems - full list of fields.
40386 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
40387 * element by passing it or its id or mask the form itself by passing in true.
40390 waitMsgTarget : undefined,
40393 initEl : function(el){
40394 this.el = Roo.get(el);
40395 this.id = this.el.id || Roo.id();
40396 this.el.on('submit', this.onSubmit, this);
40397 this.el.addClass('x-form');
40401 onSubmit : function(e){
40406 * Returns true if client-side validation on the form is successful.
40409 isValid : function(){
40411 this.items.each(function(f){
40420 * Returns true if any fields in this form have changed since their original load.
40423 isDirty : function(){
40425 this.items.each(function(f){
40435 * Performs a predefined action (submit or load) or custom actions you define on this form.
40436 * @param {String} actionName The name of the action type
40437 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
40438 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
40439 * accept other config options):
40441 Property Type Description
40442 ---------------- --------------- ----------------------------------------------------------------------------------
40443 url String The url for the action (defaults to the form's url)
40444 method String The form method to use (defaults to the form's method, or POST if not defined)
40445 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
40446 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
40447 validate the form on the client (defaults to false)
40449 * @return {BasicForm} this
40451 doAction : function(action, options){
40452 if(typeof action == 'string'){
40453 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
40455 if(this.fireEvent('beforeaction', this, action) !== false){
40456 this.beforeAction(action);
40457 action.run.defer(100, action);
40463 * Shortcut to do a submit action.
40464 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40465 * @return {BasicForm} this
40467 submit : function(options){
40468 this.doAction('submit', options);
40473 * Shortcut to do a load action.
40474 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40475 * @return {BasicForm} this
40477 load : function(options){
40478 this.doAction('load', options);
40483 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
40484 * @param {Record} record The record to edit
40485 * @return {BasicForm} this
40487 updateRecord : function(record){
40488 record.beginEdit();
40489 var fs = record.fields;
40490 fs.each(function(f){
40491 var field = this.findField(f.name);
40493 record.set(f.name, field.getValue());
40501 * Loads an Roo.data.Record into this form.
40502 * @param {Record} record The record to load
40503 * @return {BasicForm} this
40505 loadRecord : function(record){
40506 this.setValues(record.data);
40511 beforeAction : function(action){
40512 var o = action.options;
40514 if(this.waitMsgTarget === true){
40515 this.el.mask(o.waitMsg, 'x-mask-loading');
40516 }else if(this.waitMsgTarget){
40517 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
40518 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
40520 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
40526 afterAction : function(action, success){
40527 this.activeAction = null;
40528 var o = action.options;
40530 if(this.waitMsgTarget === true){
40532 }else if(this.waitMsgTarget){
40533 this.waitMsgTarget.unmask();
40535 Roo.MessageBox.updateProgress(1);
40536 Roo.MessageBox.hide();
40543 Roo.callback(o.success, o.scope, [this, action]);
40544 this.fireEvent('actioncomplete', this, action);
40546 Roo.callback(o.failure, o.scope, [this, action]);
40547 this.fireEvent('actionfailed', this, action);
40552 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
40553 * @param {String} id The value to search for
40556 findField : function(id){
40557 var field = this.items.get(id);
40559 this.items.each(function(f){
40560 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
40566 return field || null;
40570 * Add a secondary form to this one,
40571 * Used to provide tabbed forms. One form is primary, with hidden values
40572 * which mirror the elements from the other forms.
40574 * @param {Roo.form.Form} form to add.
40577 addForm : function(form)
40580 if (this.childForms.indexOf(form) > -1) {
40584 this.childForms.push(form);
40586 Roo.each(form.allItems, function (fe) {
40588 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
40589 if (this.findField(n)) { // already added..
40592 var add = new Roo.form.Hidden({
40595 add.render(this.el);
40602 * Mark fields in this form invalid in bulk.
40603 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
40604 * @return {BasicForm} this
40606 markInvalid : function(errors){
40607 if(errors instanceof Array){
40608 for(var i = 0, len = errors.length; i < len; i++){
40609 var fieldError = errors[i];
40610 var f = this.findField(fieldError.id);
40612 f.markInvalid(fieldError.msg);
40618 if(typeof errors[id] != 'function' && (field = this.findField(id))){
40619 field.markInvalid(errors[id]);
40623 Roo.each(this.childForms || [], function (f) {
40624 f.markInvalid(errors);
40631 * Set values for fields in this form in bulk.
40632 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40633 * @return {BasicForm} this
40635 setValues : function(values){
40636 if(values instanceof Array){ // array of objects
40637 for(var i = 0, len = values.length; i < len; i++){
40639 var f = this.findField(v.id);
40641 f.setValue(v.value);
40642 if(this.trackResetOnLoad){
40643 f.originalValue = f.getValue();
40647 }else{ // object hash
40650 if(typeof values[id] != 'function' && (field = this.findField(id))){
40652 if (field.setFromData &&
40653 field.valueField &&
40654 field.displayField &&
40655 // combos' with local stores can
40656 // be queried via setValue()
40657 // to set their value..
40658 (field.store && !field.store.isLocal)
40662 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40663 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40664 field.setFromData(sd);
40667 field.setValue(values[id]);
40671 if(this.trackResetOnLoad){
40672 field.originalValue = field.getValue();
40678 Roo.each(this.childForms || [], function (f) {
40679 f.setValues(values);
40686 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40687 * they are returned as an array.
40688 * @param {Boolean} asString
40691 getValues : function(asString){
40692 if (this.childForms) {
40693 // copy values from the child forms
40694 Roo.each(this.childForms, function (f) {
40695 this.setValues(f.getValues());
40701 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40702 if(asString === true){
40705 return Roo.urlDecode(fs);
40709 * Returns the fields in this form as an object with key/value pairs.
40710 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
40713 getFieldValues : function()
40715 if (this.childForms) {
40716 // copy values from the child forms
40717 Roo.each(this.childForms, function (f) {
40718 this.setValues(f.getValues());
40723 this.items.each(function(f){
40724 if (!f.getName()) {
40727 var v = f.getValue();
40728 if ((typeof(v) == 'object') && f.getRawValue) {
40729 v = f.getRawValue() ; // dates..
40731 ret[f.getName()] = v;
40738 * Clears all invalid messages in this form.
40739 * @return {BasicForm} this
40741 clearInvalid : function(){
40742 this.items.each(function(f){
40746 Roo.each(this.childForms || [], function (f) {
40755 * Resets this form.
40756 * @return {BasicForm} this
40758 reset : function(){
40759 this.items.each(function(f){
40763 Roo.each(this.childForms || [], function (f) {
40772 * Add Roo.form components to this form.
40773 * @param {Field} field1
40774 * @param {Field} field2 (optional)
40775 * @param {Field} etc (optional)
40776 * @return {BasicForm} this
40779 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40785 * Removes a field from the items collection (does NOT remove its markup).
40786 * @param {Field} field
40787 * @return {BasicForm} this
40789 remove : function(field){
40790 this.items.remove(field);
40795 * Looks at the fields in this form, checks them for an id attribute,
40796 * and calls applyTo on the existing dom element with that id.
40797 * @return {BasicForm} this
40799 render : function(){
40800 this.items.each(function(f){
40801 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40809 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40810 * @param {Object} values
40811 * @return {BasicForm} this
40813 applyToFields : function(o){
40814 this.items.each(function(f){
40821 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40822 * @param {Object} values
40823 * @return {BasicForm} this
40825 applyIfToFields : function(o){
40826 this.items.each(function(f){
40834 Roo.BasicForm = Roo.form.BasicForm;/*
40836 * Ext JS Library 1.1.1
40837 * Copyright(c) 2006-2007, Ext JS, LLC.
40839 * Originally Released Under LGPL - original licence link has changed is not relivant.
40842 * <script type="text/javascript">
40846 * @class Roo.form.Form
40847 * @extends Roo.form.BasicForm
40848 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40850 * @param {Object} config Configuration options
40852 Roo.form.Form = function(config){
40854 if (config.items) {
40855 xitems = config.items;
40856 delete config.items;
40860 Roo.form.Form.superclass.constructor.call(this, null, config);
40861 this.url = this.url || this.action;
40863 this.root = new Roo.form.Layout(Roo.applyIf({
40867 this.active = this.root;
40869 * Array of all the buttons that have been added to this form via {@link addButton}
40873 this.allItems = [];
40876 * @event clientvalidation
40877 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40878 * @param {Form} this
40879 * @param {Boolean} valid true if the form has passed client-side validation
40881 clientvalidation: true,
40884 * Fires when the form is rendered
40885 * @param {Roo.form.Form} form
40890 if (this.progressUrl) {
40891 // push a hidden field onto the list of fields..
40895 name : 'UPLOAD_IDENTIFIER'
40900 Roo.each(xitems, this.addxtype, this);
40906 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
40908 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
40911 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
40914 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
40916 buttonAlign:'center',
40919 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
40924 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
40925 * This property cascades to child containers if not set.
40930 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
40931 * fires a looping event with that state. This is required to bind buttons to the valid
40932 * state using the config value formBind:true on the button.
40934 monitorValid : false,
40937 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
40942 * @cfg {String} progressUrl - Url to return progress data
40945 progressUrl : false,
40948 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
40949 * fields are added and the column is closed. If no fields are passed the column remains open
40950 * until end() is called.
40951 * @param {Object} config The config to pass to the column
40952 * @param {Field} field1 (optional)
40953 * @param {Field} field2 (optional)
40954 * @param {Field} etc (optional)
40955 * @return Column The column container object
40957 column : function(c){
40958 var col = new Roo.form.Column(c);
40960 if(arguments.length > 1){ // duplicate code required because of Opera
40961 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40968 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
40969 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
40970 * until end() is called.
40971 * @param {Object} config The config to pass to the fieldset
40972 * @param {Field} field1 (optional)
40973 * @param {Field} field2 (optional)
40974 * @param {Field} etc (optional)
40975 * @return FieldSet The fieldset container object
40977 fieldset : function(c){
40978 var fs = new Roo.form.FieldSet(c);
40980 if(arguments.length > 1){ // duplicate code required because of Opera
40981 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40988 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
40989 * fields are added and the container is closed. If no fields are passed the container remains open
40990 * until end() is called.
40991 * @param {Object} config The config to pass to the Layout
40992 * @param {Field} field1 (optional)
40993 * @param {Field} field2 (optional)
40994 * @param {Field} etc (optional)
40995 * @return Layout The container object
40997 container : function(c){
40998 var l = new Roo.form.Layout(c);
41000 if(arguments.length > 1){ // duplicate code required because of Opera
41001 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41008 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41009 * @param {Object} container A Roo.form.Layout or subclass of Layout
41010 * @return {Form} this
41012 start : function(c){
41013 // cascade label info
41014 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41015 this.active.stack.push(c);
41016 c.ownerCt = this.active;
41022 * Closes the current open container
41023 * @return {Form} this
41026 if(this.active == this.root){
41029 this.active = this.active.ownerCt;
41034 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41035 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41036 * as the label of the field.
41037 * @param {Field} field1
41038 * @param {Field} field2 (optional)
41039 * @param {Field} etc. (optional)
41040 * @return {Form} this
41043 this.active.stack.push.apply(this.active.stack, arguments);
41044 this.allItems.push.apply(this.allItems,arguments);
41046 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41047 if(a[i].isFormField){
41052 Roo.form.Form.superclass.add.apply(this, r);
41062 * Find any element that has been added to a form, using it's ID or name
41063 * This can include framesets, columns etc. along with regular fields..
41064 * @param {String} id - id or name to find.
41066 * @return {Element} e - or false if nothing found.
41068 findbyId : function(id)
41074 Ext.each(this.allItems, function(f){
41075 if (f.id == id || f.name == id ){
41086 * Render this form into the passed container. This should only be called once!
41087 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41088 * @return {Form} this
41090 render : function(ct)
41096 var o = this.autoCreate || {
41098 method : this.method || 'POST',
41099 id : this.id || Roo.id()
41101 this.initEl(ct.createChild(o));
41103 this.root.render(this.el);
41107 this.items.each(function(f){
41108 f.render('x-form-el-'+f.id);
41111 if(this.buttons.length > 0){
41112 // tables are required to maintain order and for correct IE layout
41113 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41114 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41115 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41117 var tr = tb.getElementsByTagName('tr')[0];
41118 for(var i = 0, len = this.buttons.length; i < len; i++) {
41119 var b = this.buttons[i];
41120 var td = document.createElement('td');
41121 td.className = 'x-form-btn-td';
41122 b.render(tr.appendChild(td));
41125 if(this.monitorValid){ // initialize after render
41126 this.startMonitoring();
41128 this.fireEvent('rendered', this);
41133 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41134 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41135 * object or a valid Roo.DomHelper element config
41136 * @param {Function} handler The function called when the button is clicked
41137 * @param {Object} scope (optional) The scope of the handler function
41138 * @return {Roo.Button}
41140 addButton : function(config, handler, scope){
41144 minWidth: this.minButtonWidth,
41147 if(typeof config == "string"){
41150 Roo.apply(bc, config);
41152 var btn = new Roo.Button(null, bc);
41153 this.buttons.push(btn);
41158 * Adds a series of form elements (using the xtype property as the factory method.
41159 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41160 * @param {Object} config
41163 addxtype : function()
41165 var ar = Array.prototype.slice.call(arguments, 0);
41167 for(var i = 0; i < ar.length; i++) {
41169 continue; // skip -- if this happends something invalid got sent, we
41170 // should ignore it, as basically that interface element will not show up
41171 // and that should be pretty obvious!!
41174 if (Roo.form[ar[i].xtype]) {
41176 var fe = Roo.factory(ar[i], Roo.form);
41182 fe.store.form = this;
41187 this.allItems.push(fe);
41188 if (fe.items && fe.addxtype) {
41189 fe.addxtype.apply(fe, fe.items);
41199 // console.log('adding ' + ar[i].xtype);
41201 if (ar[i].xtype == 'Button') {
41202 //console.log('adding button');
41203 //console.log(ar[i]);
41204 this.addButton(ar[i]);
41205 this.allItems.push(fe);
41209 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
41210 alert('end is not supported on xtype any more, use items');
41212 // //console.log('adding end');
41220 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
41221 * option "monitorValid"
41223 startMonitoring : function(){
41226 Roo.TaskMgr.start({
41227 run : this.bindHandler,
41228 interval : this.monitorPoll || 200,
41235 * Stops monitoring of the valid state of this form
41237 stopMonitoring : function(){
41238 this.bound = false;
41242 bindHandler : function(){
41244 return false; // stops binding
41247 this.items.each(function(f){
41248 if(!f.isValid(true)){
41253 for(var i = 0, len = this.buttons.length; i < len; i++){
41254 var btn = this.buttons[i];
41255 if(btn.formBind === true && btn.disabled === valid){
41256 btn.setDisabled(!valid);
41259 this.fireEvent('clientvalidation', this, valid);
41273 Roo.Form = Roo.form.Form;
41276 * Ext JS Library 1.1.1
41277 * Copyright(c) 2006-2007, Ext JS, LLC.
41279 * Originally Released Under LGPL - original licence link has changed is not relivant.
41282 * <script type="text/javascript">
41286 * @class Roo.form.Action
41287 * Internal Class used to handle form actions
41289 * @param {Roo.form.BasicForm} el The form element or its id
41290 * @param {Object} config Configuration options
41294 // define the action interface
41295 Roo.form.Action = function(form, options){
41297 this.options = options || {};
41300 * Client Validation Failed
41303 Roo.form.Action.CLIENT_INVALID = 'client';
41305 * Server Validation Failed
41308 Roo.form.Action.SERVER_INVALID = 'server';
41310 * Connect to Server Failed
41313 Roo.form.Action.CONNECT_FAILURE = 'connect';
41315 * Reading Data from Server Failed
41318 Roo.form.Action.LOAD_FAILURE = 'load';
41320 Roo.form.Action.prototype = {
41322 failureType : undefined,
41323 response : undefined,
41324 result : undefined,
41326 // interface method
41327 run : function(options){
41331 // interface method
41332 success : function(response){
41336 // interface method
41337 handleResponse : function(response){
41341 // default connection failure
41342 failure : function(response){
41343 this.response = response;
41344 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41345 this.form.afterAction(this, false);
41348 processResponse : function(response){
41349 this.response = response;
41350 if(!response.responseText){
41353 this.result = this.handleResponse(response);
41354 return this.result;
41357 // utility functions used internally
41358 getUrl : function(appendParams){
41359 var url = this.options.url || this.form.url || this.form.el.dom.action;
41361 var p = this.getParams();
41363 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
41369 getMethod : function(){
41370 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
41373 getParams : function(){
41374 var bp = this.form.baseParams;
41375 var p = this.options.params;
41377 if(typeof p == "object"){
41378 p = Roo.urlEncode(Roo.applyIf(p, bp));
41379 }else if(typeof p == 'string' && bp){
41380 p += '&' + Roo.urlEncode(bp);
41383 p = Roo.urlEncode(bp);
41388 createCallback : function(){
41390 success: this.success,
41391 failure: this.failure,
41393 timeout: (this.form.timeout*1000),
41394 upload: this.form.fileUpload ? this.success : undefined
41399 Roo.form.Action.Submit = function(form, options){
41400 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
41403 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
41406 haveProgress : false,
41407 uploadComplete : false,
41409 // uploadProgress indicator.
41410 uploadProgress : function()
41412 if (!this.form.progressUrl) {
41416 if (!this.haveProgress) {
41417 Roo.MessageBox.progress("Uploading", "Uploading");
41419 if (this.uploadComplete) {
41420 Roo.MessageBox.hide();
41424 this.haveProgress = true;
41426 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
41428 var c = new Roo.data.Connection();
41430 url : this.form.progressUrl,
41435 success : function(req){
41436 //console.log(data);
41440 rdata = Roo.decode(req.responseText)
41442 Roo.log("Invalid data from server..");
41446 if (!rdata || !rdata.success) {
41450 var data = rdata.data;
41452 if (this.uploadComplete) {
41453 Roo.MessageBox.hide();
41458 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
41459 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
41462 this.uploadProgress.defer(2000,this);
41465 failure: function(data) {
41466 Roo.log('progress url failed ');
41477 // run get Values on the form, so it syncs any secondary forms.
41478 this.form.getValues();
41480 var o = this.options;
41481 var method = this.getMethod();
41482 var isPost = method == 'POST';
41483 if(o.clientValidation === false || this.form.isValid()){
41485 if (this.form.progressUrl) {
41486 this.form.findField('UPLOAD_IDENTIFIER').setValue(
41487 (new Date() * 1) + '' + Math.random());
41491 Roo.Ajax.request(Roo.apply(this.createCallback(), {
41492 form:this.form.el.dom,
41493 url:this.getUrl(!isPost),
41495 params:isPost ? this.getParams() : null,
41496 isUpload: this.form.fileUpload
41499 this.uploadProgress();
41501 }else if (o.clientValidation !== false){ // client validation failed
41502 this.failureType = Roo.form.Action.CLIENT_INVALID;
41503 this.form.afterAction(this, false);
41507 success : function(response)
41509 this.uploadComplete= true;
41510 if (this.haveProgress) {
41511 Roo.MessageBox.hide();
41514 var result = this.processResponse(response);
41515 if(result === true || result.success){
41516 this.form.afterAction(this, true);
41520 this.form.markInvalid(result.errors);
41521 this.failureType = Roo.form.Action.SERVER_INVALID;
41523 this.form.afterAction(this, false);
41525 failure : function(response)
41527 this.uploadComplete= true;
41528 if (this.haveProgress) {
41529 Roo.MessageBox.hide();
41532 this.response = response;
41533 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41534 this.form.afterAction(this, false);
41537 handleResponse : function(response){
41538 if(this.form.errorReader){
41539 var rs = this.form.errorReader.read(response);
41542 for(var i = 0, len = rs.records.length; i < len; i++) {
41543 var r = rs.records[i];
41544 errors[i] = r.data;
41547 if(errors.length < 1){
41551 success : rs.success,
41557 ret = Roo.decode(response.responseText);
41561 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
41571 Roo.form.Action.Load = function(form, options){
41572 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
41573 this.reader = this.form.reader;
41576 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
41580 Roo.Ajax.request(Roo.apply(
41581 this.createCallback(), {
41582 method:this.getMethod(),
41583 url:this.getUrl(false),
41584 params:this.getParams()
41588 success : function(response){
41589 var result = this.processResponse(response);
41590 if(result === true || !result.success || !result.data){
41591 this.failureType = Roo.form.Action.LOAD_FAILURE;
41592 this.form.afterAction(this, false);
41595 this.form.clearInvalid();
41596 this.form.setValues(result.data);
41597 this.form.afterAction(this, true);
41600 handleResponse : function(response){
41601 if(this.form.reader){
41602 var rs = this.form.reader.read(response);
41603 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
41605 success : rs.success,
41609 return Roo.decode(response.responseText);
41613 Roo.form.Action.ACTION_TYPES = {
41614 'load' : Roo.form.Action.Load,
41615 'submit' : Roo.form.Action.Submit
41618 * Ext JS Library 1.1.1
41619 * Copyright(c) 2006-2007, Ext JS, LLC.
41621 * Originally Released Under LGPL - original licence link has changed is not relivant.
41624 * <script type="text/javascript">
41628 * @class Roo.form.Layout
41629 * @extends Roo.Component
41630 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
41632 * @param {Object} config Configuration options
41634 Roo.form.Layout = function(config){
41636 if (config.items) {
41637 xitems = config.items;
41638 delete config.items;
41640 Roo.form.Layout.superclass.constructor.call(this, config);
41642 Roo.each(xitems, this.addxtype, this);
41646 Roo.extend(Roo.form.Layout, Roo.Component, {
41648 * @cfg {String/Object} autoCreate
41649 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
41652 * @cfg {String/Object/Function} style
41653 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
41654 * a function which returns such a specification.
41657 * @cfg {String} labelAlign
41658 * Valid values are "left," "top" and "right" (defaults to "left")
41661 * @cfg {Number} labelWidth
41662 * Fixed width in pixels of all field labels (defaults to undefined)
41665 * @cfg {Boolean} clear
41666 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
41670 * @cfg {String} labelSeparator
41671 * The separator to use after field labels (defaults to ':')
41673 labelSeparator : ':',
41675 * @cfg {Boolean} hideLabels
41676 * True to suppress the display of field labels in this layout (defaults to false)
41678 hideLabels : false,
41681 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
41686 onRender : function(ct, position){
41687 if(this.el){ // from markup
41688 this.el = Roo.get(this.el);
41689 }else { // generate
41690 var cfg = this.getAutoCreate();
41691 this.el = ct.createChild(cfg, position);
41694 this.el.applyStyles(this.style);
41696 if(this.labelAlign){
41697 this.el.addClass('x-form-label-'+this.labelAlign);
41699 if(this.hideLabels){
41700 this.labelStyle = "display:none";
41701 this.elementStyle = "padding-left:0;";
41703 if(typeof this.labelWidth == 'number'){
41704 this.labelStyle = "width:"+this.labelWidth+"px;";
41705 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
41707 if(this.labelAlign == 'top'){
41708 this.labelStyle = "width:auto;";
41709 this.elementStyle = "padding-left:0;";
41712 var stack = this.stack;
41713 var slen = stack.length;
41715 if(!this.fieldTpl){
41716 var t = new Roo.Template(
41717 '<div class="x-form-item {5}">',
41718 '<label for="{0}" style="{2}">{1}{4}</label>',
41719 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41721 '</div><div class="x-form-clear-left"></div>'
41723 t.disableFormats = true;
41725 Roo.form.Layout.prototype.fieldTpl = t;
41727 for(var i = 0; i < slen; i++) {
41728 if(stack[i].isFormField){
41729 this.renderField(stack[i]);
41731 this.renderComponent(stack[i]);
41736 this.el.createChild({cls:'x-form-clear'});
41741 renderField : function(f){
41742 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
41745 f.labelStyle||this.labelStyle||'', //2
41746 this.elementStyle||'', //3
41747 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
41748 f.itemCls||this.itemCls||'' //5
41749 ], true).getPrevSibling());
41753 renderComponent : function(c){
41754 c.render(c.isLayout ? this.el : this.el.createChild());
41757 * Adds a object form elements (using the xtype property as the factory method.)
41758 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
41759 * @param {Object} config
41761 addxtype : function(o)
41763 // create the lement.
41764 o.form = this.form;
41765 var fe = Roo.factory(o, Roo.form);
41766 this.form.allItems.push(fe);
41767 this.stack.push(fe);
41769 if (fe.isFormField) {
41770 this.form.items.add(fe);
41778 * @class Roo.form.Column
41779 * @extends Roo.form.Layout
41780 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41782 * @param {Object} config Configuration options
41784 Roo.form.Column = function(config){
41785 Roo.form.Column.superclass.constructor.call(this, config);
41788 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41790 * @cfg {Number/String} width
41791 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41794 * @cfg {String/Object} autoCreate
41795 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41799 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41802 onRender : function(ct, position){
41803 Roo.form.Column.superclass.onRender.call(this, ct, position);
41805 this.el.setWidth(this.width);
41812 * @class Roo.form.Row
41813 * @extends Roo.form.Layout
41814 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41816 * @param {Object} config Configuration options
41820 Roo.form.Row = function(config){
41821 Roo.form.Row.superclass.constructor.call(this, config);
41824 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41826 * @cfg {Number/String} width
41827 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41830 * @cfg {Number/String} height
41831 * The fixed height of the column in pixels or CSS value (defaults to "auto")
41833 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41837 onRender : function(ct, position){
41838 //console.log('row render');
41840 var t = new Roo.Template(
41841 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
41842 '<label for="{0}" style="{2}">{1}{4}</label>',
41843 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41847 t.disableFormats = true;
41849 Roo.form.Layout.prototype.rowTpl = t;
41851 this.fieldTpl = this.rowTpl;
41853 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
41854 var labelWidth = 100;
41856 if ((this.labelAlign != 'top')) {
41857 if (typeof this.labelWidth == 'number') {
41858 labelWidth = this.labelWidth
41860 this.padWidth = 20 + labelWidth;
41864 Roo.form.Column.superclass.onRender.call(this, ct, position);
41866 this.el.setWidth(this.width);
41869 this.el.setHeight(this.height);
41874 renderField : function(f){
41875 f.fieldEl = this.fieldTpl.append(this.el, [
41876 f.id, f.fieldLabel,
41877 f.labelStyle||this.labelStyle||'',
41878 this.elementStyle||'',
41879 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
41880 f.itemCls||this.itemCls||'',
41881 f.width ? f.width + this.padWidth : 160 + this.padWidth
41888 * @class Roo.form.FieldSet
41889 * @extends Roo.form.Layout
41890 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
41892 * @param {Object} config Configuration options
41894 Roo.form.FieldSet = function(config){
41895 Roo.form.FieldSet.superclass.constructor.call(this, config);
41898 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
41900 * @cfg {String} legend
41901 * The text to display as the legend for the FieldSet (defaults to '')
41904 * @cfg {String/Object} autoCreate
41905 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
41909 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
41912 onRender : function(ct, position){
41913 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
41915 this.setLegend(this.legend);
41920 setLegend : function(text){
41922 this.el.child('legend').update(text);
41927 * Ext JS Library 1.1.1
41928 * Copyright(c) 2006-2007, Ext JS, LLC.
41930 * Originally Released Under LGPL - original licence link has changed is not relivant.
41933 * <script type="text/javascript">
41936 * @class Roo.form.VTypes
41937 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
41940 Roo.form.VTypes = function(){
41941 // closure these in so they are only created once.
41942 var alpha = /^[a-zA-Z_]+$/;
41943 var alphanum = /^[a-zA-Z0-9_]+$/;
41944 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
41945 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
41947 // All these messages and functions are configurable
41950 * The function used to validate email addresses
41951 * @param {String} value The email address
41953 'email' : function(v){
41954 return email.test(v);
41957 * The error text to display when the email validation function returns false
41960 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
41962 * The keystroke filter mask to be applied on email input
41965 'emailMask' : /[a-z0-9_\.\-@]/i,
41968 * The function used to validate URLs
41969 * @param {String} value The URL
41971 'url' : function(v){
41972 return url.test(v);
41975 * The error text to display when the url validation function returns false
41978 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
41981 * The function used to validate alpha values
41982 * @param {String} value The value
41984 'alpha' : function(v){
41985 return alpha.test(v);
41988 * The error text to display when the alpha validation function returns false
41991 'alphaText' : 'This field should only contain letters and _',
41993 * The keystroke filter mask to be applied on alpha input
41996 'alphaMask' : /[a-z_]/i,
41999 * The function used to validate alphanumeric values
42000 * @param {String} value The value
42002 'alphanum' : function(v){
42003 return alphanum.test(v);
42006 * The error text to display when the alphanumeric validation function returns false
42009 'alphanumText' : 'This field should only contain letters, numbers and _',
42011 * The keystroke filter mask to be applied on alphanumeric input
42014 'alphanumMask' : /[a-z0-9_]/i
42016 }();//<script type="text/javascript">
42019 * @class Roo.form.FCKeditor
42020 * @extends Roo.form.TextArea
42021 * Wrapper around the FCKEditor http://www.fckeditor.net
42023 * Creates a new FCKeditor
42024 * @param {Object} config Configuration options
42026 Roo.form.FCKeditor = function(config){
42027 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42030 * @event editorinit
42031 * Fired when the editor is initialized - you can add extra handlers here..
42032 * @param {FCKeditor} this
42033 * @param {Object} the FCK object.
42040 Roo.form.FCKeditor.editors = { };
42041 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42043 //defaultAutoCreate : {
42044 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42048 * @cfg {Object} fck options - see fck manual for details.
42053 * @cfg {Object} fck toolbar set (Basic or Default)
42055 toolbarSet : 'Basic',
42057 * @cfg {Object} fck BasePath
42059 basePath : '/fckeditor/',
42067 onRender : function(ct, position)
42070 this.defaultAutoCreate = {
42072 style:"width:300px;height:60px;",
42073 autocomplete: "off"
42076 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42079 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42080 if(this.preventScrollbars){
42081 this.el.setStyle("overflow", "hidden");
42083 this.el.setHeight(this.growMin);
42086 //console.log('onrender' + this.getId() );
42087 Roo.form.FCKeditor.editors[this.getId()] = this;
42090 this.replaceTextarea() ;
42094 getEditor : function() {
42095 return this.fckEditor;
42098 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42099 * @param {Mixed} value The value to set
42103 setValue : function(value)
42105 //console.log('setValue: ' + value);
42107 if(typeof(value) == 'undefined') { // not sure why this is happending...
42110 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42112 //if(!this.el || !this.getEditor()) {
42113 // this.value = value;
42114 //this.setValue.defer(100,this,[value]);
42118 if(!this.getEditor()) {
42122 this.getEditor().SetData(value);
42129 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42130 * @return {Mixed} value The field value
42132 getValue : function()
42135 if (this.frame && this.frame.dom.style.display == 'none') {
42136 return Roo.form.FCKeditor.superclass.getValue.call(this);
42139 if(!this.el || !this.getEditor()) {
42141 // this.getValue.defer(100,this);
42146 var value=this.getEditor().GetData();
42147 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42148 return Roo.form.FCKeditor.superclass.getValue.call(this);
42154 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42155 * @return {Mixed} value The field value
42157 getRawValue : function()
42159 if (this.frame && this.frame.dom.style.display == 'none') {
42160 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42163 if(!this.el || !this.getEditor()) {
42164 //this.getRawValue.defer(100,this);
42171 var value=this.getEditor().GetData();
42172 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
42173 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42177 setSize : function(w,h) {
42181 //if (this.frame && this.frame.dom.style.display == 'none') {
42182 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42185 //if(!this.el || !this.getEditor()) {
42186 // this.setSize.defer(100,this, [w,h]);
42192 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42194 this.frame.dom.setAttribute('width', w);
42195 this.frame.dom.setAttribute('height', h);
42196 this.frame.setSize(w,h);
42200 toggleSourceEdit : function(value) {
42204 this.el.dom.style.display = value ? '' : 'none';
42205 this.frame.dom.style.display = value ? 'none' : '';
42210 focus: function(tag)
42212 if (this.frame.dom.style.display == 'none') {
42213 return Roo.form.FCKeditor.superclass.focus.call(this);
42215 if(!this.el || !this.getEditor()) {
42216 this.focus.defer(100,this, [tag]);
42223 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
42224 this.getEditor().Focus();
42226 if (!this.getEditor().Selection.GetSelection()) {
42227 this.focus.defer(100,this, [tag]);
42232 var r = this.getEditor().EditorDocument.createRange();
42233 r.setStart(tgs[0],0);
42234 r.setEnd(tgs[0],0);
42235 this.getEditor().Selection.GetSelection().removeAllRanges();
42236 this.getEditor().Selection.GetSelection().addRange(r);
42237 this.getEditor().Focus();
42244 replaceTextarea : function()
42246 if ( document.getElementById( this.getId() + '___Frame' ) )
42248 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
42250 // We must check the elements firstly using the Id and then the name.
42251 var oTextarea = document.getElementById( this.getId() );
42253 var colElementsByName = document.getElementsByName( this.getId() ) ;
42255 oTextarea.style.display = 'none' ;
42257 if ( oTextarea.tabIndex ) {
42258 this.TabIndex = oTextarea.tabIndex ;
42261 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
42262 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
42263 this.frame = Roo.get(this.getId() + '___Frame')
42266 _getConfigHtml : function()
42270 for ( var o in this.fckconfig ) {
42271 sConfig += sConfig.length > 0 ? '&' : '';
42272 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
42275 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
42279 _getIFrameHtml : function()
42281 var sFile = 'fckeditor.html' ;
42282 /* no idea what this is about..
42285 if ( (/fcksource=true/i).test( window.top.location.search ) )
42286 sFile = 'fckeditor.original.html' ;
42291 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
42292 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
42295 var html = '<iframe id="' + this.getId() +
42296 '___Frame" src="' + sLink +
42297 '" width="' + this.width +
42298 '" height="' + this.height + '"' +
42299 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
42300 ' frameborder="0" scrolling="no"></iframe>' ;
42305 _insertHtmlBefore : function( html, element )
42307 if ( element.insertAdjacentHTML ) {
42309 element.insertAdjacentHTML( 'beforeBegin', html ) ;
42311 var oRange = document.createRange() ;
42312 oRange.setStartBefore( element ) ;
42313 var oFragment = oRange.createContextualFragment( html );
42314 element.parentNode.insertBefore( oFragment, element ) ;
42327 //Roo.reg('fckeditor', Roo.form.FCKeditor);
42329 function FCKeditor_OnComplete(editorInstance){
42330 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
42331 f.fckEditor = editorInstance;
42332 //console.log("loaded");
42333 f.fireEvent('editorinit', f, editorInstance);
42353 //<script type="text/javascript">
42355 * @class Roo.form.GridField
42356 * @extends Roo.form.Field
42357 * Embed a grid (or editable grid into a form)
42360 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
42362 * xgrid.store = Roo.data.Store
42363 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
42364 * xgrid.store.reader = Roo.data.JsonReader
42368 * Creates a new GridField
42369 * @param {Object} config Configuration options
42371 Roo.form.GridField = function(config){
42372 Roo.form.GridField.superclass.constructor.call(this, config);
42376 Roo.extend(Roo.form.GridField, Roo.form.Field, {
42378 * @cfg {Number} width - used to restrict width of grid..
42382 * @cfg {Number} height - used to restrict height of grid..
42386 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
42392 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42393 * {tag: "input", type: "checkbox", autocomplete: "off"})
42395 // defaultAutoCreate : { tag: 'div' },
42396 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42398 * @cfg {String} addTitle Text to include for adding a title.
42402 onResize : function(){
42403 Roo.form.Field.superclass.onResize.apply(this, arguments);
42406 initEvents : function(){
42407 // Roo.form.Checkbox.superclass.initEvents.call(this);
42408 // has no events...
42413 getResizeEl : function(){
42417 getPositionEl : function(){
42422 onRender : function(ct, position){
42424 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
42425 var style = this.style;
42428 Roo.form.GridField.superclass.onRender.call(this, ct, position);
42429 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
42430 this.viewEl = this.wrap.createChild({ tag: 'div' });
42432 this.viewEl.applyStyles(style);
42435 this.viewEl.setWidth(this.width);
42438 this.viewEl.setHeight(this.height);
42440 //if(this.inputValue !== undefined){
42441 //this.setValue(this.value);
42444 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
42447 this.grid.render();
42448 this.grid.getDataSource().on('remove', this.refreshValue, this);
42449 this.grid.getDataSource().on('update', this.refreshValue, this);
42450 this.grid.on('afteredit', this.refreshValue, this);
42456 * Sets the value of the item.
42457 * @param {String} either an object or a string..
42459 setValue : function(v){
42461 v = v || []; // empty set..
42462 // this does not seem smart - it really only affects memoryproxy grids..
42463 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
42464 var ds = this.grid.getDataSource();
42465 // assumes a json reader..
42467 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
42468 ds.loadData( data);
42470 Roo.form.GridField.superclass.setValue.call(this, v);
42471 this.refreshValue();
42472 // should load data in the grid really....
42476 refreshValue: function() {
42478 this.grid.getDataSource().each(function(r) {
42481 this.el.dom.value = Roo.encode(val);
42489 * Ext JS Library 1.1.1
42490 * Copyright(c) 2006-2007, Ext JS, LLC.
42492 * Originally Released Under LGPL - original licence link has changed is not relivant.
42495 * <script type="text/javascript">
42498 * @class Roo.form.DisplayField
42499 * @extends Roo.form.Field
42500 * A generic Field to display non-editable data.
42502 * Creates a new Display Field item.
42503 * @param {Object} config Configuration options
42505 Roo.form.DisplayField = function(config){
42506 Roo.form.DisplayField.superclass.constructor.call(this, config);
42510 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
42511 inputType: 'hidden',
42517 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42519 focusClass : undefined,
42521 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42523 fieldClass: 'x-form-field',
42526 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
42528 valueRenderer: undefined,
42532 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42533 * {tag: "input", type: "checkbox", autocomplete: "off"})
42536 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42538 onResize : function(){
42539 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
42543 initEvents : function(){
42544 // Roo.form.Checkbox.superclass.initEvents.call(this);
42545 // has no events...
42550 getResizeEl : function(){
42554 getPositionEl : function(){
42559 onRender : function(ct, position){
42561 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
42562 //if(this.inputValue !== undefined){
42563 this.wrap = this.el.wrap();
42565 this.viewEl = this.wrap.createChild({ tag: 'div'});
42567 if (this.bodyStyle) {
42568 this.viewEl.applyStyles(this.bodyStyle);
42570 //this.viewEl.setStyle('padding', '2px');
42572 this.setValue(this.value);
42577 initValue : Roo.emptyFn,
42582 onClick : function(){
42587 * Sets the checked state of the checkbox.
42588 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
42590 setValue : function(v){
42592 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
42593 // this might be called before we have a dom element..
42594 if (!this.viewEl) {
42597 this.viewEl.dom.innerHTML = html;
42598 Roo.form.DisplayField.superclass.setValue.call(this, v);
42601 });//<script type="text/javasscript">
42605 * @class Roo.DDView
42606 * A DnD enabled version of Roo.View.
42607 * @param {Element/String} container The Element in which to create the View.
42608 * @param {String} tpl The template string used to create the markup for each element of the View
42609 * @param {Object} config The configuration properties. These include all the config options of
42610 * {@link Roo.View} plus some specific to this class.<br>
42612 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
42613 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
42615 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
42616 .x-view-drag-insert-above {
42617 border-top:1px dotted #3366cc;
42619 .x-view-drag-insert-below {
42620 border-bottom:1px dotted #3366cc;
42626 Roo.DDView = function(container, tpl, config) {
42627 Roo.DDView.superclass.constructor.apply(this, arguments);
42628 this.getEl().setStyle("outline", "0px none");
42629 this.getEl().unselectable();
42630 if (this.dragGroup) {
42631 this.setDraggable(this.dragGroup.split(","));
42633 if (this.dropGroup) {
42634 this.setDroppable(this.dropGroup.split(","));
42636 if (this.deletable) {
42637 this.setDeletable();
42639 this.isDirtyFlag = false;
42645 Roo.extend(Roo.DDView, Roo.View, {
42646 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
42647 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
42648 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
42649 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
42653 reset: Roo.emptyFn,
42655 clearInvalid: Roo.form.Field.prototype.clearInvalid,
42657 validate: function() {
42661 destroy: function() {
42662 this.purgeListeners();
42663 this.getEl.removeAllListeners();
42664 this.getEl().remove();
42665 if (this.dragZone) {
42666 if (this.dragZone.destroy) {
42667 this.dragZone.destroy();
42670 if (this.dropZone) {
42671 if (this.dropZone.destroy) {
42672 this.dropZone.destroy();
42677 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
42678 getName: function() {
42682 /** Loads the View from a JSON string representing the Records to put into the Store. */
42683 setValue: function(v) {
42685 throw "DDView.setValue(). DDView must be constructed with a valid Store";
42688 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
42689 this.store.proxy = new Roo.data.MemoryProxy(data);
42693 /** @return {String} a parenthesised list of the ids of the Records in the View. */
42694 getValue: function() {
42696 this.store.each(function(rec) {
42697 result += rec.id + ',';
42699 return result.substr(0, result.length - 1) + ')';
42702 getIds: function() {
42703 var i = 0, result = new Array(this.store.getCount());
42704 this.store.each(function(rec) {
42705 result[i++] = rec.id;
42710 isDirty: function() {
42711 return this.isDirtyFlag;
42715 * Part of the Roo.dd.DropZone interface. If no target node is found, the
42716 * whole Element becomes the target, and this causes the drop gesture to append.
42718 getTargetFromEvent : function(e) {
42719 var target = e.getTarget();
42720 while ((target !== null) && (target.parentNode != this.el.dom)) {
42721 target = target.parentNode;
42724 target = this.el.dom.lastChild || this.el.dom;
42730 * Create the drag data which consists of an object which has the property "ddel" as
42731 * the drag proxy element.
42733 getDragData : function(e) {
42734 var target = this.findItemFromChild(e.getTarget());
42736 this.handleSelection(e);
42737 var selNodes = this.getSelectedNodes();
42740 copy: this.copy || (this.allowCopy && e.ctrlKey),
42744 var selectedIndices = this.getSelectedIndexes();
42745 for (var i = 0; i < selectedIndices.length; i++) {
42746 dragData.records.push(this.store.getAt(selectedIndices[i]));
42748 if (selNodes.length == 1) {
42749 dragData.ddel = target.cloneNode(true); // the div element
42751 var div = document.createElement('div'); // create the multi element drag "ghost"
42752 div.className = 'multi-proxy';
42753 for (var i = 0, len = selNodes.length; i < len; i++) {
42754 div.appendChild(selNodes[i].cloneNode(true));
42756 dragData.ddel = div;
42758 //console.log(dragData)
42759 //console.log(dragData.ddel.innerHTML)
42762 //console.log('nodragData')
42766 /** Specify to which ddGroup items in this DDView may be dragged. */
42767 setDraggable: function(ddGroup) {
42768 if (ddGroup instanceof Array) {
42769 Roo.each(ddGroup, this.setDraggable, this);
42772 if (this.dragZone) {
42773 this.dragZone.addToGroup(ddGroup);
42775 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
42776 containerScroll: true,
42780 // Draggability implies selection. DragZone's mousedown selects the element.
42781 if (!this.multiSelect) { this.singleSelect = true; }
42783 // Wire the DragZone's handlers up to methods in *this*
42784 this.dragZone.getDragData = this.getDragData.createDelegate(this);
42788 /** Specify from which ddGroup this DDView accepts drops. */
42789 setDroppable: function(ddGroup) {
42790 if (ddGroup instanceof Array) {
42791 Roo.each(ddGroup, this.setDroppable, this);
42794 if (this.dropZone) {
42795 this.dropZone.addToGroup(ddGroup);
42797 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
42798 containerScroll: true,
42802 // Wire the DropZone's handlers up to methods in *this*
42803 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
42804 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
42805 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
42806 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
42807 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
42811 /** Decide whether to drop above or below a View node. */
42812 getDropPoint : function(e, n, dd){
42813 if (n == this.el.dom) { return "above"; }
42814 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
42815 var c = t + (b - t) / 2;
42816 var y = Roo.lib.Event.getPageY(e);
42824 onNodeEnter : function(n, dd, e, data){
42828 onNodeOver : function(n, dd, e, data){
42829 var pt = this.getDropPoint(e, n, dd);
42830 // set the insert point style on the target node
42831 var dragElClass = this.dropNotAllowed;
42834 if (pt == "above"){
42835 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
42836 targetElClass = "x-view-drag-insert-above";
42838 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
42839 targetElClass = "x-view-drag-insert-below";
42841 if (this.lastInsertClass != targetElClass){
42842 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
42843 this.lastInsertClass = targetElClass;
42846 return dragElClass;
42849 onNodeOut : function(n, dd, e, data){
42850 this.removeDropIndicators(n);
42853 onNodeDrop : function(n, dd, e, data){
42854 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
42857 var pt = this.getDropPoint(e, n, dd);
42858 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
42859 if (pt == "below") { insertAt++; }
42860 for (var i = 0; i < data.records.length; i++) {
42861 var r = data.records[i];
42862 var dup = this.store.getById(r.id);
42863 if (dup && (dd != this.dragZone)) {
42864 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
42867 this.store.insert(insertAt++, r.copy());
42869 data.source.isDirtyFlag = true;
42871 this.store.insert(insertAt++, r);
42873 this.isDirtyFlag = true;
42876 this.dragZone.cachedTarget = null;
42880 removeDropIndicators : function(n){
42882 Roo.fly(n).removeClass([
42883 "x-view-drag-insert-above",
42884 "x-view-drag-insert-below"]);
42885 this.lastInsertClass = "_noclass";
42890 * Utility method. Add a delete option to the DDView's context menu.
42891 * @param {String} imageUrl The URL of the "delete" icon image.
42893 setDeletable: function(imageUrl) {
42894 if (!this.singleSelect && !this.multiSelect) {
42895 this.singleSelect = true;
42897 var c = this.getContextMenu();
42898 this.contextMenu.on("itemclick", function(item) {
42901 this.remove(this.getSelectedIndexes());
42905 this.contextMenu.add({
42912 /** Return the context menu for this DDView. */
42913 getContextMenu: function() {
42914 if (!this.contextMenu) {
42915 // Create the View's context menu
42916 this.contextMenu = new Roo.menu.Menu({
42917 id: this.id + "-contextmenu"
42919 this.el.on("contextmenu", this.showContextMenu, this);
42921 return this.contextMenu;
42924 disableContextMenu: function() {
42925 if (this.contextMenu) {
42926 this.el.un("contextmenu", this.showContextMenu, this);
42930 showContextMenu: function(e, item) {
42931 item = this.findItemFromChild(e.getTarget());
42934 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
42935 this.contextMenu.showAt(e.getXY());
42940 * Remove {@link Roo.data.Record}s at the specified indices.
42941 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
42943 remove: function(selectedIndices) {
42944 selectedIndices = [].concat(selectedIndices);
42945 for (var i = 0; i < selectedIndices.length; i++) {
42946 var rec = this.store.getAt(selectedIndices[i]);
42947 this.store.remove(rec);
42952 * Double click fires the event, but also, if this is draggable, and there is only one other
42953 * related DropZone, it transfers the selected node.
42955 onDblClick : function(e){
42956 var item = this.findItemFromChild(e.getTarget());
42958 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
42961 if (this.dragGroup) {
42962 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
42963 while (targets.indexOf(this.dropZone) > -1) {
42964 targets.remove(this.dropZone);
42966 if (targets.length == 1) {
42967 this.dragZone.cachedTarget = null;
42968 var el = Roo.get(targets[0].getEl());
42969 var box = el.getBox(true);
42970 targets[0].onNodeDrop(el.dom, {
42972 xy: [box.x, box.y + box.height - 1]
42973 }, null, this.getDragData(e));
42979 handleSelection: function(e) {
42980 this.dragZone.cachedTarget = null;
42981 var item = this.findItemFromChild(e.getTarget());
42983 this.clearSelections(true);
42986 if (item && (this.multiSelect || this.singleSelect)){
42987 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
42988 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
42989 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
42990 this.unselect(item);
42992 this.select(item, this.multiSelect && e.ctrlKey);
42993 this.lastSelection = item;
42998 onItemClick : function(item, index, e){
42999 if(this.fireEvent("beforeclick", this, index, item, e) === false){
43005 unselect : function(nodeInfo, suppressEvent){
43006 var node = this.getNode(nodeInfo);
43007 if(node && this.isSelected(node)){
43008 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
43009 Roo.fly(node).removeClass(this.selectedClass);
43010 this.selections.remove(node);
43011 if(!suppressEvent){
43012 this.fireEvent("selectionchange", this, this.selections);
43020 * Ext JS Library 1.1.1
43021 * Copyright(c) 2006-2007, Ext JS, LLC.
43023 * Originally Released Under LGPL - original licence link has changed is not relivant.
43026 * <script type="text/javascript">
43030 * @class Roo.LayoutManager
43031 * @extends Roo.util.Observable
43032 * Base class for layout managers.
43034 Roo.LayoutManager = function(container, config){
43035 Roo.LayoutManager.superclass.constructor.call(this);
43036 this.el = Roo.get(container);
43037 // ie scrollbar fix
43038 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
43039 document.body.scroll = "no";
43040 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
43041 this.el.position('relative');
43043 this.id = this.el.id;
43044 this.el.addClass("x-layout-container");
43045 /** false to disable window resize monitoring @type Boolean */
43046 this.monitorWindowResize = true;
43051 * Fires when a layout is performed.
43052 * @param {Roo.LayoutManager} this
43056 * @event regionresized
43057 * Fires when the user resizes a region.
43058 * @param {Roo.LayoutRegion} region The resized region
43059 * @param {Number} newSize The new size (width for east/west, height for north/south)
43061 "regionresized" : true,
43063 * @event regioncollapsed
43064 * Fires when a region is collapsed.
43065 * @param {Roo.LayoutRegion} region The collapsed region
43067 "regioncollapsed" : true,
43069 * @event regionexpanded
43070 * Fires when a region is expanded.
43071 * @param {Roo.LayoutRegion} region The expanded region
43073 "regionexpanded" : true
43075 this.updating = false;
43076 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
43079 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
43081 * Returns true if this layout is currently being updated
43082 * @return {Boolean}
43084 isUpdating : function(){
43085 return this.updating;
43089 * Suspend the LayoutManager from doing auto-layouts while
43090 * making multiple add or remove calls
43092 beginUpdate : function(){
43093 this.updating = true;
43097 * Restore auto-layouts and optionally disable the manager from performing a layout
43098 * @param {Boolean} noLayout true to disable a layout update
43100 endUpdate : function(noLayout){
43101 this.updating = false;
43107 layout: function(){
43111 onRegionResized : function(region, newSize){
43112 this.fireEvent("regionresized", region, newSize);
43116 onRegionCollapsed : function(region){
43117 this.fireEvent("regioncollapsed", region);
43120 onRegionExpanded : function(region){
43121 this.fireEvent("regionexpanded", region);
43125 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
43126 * performs box-model adjustments.
43127 * @return {Object} The size as an object {width: (the width), height: (the height)}
43129 getViewSize : function(){
43131 if(this.el.dom != document.body){
43132 size = this.el.getSize();
43134 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
43136 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
43137 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
43142 * Returns the Element this layout is bound to.
43143 * @return {Roo.Element}
43145 getEl : function(){
43150 * Returns the specified region.
43151 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
43152 * @return {Roo.LayoutRegion}
43154 getRegion : function(target){
43155 return this.regions[target.toLowerCase()];
43158 onWindowResize : function(){
43159 if(this.monitorWindowResize){
43165 * Ext JS Library 1.1.1
43166 * Copyright(c) 2006-2007, Ext JS, LLC.
43168 * Originally Released Under LGPL - original licence link has changed is not relivant.
43171 * <script type="text/javascript">
43174 * @class Roo.BorderLayout
43175 * @extends Roo.LayoutManager
43176 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
43177 * please see: <br><br>
43178 * <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>
43179 * <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>
43182 var layout = new Roo.BorderLayout(document.body, {
43216 preferredTabWidth: 150
43221 var CP = Roo.ContentPanel;
43223 layout.beginUpdate();
43224 layout.add("north", new CP("north", "North"));
43225 layout.add("south", new CP("south", {title: "South", closable: true}));
43226 layout.add("west", new CP("west", {title: "West"}));
43227 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
43228 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
43229 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
43230 layout.getRegion("center").showPanel("center1");
43231 layout.endUpdate();
43234 <b>The container the layout is rendered into can be either the body element or any other element.
43235 If it is not the body element, the container needs to either be an absolute positioned element,
43236 or you will need to add "position:relative" to the css of the container. You will also need to specify
43237 the container size if it is not the body element.</b>
43240 * Create a new BorderLayout
43241 * @param {String/HTMLElement/Element} container The container this layout is bound to
43242 * @param {Object} config Configuration options
43244 Roo.BorderLayout = function(container, config){
43245 config = config || {};
43246 Roo.BorderLayout.superclass.constructor.call(this, container, config);
43247 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
43248 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
43249 var target = this.factory.validRegions[i];
43250 if(config[target]){
43251 this.addRegion(target, config[target]);
43256 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
43258 * Creates and adds a new region if it doesn't already exist.
43259 * @param {String} target The target region key (north, south, east, west or center).
43260 * @param {Object} config The regions config object
43261 * @return {BorderLayoutRegion} The new region
43263 addRegion : function(target, config){
43264 if(!this.regions[target]){
43265 var r = this.factory.create(target, this, config);
43266 this.bindRegion(target, r);
43268 return this.regions[target];
43272 bindRegion : function(name, r){
43273 this.regions[name] = r;
43274 r.on("visibilitychange", this.layout, this);
43275 r.on("paneladded", this.layout, this);
43276 r.on("panelremoved", this.layout, this);
43277 r.on("invalidated", this.layout, this);
43278 r.on("resized", this.onRegionResized, this);
43279 r.on("collapsed", this.onRegionCollapsed, this);
43280 r.on("expanded", this.onRegionExpanded, this);
43284 * Performs a layout update.
43286 layout : function(){
43287 if(this.updating) return;
43288 var size = this.getViewSize();
43289 var w = size.width;
43290 var h = size.height;
43295 //var x = 0, y = 0;
43297 var rs = this.regions;
43298 var north = rs["north"];
43299 var south = rs["south"];
43300 var west = rs["west"];
43301 var east = rs["east"];
43302 var center = rs["center"];
43303 //if(this.hideOnLayout){ // not supported anymore
43304 //c.el.setStyle("display", "none");
43306 if(north && north.isVisible()){
43307 var b = north.getBox();
43308 var m = north.getMargins();
43309 b.width = w - (m.left+m.right);
43312 centerY = b.height + b.y + m.bottom;
43313 centerH -= centerY;
43314 north.updateBox(this.safeBox(b));
43316 if(south && south.isVisible()){
43317 var b = south.getBox();
43318 var m = south.getMargins();
43319 b.width = w - (m.left+m.right);
43321 var totalHeight = (b.height + m.top + m.bottom);
43322 b.y = h - totalHeight + m.top;
43323 centerH -= totalHeight;
43324 south.updateBox(this.safeBox(b));
43326 if(west && west.isVisible()){
43327 var b = west.getBox();
43328 var m = west.getMargins();
43329 b.height = centerH - (m.top+m.bottom);
43331 b.y = centerY + m.top;
43332 var totalWidth = (b.width + m.left + m.right);
43333 centerX += totalWidth;
43334 centerW -= totalWidth;
43335 west.updateBox(this.safeBox(b));
43337 if(east && east.isVisible()){
43338 var b = east.getBox();
43339 var m = east.getMargins();
43340 b.height = centerH - (m.top+m.bottom);
43341 var totalWidth = (b.width + m.left + m.right);
43342 b.x = w - totalWidth + m.left;
43343 b.y = centerY + m.top;
43344 centerW -= totalWidth;
43345 east.updateBox(this.safeBox(b));
43348 var m = center.getMargins();
43350 x: centerX + m.left,
43351 y: centerY + m.top,
43352 width: centerW - (m.left+m.right),
43353 height: centerH - (m.top+m.bottom)
43355 //if(this.hideOnLayout){
43356 //center.el.setStyle("display", "block");
43358 center.updateBox(this.safeBox(centerBox));
43361 this.fireEvent("layout", this);
43365 safeBox : function(box){
43366 box.width = Math.max(0, box.width);
43367 box.height = Math.max(0, box.height);
43372 * Adds a ContentPanel (or subclass) to this layout.
43373 * @param {String} target The target region key (north, south, east, west or center).
43374 * @param {Roo.ContentPanel} panel The panel to add
43375 * @return {Roo.ContentPanel} The added panel
43377 add : function(target, panel){
43379 target = target.toLowerCase();
43380 return this.regions[target].add(panel);
43384 * Remove a ContentPanel (or subclass) to this layout.
43385 * @param {String} target The target region key (north, south, east, west or center).
43386 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
43387 * @return {Roo.ContentPanel} The removed panel
43389 remove : function(target, panel){
43390 target = target.toLowerCase();
43391 return this.regions[target].remove(panel);
43395 * Searches all regions for a panel with the specified id
43396 * @param {String} panelId
43397 * @return {Roo.ContentPanel} The panel or null if it wasn't found
43399 findPanel : function(panelId){
43400 var rs = this.regions;
43401 for(var target in rs){
43402 if(typeof rs[target] != "function"){
43403 var p = rs[target].getPanel(panelId);
43413 * Searches all regions for a panel with the specified id and activates (shows) it.
43414 * @param {String/ContentPanel} panelId The panels id or the panel itself
43415 * @return {Roo.ContentPanel} The shown panel or null
43417 showPanel : function(panelId) {
43418 var rs = this.regions;
43419 for(var target in rs){
43420 var r = rs[target];
43421 if(typeof r != "function"){
43422 if(r.hasPanel(panelId)){
43423 return r.showPanel(panelId);
43431 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
43432 * @param {Roo.state.Provider} provider (optional) An alternate state provider
43434 restoreState : function(provider){
43436 provider = Roo.state.Manager;
43438 var sm = new Roo.LayoutStateManager();
43439 sm.init(this, provider);
43443 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
43444 * object should contain properties for each region to add ContentPanels to, and each property's value should be
43445 * a valid ContentPanel config object. Example:
43447 // Create the main layout
43448 var layout = new Roo.BorderLayout('main-ct', {
43459 // Create and add multiple ContentPanels at once via configs
43462 id: 'source-files',
43464 title:'Ext Source Files',
43477 * @param {Object} regions An object containing ContentPanel configs by region name
43479 batchAdd : function(regions){
43480 this.beginUpdate();
43481 for(var rname in regions){
43482 var lr = this.regions[rname];
43484 this.addTypedPanels(lr, regions[rname]);
43491 addTypedPanels : function(lr, ps){
43492 if(typeof ps == 'string'){
43493 lr.add(new Roo.ContentPanel(ps));
43495 else if(ps instanceof Array){
43496 for(var i =0, len = ps.length; i < len; i++){
43497 this.addTypedPanels(lr, ps[i]);
43500 else if(!ps.events){ // raw config?
43502 delete ps.el; // prevent conflict
43503 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
43505 else { // panel object assumed!
43510 * Adds a xtype elements to the layout.
43514 xtype : 'ContentPanel',
43521 xtype : 'NestedLayoutPanel',
43527 items : [ ... list of content panels or nested layout panels.. ]
43531 * @param {Object} cfg Xtype definition of item to add.
43533 addxtype : function(cfg)
43535 // basically accepts a pannel...
43536 // can accept a layout region..!?!?
43537 // console.log('BorderLayout add ' + cfg.xtype)
43539 if (!cfg.xtype.match(/Panel$/)) {
43543 var region = cfg.region;
43549 xitems = cfg.items;
43556 case 'ContentPanel': // ContentPanel (el, cfg)
43557 case 'ScrollPanel': // ContentPanel (el, cfg)
43558 if(cfg.autoCreate) {
43559 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43561 var el = this.el.createChild();
43562 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
43565 this.add(region, ret);
43569 case 'TreePanel': // our new panel!
43570 cfg.el = this.el.createChild();
43571 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43572 this.add(region, ret);
43575 case 'NestedLayoutPanel':
43576 // create a new Layout (which is a Border Layout...
43577 var el = this.el.createChild();
43578 var clayout = cfg.layout;
43580 clayout.items = clayout.items || [];
43581 // replace this exitems with the clayout ones..
43582 xitems = clayout.items;
43585 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
43586 cfg.background = false;
43588 var layout = new Roo.BorderLayout(el, clayout);
43590 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
43591 //console.log('adding nested layout panel ' + cfg.toSource());
43592 this.add(region, ret);
43598 // needs grid and region
43600 //var el = this.getRegion(region).el.createChild();
43601 var el = this.el.createChild();
43602 // create the grid first...
43604 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
43606 if (region == 'center' && this.active ) {
43607 cfg.background = false;
43609 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
43611 this.add(region, ret);
43612 if (cfg.background) {
43613 ret.on('activate', function(gp) {
43614 if (!gp.grid.rendered) {
43627 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
43629 // GridPanel (grid, cfg)
43632 this.beginUpdate();
43634 Roo.each(xitems, function(i) {
43644 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
43645 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
43646 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
43647 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
43650 var CP = Roo.ContentPanel;
43652 var layout = Roo.BorderLayout.create({
43656 panels: [new CP("north", "North")]
43665 panels: [new CP("west", {title: "West"})]
43674 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
43683 panels: [new CP("south", {title: "South", closable: true})]
43690 preferredTabWidth: 150,
43692 new CP("center1", {title: "Close Me", closable: true}),
43693 new CP("center2", {title: "Center Panel", closable: false})
43698 layout.getRegion("center").showPanel("center1");
43703 Roo.BorderLayout.create = function(config, targetEl){
43704 var layout = new Roo.BorderLayout(targetEl || document.body, config);
43705 layout.beginUpdate();
43706 var regions = Roo.BorderLayout.RegionFactory.validRegions;
43707 for(var j = 0, jlen = regions.length; j < jlen; j++){
43708 var lr = regions[j];
43709 if(layout.regions[lr] && config[lr].panels){
43710 var r = layout.regions[lr];
43711 var ps = config[lr].panels;
43712 layout.addTypedPanels(r, ps);
43715 layout.endUpdate();
43720 Roo.BorderLayout.RegionFactory = {
43722 validRegions : ["north","south","east","west","center"],
43725 create : function(target, mgr, config){
43726 target = target.toLowerCase();
43727 if(config.lightweight || config.basic){
43728 return new Roo.BasicLayoutRegion(mgr, config, target);
43732 return new Roo.NorthLayoutRegion(mgr, config);
43734 return new Roo.SouthLayoutRegion(mgr, config);
43736 return new Roo.EastLayoutRegion(mgr, config);
43738 return new Roo.WestLayoutRegion(mgr, config);
43740 return new Roo.CenterLayoutRegion(mgr, config);
43742 throw 'Layout region "'+target+'" not supported.';
43746 * Ext JS Library 1.1.1
43747 * Copyright(c) 2006-2007, Ext JS, LLC.
43749 * Originally Released Under LGPL - original licence link has changed is not relivant.
43752 * <script type="text/javascript">
43756 * @class Roo.BasicLayoutRegion
43757 * @extends Roo.util.Observable
43758 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
43759 * and does not have a titlebar, tabs or any other features. All it does is size and position
43760 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
43762 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
43764 this.position = pos;
43767 * @scope Roo.BasicLayoutRegion
43771 * @event beforeremove
43772 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
43773 * @param {Roo.LayoutRegion} this
43774 * @param {Roo.ContentPanel} panel The panel
43775 * @param {Object} e The cancel event object
43777 "beforeremove" : true,
43779 * @event invalidated
43780 * Fires when the layout for this region is changed.
43781 * @param {Roo.LayoutRegion} this
43783 "invalidated" : true,
43785 * @event visibilitychange
43786 * Fires when this region is shown or hidden
43787 * @param {Roo.LayoutRegion} this
43788 * @param {Boolean} visibility true or false
43790 "visibilitychange" : true,
43792 * @event paneladded
43793 * Fires when a panel is added.
43794 * @param {Roo.LayoutRegion} this
43795 * @param {Roo.ContentPanel} panel The panel
43797 "paneladded" : true,
43799 * @event panelremoved
43800 * Fires when a panel is removed.
43801 * @param {Roo.LayoutRegion} this
43802 * @param {Roo.ContentPanel} panel The panel
43804 "panelremoved" : true,
43807 * Fires when this region is collapsed.
43808 * @param {Roo.LayoutRegion} this
43810 "collapsed" : true,
43813 * Fires when this region is expanded.
43814 * @param {Roo.LayoutRegion} this
43819 * Fires when this region is slid into view.
43820 * @param {Roo.LayoutRegion} this
43822 "slideshow" : true,
43825 * Fires when this region slides out of view.
43826 * @param {Roo.LayoutRegion} this
43828 "slidehide" : true,
43830 * @event panelactivated
43831 * Fires when a panel is activated.
43832 * @param {Roo.LayoutRegion} this
43833 * @param {Roo.ContentPanel} panel The activated panel
43835 "panelactivated" : true,
43838 * Fires when the user resizes this region.
43839 * @param {Roo.LayoutRegion} this
43840 * @param {Number} newSize The new size (width for east/west, height for north/south)
43844 /** A collection of panels in this region. @type Roo.util.MixedCollection */
43845 this.panels = new Roo.util.MixedCollection();
43846 this.panels.getKey = this.getPanelId.createDelegate(this);
43848 this.activePanel = null;
43849 // ensure listeners are added...
43851 if (config.listeners || config.events) {
43852 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
43853 listeners : config.listeners || {},
43854 events : config.events || {}
43858 if(skipConfig !== true){
43859 this.applyConfig(config);
43863 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
43864 getPanelId : function(p){
43868 applyConfig : function(config){
43869 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43870 this.config = config;
43875 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
43876 * the width, for horizontal (north, south) the height.
43877 * @param {Number} newSize The new width or height
43879 resizeTo : function(newSize){
43880 var el = this.el ? this.el :
43881 (this.activePanel ? this.activePanel.getEl() : null);
43883 switch(this.position){
43886 el.setWidth(newSize);
43887 this.fireEvent("resized", this, newSize);
43891 el.setHeight(newSize);
43892 this.fireEvent("resized", this, newSize);
43898 getBox : function(){
43899 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
43902 getMargins : function(){
43903 return this.margins;
43906 updateBox : function(box){
43908 var el = this.activePanel.getEl();
43909 el.dom.style.left = box.x + "px";
43910 el.dom.style.top = box.y + "px";
43911 this.activePanel.setSize(box.width, box.height);
43915 * Returns the container element for this region.
43916 * @return {Roo.Element}
43918 getEl : function(){
43919 return this.activePanel;
43923 * Returns true if this region is currently visible.
43924 * @return {Boolean}
43926 isVisible : function(){
43927 return this.activePanel ? true : false;
43930 setActivePanel : function(panel){
43931 panel = this.getPanel(panel);
43932 if(this.activePanel && this.activePanel != panel){
43933 this.activePanel.setActiveState(false);
43934 this.activePanel.getEl().setLeftTop(-10000,-10000);
43936 this.activePanel = panel;
43937 panel.setActiveState(true);
43939 panel.setSize(this.box.width, this.box.height);
43941 this.fireEvent("panelactivated", this, panel);
43942 this.fireEvent("invalidated");
43946 * Show the specified panel.
43947 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
43948 * @return {Roo.ContentPanel} The shown panel or null
43950 showPanel : function(panel){
43951 if(panel = this.getPanel(panel)){
43952 this.setActivePanel(panel);
43958 * Get the active panel for this region.
43959 * @return {Roo.ContentPanel} The active panel or null
43961 getActivePanel : function(){
43962 return this.activePanel;
43966 * Add the passed ContentPanel(s)
43967 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43968 * @return {Roo.ContentPanel} The panel added (if only one was added)
43970 add : function(panel){
43971 if(arguments.length > 1){
43972 for(var i = 0, len = arguments.length; i < len; i++) {
43973 this.add(arguments[i]);
43977 if(this.hasPanel(panel)){
43978 this.showPanel(panel);
43981 var el = panel.getEl();
43982 if(el.dom.parentNode != this.mgr.el.dom){
43983 this.mgr.el.dom.appendChild(el.dom);
43985 if(panel.setRegion){
43986 panel.setRegion(this);
43988 this.panels.add(panel);
43989 el.setStyle("position", "absolute");
43990 if(!panel.background){
43991 this.setActivePanel(panel);
43992 if(this.config.initialSize && this.panels.getCount()==1){
43993 this.resizeTo(this.config.initialSize);
43996 this.fireEvent("paneladded", this, panel);
44001 * Returns true if the panel is in this region.
44002 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44003 * @return {Boolean}
44005 hasPanel : function(panel){
44006 if(typeof panel == "object"){ // must be panel obj
44007 panel = panel.getId();
44009 return this.getPanel(panel) ? true : false;
44013 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44014 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44015 * @param {Boolean} preservePanel Overrides the config preservePanel option
44016 * @return {Roo.ContentPanel} The panel that was removed
44018 remove : function(panel, preservePanel){
44019 panel = this.getPanel(panel);
44024 this.fireEvent("beforeremove", this, panel, e);
44025 if(e.cancel === true){
44028 var panelId = panel.getId();
44029 this.panels.removeKey(panelId);
44034 * Returns the panel specified or null if it's not in this region.
44035 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44036 * @return {Roo.ContentPanel}
44038 getPanel : function(id){
44039 if(typeof id == "object"){ // must be panel obj
44042 return this.panels.get(id);
44046 * Returns this regions position (north/south/east/west/center).
44049 getPosition: function(){
44050 return this.position;
44054 * Ext JS Library 1.1.1
44055 * Copyright(c) 2006-2007, Ext JS, LLC.
44057 * Originally Released Under LGPL - original licence link has changed is not relivant.
44060 * <script type="text/javascript">
44064 * @class Roo.LayoutRegion
44065 * @extends Roo.BasicLayoutRegion
44066 * This class represents a region in a layout manager.
44067 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
44068 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
44069 * @cfg {Boolean} floatable False to disable floating (defaults to true)
44070 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
44071 * @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})
44072 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
44073 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
44074 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
44075 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
44076 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
44077 * @cfg {String} title The title for the region (overrides panel titles)
44078 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
44079 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
44080 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
44081 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
44082 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
44083 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
44084 * the space available, similar to FireFox 1.5 tabs (defaults to false)
44085 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
44086 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
44087 * @cfg {Boolean} showPin True to show a pin button
44088 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
44089 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
44090 * @cfg {Boolean} disableTabTips True to disable tab tooltips
44091 * @cfg {Number} width For East/West panels
44092 * @cfg {Number} height For North/South panels
44093 * @cfg {Boolean} split To show the splitter
44095 Roo.LayoutRegion = function(mgr, config, pos){
44096 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
44097 var dh = Roo.DomHelper;
44098 /** This region's container element
44099 * @type Roo.Element */
44100 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
44101 /** This region's title element
44102 * @type Roo.Element */
44104 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
44105 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
44106 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
44108 this.titleEl.enableDisplayMode();
44109 /** This region's title text element
44110 * @type HTMLElement */
44111 this.titleTextEl = this.titleEl.dom.firstChild;
44112 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
44113 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
44114 this.closeBtn.enableDisplayMode();
44115 this.closeBtn.on("click", this.closeClicked, this);
44116 this.closeBtn.hide();
44118 this.createBody(config);
44119 this.visible = true;
44120 this.collapsed = false;
44122 if(config.hideWhenEmpty){
44124 this.on("paneladded", this.validateVisibility, this);
44125 this.on("panelremoved", this.validateVisibility, this);
44127 this.applyConfig(config);
44130 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
44132 createBody : function(){
44133 /** This region's body element
44134 * @type Roo.Element */
44135 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
44138 applyConfig : function(c){
44139 if(c.collapsible && this.position != "center" && !this.collapsedEl){
44140 var dh = Roo.DomHelper;
44141 if(c.titlebar !== false){
44142 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
44143 this.collapseBtn.on("click", this.collapse, this);
44144 this.collapseBtn.enableDisplayMode();
44146 if(c.showPin === true || this.showPin){
44147 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
44148 this.stickBtn.enableDisplayMode();
44149 this.stickBtn.on("click", this.expand, this);
44150 this.stickBtn.hide();
44153 /** This region's collapsed element
44154 * @type Roo.Element */
44155 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
44156 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
44158 if(c.floatable !== false){
44159 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
44160 this.collapsedEl.on("click", this.collapseClick, this);
44163 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
44164 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
44165 id: "message", unselectable: "on", style:{"float":"left"}});
44166 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
44168 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
44169 this.expandBtn.on("click", this.expand, this);
44171 if(this.collapseBtn){
44172 this.collapseBtn.setVisible(c.collapsible == true);
44174 this.cmargins = c.cmargins || this.cmargins ||
44175 (this.position == "west" || this.position == "east" ?
44176 {top: 0, left: 2, right:2, bottom: 0} :
44177 {top: 2, left: 0, right:0, bottom: 2});
44178 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44179 this.bottomTabs = c.tabPosition != "top";
44180 this.autoScroll = c.autoScroll || false;
44181 if(this.autoScroll){
44182 this.bodyEl.setStyle("overflow", "auto");
44184 this.bodyEl.setStyle("overflow", "hidden");
44186 //if(c.titlebar !== false){
44187 if((!c.titlebar && !c.title) || c.titlebar === false){
44188 this.titleEl.hide();
44190 this.titleEl.show();
44192 this.titleTextEl.innerHTML = c.title;
44196 this.duration = c.duration || .30;
44197 this.slideDuration = c.slideDuration || .45;
44200 this.collapse(true);
44207 * Returns true if this region is currently visible.
44208 * @return {Boolean}
44210 isVisible : function(){
44211 return this.visible;
44215 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
44216 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
44218 setCollapsedTitle : function(title){
44219 title = title || " ";
44220 if(this.collapsedTitleTextEl){
44221 this.collapsedTitleTextEl.innerHTML = title;
44225 getBox : function(){
44227 if(!this.collapsed){
44228 b = this.el.getBox(false, true);
44230 b = this.collapsedEl.getBox(false, true);
44235 getMargins : function(){
44236 return this.collapsed ? this.cmargins : this.margins;
44239 highlight : function(){
44240 this.el.addClass("x-layout-panel-dragover");
44243 unhighlight : function(){
44244 this.el.removeClass("x-layout-panel-dragover");
44247 updateBox : function(box){
44249 if(!this.collapsed){
44250 this.el.dom.style.left = box.x + "px";
44251 this.el.dom.style.top = box.y + "px";
44252 this.updateBody(box.width, box.height);
44254 this.collapsedEl.dom.style.left = box.x + "px";
44255 this.collapsedEl.dom.style.top = box.y + "px";
44256 this.collapsedEl.setSize(box.width, box.height);
44259 this.tabs.autoSizeTabs();
44263 updateBody : function(w, h){
44265 this.el.setWidth(w);
44266 w -= this.el.getBorderWidth("rl");
44267 if(this.config.adjustments){
44268 w += this.config.adjustments[0];
44272 this.el.setHeight(h);
44273 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
44274 h -= this.el.getBorderWidth("tb");
44275 if(this.config.adjustments){
44276 h += this.config.adjustments[1];
44278 this.bodyEl.setHeight(h);
44280 h = this.tabs.syncHeight(h);
44283 if(this.panelSize){
44284 w = w !== null ? w : this.panelSize.width;
44285 h = h !== null ? h : this.panelSize.height;
44287 if(this.activePanel){
44288 var el = this.activePanel.getEl();
44289 w = w !== null ? w : el.getWidth();
44290 h = h !== null ? h : el.getHeight();
44291 this.panelSize = {width: w, height: h};
44292 this.activePanel.setSize(w, h);
44294 if(Roo.isIE && this.tabs){
44295 this.tabs.el.repaint();
44300 * Returns the container element for this region.
44301 * @return {Roo.Element}
44303 getEl : function(){
44308 * Hides this region.
44311 if(!this.collapsed){
44312 this.el.dom.style.left = "-2000px";
44315 this.collapsedEl.dom.style.left = "-2000px";
44316 this.collapsedEl.hide();
44318 this.visible = false;
44319 this.fireEvent("visibilitychange", this, false);
44323 * Shows this region if it was previously hidden.
44326 if(!this.collapsed){
44329 this.collapsedEl.show();
44331 this.visible = true;
44332 this.fireEvent("visibilitychange", this, true);
44335 closeClicked : function(){
44336 if(this.activePanel){
44337 this.remove(this.activePanel);
44341 collapseClick : function(e){
44343 e.stopPropagation();
44346 e.stopPropagation();
44352 * Collapses this region.
44353 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
44355 collapse : function(skipAnim){
44356 if(this.collapsed) return;
44357 this.collapsed = true;
44359 this.split.el.hide();
44361 if(this.config.animate && skipAnim !== true){
44362 this.fireEvent("invalidated", this);
44363 this.animateCollapse();
44365 this.el.setLocation(-20000,-20000);
44367 this.collapsedEl.show();
44368 this.fireEvent("collapsed", this);
44369 this.fireEvent("invalidated", this);
44373 animateCollapse : function(){
44378 * Expands this region if it was previously collapsed.
44379 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
44380 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
44382 expand : function(e, skipAnim){
44383 if(e) e.stopPropagation();
44384 if(!this.collapsed || this.el.hasActiveFx()) return;
44386 this.afterSlideIn();
44389 this.collapsed = false;
44390 if(this.config.animate && skipAnim !== true){
44391 this.animateExpand();
44395 this.split.el.show();
44397 this.collapsedEl.setLocation(-2000,-2000);
44398 this.collapsedEl.hide();
44399 this.fireEvent("invalidated", this);
44400 this.fireEvent("expanded", this);
44404 animateExpand : function(){
44408 initTabs : function(){
44409 this.bodyEl.setStyle("overflow", "hidden");
44410 var ts = new Roo.TabPanel(this.bodyEl.dom, {
44411 tabPosition: this.bottomTabs ? 'bottom' : 'top',
44412 disableTooltips: this.config.disableTabTips
44414 if(this.config.hideTabs){
44415 ts.stripWrap.setDisplayed(false);
44418 ts.resizeTabs = this.config.resizeTabs === true;
44419 ts.minTabWidth = this.config.minTabWidth || 40;
44420 ts.maxTabWidth = this.config.maxTabWidth || 250;
44421 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
44422 ts.monitorResize = false;
44423 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44424 ts.bodyEl.addClass('x-layout-tabs-body');
44425 this.panels.each(this.initPanelAsTab, this);
44428 initPanelAsTab : function(panel){
44429 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
44430 this.config.closeOnTab && panel.isClosable());
44431 if(panel.tabTip !== undefined){
44432 ti.setTooltip(panel.tabTip);
44434 ti.on("activate", function(){
44435 this.setActivePanel(panel);
44437 if(this.config.closeOnTab){
44438 ti.on("beforeclose", function(t, e){
44440 this.remove(panel);
44446 updatePanelTitle : function(panel, title){
44447 if(this.activePanel == panel){
44448 this.updateTitle(title);
44451 var ti = this.tabs.getTab(panel.getEl().id);
44453 if(panel.tabTip !== undefined){
44454 ti.setTooltip(panel.tabTip);
44459 updateTitle : function(title){
44460 if(this.titleTextEl && !this.config.title){
44461 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
44465 setActivePanel : function(panel){
44466 panel = this.getPanel(panel);
44467 if(this.activePanel && this.activePanel != panel){
44468 this.activePanel.setActiveState(false);
44470 this.activePanel = panel;
44471 panel.setActiveState(true);
44472 if(this.panelSize){
44473 panel.setSize(this.panelSize.width, this.panelSize.height);
44476 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
44478 this.updateTitle(panel.getTitle());
44480 this.fireEvent("invalidated", this);
44482 this.fireEvent("panelactivated", this, panel);
44486 * Shows the specified panel.
44487 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
44488 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
44490 showPanel : function(panel){
44491 if(panel = this.getPanel(panel)){
44493 var tab = this.tabs.getTab(panel.getEl().id);
44494 if(tab.isHidden()){
44495 this.tabs.unhideTab(tab.id);
44499 this.setActivePanel(panel);
44506 * Get the active panel for this region.
44507 * @return {Roo.ContentPanel} The active panel or null
44509 getActivePanel : function(){
44510 return this.activePanel;
44513 validateVisibility : function(){
44514 if(this.panels.getCount() < 1){
44515 this.updateTitle(" ");
44516 this.closeBtn.hide();
44519 if(!this.isVisible()){
44526 * Adds the passed ContentPanel(s) to this region.
44527 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44528 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
44530 add : function(panel){
44531 if(arguments.length > 1){
44532 for(var i = 0, len = arguments.length; i < len; i++) {
44533 this.add(arguments[i]);
44537 if(this.hasPanel(panel)){
44538 this.showPanel(panel);
44541 panel.setRegion(this);
44542 this.panels.add(panel);
44543 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
44544 this.bodyEl.dom.appendChild(panel.getEl().dom);
44545 if(panel.background !== true){
44546 this.setActivePanel(panel);
44548 this.fireEvent("paneladded", this, panel);
44554 this.initPanelAsTab(panel);
44556 if(panel.background !== true){
44557 this.tabs.activate(panel.getEl().id);
44559 this.fireEvent("paneladded", this, panel);
44564 * Hides the tab for the specified panel.
44565 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44567 hidePanel : function(panel){
44568 if(this.tabs && (panel = this.getPanel(panel))){
44569 this.tabs.hideTab(panel.getEl().id);
44574 * Unhides the tab for a previously hidden panel.
44575 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44577 unhidePanel : function(panel){
44578 if(this.tabs && (panel = this.getPanel(panel))){
44579 this.tabs.unhideTab(panel.getEl().id);
44583 clearPanels : function(){
44584 while(this.panels.getCount() > 0){
44585 this.remove(this.panels.first());
44590 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44591 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44592 * @param {Boolean} preservePanel Overrides the config preservePanel option
44593 * @return {Roo.ContentPanel} The panel that was removed
44595 remove : function(panel, preservePanel){
44596 panel = this.getPanel(panel);
44601 this.fireEvent("beforeremove", this, panel, e);
44602 if(e.cancel === true){
44605 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
44606 var panelId = panel.getId();
44607 this.panels.removeKey(panelId);
44609 document.body.appendChild(panel.getEl().dom);
44612 this.tabs.removeTab(panel.getEl().id);
44613 }else if (!preservePanel){
44614 this.bodyEl.dom.removeChild(panel.getEl().dom);
44616 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
44617 var p = this.panels.first();
44618 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
44619 tempEl.appendChild(p.getEl().dom);
44620 this.bodyEl.update("");
44621 this.bodyEl.dom.appendChild(p.getEl().dom);
44623 this.updateTitle(p.getTitle());
44625 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44626 this.setActivePanel(p);
44628 panel.setRegion(null);
44629 if(this.activePanel == panel){
44630 this.activePanel = null;
44632 if(this.config.autoDestroy !== false && preservePanel !== true){
44633 try{panel.destroy();}catch(e){}
44635 this.fireEvent("panelremoved", this, panel);
44640 * Returns the TabPanel component used by this region
44641 * @return {Roo.TabPanel}
44643 getTabs : function(){
44647 createTool : function(parentEl, className){
44648 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
44649 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
44650 btn.addClassOnOver("x-layout-tools-button-over");
44655 * Ext JS Library 1.1.1
44656 * Copyright(c) 2006-2007, Ext JS, LLC.
44658 * Originally Released Under LGPL - original licence link has changed is not relivant.
44661 * <script type="text/javascript">
44667 * @class Roo.SplitLayoutRegion
44668 * @extends Roo.LayoutRegion
44669 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
44671 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
44672 this.cursor = cursor;
44673 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
44676 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
44677 splitTip : "Drag to resize.",
44678 collapsibleSplitTip : "Drag to resize. Double click to hide.",
44679 useSplitTips : false,
44681 applyConfig : function(config){
44682 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
44685 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
44686 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
44687 /** The SplitBar for this region
44688 * @type Roo.SplitBar */
44689 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
44690 this.split.on("moved", this.onSplitMove, this);
44691 this.split.useShim = config.useShim === true;
44692 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
44693 if(this.useSplitTips){
44694 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
44696 if(config.collapsible){
44697 this.split.el.on("dblclick", this.collapse, this);
44700 if(typeof config.minSize != "undefined"){
44701 this.split.minSize = config.minSize;
44703 if(typeof config.maxSize != "undefined"){
44704 this.split.maxSize = config.maxSize;
44706 if(config.hideWhenEmpty || config.hidden || config.collapsed){
44707 this.hideSplitter();
44712 getHMaxSize : function(){
44713 var cmax = this.config.maxSize || 10000;
44714 var center = this.mgr.getRegion("center");
44715 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
44718 getVMaxSize : function(){
44719 var cmax = this.config.maxSize || 10000;
44720 var center = this.mgr.getRegion("center");
44721 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
44724 onSplitMove : function(split, newSize){
44725 this.fireEvent("resized", this, newSize);
44729 * Returns the {@link Roo.SplitBar} for this region.
44730 * @return {Roo.SplitBar}
44732 getSplitBar : function(){
44737 this.hideSplitter();
44738 Roo.SplitLayoutRegion.superclass.hide.call(this);
44741 hideSplitter : function(){
44743 this.split.el.setLocation(-2000,-2000);
44744 this.split.el.hide();
44750 this.split.el.show();
44752 Roo.SplitLayoutRegion.superclass.show.call(this);
44755 beforeSlide: function(){
44756 if(Roo.isGecko){// firefox overflow auto bug workaround
44757 this.bodyEl.clip();
44758 if(this.tabs) this.tabs.bodyEl.clip();
44759 if(this.activePanel){
44760 this.activePanel.getEl().clip();
44762 if(this.activePanel.beforeSlide){
44763 this.activePanel.beforeSlide();
44769 afterSlide : function(){
44770 if(Roo.isGecko){// firefox overflow auto bug workaround
44771 this.bodyEl.unclip();
44772 if(this.tabs) this.tabs.bodyEl.unclip();
44773 if(this.activePanel){
44774 this.activePanel.getEl().unclip();
44775 if(this.activePanel.afterSlide){
44776 this.activePanel.afterSlide();
44782 initAutoHide : function(){
44783 if(this.autoHide !== false){
44784 if(!this.autoHideHd){
44785 var st = new Roo.util.DelayedTask(this.slideIn, this);
44786 this.autoHideHd = {
44787 "mouseout": function(e){
44788 if(!e.within(this.el, true)){
44792 "mouseover" : function(e){
44798 this.el.on(this.autoHideHd);
44802 clearAutoHide : function(){
44803 if(this.autoHide !== false){
44804 this.el.un("mouseout", this.autoHideHd.mouseout);
44805 this.el.un("mouseover", this.autoHideHd.mouseover);
44809 clearMonitor : function(){
44810 Roo.get(document).un("click", this.slideInIf, this);
44813 // these names are backwards but not changed for compat
44814 slideOut : function(){
44815 if(this.isSlid || this.el.hasActiveFx()){
44818 this.isSlid = true;
44819 if(this.collapseBtn){
44820 this.collapseBtn.hide();
44822 this.closeBtnState = this.closeBtn.getStyle('display');
44823 this.closeBtn.hide();
44825 this.stickBtn.show();
44828 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
44829 this.beforeSlide();
44830 this.el.setStyle("z-index", 10001);
44831 this.el.slideIn(this.getSlideAnchor(), {
44832 callback: function(){
44834 this.initAutoHide();
44835 Roo.get(document).on("click", this.slideInIf, this);
44836 this.fireEvent("slideshow", this);
44843 afterSlideIn : function(){
44844 this.clearAutoHide();
44845 this.isSlid = false;
44846 this.clearMonitor();
44847 this.el.setStyle("z-index", "");
44848 if(this.collapseBtn){
44849 this.collapseBtn.show();
44851 this.closeBtn.setStyle('display', this.closeBtnState);
44853 this.stickBtn.hide();
44855 this.fireEvent("slidehide", this);
44858 slideIn : function(cb){
44859 if(!this.isSlid || this.el.hasActiveFx()){
44863 this.isSlid = false;
44864 this.beforeSlide();
44865 this.el.slideOut(this.getSlideAnchor(), {
44866 callback: function(){
44867 this.el.setLeftTop(-10000, -10000);
44869 this.afterSlideIn();
44877 slideInIf : function(e){
44878 if(!e.within(this.el)){
44883 animateCollapse : function(){
44884 this.beforeSlide();
44885 this.el.setStyle("z-index", 20000);
44886 var anchor = this.getSlideAnchor();
44887 this.el.slideOut(anchor, {
44888 callback : function(){
44889 this.el.setStyle("z-index", "");
44890 this.collapsedEl.slideIn(anchor, {duration:.3});
44892 this.el.setLocation(-10000,-10000);
44894 this.fireEvent("collapsed", this);
44901 animateExpand : function(){
44902 this.beforeSlide();
44903 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
44904 this.el.setStyle("z-index", 20000);
44905 this.collapsedEl.hide({
44908 this.el.slideIn(this.getSlideAnchor(), {
44909 callback : function(){
44910 this.el.setStyle("z-index", "");
44913 this.split.el.show();
44915 this.fireEvent("invalidated", this);
44916 this.fireEvent("expanded", this);
44944 getAnchor : function(){
44945 return this.anchors[this.position];
44948 getCollapseAnchor : function(){
44949 return this.canchors[this.position];
44952 getSlideAnchor : function(){
44953 return this.sanchors[this.position];
44956 getAlignAdj : function(){
44957 var cm = this.cmargins;
44958 switch(this.position){
44974 getExpandAdj : function(){
44975 var c = this.collapsedEl, cm = this.cmargins;
44976 switch(this.position){
44978 return [-(cm.right+c.getWidth()+cm.left), 0];
44981 return [cm.right+c.getWidth()+cm.left, 0];
44984 return [0, -(cm.top+cm.bottom+c.getHeight())];
44987 return [0, cm.top+cm.bottom+c.getHeight()];
44993 * Ext JS Library 1.1.1
44994 * Copyright(c) 2006-2007, Ext JS, LLC.
44996 * Originally Released Under LGPL - original licence link has changed is not relivant.
44999 * <script type="text/javascript">
45002 * These classes are private internal classes
45004 Roo.CenterLayoutRegion = function(mgr, config){
45005 Roo.LayoutRegion.call(this, mgr, config, "center");
45006 this.visible = true;
45007 this.minWidth = config.minWidth || 20;
45008 this.minHeight = config.minHeight || 20;
45011 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
45013 // center panel can't be hidden
45017 // center panel can't be hidden
45020 getMinWidth: function(){
45021 return this.minWidth;
45024 getMinHeight: function(){
45025 return this.minHeight;
45030 Roo.NorthLayoutRegion = function(mgr, config){
45031 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
45033 this.split.placement = Roo.SplitBar.TOP;
45034 this.split.orientation = Roo.SplitBar.VERTICAL;
45035 this.split.el.addClass("x-layout-split-v");
45037 var size = config.initialSize || config.height;
45038 if(typeof size != "undefined"){
45039 this.el.setHeight(size);
45042 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
45043 orientation: Roo.SplitBar.VERTICAL,
45044 getBox : function(){
45045 if(this.collapsed){
45046 return this.collapsedEl.getBox();
45048 var box = this.el.getBox();
45050 box.height += this.split.el.getHeight();
45055 updateBox : function(box){
45056 if(this.split && !this.collapsed){
45057 box.height -= this.split.el.getHeight();
45058 this.split.el.setLeft(box.x);
45059 this.split.el.setTop(box.y+box.height);
45060 this.split.el.setWidth(box.width);
45062 if(this.collapsed){
45063 this.updateBody(box.width, null);
45065 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45069 Roo.SouthLayoutRegion = function(mgr, config){
45070 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
45072 this.split.placement = Roo.SplitBar.BOTTOM;
45073 this.split.orientation = Roo.SplitBar.VERTICAL;
45074 this.split.el.addClass("x-layout-split-v");
45076 var size = config.initialSize || config.height;
45077 if(typeof size != "undefined"){
45078 this.el.setHeight(size);
45081 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
45082 orientation: Roo.SplitBar.VERTICAL,
45083 getBox : function(){
45084 if(this.collapsed){
45085 return this.collapsedEl.getBox();
45087 var box = this.el.getBox();
45089 var sh = this.split.el.getHeight();
45096 updateBox : function(box){
45097 if(this.split && !this.collapsed){
45098 var sh = this.split.el.getHeight();
45101 this.split.el.setLeft(box.x);
45102 this.split.el.setTop(box.y-sh);
45103 this.split.el.setWidth(box.width);
45105 if(this.collapsed){
45106 this.updateBody(box.width, null);
45108 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45112 Roo.EastLayoutRegion = function(mgr, config){
45113 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
45115 this.split.placement = Roo.SplitBar.RIGHT;
45116 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45117 this.split.el.addClass("x-layout-split-h");
45119 var size = config.initialSize || config.width;
45120 if(typeof size != "undefined"){
45121 this.el.setWidth(size);
45124 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
45125 orientation: Roo.SplitBar.HORIZONTAL,
45126 getBox : function(){
45127 if(this.collapsed){
45128 return this.collapsedEl.getBox();
45130 var box = this.el.getBox();
45132 var sw = this.split.el.getWidth();
45139 updateBox : function(box){
45140 if(this.split && !this.collapsed){
45141 var sw = this.split.el.getWidth();
45143 this.split.el.setLeft(box.x);
45144 this.split.el.setTop(box.y);
45145 this.split.el.setHeight(box.height);
45148 if(this.collapsed){
45149 this.updateBody(null, box.height);
45151 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45155 Roo.WestLayoutRegion = function(mgr, config){
45156 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
45158 this.split.placement = Roo.SplitBar.LEFT;
45159 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45160 this.split.el.addClass("x-layout-split-h");
45162 var size = config.initialSize || config.width;
45163 if(typeof size != "undefined"){
45164 this.el.setWidth(size);
45167 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
45168 orientation: Roo.SplitBar.HORIZONTAL,
45169 getBox : function(){
45170 if(this.collapsed){
45171 return this.collapsedEl.getBox();
45173 var box = this.el.getBox();
45175 box.width += this.split.el.getWidth();
45180 updateBox : function(box){
45181 if(this.split && !this.collapsed){
45182 var sw = this.split.el.getWidth();
45184 this.split.el.setLeft(box.x+box.width);
45185 this.split.el.setTop(box.y);
45186 this.split.el.setHeight(box.height);
45188 if(this.collapsed){
45189 this.updateBody(null, box.height);
45191 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45196 * Ext JS Library 1.1.1
45197 * Copyright(c) 2006-2007, Ext JS, LLC.
45199 * Originally Released Under LGPL - original licence link has changed is not relivant.
45202 * <script type="text/javascript">
45207 * Private internal class for reading and applying state
45209 Roo.LayoutStateManager = function(layout){
45210 // default empty state
45219 Roo.LayoutStateManager.prototype = {
45220 init : function(layout, provider){
45221 this.provider = provider;
45222 var state = provider.get(layout.id+"-layout-state");
45224 var wasUpdating = layout.isUpdating();
45226 layout.beginUpdate();
45228 for(var key in state){
45229 if(typeof state[key] != "function"){
45230 var rstate = state[key];
45231 var r = layout.getRegion(key);
45234 r.resizeTo(rstate.size);
45236 if(rstate.collapsed == true){
45239 r.expand(null, true);
45245 layout.endUpdate();
45247 this.state = state;
45249 this.layout = layout;
45250 layout.on("regionresized", this.onRegionResized, this);
45251 layout.on("regioncollapsed", this.onRegionCollapsed, this);
45252 layout.on("regionexpanded", this.onRegionExpanded, this);
45255 storeState : function(){
45256 this.provider.set(this.layout.id+"-layout-state", this.state);
45259 onRegionResized : function(region, newSize){
45260 this.state[region.getPosition()].size = newSize;
45264 onRegionCollapsed : function(region){
45265 this.state[region.getPosition()].collapsed = true;
45269 onRegionExpanded : function(region){
45270 this.state[region.getPosition()].collapsed = false;
45275 * Ext JS Library 1.1.1
45276 * Copyright(c) 2006-2007, Ext JS, LLC.
45278 * Originally Released Under LGPL - original licence link has changed is not relivant.
45281 * <script type="text/javascript">
45284 * @class Roo.ContentPanel
45285 * @extends Roo.util.Observable
45286 * A basic ContentPanel element.
45287 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
45288 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
45289 * @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
45290 * @cfg {Boolean} closable True if the panel can be closed/removed
45291 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
45292 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
45293 * @cfg {Toolbar} toolbar A toolbar for this panel
45294 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
45295 * @cfg {String} title The title for this panel
45296 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
45297 * @cfg {String} url Calls {@link #setUrl} with this value
45298 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
45299 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
45300 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
45302 * Create a new ContentPanel.
45303 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
45304 * @param {String/Object} config A string to set only the title or a config object
45305 * @param {String} content (optional) Set the HTML content for this panel
45306 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
45308 Roo.ContentPanel = function(el, config, content){
45312 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
45316 if (config && config.parentLayout) {
45317 el = config.parentLayout.el.createChild();
45320 if(el.autoCreate){ // xtype is available if this is called from factory
45324 this.el = Roo.get(el);
45325 if(!this.el && config && config.autoCreate){
45326 if(typeof config.autoCreate == "object"){
45327 if(!config.autoCreate.id){
45328 config.autoCreate.id = config.id||el;
45330 this.el = Roo.DomHelper.append(document.body,
45331 config.autoCreate, true);
45333 this.el = Roo.DomHelper.append(document.body,
45334 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
45337 this.closable = false;
45338 this.loaded = false;
45339 this.active = false;
45340 if(typeof config == "string"){
45341 this.title = config;
45343 Roo.apply(this, config);
45346 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
45347 this.wrapEl = this.el.wrap();
45348 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
45355 this.resizeEl = Roo.get(this.resizeEl, true);
45357 this.resizeEl = this.el;
45362 * Fires when this panel is activated.
45363 * @param {Roo.ContentPanel} this
45367 * @event deactivate
45368 * Fires when this panel is activated.
45369 * @param {Roo.ContentPanel} this
45371 "deactivate" : true,
45375 * Fires when this panel is resized if fitToFrame is true.
45376 * @param {Roo.ContentPanel} this
45377 * @param {Number} width The width after any component adjustments
45378 * @param {Number} height The height after any component adjustments
45382 if(this.autoScroll){
45383 this.resizeEl.setStyle("overflow", "auto");
45385 // fix randome scrolling
45386 this.el.on('scroll', function() {
45387 this.scrollTo('top',0);
45390 content = content || this.content;
45392 this.setContent(content);
45394 if(config && config.url){
45395 this.setUrl(this.url, this.params, this.loadOnce);
45400 Roo.ContentPanel.superclass.constructor.call(this);
45403 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
45405 setRegion : function(region){
45406 this.region = region;
45408 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
45410 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
45415 * Returns the toolbar for this Panel if one was configured.
45416 * @return {Roo.Toolbar}
45418 getToolbar : function(){
45419 return this.toolbar;
45422 setActiveState : function(active){
45423 this.active = active;
45425 this.fireEvent("deactivate", this);
45427 this.fireEvent("activate", this);
45431 * Updates this panel's element
45432 * @param {String} content The new content
45433 * @param {Boolean} loadScripts (optional) true to look for and process scripts
45435 setContent : function(content, loadScripts){
45436 this.el.update(content, loadScripts);
45439 ignoreResize : function(w, h){
45440 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
45443 this.lastSize = {width: w, height: h};
45448 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
45449 * @return {Roo.UpdateManager} The UpdateManager
45451 getUpdateManager : function(){
45452 return this.el.getUpdateManager();
45455 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
45456 * @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:
45459 url: "your-url.php",
45460 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
45461 callback: yourFunction,
45462 scope: yourObject, //(optional scope)
45465 text: "Loading...",
45470 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
45471 * 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.
45472 * @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}
45473 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
45474 * @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.
45475 * @return {Roo.ContentPanel} this
45478 var um = this.el.getUpdateManager();
45479 um.update.apply(um, arguments);
45485 * 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.
45486 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
45487 * @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)
45488 * @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)
45489 * @return {Roo.UpdateManager} The UpdateManager
45491 setUrl : function(url, params, loadOnce){
45492 if(this.refreshDelegate){
45493 this.removeListener("activate", this.refreshDelegate);
45495 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
45496 this.on("activate", this.refreshDelegate);
45497 return this.el.getUpdateManager();
45500 _handleRefresh : function(url, params, loadOnce){
45501 if(!loadOnce || !this.loaded){
45502 var updater = this.el.getUpdateManager();
45503 updater.update(url, params, this._setLoaded.createDelegate(this));
45507 _setLoaded : function(){
45508 this.loaded = true;
45512 * Returns this panel's id
45515 getId : function(){
45520 * Returns this panel's element - used by regiosn to add.
45521 * @return {Roo.Element}
45523 getEl : function(){
45524 return this.wrapEl || this.el;
45527 adjustForComponents : function(width, height){
45528 if(this.resizeEl != this.el){
45529 width -= this.el.getFrameWidth('lr');
45530 height -= this.el.getFrameWidth('tb');
45533 var te = this.toolbar.getEl();
45534 height -= te.getHeight();
45535 te.setWidth(width);
45537 if(this.adjustments){
45538 width += this.adjustments[0];
45539 height += this.adjustments[1];
45541 return {"width": width, "height": height};
45544 setSize : function(width, height){
45545 if(this.fitToFrame && !this.ignoreResize(width, height)){
45546 if(this.fitContainer && this.resizeEl != this.el){
45547 this.el.setSize(width, height);
45549 var size = this.adjustForComponents(width, height);
45550 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
45551 this.fireEvent('resize', this, size.width, size.height);
45556 * Returns this panel's title
45559 getTitle : function(){
45564 * Set this panel's title
45565 * @param {String} title
45567 setTitle : function(title){
45568 this.title = title;
45570 this.region.updatePanelTitle(this, title);
45575 * Returns true is this panel was configured to be closable
45576 * @return {Boolean}
45578 isClosable : function(){
45579 return this.closable;
45582 beforeSlide : function(){
45584 this.resizeEl.clip();
45587 afterSlide : function(){
45589 this.resizeEl.unclip();
45593 * Force a content refresh from the URL specified in the {@link #setUrl} method.
45594 * Will fail silently if the {@link #setUrl} method has not been called.
45595 * This does not activate the panel, just updates its content.
45597 refresh : function(){
45598 if(this.refreshDelegate){
45599 this.loaded = false;
45600 this.refreshDelegate();
45605 * Destroys this panel
45607 destroy : function(){
45608 this.el.removeAllListeners();
45609 var tempEl = document.createElement("span");
45610 tempEl.appendChild(this.el.dom);
45611 tempEl.innerHTML = "";
45617 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
45627 * @param {Object} cfg Xtype definition of item to add.
45630 addxtype : function(cfg) {
45632 if (cfg.xtype.match(/^Form$/)) {
45633 var el = this.el.createChild();
45635 this.form = new Roo.form.Form(cfg);
45638 if ( this.form.allItems.length) this.form.render(el.dom);
45641 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
45643 cfg.el = this.el.appendChild(document.createElement("div"));
45645 var ret = new Roo[cfg.xtype](cfg);
45646 ret.render(false, ''); // render blank..
45656 * @class Roo.GridPanel
45657 * @extends Roo.ContentPanel
45659 * Create a new GridPanel.
45660 * @param {Roo.grid.Grid} grid The grid for this panel
45661 * @param {String/Object} config A string to set only the panel's title, or a config object
45663 Roo.GridPanel = function(grid, config){
45666 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
45667 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
45669 this.wrapper.dom.appendChild(grid.getGridEl().dom);
45671 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
45674 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
45676 // xtype created footer. - not sure if will work as we normally have to render first..
45677 if (this.footer && !this.footer.el && this.footer.xtype) {
45679 this.footer.container = this.grid.getView().getFooterPanel(true);
45680 this.footer.dataSource = this.grid.dataSource;
45681 this.footer = Roo.factory(this.footer, Roo);
45685 grid.monitorWindowResize = false; // turn off autosizing
45686 grid.autoHeight = false;
45687 grid.autoWidth = false;
45689 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
45692 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
45693 getId : function(){
45694 return this.grid.id;
45698 * Returns the grid for this panel
45699 * @return {Roo.grid.Grid}
45701 getGrid : function(){
45705 setSize : function(width, height){
45706 if(!this.ignoreResize(width, height)){
45707 var grid = this.grid;
45708 var size = this.adjustForComponents(width, height);
45709 grid.getGridEl().setSize(size.width, size.height);
45714 beforeSlide : function(){
45715 this.grid.getView().scroller.clip();
45718 afterSlide : function(){
45719 this.grid.getView().scroller.unclip();
45722 destroy : function(){
45723 this.grid.destroy();
45725 Roo.GridPanel.superclass.destroy.call(this);
45731 * @class Roo.NestedLayoutPanel
45732 * @extends Roo.ContentPanel
45734 * Create a new NestedLayoutPanel.
45737 * @param {Roo.BorderLayout} layout The layout for this panel
45738 * @param {String/Object} config A string to set only the title or a config object
45740 Roo.NestedLayoutPanel = function(layout, config)
45742 // construct with only one argument..
45743 /* FIXME - implement nicer consturctors
45744 if (layout.layout) {
45746 layout = config.layout;
45747 delete config.layout;
45749 if (layout.xtype && !layout.getEl) {
45750 // then layout needs constructing..
45751 layout = Roo.factory(layout, Roo);
45756 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
45758 layout.monitorWindowResize = false; // turn off autosizing
45759 this.layout = layout;
45760 this.layout.getEl().addClass("x-layout-nested-layout");
45767 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
45769 setSize : function(width, height){
45770 if(!this.ignoreResize(width, height)){
45771 var size = this.adjustForComponents(width, height);
45772 var el = this.layout.getEl();
45773 el.setSize(size.width, size.height);
45774 var touch = el.dom.offsetWidth;
45775 this.layout.layout();
45776 // ie requires a double layout on the first pass
45777 if(Roo.isIE && !this.initialized){
45778 this.initialized = true;
45779 this.layout.layout();
45784 // activate all subpanels if not currently active..
45786 setActiveState : function(active){
45787 this.active = active;
45789 this.fireEvent("deactivate", this);
45793 this.fireEvent("activate", this);
45794 // not sure if this should happen before or after..
45795 if (!this.layout) {
45796 return; // should not happen..
45799 for (var r in this.layout.regions) {
45800 reg = this.layout.getRegion(r);
45801 if (reg.getActivePanel()) {
45802 //reg.showPanel(reg.getActivePanel()); // force it to activate..
45803 reg.setActivePanel(reg.getActivePanel());
45806 if (!reg.panels.length) {
45809 reg.showPanel(reg.getPanel(0));
45818 * Returns the nested BorderLayout for this panel
45819 * @return {Roo.BorderLayout}
45821 getLayout : function(){
45822 return this.layout;
45826 * Adds a xtype elements to the layout of the nested panel
45830 xtype : 'ContentPanel',
45837 xtype : 'NestedLayoutPanel',
45843 items : [ ... list of content panels or nested layout panels.. ]
45847 * @param {Object} cfg Xtype definition of item to add.
45849 addxtype : function(cfg) {
45850 return this.layout.addxtype(cfg);
45855 Roo.ScrollPanel = function(el, config, content){
45856 config = config || {};
45857 config.fitToFrame = true;
45858 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
45860 this.el.dom.style.overflow = "hidden";
45861 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
45862 this.el.removeClass("x-layout-inactive-content");
45863 this.el.on("mousewheel", this.onWheel, this);
45865 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
45866 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
45867 up.unselectable(); down.unselectable();
45868 up.on("click", this.scrollUp, this);
45869 down.on("click", this.scrollDown, this);
45870 up.addClassOnOver("x-scroller-btn-over");
45871 down.addClassOnOver("x-scroller-btn-over");
45872 up.addClassOnClick("x-scroller-btn-click");
45873 down.addClassOnClick("x-scroller-btn-click");
45874 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
45876 this.resizeEl = this.el;
45877 this.el = wrap; this.up = up; this.down = down;
45880 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
45882 wheelIncrement : 5,
45883 scrollUp : function(){
45884 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
45887 scrollDown : function(){
45888 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
45891 afterScroll : function(){
45892 var el = this.resizeEl;
45893 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
45894 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45895 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45898 setSize : function(){
45899 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
45900 this.afterScroll();
45903 onWheel : function(e){
45904 var d = e.getWheelDelta();
45905 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
45906 this.afterScroll();
45910 setContent : function(content, loadScripts){
45911 this.resizeEl.update(content, loadScripts);
45925 * @class Roo.TreePanel
45926 * @extends Roo.ContentPanel
45928 * Create a new TreePanel. - defaults to fit/scoll contents.
45929 * @param {String/Object} config A string to set only the panel's title, or a config object
45930 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
45932 Roo.TreePanel = function(config){
45933 var el = config.el;
45934 var tree = config.tree;
45935 delete config.tree;
45936 delete config.el; // hopefull!
45938 // wrapper for IE7 strict & safari scroll issue
45940 var treeEl = el.createChild();
45941 config.resizeEl = treeEl;
45945 Roo.TreePanel.superclass.constructor.call(this, el, config);
45948 this.tree = new Roo.tree.TreePanel(treeEl , tree);
45949 //console.log(tree);
45950 this.on('activate', function()
45952 if (this.tree.rendered) {
45955 //console.log('render tree');
45956 this.tree.render();
45959 this.on('resize', function (cp, w, h) {
45960 this.tree.innerCt.setWidth(w);
45961 this.tree.innerCt.setHeight(h);
45962 this.tree.innerCt.setStyle('overflow-y', 'auto');
45969 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
45986 * Ext JS Library 1.1.1
45987 * Copyright(c) 2006-2007, Ext JS, LLC.
45989 * Originally Released Under LGPL - original licence link has changed is not relivant.
45992 * <script type="text/javascript">
45997 * @class Roo.ReaderLayout
45998 * @extends Roo.BorderLayout
45999 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
46000 * center region containing two nested regions (a top one for a list view and one for item preview below),
46001 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
46002 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
46003 * expedites the setup of the overall layout and regions for this common application style.
46006 var reader = new Roo.ReaderLayout();
46007 var CP = Roo.ContentPanel; // shortcut for adding
46009 reader.beginUpdate();
46010 reader.add("north", new CP("north", "North"));
46011 reader.add("west", new CP("west", {title: "West"}));
46012 reader.add("east", new CP("east", {title: "East"}));
46014 reader.regions.listView.add(new CP("listView", "List"));
46015 reader.regions.preview.add(new CP("preview", "Preview"));
46016 reader.endUpdate();
46019 * Create a new ReaderLayout
46020 * @param {Object} config Configuration options
46021 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
46022 * document.body if omitted)
46024 Roo.ReaderLayout = function(config, renderTo){
46025 var c = config || {size:{}};
46026 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
46027 north: c.north !== false ? Roo.apply({
46031 }, c.north) : false,
46032 west: c.west !== false ? Roo.apply({
46040 margins:{left:5,right:0,bottom:5,top:5},
46041 cmargins:{left:5,right:5,bottom:5,top:5}
46042 }, c.west) : false,
46043 east: c.east !== false ? Roo.apply({
46051 margins:{left:0,right:5,bottom:5,top:5},
46052 cmargins:{left:5,right:5,bottom:5,top:5}
46053 }, c.east) : false,
46054 center: Roo.apply({
46055 tabPosition: 'top',
46059 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
46063 this.el.addClass('x-reader');
46065 this.beginUpdate();
46067 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
46068 south: c.preview !== false ? Roo.apply({
46075 cmargins:{top:5,left:0, right:0, bottom:0}
46076 }, c.preview) : false,
46077 center: Roo.apply({
46083 this.add('center', new Roo.NestedLayoutPanel(inner,
46084 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
46088 this.regions.preview = inner.getRegion('south');
46089 this.regions.listView = inner.getRegion('center');
46092 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
46094 * Ext JS Library 1.1.1
46095 * Copyright(c) 2006-2007, Ext JS, LLC.
46097 * Originally Released Under LGPL - original licence link has changed is not relivant.
46100 * <script type="text/javascript">
46104 * @class Roo.grid.Grid
46105 * @extends Roo.util.Observable
46106 * This class represents the primary interface of a component based grid control.
46107 * <br><br>Usage:<pre><code>
46108 var grid = new Roo.grid.Grid("my-container-id", {
46111 selModel: mySelectionModel,
46112 autoSizeColumns: true,
46113 monitorWindowResize: false,
46114 trackMouseOver: true
46119 * <b>Common Problems:</b><br/>
46120 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
46121 * element will correct this<br/>
46122 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
46123 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
46124 * are unpredictable.<br/>
46125 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
46126 * grid to calculate dimensions/offsets.<br/>
46128 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
46129 * The container MUST have some type of size defined for the grid to fill. The container will be
46130 * automatically set to position relative if it isn't already.
46131 * @param {Object} config A config object that sets properties on this grid.
46133 Roo.grid.Grid = function(container, config){
46134 // initialize the container
46135 this.container = Roo.get(container);
46136 this.container.update("");
46137 this.container.setStyle("overflow", "hidden");
46138 this.container.addClass('x-grid-container');
46140 this.id = this.container.id;
46142 Roo.apply(this, config);
46143 // check and correct shorthanded configs
46145 this.dataSource = this.ds;
46149 this.colModel = this.cm;
46153 this.selModel = this.sm;
46157 if (this.selModel) {
46158 this.selModel = Roo.factory(this.selModel, Roo.grid);
46159 this.sm = this.selModel;
46160 this.sm.xmodule = this.xmodule || false;
46162 if (typeof(this.colModel.config) == 'undefined') {
46163 this.colModel = new Roo.grid.ColumnModel(this.colModel);
46164 this.cm = this.colModel;
46165 this.cm.xmodule = this.xmodule || false;
46167 if (this.dataSource) {
46168 this.dataSource= Roo.factory(this.dataSource, Roo.data);
46169 this.ds = this.dataSource;
46170 this.ds.xmodule = this.xmodule || false;
46177 this.container.setWidth(this.width);
46181 this.container.setHeight(this.height);
46188 * The raw click event for the entire grid.
46189 * @param {Roo.EventObject} e
46194 * The raw dblclick event for the entire grid.
46195 * @param {Roo.EventObject} e
46199 * @event contextmenu
46200 * The raw contextmenu event for the entire grid.
46201 * @param {Roo.EventObject} e
46203 "contextmenu" : true,
46206 * The raw mousedown event for the entire grid.
46207 * @param {Roo.EventObject} e
46209 "mousedown" : true,
46212 * The raw mouseup event for the entire grid.
46213 * @param {Roo.EventObject} e
46218 * The raw mouseover event for the entire grid.
46219 * @param {Roo.EventObject} e
46221 "mouseover" : true,
46224 * The raw mouseout event for the entire grid.
46225 * @param {Roo.EventObject} e
46230 * The raw keypress event for the entire grid.
46231 * @param {Roo.EventObject} e
46236 * The raw keydown event for the entire grid.
46237 * @param {Roo.EventObject} e
46245 * Fires when a cell is clicked
46246 * @param {Grid} this
46247 * @param {Number} rowIndex
46248 * @param {Number} columnIndex
46249 * @param {Roo.EventObject} e
46251 "cellclick" : true,
46253 * @event celldblclick
46254 * Fires when a cell is double clicked
46255 * @param {Grid} this
46256 * @param {Number} rowIndex
46257 * @param {Number} columnIndex
46258 * @param {Roo.EventObject} e
46260 "celldblclick" : true,
46263 * Fires when a row is clicked
46264 * @param {Grid} this
46265 * @param {Number} rowIndex
46266 * @param {Roo.EventObject} e
46270 * @event rowdblclick
46271 * Fires when a row is double clicked
46272 * @param {Grid} this
46273 * @param {Number} rowIndex
46274 * @param {Roo.EventObject} e
46276 "rowdblclick" : true,
46278 * @event headerclick
46279 * Fires when a header is clicked
46280 * @param {Grid} this
46281 * @param {Number} columnIndex
46282 * @param {Roo.EventObject} e
46284 "headerclick" : true,
46286 * @event headerdblclick
46287 * Fires when a header cell is double clicked
46288 * @param {Grid} this
46289 * @param {Number} columnIndex
46290 * @param {Roo.EventObject} e
46292 "headerdblclick" : true,
46294 * @event rowcontextmenu
46295 * Fires when a row is right clicked
46296 * @param {Grid} this
46297 * @param {Number} rowIndex
46298 * @param {Roo.EventObject} e
46300 "rowcontextmenu" : true,
46302 * @event cellcontextmenu
46303 * Fires when a cell is right clicked
46304 * @param {Grid} this
46305 * @param {Number} rowIndex
46306 * @param {Number} cellIndex
46307 * @param {Roo.EventObject} e
46309 "cellcontextmenu" : true,
46311 * @event headercontextmenu
46312 * Fires when a header is right clicked
46313 * @param {Grid} this
46314 * @param {Number} columnIndex
46315 * @param {Roo.EventObject} e
46317 "headercontextmenu" : true,
46319 * @event bodyscroll
46320 * Fires when the body element is scrolled
46321 * @param {Number} scrollLeft
46322 * @param {Number} scrollTop
46324 "bodyscroll" : true,
46326 * @event columnresize
46327 * Fires when the user resizes a column
46328 * @param {Number} columnIndex
46329 * @param {Number} newSize
46331 "columnresize" : true,
46333 * @event columnmove
46334 * Fires when the user moves a column
46335 * @param {Number} oldIndex
46336 * @param {Number} newIndex
46338 "columnmove" : true,
46341 * Fires when row(s) start being dragged
46342 * @param {Grid} this
46343 * @param {Roo.GridDD} dd The drag drop object
46344 * @param {event} e The raw browser event
46346 "startdrag" : true,
46349 * Fires when a drag operation is complete
46350 * @param {Grid} this
46351 * @param {Roo.GridDD} dd The drag drop object
46352 * @param {event} e The raw browser event
46357 * Fires when dragged row(s) are dropped on a valid DD target
46358 * @param {Grid} this
46359 * @param {Roo.GridDD} dd The drag drop object
46360 * @param {String} targetId The target drag drop object
46361 * @param {event} e The raw browser event
46366 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
46367 * @param {Grid} this
46368 * @param {Roo.GridDD} dd The drag drop object
46369 * @param {String} targetId The target drag drop object
46370 * @param {event} e The raw browser event
46375 * Fires when the dragged row(s) first cross another DD target while being dragged
46376 * @param {Grid} this
46377 * @param {Roo.GridDD} dd The drag drop object
46378 * @param {String} targetId The target drag drop object
46379 * @param {event} e The raw browser event
46381 "dragenter" : true,
46384 * Fires when the dragged row(s) leave another DD target while being dragged
46385 * @param {Grid} this
46386 * @param {Roo.GridDD} dd The drag drop object
46387 * @param {String} targetId The target drag drop object
46388 * @param {event} e The raw browser event
46393 * Fires when the grid is rendered
46394 * @param {Grid} grid
46399 Roo.grid.Grid.superclass.constructor.call(this);
46401 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
46404 * @cfg {String} ddGroup - drag drop group.
46408 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
46410 minColumnWidth : 25,
46413 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
46414 * <b>on initial render.</b> It is more efficient to explicitly size the columns
46415 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
46417 autoSizeColumns : false,
46420 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
46422 autoSizeHeaders : true,
46425 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
46427 monitorWindowResize : true,
46430 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
46431 * rows measured to get a columns size. Default is 0 (all rows).
46433 maxRowsToMeasure : 0,
46436 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
46438 trackMouseOver : true,
46441 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
46445 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
46447 enableDragDrop : false,
46450 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
46452 enableColumnMove : true,
46455 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
46457 enableColumnHide : true,
46460 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
46462 enableRowHeightSync : false,
46465 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
46470 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
46472 autoHeight : false,
46475 * @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.
46477 autoExpandColumn : false,
46480 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
46483 autoExpandMin : 50,
46486 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
46488 autoExpandMax : 1000,
46491 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
46496 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
46500 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
46507 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
46508 * of a fixed width. Default is false.
46511 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
46514 * Called once after all setup has been completed and the grid is ready to be rendered.
46515 * @return {Roo.grid.Grid} this
46517 render : function(){
46518 var c = this.container;
46519 // try to detect autoHeight/width mode
46520 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
46521 this.autoHeight = true;
46523 var view = this.getView();
46526 c.on("click", this.onClick, this);
46527 c.on("dblclick", this.onDblClick, this);
46528 c.on("contextmenu", this.onContextMenu, this);
46529 c.on("keydown", this.onKeyDown, this);
46531 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
46533 this.getSelectionModel().init(this);
46538 this.loadMask = new Roo.LoadMask(this.container,
46539 Roo.apply({store:this.dataSource}, this.loadMask));
46543 if (this.toolbar && this.toolbar.xtype) {
46544 this.toolbar.container = this.getView().getHeaderPanel(true);
46545 this.toolbar = new Ext.Toolbar(this.toolbar);
46547 if (this.footer && this.footer.xtype) {
46548 this.footer.dataSource = this.getDataSource();
46549 this.footer.container = this.getView().getFooterPanel(true);
46550 this.footer = Roo.factory(this.footer, Roo);
46552 if (this.dropTarget && this.dropTarget.xtype) {
46553 delete this.dropTarget.xtype;
46554 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
46558 this.rendered = true;
46559 this.fireEvent('render', this);
46564 * Reconfigures the grid to use a different Store and Column Model.
46565 * The View will be bound to the new objects and refreshed.
46566 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
46567 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
46569 reconfigure : function(dataSource, colModel){
46571 this.loadMask.destroy();
46572 this.loadMask = new Roo.LoadMask(this.container,
46573 Roo.apply({store:dataSource}, this.loadMask));
46575 this.view.bind(dataSource, colModel);
46576 this.dataSource = dataSource;
46577 this.colModel = colModel;
46578 this.view.refresh(true);
46582 onKeyDown : function(e){
46583 this.fireEvent("keydown", e);
46587 * Destroy this grid.
46588 * @param {Boolean} removeEl True to remove the element
46590 destroy : function(removeEl, keepListeners){
46592 this.loadMask.destroy();
46594 var c = this.container;
46595 c.removeAllListeners();
46596 this.view.destroy();
46597 this.colModel.purgeListeners();
46598 if(!keepListeners){
46599 this.purgeListeners();
46602 if(removeEl === true){
46608 processEvent : function(name, e){
46609 this.fireEvent(name, e);
46610 var t = e.getTarget();
46612 var header = v.findHeaderIndex(t);
46613 if(header !== false){
46614 this.fireEvent("header" + name, this, header, e);
46616 var row = v.findRowIndex(t);
46617 var cell = v.findCellIndex(t);
46619 this.fireEvent("row" + name, this, row, e);
46620 if(cell !== false){
46621 this.fireEvent("cell" + name, this, row, cell, e);
46628 onClick : function(e){
46629 this.processEvent("click", e);
46633 onContextMenu : function(e, t){
46634 this.processEvent("contextmenu", e);
46638 onDblClick : function(e){
46639 this.processEvent("dblclick", e);
46643 walkCells : function(row, col, step, fn, scope){
46644 var cm = this.colModel, clen = cm.getColumnCount();
46645 var ds = this.dataSource, rlen = ds.getCount(), first = true;
46657 if(fn.call(scope || this, row, col, cm) === true){
46675 if(fn.call(scope || this, row, col, cm) === true){
46687 getSelections : function(){
46688 return this.selModel.getSelections();
46692 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
46693 * but if manual update is required this method will initiate it.
46695 autoSize : function(){
46697 this.view.layout();
46698 if(this.view.adjustForScroll){
46699 this.view.adjustForScroll();
46705 * Returns the grid's underlying element.
46706 * @return {Element} The element
46708 getGridEl : function(){
46709 return this.container;
46712 // private for compatibility, overridden by editor grid
46713 stopEditing : function(){},
46716 * Returns the grid's SelectionModel.
46717 * @return {SelectionModel}
46719 getSelectionModel : function(){
46720 if(!this.selModel){
46721 this.selModel = new Roo.grid.RowSelectionModel();
46723 return this.selModel;
46727 * Returns the grid's DataSource.
46728 * @return {DataSource}
46730 getDataSource : function(){
46731 return this.dataSource;
46735 * Returns the grid's ColumnModel.
46736 * @return {ColumnModel}
46738 getColumnModel : function(){
46739 return this.colModel;
46743 * Returns the grid's GridView object.
46744 * @return {GridView}
46746 getView : function(){
46748 this.view = new Roo.grid.GridView(this.viewConfig);
46753 * Called to get grid's drag proxy text, by default returns this.ddText.
46756 getDragDropText : function(){
46757 var count = this.selModel.getCount();
46758 return String.format(this.ddText, count, count == 1 ? '' : 's');
46762 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
46763 * %0 is replaced with the number of selected rows.
46766 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
46768 * Ext JS Library 1.1.1
46769 * Copyright(c) 2006-2007, Ext JS, LLC.
46771 * Originally Released Under LGPL - original licence link has changed is not relivant.
46774 * <script type="text/javascript">
46777 Roo.grid.AbstractGridView = function(){
46781 "beforerowremoved" : true,
46782 "beforerowsinserted" : true,
46783 "beforerefresh" : true,
46784 "rowremoved" : true,
46785 "rowsinserted" : true,
46786 "rowupdated" : true,
46789 Roo.grid.AbstractGridView.superclass.constructor.call(this);
46792 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
46793 rowClass : "x-grid-row",
46794 cellClass : "x-grid-cell",
46795 tdClass : "x-grid-td",
46796 hdClass : "x-grid-hd",
46797 splitClass : "x-grid-hd-split",
46799 init: function(grid){
46801 var cid = this.grid.getGridEl().id;
46802 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
46803 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
46804 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
46805 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
46808 getColumnRenderers : function(){
46809 var renderers = [];
46810 var cm = this.grid.colModel;
46811 var colCount = cm.getColumnCount();
46812 for(var i = 0; i < colCount; i++){
46813 renderers[i] = cm.getRenderer(i);
46818 getColumnIds : function(){
46820 var cm = this.grid.colModel;
46821 var colCount = cm.getColumnCount();
46822 for(var i = 0; i < colCount; i++){
46823 ids[i] = cm.getColumnId(i);
46828 getDataIndexes : function(){
46829 if(!this.indexMap){
46830 this.indexMap = this.buildIndexMap();
46832 return this.indexMap.colToData;
46835 getColumnIndexByDataIndex : function(dataIndex){
46836 if(!this.indexMap){
46837 this.indexMap = this.buildIndexMap();
46839 return this.indexMap.dataToCol[dataIndex];
46843 * Set a css style for a column dynamically.
46844 * @param {Number} colIndex The index of the column
46845 * @param {String} name The css property name
46846 * @param {String} value The css value
46848 setCSSStyle : function(colIndex, name, value){
46849 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
46850 Roo.util.CSS.updateRule(selector, name, value);
46853 generateRules : function(cm){
46854 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
46855 Roo.util.CSS.removeStyleSheet(rulesId);
46856 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46857 var cid = cm.getColumnId(i);
46858 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
46859 this.tdSelector, cid, " {\n}\n",
46860 this.hdSelector, cid, " {\n}\n",
46861 this.splitSelector, cid, " {\n}\n");
46863 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
46867 * Ext JS Library 1.1.1
46868 * Copyright(c) 2006-2007, Ext JS, LLC.
46870 * Originally Released Under LGPL - original licence link has changed is not relivant.
46873 * <script type="text/javascript">
46877 // This is a support class used internally by the Grid components
46878 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
46880 this.view = grid.getView();
46881 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46882 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
46884 this.setHandleElId(Roo.id(hd));
46885 this.setOuterHandleElId(Roo.id(hd2));
46887 this.scroll = false;
46889 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
46891 getDragData : function(e){
46892 var t = Roo.lib.Event.getTarget(e);
46893 var h = this.view.findHeaderCell(t);
46895 return {ddel: h.firstChild, header:h};
46900 onInitDrag : function(e){
46901 this.view.headersDisabled = true;
46902 var clone = this.dragData.ddel.cloneNode(true);
46903 clone.id = Roo.id();
46904 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
46905 this.proxy.update(clone);
46909 afterValidDrop : function(){
46911 setTimeout(function(){
46912 v.headersDisabled = false;
46916 afterInvalidDrop : function(){
46918 setTimeout(function(){
46919 v.headersDisabled = false;
46925 * Ext JS Library 1.1.1
46926 * Copyright(c) 2006-2007, Ext JS, LLC.
46928 * Originally Released Under LGPL - original licence link has changed is not relivant.
46931 * <script type="text/javascript">
46934 // This is a support class used internally by the Grid components
46935 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
46937 this.view = grid.getView();
46938 // split the proxies so they don't interfere with mouse events
46939 this.proxyTop = Roo.DomHelper.append(document.body, {
46940 cls:"col-move-top", html:" "
46942 this.proxyBottom = Roo.DomHelper.append(document.body, {
46943 cls:"col-move-bottom", html:" "
46945 this.proxyTop.hide = this.proxyBottom.hide = function(){
46946 this.setLeftTop(-100,-100);
46947 this.setStyle("visibility", "hidden");
46949 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46950 // temporarily disabled
46951 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
46952 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
46954 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
46955 proxyOffsets : [-4, -9],
46956 fly: Roo.Element.fly,
46958 getTargetFromEvent : function(e){
46959 var t = Roo.lib.Event.getTarget(e);
46960 var cindex = this.view.findCellIndex(t);
46961 if(cindex !== false){
46962 return this.view.getHeaderCell(cindex);
46966 nextVisible : function(h){
46967 var v = this.view, cm = this.grid.colModel;
46970 if(!cm.isHidden(v.getCellIndex(h))){
46978 prevVisible : function(h){
46979 var v = this.view, cm = this.grid.colModel;
46982 if(!cm.isHidden(v.getCellIndex(h))){
46990 positionIndicator : function(h, n, e){
46991 var x = Roo.lib.Event.getPageX(e);
46992 var r = Roo.lib.Dom.getRegion(n.firstChild);
46993 var px, pt, py = r.top + this.proxyOffsets[1];
46994 if((r.right - x) <= (r.right-r.left)/2){
46995 px = r.right+this.view.borderWidth;
47001 var oldIndex = this.view.getCellIndex(h);
47002 var newIndex = this.view.getCellIndex(n);
47004 if(this.grid.colModel.isFixed(newIndex)){
47008 var locked = this.grid.colModel.isLocked(newIndex);
47013 if(oldIndex < newIndex){
47016 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
47019 px += this.proxyOffsets[0];
47020 this.proxyTop.setLeftTop(px, py);
47021 this.proxyTop.show();
47022 if(!this.bottomOffset){
47023 this.bottomOffset = this.view.mainHd.getHeight();
47025 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
47026 this.proxyBottom.show();
47030 onNodeEnter : function(n, dd, e, data){
47031 if(data.header != n){
47032 this.positionIndicator(data.header, n, e);
47036 onNodeOver : function(n, dd, e, data){
47037 var result = false;
47038 if(data.header != n){
47039 result = this.positionIndicator(data.header, n, e);
47042 this.proxyTop.hide();
47043 this.proxyBottom.hide();
47045 return result ? this.dropAllowed : this.dropNotAllowed;
47048 onNodeOut : function(n, dd, e, data){
47049 this.proxyTop.hide();
47050 this.proxyBottom.hide();
47053 onNodeDrop : function(n, dd, e, data){
47054 var h = data.header;
47056 var cm = this.grid.colModel;
47057 var x = Roo.lib.Event.getPageX(e);
47058 var r = Roo.lib.Dom.getRegion(n.firstChild);
47059 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
47060 var oldIndex = this.view.getCellIndex(h);
47061 var newIndex = this.view.getCellIndex(n);
47062 var locked = cm.isLocked(newIndex);
47066 if(oldIndex < newIndex){
47069 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
47072 cm.setLocked(oldIndex, locked, true);
47073 cm.moveColumn(oldIndex, newIndex);
47074 this.grid.fireEvent("columnmove", oldIndex, newIndex);
47082 * Ext JS Library 1.1.1
47083 * Copyright(c) 2006-2007, Ext JS, LLC.
47085 * Originally Released Under LGPL - original licence link has changed is not relivant.
47088 * <script type="text/javascript">
47092 * @class Roo.grid.GridView
47093 * @extends Roo.util.Observable
47096 * @param {Object} config
47098 Roo.grid.GridView = function(config){
47099 Roo.grid.GridView.superclass.constructor.call(this);
47102 Roo.apply(this, config);
47105 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
47108 * Override this function to apply custom css classes to rows during rendering
47109 * @param {Record} record The record
47110 * @param {Number} index
47111 * @method getRowClass
47113 rowClass : "x-grid-row",
47115 cellClass : "x-grid-col",
47117 tdClass : "x-grid-td",
47119 hdClass : "x-grid-hd",
47121 splitClass : "x-grid-split",
47123 sortClasses : ["sort-asc", "sort-desc"],
47125 enableMoveAnim : false,
47129 dh : Roo.DomHelper,
47131 fly : Roo.Element.fly,
47133 css : Roo.util.CSS,
47139 scrollIncrement : 22,
47141 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
47143 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
47145 bind : function(ds, cm){
47147 this.ds.un("load", this.onLoad, this);
47148 this.ds.un("datachanged", this.onDataChange, this);
47149 this.ds.un("add", this.onAdd, this);
47150 this.ds.un("remove", this.onRemove, this);
47151 this.ds.un("update", this.onUpdate, this);
47152 this.ds.un("clear", this.onClear, this);
47155 ds.on("load", this.onLoad, this);
47156 ds.on("datachanged", this.onDataChange, this);
47157 ds.on("add", this.onAdd, this);
47158 ds.on("remove", this.onRemove, this);
47159 ds.on("update", this.onUpdate, this);
47160 ds.on("clear", this.onClear, this);
47165 this.cm.un("widthchange", this.onColWidthChange, this);
47166 this.cm.un("headerchange", this.onHeaderChange, this);
47167 this.cm.un("hiddenchange", this.onHiddenChange, this);
47168 this.cm.un("columnmoved", this.onColumnMove, this);
47169 this.cm.un("columnlockchange", this.onColumnLock, this);
47172 this.generateRules(cm);
47173 cm.on("widthchange", this.onColWidthChange, this);
47174 cm.on("headerchange", this.onHeaderChange, this);
47175 cm.on("hiddenchange", this.onHiddenChange, this);
47176 cm.on("columnmoved", this.onColumnMove, this);
47177 cm.on("columnlockchange", this.onColumnLock, this);
47182 init: function(grid){
47183 Roo.grid.GridView.superclass.init.call(this, grid);
47185 this.bind(grid.dataSource, grid.colModel);
47187 grid.on("headerclick", this.handleHeaderClick, this);
47189 if(grid.trackMouseOver){
47190 grid.on("mouseover", this.onRowOver, this);
47191 grid.on("mouseout", this.onRowOut, this);
47193 grid.cancelTextSelection = function(){};
47194 this.gridId = grid.id;
47196 var tpls = this.templates || {};
47199 tpls.master = new Roo.Template(
47200 '<div class="x-grid" hidefocus="true">',
47201 '<div class="x-grid-topbar"></div>',
47202 '<div class="x-grid-scroller"><div></div></div>',
47203 '<div class="x-grid-locked">',
47204 '<div class="x-grid-header">{lockedHeader}</div>',
47205 '<div class="x-grid-body">{lockedBody}</div>',
47207 '<div class="x-grid-viewport">',
47208 '<div class="x-grid-header">{header}</div>',
47209 '<div class="x-grid-body">{body}</div>',
47211 '<div class="x-grid-bottombar"></div>',
47212 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
47213 '<div class="x-grid-resize-proxy"> </div>',
47216 tpls.master.disableformats = true;
47220 tpls.header = new Roo.Template(
47221 '<table border="0" cellspacing="0" cellpadding="0">',
47222 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
47225 tpls.header.disableformats = true;
47227 tpls.header.compile();
47230 tpls.hcell = new Roo.Template(
47231 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
47232 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
47235 tpls.hcell.disableFormats = true;
47237 tpls.hcell.compile();
47240 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
47241 tpls.hsplit.disableFormats = true;
47243 tpls.hsplit.compile();
47246 tpls.body = new Roo.Template(
47247 '<table border="0" cellspacing="0" cellpadding="0">',
47248 "<tbody>{rows}</tbody>",
47251 tpls.body.disableFormats = true;
47253 tpls.body.compile();
47256 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
47257 tpls.row.disableFormats = true;
47259 tpls.row.compile();
47262 tpls.cell = new Roo.Template(
47263 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
47264 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
47267 tpls.cell.disableFormats = true;
47269 tpls.cell.compile();
47271 this.templates = tpls;
47274 // remap these for backwards compat
47275 onColWidthChange : function(){
47276 this.updateColumns.apply(this, arguments);
47278 onHeaderChange : function(){
47279 this.updateHeaders.apply(this, arguments);
47281 onHiddenChange : function(){
47282 this.handleHiddenChange.apply(this, arguments);
47284 onColumnMove : function(){
47285 this.handleColumnMove.apply(this, arguments);
47287 onColumnLock : function(){
47288 this.handleLockChange.apply(this, arguments);
47291 onDataChange : function(){
47293 this.updateHeaderSortState();
47296 onClear : function(){
47300 onUpdate : function(ds, record){
47301 this.refreshRow(record);
47304 refreshRow : function(record){
47305 var ds = this.ds, index;
47306 if(typeof record == 'number'){
47308 record = ds.getAt(index);
47310 index = ds.indexOf(record);
47312 this.insertRows(ds, index, index, true);
47313 this.onRemove(ds, record, index+1, true);
47314 this.syncRowHeights(index, index);
47316 this.fireEvent("rowupdated", this, index, record);
47319 onAdd : function(ds, records, index){
47320 this.insertRows(ds, index, index + (records.length-1));
47323 onRemove : function(ds, record, index, isUpdate){
47324 if(isUpdate !== true){
47325 this.fireEvent("beforerowremoved", this, index, record);
47327 var bt = this.getBodyTable(), lt = this.getLockedTable();
47328 if(bt.rows[index]){
47329 bt.firstChild.removeChild(bt.rows[index]);
47331 if(lt.rows[index]){
47332 lt.firstChild.removeChild(lt.rows[index]);
47334 if(isUpdate !== true){
47335 this.stripeRows(index);
47336 this.syncRowHeights(index, index);
47338 this.fireEvent("rowremoved", this, index, record);
47342 onLoad : function(){
47343 this.scrollToTop();
47347 * Scrolls the grid to the top
47349 scrollToTop : function(){
47351 this.scroller.dom.scrollTop = 0;
47357 * Gets a panel in the header of the grid that can be used for toolbars etc.
47358 * After modifying the contents of this panel a call to grid.autoSize() may be
47359 * required to register any changes in size.
47360 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
47361 * @return Roo.Element
47363 getHeaderPanel : function(doShow){
47365 this.headerPanel.show();
47367 return this.headerPanel;
47371 * Gets a panel in the footer of the grid that can be used for toolbars etc.
47372 * After modifying the contents of this panel a call to grid.autoSize() may be
47373 * required to register any changes in size.
47374 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
47375 * @return Roo.Element
47377 getFooterPanel : function(doShow){
47379 this.footerPanel.show();
47381 return this.footerPanel;
47384 initElements : function(){
47385 var E = Roo.Element;
47386 var el = this.grid.getGridEl().dom.firstChild;
47387 var cs = el.childNodes;
47389 this.el = new E(el);
47390 this.headerPanel = new E(el.firstChild);
47391 this.headerPanel.enableDisplayMode("block");
47393 this.scroller = new E(cs[1]);
47394 this.scrollSizer = new E(this.scroller.dom.firstChild);
47396 this.lockedWrap = new E(cs[2]);
47397 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
47398 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
47400 this.mainWrap = new E(cs[3]);
47401 this.mainHd = new E(this.mainWrap.dom.firstChild);
47402 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
47404 this.footerPanel = new E(cs[4]);
47405 this.footerPanel.enableDisplayMode("block");
47407 this.focusEl = new E(cs[5]);
47408 this.focusEl.swallowEvent("click", true);
47409 this.resizeProxy = new E(cs[6]);
47411 this.headerSelector = String.format(
47412 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
47413 this.lockedHd.id, this.mainHd.id
47416 this.splitterSelector = String.format(
47417 '#{0} div.x-grid-split, #{1} div.x-grid-split',
47418 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
47421 idToCssName : function(s)
47423 return s.replace(/[^a-z0-9]+/ig, '-');
47426 getHeaderCell : function(index){
47427 return Roo.DomQuery.select(this.headerSelector)[index];
47430 getHeaderCellMeasure : function(index){
47431 return this.getHeaderCell(index).firstChild;
47434 getHeaderCellText : function(index){
47435 return this.getHeaderCell(index).firstChild.firstChild;
47438 getLockedTable : function(){
47439 return this.lockedBody.dom.firstChild;
47442 getBodyTable : function(){
47443 return this.mainBody.dom.firstChild;
47446 getLockedRow : function(index){
47447 return this.getLockedTable().rows[index];
47450 getRow : function(index){
47451 return this.getBodyTable().rows[index];
47454 getRowComposite : function(index){
47456 this.rowEl = new Roo.CompositeElementLite();
47458 var els = [], lrow, mrow;
47459 if(lrow = this.getLockedRow(index)){
47462 if(mrow = this.getRow(index)){
47465 this.rowEl.elements = els;
47469 getCell : function(rowIndex, colIndex){
47470 var locked = this.cm.getLockedCount();
47472 if(colIndex < locked){
47473 source = this.lockedBody.dom.firstChild;
47475 source = this.mainBody.dom.firstChild;
47476 colIndex -= locked;
47478 return source.rows[rowIndex].childNodes[colIndex];
47481 getCellText : function(rowIndex, colIndex){
47482 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
47485 getCellBox : function(cell){
47486 var b = this.fly(cell).getBox();
47487 if(Roo.isOpera){ // opera fails to report the Y
47488 b.y = cell.offsetTop + this.mainBody.getY();
47493 getCellIndex : function(cell){
47494 var id = String(cell.className).match(this.cellRE);
47496 return parseInt(id[1], 10);
47501 findHeaderIndex : function(n){
47502 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47503 return r ? this.getCellIndex(r) : false;
47506 findHeaderCell : function(n){
47507 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47508 return r ? r : false;
47511 findRowIndex : function(n){
47515 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
47516 return r ? r.rowIndex : false;
47519 findCellIndex : function(node){
47520 var stop = this.el.dom;
47521 while(node && node != stop){
47522 if(this.findRE.test(node.className)){
47523 return this.getCellIndex(node);
47525 node = node.parentNode;
47530 getColumnId : function(index){
47531 return this.cm.getColumnId(index);
47534 getSplitters : function(){
47535 if(this.splitterSelector){
47536 return Roo.DomQuery.select(this.splitterSelector);
47542 getSplitter : function(index){
47543 return this.getSplitters()[index];
47546 onRowOver : function(e, t){
47548 if((row = this.findRowIndex(t)) !== false){
47549 this.getRowComposite(row).addClass("x-grid-row-over");
47553 onRowOut : function(e, t){
47555 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
47556 this.getRowComposite(row).removeClass("x-grid-row-over");
47560 renderHeaders : function(){
47562 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
47563 var cb = [], lb = [], sb = [], lsb = [], p = {};
47564 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47565 p.cellId = "x-grid-hd-0-" + i;
47566 p.splitId = "x-grid-csplit-0-" + i;
47567 p.id = cm.getColumnId(i);
47568 p.title = cm.getColumnTooltip(i) || "";
47569 p.value = cm.getColumnHeader(i) || "";
47570 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
47571 if(!cm.isLocked(i)){
47572 cb[cb.length] = ct.apply(p);
47573 sb[sb.length] = st.apply(p);
47575 lb[lb.length] = ct.apply(p);
47576 lsb[lsb.length] = st.apply(p);
47579 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
47580 ht.apply({cells: cb.join(""), splits:sb.join("")})];
47583 updateHeaders : function(){
47584 var html = this.renderHeaders();
47585 this.lockedHd.update(html[0]);
47586 this.mainHd.update(html[1]);
47590 * Focuses the specified row.
47591 * @param {Number} row The row index
47593 focusRow : function(row){
47594 var x = this.scroller.dom.scrollLeft;
47595 this.focusCell(row, 0, false);
47596 this.scroller.dom.scrollLeft = x;
47600 * Focuses the specified cell.
47601 * @param {Number} row The row index
47602 * @param {Number} col The column index
47603 * @param {Boolean} hscroll false to disable horizontal scrolling
47605 focusCell : function(row, col, hscroll){
47606 var el = this.ensureVisible(row, col, hscroll);
47607 this.focusEl.alignTo(el, "tl-tl");
47609 this.focusEl.focus();
47611 this.focusEl.focus.defer(1, this.focusEl);
47616 * Scrolls the specified cell into view
47617 * @param {Number} row The row index
47618 * @param {Number} col The column index
47619 * @param {Boolean} hscroll false to disable horizontal scrolling
47621 ensureVisible : function(row, col, hscroll){
47622 if(typeof row != "number"){
47623 row = row.rowIndex;
47625 if(row < 0 && row >= this.ds.getCount()){
47628 col = (col !== undefined ? col : 0);
47629 var cm = this.grid.colModel;
47630 while(cm.isHidden(col)){
47634 var el = this.getCell(row, col);
47638 var c = this.scroller.dom;
47640 var ctop = parseInt(el.offsetTop, 10);
47641 var cleft = parseInt(el.offsetLeft, 10);
47642 var cbot = ctop + el.offsetHeight;
47643 var cright = cleft + el.offsetWidth;
47645 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
47646 var stop = parseInt(c.scrollTop, 10);
47647 var sleft = parseInt(c.scrollLeft, 10);
47648 var sbot = stop + ch;
47649 var sright = sleft + c.clientWidth;
47652 c.scrollTop = ctop;
47653 }else if(cbot > sbot){
47654 c.scrollTop = cbot-ch;
47657 if(hscroll !== false){
47659 c.scrollLeft = cleft;
47660 }else if(cright > sright){
47661 c.scrollLeft = cright-c.clientWidth;
47667 updateColumns : function(){
47668 this.grid.stopEditing();
47669 var cm = this.grid.colModel, colIds = this.getColumnIds();
47670 //var totalWidth = cm.getTotalWidth();
47672 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47673 //if(cm.isHidden(i)) continue;
47674 var w = cm.getColumnWidth(i);
47675 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
47676 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
47678 this.updateSplitters();
47681 generateRules : function(cm){
47682 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
47683 Roo.util.CSS.removeStyleSheet(rulesId);
47684 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47685 var cid = cm.getColumnId(i);
47687 if(cm.config[i].align){
47688 align = 'text-align:'+cm.config[i].align+';';
47691 if(cm.isHidden(i)){
47692 hidden = 'display:none;';
47694 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
47696 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
47697 this.hdSelector, cid, " {\n", align, width, "}\n",
47698 this.tdSelector, cid, " {\n",hidden,"\n}\n",
47699 this.splitSelector, cid, " {\n", hidden , "\n}\n");
47701 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
47704 updateSplitters : function(){
47705 var cm = this.cm, s = this.getSplitters();
47706 if(s){ // splitters not created yet
47707 var pos = 0, locked = true;
47708 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47709 if(cm.isHidden(i)) continue;
47710 var w = cm.getColumnWidth(i);
47711 if(!cm.isLocked(i) && locked){
47716 s[i].style.left = (pos-this.splitOffset) + "px";
47721 handleHiddenChange : function(colModel, colIndex, hidden){
47723 this.hideColumn(colIndex);
47725 this.unhideColumn(colIndex);
47729 hideColumn : function(colIndex){
47730 var cid = this.getColumnId(colIndex);
47731 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
47732 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
47734 this.updateHeaders();
47736 this.updateSplitters();
47740 unhideColumn : function(colIndex){
47741 var cid = this.getColumnId(colIndex);
47742 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
47743 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
47746 this.updateHeaders();
47748 this.updateSplitters();
47752 insertRows : function(dm, firstRow, lastRow, isUpdate){
47753 if(firstRow == 0 && lastRow == dm.getCount()-1){
47757 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
47759 var s = this.getScrollState();
47760 var markup = this.renderRows(firstRow, lastRow);
47761 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
47762 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
47763 this.restoreScroll(s);
47765 this.fireEvent("rowsinserted", this, firstRow, lastRow);
47766 this.syncRowHeights(firstRow, lastRow);
47767 this.stripeRows(firstRow);
47773 bufferRows : function(markup, target, index){
47774 var before = null, trows = target.rows, tbody = target.tBodies[0];
47775 if(index < trows.length){
47776 before = trows[index];
47778 var b = document.createElement("div");
47779 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
47780 var rows = b.firstChild.rows;
47781 for(var i = 0, len = rows.length; i < len; i++){
47783 tbody.insertBefore(rows[0], before);
47785 tbody.appendChild(rows[0]);
47792 deleteRows : function(dm, firstRow, lastRow){
47793 if(dm.getRowCount()<1){
47794 this.fireEvent("beforerefresh", this);
47795 this.mainBody.update("");
47796 this.lockedBody.update("");
47797 this.fireEvent("refresh", this);
47799 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
47800 var bt = this.getBodyTable();
47801 var tbody = bt.firstChild;
47802 var rows = bt.rows;
47803 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
47804 tbody.removeChild(rows[firstRow]);
47806 this.stripeRows(firstRow);
47807 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
47811 updateRows : function(dataSource, firstRow, lastRow){
47812 var s = this.getScrollState();
47814 this.restoreScroll(s);
47817 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
47821 this.updateHeaderSortState();
47824 getScrollState : function(){
47825 var sb = this.scroller.dom;
47826 return {left: sb.scrollLeft, top: sb.scrollTop};
47829 stripeRows : function(startRow){
47830 if(!this.grid.stripeRows || this.ds.getCount() < 1){
47833 startRow = startRow || 0;
47834 var rows = this.getBodyTable().rows;
47835 var lrows = this.getLockedTable().rows;
47836 var cls = ' x-grid-row-alt ';
47837 for(var i = startRow, len = rows.length; i < len; i++){
47838 var row = rows[i], lrow = lrows[i];
47839 var isAlt = ((i+1) % 2 == 0);
47840 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
47841 if(isAlt == hasAlt){
47845 row.className += " x-grid-row-alt";
47847 row.className = row.className.replace("x-grid-row-alt", "");
47850 lrow.className = row.className;
47855 restoreScroll : function(state){
47856 var sb = this.scroller.dom;
47857 sb.scrollLeft = state.left;
47858 sb.scrollTop = state.top;
47862 syncScroll : function(){
47863 var sb = this.scroller.dom;
47864 var sh = this.mainHd.dom;
47865 var bs = this.mainBody.dom;
47866 var lv = this.lockedBody.dom;
47867 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
47868 lv.scrollTop = bs.scrollTop = sb.scrollTop;
47871 handleScroll : function(e){
47873 var sb = this.scroller.dom;
47874 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
47878 handleWheel : function(e){
47879 var d = e.getWheelDelta();
47880 this.scroller.dom.scrollTop -= d*22;
47881 // set this here to prevent jumpy scrolling on large tables
47882 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
47886 renderRows : function(startRow, endRow){
47887 // pull in all the crap needed to render rows
47888 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
47889 var colCount = cm.getColumnCount();
47891 if(ds.getCount() < 1){
47895 // build a map for all the columns
47897 for(var i = 0; i < colCount; i++){
47898 var name = cm.getDataIndex(i);
47900 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
47901 renderer : cm.getRenderer(i),
47902 id : cm.getColumnId(i),
47903 locked : cm.isLocked(i)
47907 startRow = startRow || 0;
47908 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
47910 // records to render
47911 var rs = ds.getRange(startRow, endRow);
47913 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
47916 // As much as I hate to duplicate code, this was branched because FireFox really hates
47917 // [].join("") on strings. The performance difference was substantial enough to
47918 // branch this function
47919 doRender : Roo.isGecko ?
47920 function(cs, rs, ds, startRow, colCount, stripe){
47921 var ts = this.templates, ct = ts.cell, rt = ts.row;
47923 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
47924 for(var j = 0, len = rs.length; j < len; j++){
47925 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
47926 for(var i = 0; i < colCount; i++){
47928 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
47930 p.css = p.attr = "";
47931 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
47932 if(p.value == undefined || p.value === "") p.value = " ";
47933 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
47934 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47936 var markup = ct.apply(p);
47944 if(stripe && ((rowIndex+1) % 2 == 0)){
47945 alt[0] = "x-grid-row-alt";
47948 alt[1] = " x-grid-dirty-row";
47951 if(this.getRowClass){
47952 alt[2] = this.getRowClass(r, rowIndex);
47954 rp.alt = alt.join(" ");
47955 lbuf+= rt.apply(rp);
47957 buf+= rt.apply(rp);
47959 return [lbuf, buf];
47961 function(cs, rs, ds, startRow, colCount, stripe){
47962 var ts = this.templates, ct = ts.cell, rt = ts.row;
47964 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
47965 for(var j = 0, len = rs.length; j < len; j++){
47966 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
47967 for(var i = 0; i < colCount; i++){
47969 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
47971 p.css = p.attr = "";
47972 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
47973 if(p.value == undefined || p.value === "") p.value = " ";
47974 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
47975 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47977 var markup = ct.apply(p);
47979 cb[cb.length] = markup;
47981 lcb[lcb.length] = markup;
47985 if(stripe && ((rowIndex+1) % 2 == 0)){
47986 alt[0] = "x-grid-row-alt";
47989 alt[1] = " x-grid-dirty-row";
47992 if(this.getRowClass){
47993 alt[2] = this.getRowClass(r, rowIndex);
47995 rp.alt = alt.join(" ");
47996 rp.cells = lcb.join("");
47997 lbuf[lbuf.length] = rt.apply(rp);
47998 rp.cells = cb.join("");
47999 buf[buf.length] = rt.apply(rp);
48001 return [lbuf.join(""), buf.join("")];
48004 renderBody : function(){
48005 var markup = this.renderRows();
48006 var bt = this.templates.body;
48007 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
48011 * Refreshes the grid
48012 * @param {Boolean} headersToo
48014 refresh : function(headersToo){
48015 this.fireEvent("beforerefresh", this);
48016 this.grid.stopEditing();
48017 var result = this.renderBody();
48018 this.lockedBody.update(result[0]);
48019 this.mainBody.update(result[1]);
48020 if(headersToo === true){
48021 this.updateHeaders();
48022 this.updateColumns();
48023 this.updateSplitters();
48024 this.updateHeaderSortState();
48026 this.syncRowHeights();
48028 this.fireEvent("refresh", this);
48031 handleColumnMove : function(cm, oldIndex, newIndex){
48032 this.indexMap = null;
48033 var s = this.getScrollState();
48034 this.refresh(true);
48035 this.restoreScroll(s);
48036 this.afterMove(newIndex);
48039 afterMove : function(colIndex){
48040 if(this.enableMoveAnim && Roo.enableFx){
48041 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
48045 updateCell : function(dm, rowIndex, dataIndex){
48046 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
48047 if(typeof colIndex == "undefined"){ // not present in grid
48050 var cm = this.grid.colModel;
48051 var cell = this.getCell(rowIndex, colIndex);
48052 var cellText = this.getCellText(rowIndex, colIndex);
48055 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
48056 id : cm.getColumnId(colIndex),
48057 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
48059 var renderer = cm.getRenderer(colIndex);
48060 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
48061 if(typeof val == "undefined" || val === "") val = " ";
48062 cellText.innerHTML = val;
48063 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
48064 this.syncRowHeights(rowIndex, rowIndex);
48067 calcColumnWidth : function(colIndex, maxRowsToMeasure){
48069 if(this.grid.autoSizeHeaders){
48070 var h = this.getHeaderCellMeasure(colIndex);
48071 maxWidth = Math.max(maxWidth, h.scrollWidth);
48074 if(this.cm.isLocked(colIndex)){
48075 tb = this.getLockedTable();
48078 tb = this.getBodyTable();
48079 index = colIndex - this.cm.getLockedCount();
48082 var rows = tb.rows;
48083 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
48084 for(var i = 0; i < stopIndex; i++){
48085 var cell = rows[i].childNodes[index].firstChild;
48086 maxWidth = Math.max(maxWidth, cell.scrollWidth);
48089 return maxWidth + /*margin for error in IE*/ 5;
48092 * Autofit a column to its content.
48093 * @param {Number} colIndex
48094 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
48096 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
48097 if(this.cm.isHidden(colIndex)){
48098 return; // can't calc a hidden column
48101 var cid = this.cm.getColumnId(colIndex);
48102 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
48103 if(this.grid.autoSizeHeaders){
48104 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
48107 var newWidth = this.calcColumnWidth(colIndex);
48108 this.cm.setColumnWidth(colIndex,
48109 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
48110 if(!suppressEvent){
48111 this.grid.fireEvent("columnresize", colIndex, newWidth);
48116 * Autofits all columns to their content and then expands to fit any extra space in the grid
48118 autoSizeColumns : function(){
48119 var cm = this.grid.colModel;
48120 var colCount = cm.getColumnCount();
48121 for(var i = 0; i < colCount; i++){
48122 this.autoSizeColumn(i, true, true);
48124 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
48127 this.updateColumns();
48133 * Autofits all columns to the grid's width proportionate with their current size
48134 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
48136 fitColumns : function(reserveScrollSpace){
48137 var cm = this.grid.colModel;
48138 var colCount = cm.getColumnCount();
48142 for (i = 0; i < colCount; i++){
48143 if(!cm.isHidden(i) && !cm.isFixed(i)){
48144 w = cm.getColumnWidth(i);
48150 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
48151 if(reserveScrollSpace){
48154 var frac = (avail - cm.getTotalWidth())/width;
48155 while (cols.length){
48158 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
48160 this.updateColumns();
48164 onRowSelect : function(rowIndex){
48165 var row = this.getRowComposite(rowIndex);
48166 row.addClass("x-grid-row-selected");
48169 onRowDeselect : function(rowIndex){
48170 var row = this.getRowComposite(rowIndex);
48171 row.removeClass("x-grid-row-selected");
48174 onCellSelect : function(row, col){
48175 var cell = this.getCell(row, col);
48177 Roo.fly(cell).addClass("x-grid-cell-selected");
48181 onCellDeselect : function(row, col){
48182 var cell = this.getCell(row, col);
48184 Roo.fly(cell).removeClass("x-grid-cell-selected");
48188 updateHeaderSortState : function(){
48189 var state = this.ds.getSortState();
48193 this.sortState = state;
48194 var sortColumn = this.cm.findColumnIndex(state.field);
48195 if(sortColumn != -1){
48196 var sortDir = state.direction;
48197 var sc = this.sortClasses;
48198 var hds = this.el.select(this.headerSelector).removeClass(sc);
48199 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
48203 handleHeaderClick : function(g, index){
48204 if(this.headersDisabled){
48207 var dm = g.dataSource, cm = g.colModel;
48208 if(!cm.isSortable(index)){
48212 dm.sort(cm.getDataIndex(index));
48216 destroy : function(){
48218 this.colMenu.removeAll();
48219 Roo.menu.MenuMgr.unregister(this.colMenu);
48220 this.colMenu.getEl().remove();
48221 delete this.colMenu;
48224 this.hmenu.removeAll();
48225 Roo.menu.MenuMgr.unregister(this.hmenu);
48226 this.hmenu.getEl().remove();
48229 if(this.grid.enableColumnMove){
48230 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48232 for(var dd in dds){
48233 if(!dds[dd].config.isTarget && dds[dd].dragElId){
48234 var elid = dds[dd].dragElId;
48236 Roo.get(elid).remove();
48237 } else if(dds[dd].config.isTarget){
48238 dds[dd].proxyTop.remove();
48239 dds[dd].proxyBottom.remove();
48242 if(Roo.dd.DDM.locationCache[dd]){
48243 delete Roo.dd.DDM.locationCache[dd];
48246 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48249 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
48250 this.bind(null, null);
48251 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
48254 handleLockChange : function(){
48255 this.refresh(true);
48258 onDenyColumnLock : function(){
48262 onDenyColumnHide : function(){
48266 handleHdMenuClick : function(item){
48267 var index = this.hdCtxIndex;
48268 var cm = this.cm, ds = this.ds;
48271 ds.sort(cm.getDataIndex(index), "ASC");
48274 ds.sort(cm.getDataIndex(index), "DESC");
48277 var lc = cm.getLockedCount();
48278 if(cm.getColumnCount(true) <= lc+1){
48279 this.onDenyColumnLock();
48283 cm.setLocked(index, true, true);
48284 cm.moveColumn(index, lc);
48285 this.grid.fireEvent("columnmove", index, lc);
48287 cm.setLocked(index, true);
48291 var lc = cm.getLockedCount();
48292 if((lc-1) != index){
48293 cm.setLocked(index, false, true);
48294 cm.moveColumn(index, lc-1);
48295 this.grid.fireEvent("columnmove", index, lc-1);
48297 cm.setLocked(index, false);
48301 index = cm.getIndexById(item.id.substr(4));
48303 if(item.checked && cm.getColumnCount(true) <= 1){
48304 this.onDenyColumnHide();
48307 cm.setHidden(index, item.checked);
48313 beforeColMenuShow : function(){
48314 var cm = this.cm, colCount = cm.getColumnCount();
48315 this.colMenu.removeAll();
48316 for(var i = 0; i < colCount; i++){
48317 this.colMenu.add(new Roo.menu.CheckItem({
48318 id: "col-"+cm.getColumnId(i),
48319 text: cm.getColumnHeader(i),
48320 checked: !cm.isHidden(i),
48326 handleHdCtx : function(g, index, e){
48328 var hd = this.getHeaderCell(index);
48329 this.hdCtxIndex = index;
48330 var ms = this.hmenu.items, cm = this.cm;
48331 ms.get("asc").setDisabled(!cm.isSortable(index));
48332 ms.get("desc").setDisabled(!cm.isSortable(index));
48333 if(this.grid.enableColLock !== false){
48334 ms.get("lock").setDisabled(cm.isLocked(index));
48335 ms.get("unlock").setDisabled(!cm.isLocked(index));
48337 this.hmenu.show(hd, "tl-bl");
48340 handleHdOver : function(e){
48341 var hd = this.findHeaderCell(e.getTarget());
48342 if(hd && !this.headersDisabled){
48343 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
48344 this.fly(hd).addClass("x-grid-hd-over");
48349 handleHdOut : function(e){
48350 var hd = this.findHeaderCell(e.getTarget());
48352 this.fly(hd).removeClass("x-grid-hd-over");
48356 handleSplitDblClick : function(e, t){
48357 var i = this.getCellIndex(t);
48358 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
48359 this.autoSizeColumn(i, true);
48364 render : function(){
48367 var colCount = cm.getColumnCount();
48369 if(this.grid.monitorWindowResize === true){
48370 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48372 var header = this.renderHeaders();
48373 var body = this.templates.body.apply({rows:""});
48374 var html = this.templates.master.apply({
48377 lockedHeader: header[0],
48381 //this.updateColumns();
48383 this.grid.getGridEl().dom.innerHTML = html;
48385 this.initElements();
48387 // a kludge to fix the random scolling effect in webkit
48388 this.el.on("scroll", function() {
48389 this.el.dom.scrollTop=0; // hopefully not recursive..
48392 this.scroller.on("scroll", this.handleScroll, this);
48393 this.lockedBody.on("mousewheel", this.handleWheel, this);
48394 this.mainBody.on("mousewheel", this.handleWheel, this);
48396 this.mainHd.on("mouseover", this.handleHdOver, this);
48397 this.mainHd.on("mouseout", this.handleHdOut, this);
48398 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
48399 {delegate: "."+this.splitClass});
48401 this.lockedHd.on("mouseover", this.handleHdOver, this);
48402 this.lockedHd.on("mouseout", this.handleHdOut, this);
48403 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
48404 {delegate: "."+this.splitClass});
48406 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
48407 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48410 this.updateSplitters();
48412 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
48413 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48414 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48417 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
48418 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
48420 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
48421 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
48423 if(this.grid.enableColLock !== false){
48424 this.hmenu.add('-',
48425 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
48426 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
48429 if(this.grid.enableColumnHide !== false){
48431 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
48432 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
48433 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
48435 this.hmenu.add('-',
48436 {id:"columns", text: this.columnsText, menu: this.colMenu}
48439 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
48441 this.grid.on("headercontextmenu", this.handleHdCtx, this);
48444 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
48445 this.dd = new Roo.grid.GridDragZone(this.grid, {
48446 ddGroup : this.grid.ddGroup || 'GridDD'
48451 for(var i = 0; i < colCount; i++){
48452 if(cm.isHidden(i)){
48453 this.hideColumn(i);
48455 if(cm.config[i].align){
48456 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
48457 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
48461 this.updateHeaderSortState();
48463 this.beforeInitialResize();
48466 // two part rendering gives faster view to the user
48467 this.renderPhase2.defer(1, this);
48470 renderPhase2 : function(){
48471 // render the rows now
48473 if(this.grid.autoSizeColumns){
48474 this.autoSizeColumns();
48478 beforeInitialResize : function(){
48482 onColumnSplitterMoved : function(i, w){
48483 this.userResized = true;
48484 var cm = this.grid.colModel;
48485 cm.setColumnWidth(i, w, true);
48486 var cid = cm.getColumnId(i);
48487 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48488 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48489 this.updateSplitters();
48491 this.grid.fireEvent("columnresize", i, w);
48494 syncRowHeights : function(startIndex, endIndex){
48495 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
48496 startIndex = startIndex || 0;
48497 var mrows = this.getBodyTable().rows;
48498 var lrows = this.getLockedTable().rows;
48499 var len = mrows.length-1;
48500 endIndex = Math.min(endIndex || len, len);
48501 for(var i = startIndex; i <= endIndex; i++){
48502 var m = mrows[i], l = lrows[i];
48503 var h = Math.max(m.offsetHeight, l.offsetHeight);
48504 m.style.height = l.style.height = h + "px";
48509 layout : function(initialRender, is2ndPass){
48511 var auto = g.autoHeight;
48512 var scrollOffset = 16;
48513 var c = g.getGridEl(), cm = this.cm,
48514 expandCol = g.autoExpandColumn,
48516 //c.beginMeasure();
48518 if(!c.dom.offsetWidth){ // display:none?
48520 this.lockedWrap.show();
48521 this.mainWrap.show();
48526 var hasLock = this.cm.isLocked(0);
48528 var tbh = this.headerPanel.getHeight();
48529 var bbh = this.footerPanel.getHeight();
48532 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
48533 var newHeight = ch + c.getBorderWidth("tb");
48535 newHeight = Math.min(g.maxHeight, newHeight);
48537 c.setHeight(newHeight);
48541 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
48544 var s = this.scroller;
48546 var csize = c.getSize(true);
48548 this.el.setSize(csize.width, csize.height);
48550 this.headerPanel.setWidth(csize.width);
48551 this.footerPanel.setWidth(csize.width);
48553 var hdHeight = this.mainHd.getHeight();
48554 var vw = csize.width;
48555 var vh = csize.height - (tbh + bbh);
48559 var bt = this.getBodyTable();
48560 var ltWidth = hasLock ?
48561 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
48563 var scrollHeight = bt.offsetHeight;
48564 var scrollWidth = ltWidth + bt.offsetWidth;
48565 var vscroll = false, hscroll = false;
48567 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
48569 var lw = this.lockedWrap, mw = this.mainWrap;
48570 var lb = this.lockedBody, mb = this.mainBody;
48572 setTimeout(function(){
48573 var t = s.dom.offsetTop;
48574 var w = s.dom.clientWidth,
48575 h = s.dom.clientHeight;
48578 lw.setSize(ltWidth, h);
48580 mw.setLeftTop(ltWidth, t);
48581 mw.setSize(w-ltWidth, h);
48583 lb.setHeight(h-hdHeight);
48584 mb.setHeight(h-hdHeight);
48586 if(is2ndPass !== true && !gv.userResized && expandCol){
48587 // high speed resize without full column calculation
48589 var ci = cm.getIndexById(expandCol);
48591 ci = cm.findColumnIndex(expandCol);
48593 ci = Math.max(0, ci); // make sure it's got at least the first col.
48594 var expandId = cm.getColumnId(ci);
48595 var tw = cm.getTotalWidth(false);
48596 var currentWidth = cm.getColumnWidth(ci);
48597 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
48598 if(currentWidth != cw){
48599 cm.setColumnWidth(ci, cw, true);
48600 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48601 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48602 gv.updateSplitters();
48603 gv.layout(false, true);
48615 onWindowResize : function(){
48616 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
48622 appendFooter : function(parentEl){
48626 sortAscText : "Sort Ascending",
48627 sortDescText : "Sort Descending",
48628 lockText : "Lock Column",
48629 unlockText : "Unlock Column",
48630 columnsText : "Columns"
48634 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
48635 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
48636 this.proxy.el.addClass('x-grid3-col-dd');
48639 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
48640 handleMouseDown : function(e){
48644 callHandleMouseDown : function(e){
48645 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
48650 * Ext JS Library 1.1.1
48651 * Copyright(c) 2006-2007, Ext JS, LLC.
48653 * Originally Released Under LGPL - original licence link has changed is not relivant.
48656 * <script type="text/javascript">
48660 // This is a support class used internally by the Grid components
48661 Roo.grid.SplitDragZone = function(grid, hd, hd2){
48663 this.view = grid.getView();
48664 this.proxy = this.view.resizeProxy;
48665 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
48666 "gridSplitters" + this.grid.getGridEl().id, {
48667 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
48669 this.setHandleElId(Roo.id(hd));
48670 this.setOuterHandleElId(Roo.id(hd2));
48671 this.scroll = false;
48673 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
48674 fly: Roo.Element.fly,
48676 b4StartDrag : function(x, y){
48677 this.view.headersDisabled = true;
48678 this.proxy.setHeight(this.view.mainWrap.getHeight());
48679 var w = this.cm.getColumnWidth(this.cellIndex);
48680 var minw = Math.max(w-this.grid.minColumnWidth, 0);
48681 this.resetConstraints();
48682 this.setXConstraint(minw, 1000);
48683 this.setYConstraint(0, 0);
48684 this.minX = x - minw;
48685 this.maxX = x + 1000;
48687 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
48691 handleMouseDown : function(e){
48692 ev = Roo.EventObject.setEvent(e);
48693 var t = this.fly(ev.getTarget());
48694 if(t.hasClass("x-grid-split")){
48695 this.cellIndex = this.view.getCellIndex(t.dom);
48696 this.split = t.dom;
48697 this.cm = this.grid.colModel;
48698 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
48699 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
48704 endDrag : function(e){
48705 this.view.headersDisabled = false;
48706 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
48707 var diff = endX - this.startPos;
48708 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
48711 autoOffset : function(){
48712 this.setDelta(0,0);
48716 * Ext JS Library 1.1.1
48717 * Copyright(c) 2006-2007, Ext JS, LLC.
48719 * Originally Released Under LGPL - original licence link has changed is not relivant.
48722 * <script type="text/javascript">
48726 // This is a support class used internally by the Grid components
48727 Roo.grid.GridDragZone = function(grid, config){
48728 this.view = grid.getView();
48729 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
48730 if(this.view.lockedBody){
48731 this.setHandleElId(Roo.id(this.view.mainBody.dom));
48732 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
48734 this.scroll = false;
48736 this.ddel = document.createElement('div');
48737 this.ddel.className = 'x-grid-dd-wrap';
48740 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
48741 ddGroup : "GridDD",
48743 getDragData : function(e){
48744 var t = Roo.lib.Event.getTarget(e);
48745 var rowIndex = this.view.findRowIndex(t);
48746 if(rowIndex !== false){
48747 var sm = this.grid.selModel;
48748 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
48749 // sm.mouseDown(e, t);
48751 if (e.hasModifier()){
48752 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
48754 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
48759 onInitDrag : function(e){
48760 var data = this.dragData;
48761 this.ddel.innerHTML = this.grid.getDragDropText();
48762 this.proxy.update(this.ddel);
48763 // fire start drag?
48766 afterRepair : function(){
48767 this.dragging = false;
48770 getRepairXY : function(e, data){
48774 onEndDrag : function(data, e){
48778 onValidDrop : function(dd, e, id){
48783 beforeInvalidDrop : function(e, id){
48788 * Ext JS Library 1.1.1
48789 * Copyright(c) 2006-2007, Ext JS, LLC.
48791 * Originally Released Under LGPL - original licence link has changed is not relivant.
48794 * <script type="text/javascript">
48799 * @class Roo.grid.ColumnModel
48800 * @extends Roo.util.Observable
48801 * This is the default implementation of a ColumnModel used by the Grid. It defines
48802 * the columns in the grid.
48805 var colModel = new Roo.grid.ColumnModel([
48806 {header: "Ticker", width: 60, sortable: true, locked: true},
48807 {header: "Company Name", width: 150, sortable: true},
48808 {header: "Market Cap.", width: 100, sortable: true},
48809 {header: "$ Sales", width: 100, sortable: true, renderer: money},
48810 {header: "Employees", width: 100, sortable: true, resizable: false}
48815 * The config options listed for this class are options which may appear in each
48816 * individual column definition.
48817 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
48819 * @param {Object} config An Array of column config objects. See this class's
48820 * config objects for details.
48822 Roo.grid.ColumnModel = function(config){
48824 * The config passed into the constructor
48826 this.config = config;
48829 // if no id, create one
48830 // if the column does not have a dataIndex mapping,
48831 // map it to the order it is in the config
48832 for(var i = 0, len = config.length; i < len; i++){
48834 if(typeof c.dataIndex == "undefined"){
48837 if(typeof c.renderer == "string"){
48838 c.renderer = Roo.util.Format[c.renderer];
48840 if(typeof c.id == "undefined"){
48843 if(c.editor && c.editor.xtype){
48844 c.editor = Roo.factory(c.editor, Roo.grid);
48846 if(c.editor && c.editor.isFormField){
48847 c.editor = new Roo.grid.GridEditor(c.editor);
48849 this.lookup[c.id] = c;
48853 * The width of columns which have no width specified (defaults to 100)
48856 this.defaultWidth = 100;
48859 * Default sortable of columns which have no sortable specified (defaults to false)
48862 this.defaultSortable = false;
48866 * @event widthchange
48867 * Fires when the width of a column changes.
48868 * @param {ColumnModel} this
48869 * @param {Number} columnIndex The column index
48870 * @param {Number} newWidth The new width
48872 "widthchange": true,
48874 * @event headerchange
48875 * Fires when the text of a header changes.
48876 * @param {ColumnModel} this
48877 * @param {Number} columnIndex The column index
48878 * @param {Number} newText The new header text
48880 "headerchange": true,
48882 * @event hiddenchange
48883 * Fires when a column is hidden or "unhidden".
48884 * @param {ColumnModel} this
48885 * @param {Number} columnIndex The column index
48886 * @param {Boolean} hidden true if hidden, false otherwise
48888 "hiddenchange": true,
48890 * @event columnmoved
48891 * Fires when a column is moved.
48892 * @param {ColumnModel} this
48893 * @param {Number} oldIndex
48894 * @param {Number} newIndex
48896 "columnmoved" : true,
48898 * @event columlockchange
48899 * Fires when a column's locked state is changed
48900 * @param {ColumnModel} this
48901 * @param {Number} colIndex
48902 * @param {Boolean} locked true if locked
48904 "columnlockchange" : true
48906 Roo.grid.ColumnModel.superclass.constructor.call(this);
48908 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
48910 * @cfg {String} header The header text to display in the Grid view.
48913 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
48914 * {@link Roo.data.Record} definition from which to draw the column's value. If not
48915 * specified, the column's index is used as an index into the Record's data Array.
48918 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
48919 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
48922 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
48923 * Defaults to the value of the {@link #defaultSortable} property.
48924 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
48927 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
48930 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
48933 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
48936 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
48939 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
48940 * given the cell's data value. See {@link #setRenderer}. If not specified, the
48941 * default renderer uses the raw data value.
48944 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
48947 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
48951 * Returns the id of the column at the specified index.
48952 * @param {Number} index The column index
48953 * @return {String} the id
48955 getColumnId : function(index){
48956 return this.config[index].id;
48960 * Returns the column for a specified id.
48961 * @param {String} id The column id
48962 * @return {Object} the column
48964 getColumnById : function(id){
48965 return this.lookup[id];
48970 * Returns the column for a specified dataIndex.
48971 * @param {String} dataIndex The column dataIndex
48972 * @return {Object|Boolean} the column or false if not found
48974 getColumnByDataIndex: function(dataIndex){
48975 var index = this.findColumnIndex(dataIndex);
48976 return index > -1 ? this.config[index] : false;
48980 * Returns the index for a specified column id.
48981 * @param {String} id The column id
48982 * @return {Number} the index, or -1 if not found
48984 getIndexById : function(id){
48985 for(var i = 0, len = this.config.length; i < len; i++){
48986 if(this.config[i].id == id){
48994 * Returns the index for a specified column dataIndex.
48995 * @param {String} dataIndex The column dataIndex
48996 * @return {Number} the index, or -1 if not found
48999 findColumnIndex : function(dataIndex){
49000 for(var i = 0, len = this.config.length; i < len; i++){
49001 if(this.config[i].dataIndex == dataIndex){
49009 moveColumn : function(oldIndex, newIndex){
49010 var c = this.config[oldIndex];
49011 this.config.splice(oldIndex, 1);
49012 this.config.splice(newIndex, 0, c);
49013 this.dataMap = null;
49014 this.fireEvent("columnmoved", this, oldIndex, newIndex);
49017 isLocked : function(colIndex){
49018 return this.config[colIndex].locked === true;
49021 setLocked : function(colIndex, value, suppressEvent){
49022 if(this.isLocked(colIndex) == value){
49025 this.config[colIndex].locked = value;
49026 if(!suppressEvent){
49027 this.fireEvent("columnlockchange", this, colIndex, value);
49031 getTotalLockedWidth : function(){
49032 var totalWidth = 0;
49033 for(var i = 0; i < this.config.length; i++){
49034 if(this.isLocked(i) && !this.isHidden(i)){
49035 this.totalWidth += this.getColumnWidth(i);
49041 getLockedCount : function(){
49042 for(var i = 0, len = this.config.length; i < len; i++){
49043 if(!this.isLocked(i)){
49050 * Returns the number of columns.
49053 getColumnCount : function(visibleOnly){
49054 if(visibleOnly === true){
49056 for(var i = 0, len = this.config.length; i < len; i++){
49057 if(!this.isHidden(i)){
49063 return this.config.length;
49067 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
49068 * @param {Function} fn
49069 * @param {Object} scope (optional)
49070 * @return {Array} result
49072 getColumnsBy : function(fn, scope){
49074 for(var i = 0, len = this.config.length; i < len; i++){
49075 var c = this.config[i];
49076 if(fn.call(scope||this, c, i) === true){
49084 * Returns true if the specified column is sortable.
49085 * @param {Number} col The column index
49086 * @return {Boolean}
49088 isSortable : function(col){
49089 if(typeof this.config[col].sortable == "undefined"){
49090 return this.defaultSortable;
49092 return this.config[col].sortable;
49096 * Returns the rendering (formatting) function defined for the column.
49097 * @param {Number} col The column index.
49098 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
49100 getRenderer : function(col){
49101 if(!this.config[col].renderer){
49102 return Roo.grid.ColumnModel.defaultRenderer;
49104 return this.config[col].renderer;
49108 * Sets the rendering (formatting) function for a column.
49109 * @param {Number} col The column index
49110 * @param {Function} fn The function to use to process the cell's raw data
49111 * to return HTML markup for the grid view. The render function is called with
49112 * the following parameters:<ul>
49113 * <li>Data value.</li>
49114 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
49115 * <li>css A CSS style string to apply to the table cell.</li>
49116 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
49117 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
49118 * <li>Row index</li>
49119 * <li>Column index</li>
49120 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
49122 setRenderer : function(col, fn){
49123 this.config[col].renderer = fn;
49127 * Returns the width for the specified column.
49128 * @param {Number} col The column index
49131 getColumnWidth : function(col){
49132 return this.config[col].width || this.defaultWidth;
49136 * Sets the width for a column.
49137 * @param {Number} col The column index
49138 * @param {Number} width The new width
49140 setColumnWidth : function(col, width, suppressEvent){
49141 this.config[col].width = width;
49142 this.totalWidth = null;
49143 if(!suppressEvent){
49144 this.fireEvent("widthchange", this, col, width);
49149 * Returns the total width of all columns.
49150 * @param {Boolean} includeHidden True to include hidden column widths
49153 getTotalWidth : function(includeHidden){
49154 if(!this.totalWidth){
49155 this.totalWidth = 0;
49156 for(var i = 0, len = this.config.length; i < len; i++){
49157 if(includeHidden || !this.isHidden(i)){
49158 this.totalWidth += this.getColumnWidth(i);
49162 return this.totalWidth;
49166 * Returns the header for the specified column.
49167 * @param {Number} col The column index
49170 getColumnHeader : function(col){
49171 return this.config[col].header;
49175 * Sets the header for a column.
49176 * @param {Number} col The column index
49177 * @param {String} header The new header
49179 setColumnHeader : function(col, header){
49180 this.config[col].header = header;
49181 this.fireEvent("headerchange", this, col, header);
49185 * Returns the tooltip for the specified column.
49186 * @param {Number} col The column index
49189 getColumnTooltip : function(col){
49190 return this.config[col].tooltip;
49193 * Sets the tooltip for a column.
49194 * @param {Number} col The column index
49195 * @param {String} tooltip The new tooltip
49197 setColumnTooltip : function(col, tooltip){
49198 this.config[col].tooltip = tooltip;
49202 * Returns the dataIndex for the specified column.
49203 * @param {Number} col The column index
49206 getDataIndex : function(col){
49207 return this.config[col].dataIndex;
49211 * Sets the dataIndex for a column.
49212 * @param {Number} col The column index
49213 * @param {Number} dataIndex The new dataIndex
49215 setDataIndex : function(col, dataIndex){
49216 this.config[col].dataIndex = dataIndex;
49222 * Returns true if the cell is editable.
49223 * @param {Number} colIndex The column index
49224 * @param {Number} rowIndex The row index
49225 * @return {Boolean}
49227 isCellEditable : function(colIndex, rowIndex){
49228 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
49232 * Returns the editor defined for the cell/column.
49233 * return false or null to disable editing.
49234 * @param {Number} colIndex The column index
49235 * @param {Number} rowIndex The row index
49238 getCellEditor : function(colIndex, rowIndex){
49239 return this.config[colIndex].editor;
49243 * Sets if a column is editable.
49244 * @param {Number} col The column index
49245 * @param {Boolean} editable True if the column is editable
49247 setEditable : function(col, editable){
49248 this.config[col].editable = editable;
49253 * Returns true if the column is hidden.
49254 * @param {Number} colIndex The column index
49255 * @return {Boolean}
49257 isHidden : function(colIndex){
49258 return this.config[colIndex].hidden;
49263 * Returns true if the column width cannot be changed
49265 isFixed : function(colIndex){
49266 return this.config[colIndex].fixed;
49270 * Returns true if the column can be resized
49271 * @return {Boolean}
49273 isResizable : function(colIndex){
49274 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
49277 * Sets if a column is hidden.
49278 * @param {Number} colIndex The column index
49279 * @param {Boolean} hidden True if the column is hidden
49281 setHidden : function(colIndex, hidden){
49282 this.config[colIndex].hidden = hidden;
49283 this.totalWidth = null;
49284 this.fireEvent("hiddenchange", this, colIndex, hidden);
49288 * Sets the editor for a column.
49289 * @param {Number} col The column index
49290 * @param {Object} editor The editor object
49292 setEditor : function(col, editor){
49293 this.config[col].editor = editor;
49297 Roo.grid.ColumnModel.defaultRenderer = function(value){
49298 if(typeof value == "string" && value.length < 1){
49304 // Alias for backwards compatibility
49305 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
49308 * Ext JS Library 1.1.1
49309 * Copyright(c) 2006-2007, Ext JS, LLC.
49311 * Originally Released Under LGPL - original licence link has changed is not relivant.
49314 * <script type="text/javascript">
49318 * @class Roo.grid.AbstractSelectionModel
49319 * @extends Roo.util.Observable
49320 * Abstract base class for grid SelectionModels. It provides the interface that should be
49321 * implemented by descendant classes. This class should not be directly instantiated.
49324 Roo.grid.AbstractSelectionModel = function(){
49325 this.locked = false;
49326 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
49329 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
49330 /** @ignore Called by the grid automatically. Do not call directly. */
49331 init : function(grid){
49337 * Locks the selections.
49340 this.locked = true;
49344 * Unlocks the selections.
49346 unlock : function(){
49347 this.locked = false;
49351 * Returns true if the selections are locked.
49352 * @return {Boolean}
49354 isLocked : function(){
49355 return this.locked;
49359 * Ext JS Library 1.1.1
49360 * Copyright(c) 2006-2007, Ext JS, LLC.
49362 * Originally Released Under LGPL - original licence link has changed is not relivant.
49365 * <script type="text/javascript">
49368 * @extends Roo.grid.AbstractSelectionModel
49369 * @class Roo.grid.RowSelectionModel
49370 * The default SelectionModel used by {@link Roo.grid.Grid}.
49371 * It supports multiple selections and keyboard selection/navigation.
49373 * @param {Object} config
49375 Roo.grid.RowSelectionModel = function(config){
49376 Roo.apply(this, config);
49377 this.selections = new Roo.util.MixedCollection(false, function(o){
49382 this.lastActive = false;
49386 * @event selectionchange
49387 * Fires when the selection changes
49388 * @param {SelectionModel} this
49390 "selectionchange" : true,
49392 * @event afterselectionchange
49393 * Fires after the selection changes (eg. by key press or clicking)
49394 * @param {SelectionModel} this
49396 "afterselectionchange" : true,
49398 * @event beforerowselect
49399 * Fires when a row is selected being selected, return false to cancel.
49400 * @param {SelectionModel} this
49401 * @param {Number} rowIndex The selected index
49402 * @param {Boolean} keepExisting False if other selections will be cleared
49404 "beforerowselect" : true,
49407 * Fires when a row is selected.
49408 * @param {SelectionModel} this
49409 * @param {Number} rowIndex The selected index
49410 * @param {Roo.data.Record} r The record
49412 "rowselect" : true,
49414 * @event rowdeselect
49415 * Fires when a row is deselected.
49416 * @param {SelectionModel} this
49417 * @param {Number} rowIndex The selected index
49419 "rowdeselect" : true
49421 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
49422 this.locked = false;
49425 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
49427 * @cfg {Boolean} singleSelect
49428 * True to allow selection of only one row at a time (defaults to false)
49430 singleSelect : false,
49433 initEvents : function(){
49435 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
49436 this.grid.on("mousedown", this.handleMouseDown, this);
49437 }else{ // allow click to work like normal
49438 this.grid.on("rowclick", this.handleDragableRowClick, this);
49441 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
49442 "up" : function(e){
49444 this.selectPrevious(e.shiftKey);
49445 }else if(this.last !== false && this.lastActive !== false){
49446 var last = this.last;
49447 this.selectRange(this.last, this.lastActive-1);
49448 this.grid.getView().focusRow(this.lastActive);
49449 if(last !== false){
49453 this.selectFirstRow();
49455 this.fireEvent("afterselectionchange", this);
49457 "down" : function(e){
49459 this.selectNext(e.shiftKey);
49460 }else if(this.last !== false && this.lastActive !== false){
49461 var last = this.last;
49462 this.selectRange(this.last, this.lastActive+1);
49463 this.grid.getView().focusRow(this.lastActive);
49464 if(last !== false){
49468 this.selectFirstRow();
49470 this.fireEvent("afterselectionchange", this);
49475 var view = this.grid.view;
49476 view.on("refresh", this.onRefresh, this);
49477 view.on("rowupdated", this.onRowUpdated, this);
49478 view.on("rowremoved", this.onRemove, this);
49482 onRefresh : function(){
49483 var ds = this.grid.dataSource, i, v = this.grid.view;
49484 var s = this.selections;
49485 s.each(function(r){
49486 if((i = ds.indexOfId(r.id)) != -1){
49495 onRemove : function(v, index, r){
49496 this.selections.remove(r);
49500 onRowUpdated : function(v, index, r){
49501 if(this.isSelected(r)){
49502 v.onRowSelect(index);
49508 * @param {Array} records The records to select
49509 * @param {Boolean} keepExisting (optional) True to keep existing selections
49511 selectRecords : function(records, keepExisting){
49513 this.clearSelections();
49515 var ds = this.grid.dataSource;
49516 for(var i = 0, len = records.length; i < len; i++){
49517 this.selectRow(ds.indexOf(records[i]), true);
49522 * Gets the number of selected rows.
49525 getCount : function(){
49526 return this.selections.length;
49530 * Selects the first row in the grid.
49532 selectFirstRow : function(){
49537 * Select the last row.
49538 * @param {Boolean} keepExisting (optional) True to keep existing selections
49540 selectLastRow : function(keepExisting){
49541 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
49545 * Selects the row immediately following the last selected row.
49546 * @param {Boolean} keepExisting (optional) True to keep existing selections
49548 selectNext : function(keepExisting){
49549 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
49550 this.selectRow(this.last+1, keepExisting);
49551 this.grid.getView().focusRow(this.last);
49556 * Selects the row that precedes the last selected row.
49557 * @param {Boolean} keepExisting (optional) True to keep existing selections
49559 selectPrevious : function(keepExisting){
49561 this.selectRow(this.last-1, keepExisting);
49562 this.grid.getView().focusRow(this.last);
49567 * Returns the selected records
49568 * @return {Array} Array of selected records
49570 getSelections : function(){
49571 return [].concat(this.selections.items);
49575 * Returns the first selected record.
49578 getSelected : function(){
49579 return this.selections.itemAt(0);
49584 * Clears all selections.
49586 clearSelections : function(fast){
49587 if(this.locked) return;
49589 var ds = this.grid.dataSource;
49590 var s = this.selections;
49591 s.each(function(r){
49592 this.deselectRow(ds.indexOfId(r.id));
49596 this.selections.clear();
49603 * Selects all rows.
49605 selectAll : function(){
49606 if(this.locked) return;
49607 this.selections.clear();
49608 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
49609 this.selectRow(i, true);
49614 * Returns True if there is a selection.
49615 * @return {Boolean}
49617 hasSelection : function(){
49618 return this.selections.length > 0;
49622 * Returns True if the specified row is selected.
49623 * @param {Number/Record} record The record or index of the record to check
49624 * @return {Boolean}
49626 isSelected : function(index){
49627 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
49628 return (r && this.selections.key(r.id) ? true : false);
49632 * Returns True if the specified record id is selected.
49633 * @param {String} id The id of record to check
49634 * @return {Boolean}
49636 isIdSelected : function(id){
49637 return (this.selections.key(id) ? true : false);
49641 handleMouseDown : function(e, t){
49642 var view = this.grid.getView(), rowIndex;
49643 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
49646 if(e.shiftKey && this.last !== false){
49647 var last = this.last;
49648 this.selectRange(last, rowIndex, e.ctrlKey);
49649 this.last = last; // reset the last
49650 view.focusRow(rowIndex);
49652 var isSelected = this.isSelected(rowIndex);
49653 if(e.button !== 0 && isSelected){
49654 view.focusRow(rowIndex);
49655 }else if(e.ctrlKey && isSelected){
49656 this.deselectRow(rowIndex);
49657 }else if(!isSelected){
49658 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
49659 view.focusRow(rowIndex);
49662 this.fireEvent("afterselectionchange", this);
49665 handleDragableRowClick : function(grid, rowIndex, e)
49667 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
49668 this.selectRow(rowIndex, false);
49669 grid.view.focusRow(rowIndex);
49670 this.fireEvent("afterselectionchange", this);
49675 * Selects multiple rows.
49676 * @param {Array} rows Array of the indexes of the row to select
49677 * @param {Boolean} keepExisting (optional) True to keep existing selections
49679 selectRows : function(rows, keepExisting){
49681 this.clearSelections();
49683 for(var i = 0, len = rows.length; i < len; i++){
49684 this.selectRow(rows[i], true);
49689 * Selects a range of rows. All rows in between startRow and endRow are also selected.
49690 * @param {Number} startRow The index of the first row in the range
49691 * @param {Number} endRow The index of the last row in the range
49692 * @param {Boolean} keepExisting (optional) True to retain existing selections
49694 selectRange : function(startRow, endRow, keepExisting){
49695 if(this.locked) return;
49697 this.clearSelections();
49699 if(startRow <= endRow){
49700 for(var i = startRow; i <= endRow; i++){
49701 this.selectRow(i, true);
49704 for(var i = startRow; i >= endRow; i--){
49705 this.selectRow(i, true);
49711 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
49712 * @param {Number} startRow The index of the first row in the range
49713 * @param {Number} endRow The index of the last row in the range
49715 deselectRange : function(startRow, endRow, preventViewNotify){
49716 if(this.locked) return;
49717 for(var i = startRow; i <= endRow; i++){
49718 this.deselectRow(i, preventViewNotify);
49724 * @param {Number} row The index of the row to select
49725 * @param {Boolean} keepExisting (optional) True to keep existing selections
49727 selectRow : function(index, keepExisting, preventViewNotify){
49728 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
49729 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
49730 if(!keepExisting || this.singleSelect){
49731 this.clearSelections();
49733 var r = this.grid.dataSource.getAt(index);
49734 this.selections.add(r);
49735 this.last = this.lastActive = index;
49736 if(!preventViewNotify){
49737 this.grid.getView().onRowSelect(index);
49739 this.fireEvent("rowselect", this, index, r);
49740 this.fireEvent("selectionchange", this);
49746 * @param {Number} row The index of the row to deselect
49748 deselectRow : function(index, preventViewNotify){
49749 if(this.locked) return;
49750 if(this.last == index){
49753 if(this.lastActive == index){
49754 this.lastActive = false;
49756 var r = this.grid.dataSource.getAt(index);
49757 this.selections.remove(r);
49758 if(!preventViewNotify){
49759 this.grid.getView().onRowDeselect(index);
49761 this.fireEvent("rowdeselect", this, index);
49762 this.fireEvent("selectionchange", this);
49766 restoreLast : function(){
49768 this.last = this._last;
49773 acceptsNav : function(row, col, cm){
49774 return !cm.isHidden(col) && cm.isCellEditable(col, row);
49778 onEditorKey : function(field, e){
49779 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
49784 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
49786 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
49788 }else if(k == e.ENTER && !e.ctrlKey){
49792 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
49794 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
49796 }else if(k == e.ESC){
49800 g.startEditing(newCell[0], newCell[1]);
49805 * Ext JS Library 1.1.1
49806 * Copyright(c) 2006-2007, Ext JS, LLC.
49808 * Originally Released Under LGPL - original licence link has changed is not relivant.
49811 * <script type="text/javascript">
49814 * @class Roo.grid.CellSelectionModel
49815 * @extends Roo.grid.AbstractSelectionModel
49816 * This class provides the basic implementation for cell selection in a grid.
49818 * @param {Object} config The object containing the configuration of this model.
49820 Roo.grid.CellSelectionModel = function(config){
49821 Roo.apply(this, config);
49823 this.selection = null;
49827 * @event beforerowselect
49828 * Fires before a cell is selected.
49829 * @param {SelectionModel} this
49830 * @param {Number} rowIndex The selected row index
49831 * @param {Number} colIndex The selected cell index
49833 "beforecellselect" : true,
49835 * @event cellselect
49836 * Fires when a cell is selected.
49837 * @param {SelectionModel} this
49838 * @param {Number} rowIndex The selected row index
49839 * @param {Number} colIndex The selected cell index
49841 "cellselect" : true,
49843 * @event selectionchange
49844 * Fires when the active selection changes.
49845 * @param {SelectionModel} this
49846 * @param {Object} selection null for no selection or an object (o) with two properties
49848 <li>o.record: the record object for the row the selection is in</li>
49849 <li>o.cell: An array of [rowIndex, columnIndex]</li>
49852 "selectionchange" : true
49854 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
49857 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
49860 initEvents : function(){
49861 this.grid.on("mousedown", this.handleMouseDown, this);
49862 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
49863 var view = this.grid.view;
49864 view.on("refresh", this.onViewChange, this);
49865 view.on("rowupdated", this.onRowUpdated, this);
49866 view.on("beforerowremoved", this.clearSelections, this);
49867 view.on("beforerowsinserted", this.clearSelections, this);
49868 if(this.grid.isEditor){
49869 this.grid.on("beforeedit", this.beforeEdit, this);
49874 beforeEdit : function(e){
49875 this.select(e.row, e.column, false, true, e.record);
49879 onRowUpdated : function(v, index, r){
49880 if(this.selection && this.selection.record == r){
49881 v.onCellSelect(index, this.selection.cell[1]);
49886 onViewChange : function(){
49887 this.clearSelections(true);
49891 * Returns the currently selected cell,.
49892 * @return {Array} The selected cell (row, column) or null if none selected.
49894 getSelectedCell : function(){
49895 return this.selection ? this.selection.cell : null;
49899 * Clears all selections.
49900 * @param {Boolean} true to prevent the gridview from being notified about the change.
49902 clearSelections : function(preventNotify){
49903 var s = this.selection;
49905 if(preventNotify !== true){
49906 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
49908 this.selection = null;
49909 this.fireEvent("selectionchange", this, null);
49914 * Returns true if there is a selection.
49915 * @return {Boolean}
49917 hasSelection : function(){
49918 return this.selection ? true : false;
49922 handleMouseDown : function(e, t){
49923 var v = this.grid.getView();
49924 if(this.isLocked()){
49927 var row = v.findRowIndex(t);
49928 var cell = v.findCellIndex(t);
49929 if(row !== false && cell !== false){
49930 this.select(row, cell);
49936 * @param {Number} rowIndex
49937 * @param {Number} collIndex
49939 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
49940 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
49941 this.clearSelections();
49942 r = r || this.grid.dataSource.getAt(rowIndex);
49945 cell : [rowIndex, colIndex]
49947 if(!preventViewNotify){
49948 var v = this.grid.getView();
49949 v.onCellSelect(rowIndex, colIndex);
49950 if(preventFocus !== true){
49951 v.focusCell(rowIndex, colIndex);
49954 this.fireEvent("cellselect", this, rowIndex, colIndex);
49955 this.fireEvent("selectionchange", this, this.selection);
49960 isSelectable : function(rowIndex, colIndex, cm){
49961 return !cm.isHidden(colIndex);
49965 handleKeyDown : function(e){
49966 Roo.log('Cell Sel Model handleKeyDown');
49967 if(!e.isNavKeyPress()){
49970 var g = this.grid, s = this.selection;
49973 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
49975 this.select(cell[0], cell[1]);
49980 var walk = function(row, col, step){
49981 return g.walkCells(row, col, step, sm.isSelectable, sm);
49983 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
49988 // handled by onEditorKey
49989 if (g.isEditor && g.editing) {
49993 newCell = walk(r, c-1, -1);
49995 newCell = walk(r, c+1, 1);
49999 newCell = walk(r+1, c, 1);
50002 newCell = walk(r-1, c, -1);
50005 newCell = walk(r, c+1, 1);
50008 newCell = walk(r, c-1, -1);
50011 if(g.isEditor && !g.editing){
50012 g.startEditing(r, c);
50019 this.select(newCell[0], newCell[1]);
50024 acceptsNav : function(row, col, cm){
50025 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50028 onEditorKey : function(field, e){
50030 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50031 ///Roo.log('onEditorKey' + k);
50035 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50037 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50040 }else if(k == e.ENTER && !e.ctrlKey){
50043 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50044 }else if(k == e.ESC){
50050 //Roo.log('next cell after edit');
50051 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
50056 * Ext JS Library 1.1.1
50057 * Copyright(c) 2006-2007, Ext JS, LLC.
50059 * Originally Released Under LGPL - original licence link has changed is not relivant.
50062 * <script type="text/javascript">
50066 * @class Roo.grid.EditorGrid
50067 * @extends Roo.grid.Grid
50068 * Class for creating and editable grid.
50069 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50070 * The container MUST have some type of size defined for the grid to fill. The container will be
50071 * automatically set to position relative if it isn't already.
50072 * @param {Object} dataSource The data model to bind to
50073 * @param {Object} colModel The column model with info about this grid's columns
50075 Roo.grid.EditorGrid = function(container, config){
50076 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
50077 this.getGridEl().addClass("xedit-grid");
50079 if(!this.selModel){
50080 this.selModel = new Roo.grid.CellSelectionModel();
50083 this.activeEditor = null;
50087 * @event beforeedit
50088 * Fires before cell editing is triggered. The edit event object has the following properties <br />
50089 * <ul style="padding:5px;padding-left:16px;">
50090 * <li>grid - This grid</li>
50091 * <li>record - The record being edited</li>
50092 * <li>field - The field name being edited</li>
50093 * <li>value - The value for the field being edited.</li>
50094 * <li>row - The grid row index</li>
50095 * <li>column - The grid column index</li>
50096 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50098 * @param {Object} e An edit event (see above for description)
50100 "beforeedit" : true,
50103 * Fires after a cell is edited. <br />
50104 * <ul style="padding:5px;padding-left:16px;">
50105 * <li>grid - This grid</li>
50106 * <li>record - The record being edited</li>
50107 * <li>field - The field name being edited</li>
50108 * <li>value - The value being set</li>
50109 * <li>originalValue - The original value for the field, before the edit.</li>
50110 * <li>row - The grid row index</li>
50111 * <li>column - The grid column index</li>
50113 * @param {Object} e An edit event (see above for description)
50115 "afteredit" : true,
50117 * @event validateedit
50118 * Fires after a cell is edited, but before the value is set in the record.
50119 * You can use this to modify the value being set in the field, Return false
50120 * to cancel the change. The edit event object has the following properties <br />
50121 * <ul style="padding:5px;padding-left:16px;">
50122 * <li>editor - This editor</li>
50123 * <li>grid - This grid</li>
50124 * <li>record - The record being edited</li>
50125 * <li>field - The field name being edited</li>
50126 * <li>value - The value being set</li>
50127 * <li>originalValue - The original value for the field, before the edit.</li>
50128 * <li>row - The grid row index</li>
50129 * <li>column - The grid column index</li>
50130 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50132 * @param {Object} e An edit event (see above for description)
50134 "validateedit" : true
50136 this.on("bodyscroll", this.stopEditing, this);
50137 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
50140 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
50142 * @cfg {Number} clicksToEdit
50143 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
50150 trackMouseOver: false, // causes very odd FF errors
50152 onCellDblClick : function(g, row, col){
50153 this.startEditing(row, col);
50156 onEditComplete : function(ed, value, startValue){
50157 this.editing = false;
50158 this.activeEditor = null;
50159 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
50161 var field = this.colModel.getDataIndex(ed.col);
50166 originalValue: startValue,
50173 if(String(value) !== String(startValue)){
50175 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
50176 r.set(field, e.value);
50177 // if we are dealing with a combo box..
50178 // then we also set the 'name' colum to be the displayField
50179 if (ed.field.displayField && ed.field.name) {
50180 r.set(ed.field.name, ed.field.el.dom.value);
50183 delete e.cancel; //?? why!!!
50184 this.fireEvent("afteredit", e);
50187 this.fireEvent("afteredit", e); // always fire it!
50189 this.view.focusCell(ed.row, ed.col);
50193 * Starts editing the specified for the specified row/column
50194 * @param {Number} rowIndex
50195 * @param {Number} colIndex
50197 startEditing : function(row, col){
50198 this.stopEditing();
50199 if(this.colModel.isCellEditable(col, row)){
50200 this.view.ensureVisible(row, col, true);
50201 var r = this.dataSource.getAt(row);
50202 var field = this.colModel.getDataIndex(col);
50207 value: r.data[field],
50212 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
50213 this.editing = true;
50214 var ed = this.colModel.getCellEditor(col, row);
50220 ed.render(ed.parentEl || document.body);
50223 (function(){ // complex but required for focus issues in safari, ie and opera
50227 ed.on("complete", this.onEditComplete, this, {single: true});
50228 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
50229 this.activeEditor = ed;
50230 var v = r.data[field];
50231 ed.startEdit(this.view.getCell(row, col), v);
50232 // combo's with 'displayField and name set
50233 if (ed.field.displayField && ed.field.name) {
50234 ed.field.el.dom.value = r.data[ed.field.name];
50238 }).defer(50, this);
50244 * Stops any active editing
50246 stopEditing : function(){
50247 if(this.activeEditor){
50248 this.activeEditor.completeEdit();
50250 this.activeEditor = null;
50254 * Ext JS Library 1.1.1
50255 * Copyright(c) 2006-2007, Ext JS, LLC.
50257 * Originally Released Under LGPL - original licence link has changed is not relivant.
50260 * <script type="text/javascript">
50263 // private - not really -- you end up using it !
50264 // This is a support class used internally by the Grid components
50267 * @class Roo.grid.GridEditor
50268 * @extends Roo.Editor
50269 * Class for creating and editable grid elements.
50270 * @param {Object} config any settings (must include field)
50272 Roo.grid.GridEditor = function(field, config){
50273 if (!config && field.field) {
50275 field = Roo.factory(config.field, Roo.form);
50277 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
50278 field.monitorTab = false;
50281 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
50284 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
50287 alignment: "tl-tl",
50290 cls: "x-small-editor x-grid-editor",
50295 * Ext JS Library 1.1.1
50296 * Copyright(c) 2006-2007, Ext JS, LLC.
50298 * Originally Released Under LGPL - original licence link has changed is not relivant.
50301 * <script type="text/javascript">
50306 Roo.grid.PropertyRecord = Roo.data.Record.create([
50307 {name:'name',type:'string'}, 'value'
50311 Roo.grid.PropertyStore = function(grid, source){
50313 this.store = new Roo.data.Store({
50314 recordType : Roo.grid.PropertyRecord
50316 this.store.on('update', this.onUpdate, this);
50318 this.setSource(source);
50320 Roo.grid.PropertyStore.superclass.constructor.call(this);
50325 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
50326 setSource : function(o){
50328 this.store.removeAll();
50331 if(this.isEditableValue(o[k])){
50332 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
50335 this.store.loadRecords({records: data}, {}, true);
50338 onUpdate : function(ds, record, type){
50339 if(type == Roo.data.Record.EDIT){
50340 var v = record.data['value'];
50341 var oldValue = record.modified['value'];
50342 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
50343 this.source[record.id] = v;
50345 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
50352 getProperty : function(row){
50353 return this.store.getAt(row);
50356 isEditableValue: function(val){
50357 if(val && val instanceof Date){
50359 }else if(typeof val == 'object' || typeof val == 'function'){
50365 setValue : function(prop, value){
50366 this.source[prop] = value;
50367 this.store.getById(prop).set('value', value);
50370 getSource : function(){
50371 return this.source;
50375 Roo.grid.PropertyColumnModel = function(grid, store){
50378 g.PropertyColumnModel.superclass.constructor.call(this, [
50379 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
50380 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
50382 this.store = store;
50383 this.bselect = Roo.DomHelper.append(document.body, {
50384 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
50385 {tag: 'option', value: 'true', html: 'true'},
50386 {tag: 'option', value: 'false', html: 'false'}
50389 Roo.id(this.bselect);
50392 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
50393 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
50394 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
50395 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
50396 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
50398 this.renderCellDelegate = this.renderCell.createDelegate(this);
50399 this.renderPropDelegate = this.renderProp.createDelegate(this);
50402 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
50406 valueText : 'Value',
50408 dateFormat : 'm/j/Y',
50411 renderDate : function(dateVal){
50412 return dateVal.dateFormat(this.dateFormat);
50415 renderBool : function(bVal){
50416 return bVal ? 'true' : 'false';
50419 isCellEditable : function(colIndex, rowIndex){
50420 return colIndex == 1;
50423 getRenderer : function(col){
50425 this.renderCellDelegate : this.renderPropDelegate;
50428 renderProp : function(v){
50429 return this.getPropertyName(v);
50432 renderCell : function(val){
50434 if(val instanceof Date){
50435 rv = this.renderDate(val);
50436 }else if(typeof val == 'boolean'){
50437 rv = this.renderBool(val);
50439 return Roo.util.Format.htmlEncode(rv);
50442 getPropertyName : function(name){
50443 var pn = this.grid.propertyNames;
50444 return pn && pn[name] ? pn[name] : name;
50447 getCellEditor : function(colIndex, rowIndex){
50448 var p = this.store.getProperty(rowIndex);
50449 var n = p.data['name'], val = p.data['value'];
50451 if(typeof(this.grid.customEditors[n]) == 'string'){
50452 return this.editors[this.grid.customEditors[n]];
50454 if(typeof(this.grid.customEditors[n]) != 'undefined'){
50455 return this.grid.customEditors[n];
50457 if(val instanceof Date){
50458 return this.editors['date'];
50459 }else if(typeof val == 'number'){
50460 return this.editors['number'];
50461 }else if(typeof val == 'boolean'){
50462 return this.editors['boolean'];
50464 return this.editors['string'];
50470 * @class Roo.grid.PropertyGrid
50471 * @extends Roo.grid.EditorGrid
50472 * This class represents the interface of a component based property grid control.
50473 * <br><br>Usage:<pre><code>
50474 var grid = new Roo.grid.PropertyGrid("my-container-id", {
50482 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50483 * The container MUST have some type of size defined for the grid to fill. The container will be
50484 * automatically set to position relative if it isn't already.
50485 * @param {Object} config A config object that sets properties on this grid.
50487 Roo.grid.PropertyGrid = function(container, config){
50488 config = config || {};
50489 var store = new Roo.grid.PropertyStore(this);
50490 this.store = store;
50491 var cm = new Roo.grid.PropertyColumnModel(this, store);
50492 store.store.sort('name', 'ASC');
50493 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
50496 enableColLock:false,
50497 enableColumnMove:false,
50499 trackMouseOver: false,
50502 this.getGridEl().addClass('x-props-grid');
50503 this.lastEditRow = null;
50504 this.on('columnresize', this.onColumnResize, this);
50507 * @event beforepropertychange
50508 * Fires before a property changes (return false to stop?)
50509 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50510 * @param {String} id Record Id
50511 * @param {String} newval New Value
50512 * @param {String} oldval Old Value
50514 "beforepropertychange": true,
50516 * @event propertychange
50517 * Fires after a property changes
50518 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50519 * @param {String} id Record Id
50520 * @param {String} newval New Value
50521 * @param {String} oldval Old Value
50523 "propertychange": true
50525 this.customEditors = this.customEditors || {};
50527 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
50530 * @cfg {Object} customEditors map of colnames=> custom editors.
50531 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
50532 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
50533 * false disables editing of the field.
50537 * @cfg {Object} propertyNames map of property Names to their displayed value
50540 render : function(){
50541 Roo.grid.PropertyGrid.superclass.render.call(this);
50542 this.autoSize.defer(100, this);
50545 autoSize : function(){
50546 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
50548 this.view.fitColumns();
50552 onColumnResize : function(){
50553 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
50557 * Sets the data for the Grid
50558 * accepts a Key => Value object of all the elements avaiable.
50559 * @param {Object} data to appear in grid.
50561 setSource : function(source){
50562 this.store.setSource(source);
50566 * Gets all the data from the grid.
50567 * @return {Object} data data stored in grid
50569 getSource : function(){
50570 return this.store.getSource();
50574 * Ext JS Library 1.1.1
50575 * Copyright(c) 2006-2007, Ext JS, LLC.
50577 * Originally Released Under LGPL - original licence link has changed is not relivant.
50580 * <script type="text/javascript">
50584 * @class Roo.LoadMask
50585 * A simple utility class for generically masking elements while loading data. If the element being masked has
50586 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
50587 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
50588 * element's UpdateManager load indicator and will be destroyed after the initial load.
50590 * Create a new LoadMask
50591 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
50592 * @param {Object} config The config object
50594 Roo.LoadMask = function(el, config){
50595 this.el = Roo.get(el);
50596 Roo.apply(this, config);
50598 this.store.on('beforeload', this.onBeforeLoad, this);
50599 this.store.on('load', this.onLoad, this);
50600 this.store.on('loadexception', this.onLoad, this);
50601 this.removeMask = false;
50603 var um = this.el.getUpdateManager();
50604 um.showLoadIndicator = false; // disable the default indicator
50605 um.on('beforeupdate', this.onBeforeLoad, this);
50606 um.on('update', this.onLoad, this);
50607 um.on('failure', this.onLoad, this);
50608 this.removeMask = true;
50612 Roo.LoadMask.prototype = {
50614 * @cfg {Boolean} removeMask
50615 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
50616 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
50619 * @cfg {String} msg
50620 * The text to display in a centered loading message box (defaults to 'Loading...')
50622 msg : 'Loading...',
50624 * @cfg {String} msgCls
50625 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
50627 msgCls : 'x-mask-loading',
50630 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
50636 * Disables the mask to prevent it from being displayed
50638 disable : function(){
50639 this.disabled = true;
50643 * Enables the mask so that it can be displayed
50645 enable : function(){
50646 this.disabled = false;
50650 onLoad : function(){
50651 this.el.unmask(this.removeMask);
50655 onBeforeLoad : function(){
50656 if(!this.disabled){
50657 this.el.mask(this.msg, this.msgCls);
50662 destroy : function(){
50664 this.store.un('beforeload', this.onBeforeLoad, this);
50665 this.store.un('load', this.onLoad, this);
50666 this.store.un('loadexception', this.onLoad, this);
50668 var um = this.el.getUpdateManager();
50669 um.un('beforeupdate', this.onBeforeLoad, this);
50670 um.un('update', this.onLoad, this);
50671 um.un('failure', this.onLoad, this);
50676 * Ext JS Library 1.1.1
50677 * Copyright(c) 2006-2007, Ext JS, LLC.
50679 * Originally Released Under LGPL - original licence link has changed is not relivant.
50682 * <script type="text/javascript">
50684 Roo.XTemplate = function(){
50685 Roo.XTemplate.superclass.constructor.apply(this, arguments);
50688 s = ['<tpl>', s, '</tpl>'].join('');
50690 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
50692 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
50693 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
50694 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
50698 while(m = s.match(re)){
50699 var m2 = m[0].match(nameRe);
50700 var m3 = m[0].match(ifRe);
50701 var m4 = m[0].match(execRe);
50702 var exp = null, fn = null, exec = null;
50703 var name = m2 && m2[1] ? m2[1] : '';
50705 exp = m3 && m3[1] ? m3[1] : null;
50707 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
50711 exp = m4 && m4[1] ? m4[1] : null;
50713 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
50718 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
50719 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
50720 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
50730 s = s.replace(m[0], '{xtpl'+ id + '}');
50733 for(var i = tpls.length-1; i >= 0; --i){
50734 this.compileTpl(tpls[i]);
50736 this.master = tpls[tpls.length-1];
50739 Roo.extend(Roo.XTemplate, Roo.Template, {
50741 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
50743 applySubTemplate : function(id, values, parent){
50744 var t = this.tpls[id];
50745 if(t.test && !t.test.call(this, values, parent)){
50748 if(t.exec && t.exec.call(this, values, parent)){
50751 var vs = t.target ? t.target.call(this, values, parent) : values;
50752 parent = t.target ? values : parent;
50753 if(t.target && vs instanceof Array){
50755 for(var i = 0, len = vs.length; i < len; i++){
50756 buf[buf.length] = t.compiled.call(this, vs[i], parent);
50758 return buf.join('');
50760 return t.compiled.call(this, vs, parent);
50763 compileTpl : function(tpl){
50764 var fm = Roo.util.Format;
50765 var useF = this.disableFormats !== true;
50766 var sep = Roo.isGecko ? "+" : ",";
50767 var fn = function(m, name, format, args){
50768 if(name.substr(0, 4) == 'xtpl'){
50769 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
50772 if(name.indexOf('.') != -1){
50775 v = "values['" + name + "']";
50777 if(format && useF){
50778 args = args ? ',' + args : "";
50779 if(format.substr(0, 5) != "this."){
50780 format = "fm." + format + '(';
50782 format = 'this.call("'+ format.substr(5) + '", ';
50786 args= ''; format = "("+v+" === undefined ? '' : ";
50788 return "'"+ sep + format + v + args + ")"+sep+"'";
50791 // branched to use + in gecko and [].join() in others
50793 body = "tpl.compiled = function(values, parent){ return '" +
50794 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
50797 body = ["tpl.compiled = function(values, parent){ return ['"];
50798 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
50799 body.push("'].join('');};");
50800 body = body.join('');
50802 /** eval:var:zzzzzzz */
50807 applyTemplate : function(values){
50808 return this.master.compiled.call(this, values, {});
50812 apply : function(){
50813 return this.applyTemplate.apply(this, arguments);
50816 compile : function(){return this;}
50819 Roo.XTemplate.from = function(el){
50820 el = Roo.getDom(el);
50821 return new Roo.XTemplate(el.value || el.innerHTML);
50823 * Original code for Roojs - LGPL
50824 * <script type="text/javascript">
50828 * @class Roo.XComponent
50829 * A delayed Element creator...
50831 * Mypart.xyx = new Roo.XComponent({
50833 parent : 'Mypart.xyz', // empty == document.element.!!
50837 disabled : function() {}
50839 tree : function() { // return an tree of xtype declared components
50843 xtype : 'NestedLayoutPanel',
50848 * @extends Roo.util.Observable
50850 * @param cfg {Object} configuration of component
50853 Roo.XComponent = function(cfg) {
50854 Roo.apply(this, cfg);
50858 * Fires when this the componnt is built
50859 * @param {Roo.XComponent} c the component
50863 * @event buildcomplete
50864 * Fires on the top level element when all elements have been built
50865 * @param {Roo.XComponent} c the top level component.
50867 'buildcomplete' : true
50871 Roo.XComponent.register(this);
50872 this.modules = false;
50873 this.el = false; // where the layout goes..
50877 Roo.extend(Roo.XComponent, Roo.util.Observable, {
50880 * The created element (with Roo.factory())
50881 * @type {Roo.Layout}
50887 * for BC - use el in new code
50888 * @type {Roo.Layout}
50894 * for BC - use el in new code
50895 * @type {Roo.Layout}
50900 * @cfg {Function|boolean} disabled
50901 * If this module is disabled by some rule, return true from the funtion
50906 * @cfg {String} parent
50907 * Name of parent element which it get xtype added to..
50912 * @cfg {String} order
50913 * Used to set the order in which elements are created (usefull for multiple tabs)
50918 * @cfg {String} name
50919 * String to display while loading.
50923 * @cfg {Array} items
50924 * A single item array - the first element is the root of the tree..
50925 * It's done this way to stay compatible with the Xtype system...
50933 Roo.apply(Roo.XComponent, {
50936 * @property buildCompleted
50937 * True when the builder has completed building the interface.
50940 buildCompleted : false,
50943 * @property topModule
50944 * the upper most module - uses document.element as it's constructor.
50951 * @property modules
50952 * array of modules to be created by registration system.
50953 * @type Roo.XComponent
50960 * Register components to be built later.
50962 * This solves the following issues
50963 * - Building is not done on page load, but after an authentication process has occured.
50964 * - Interface elements are registered on page load
50965 * - Parent Interface elements may not be loaded before child, so this handles that..
50972 module : 'Pman.Tab.projectMgr',
50974 parent : 'Pman.layout',
50975 disabled : false, // or use a function..
50978 * * @param {Object} details about module
50980 register : function(obj) {
50981 this.modules.push(obj);
50985 * convert a string to an object..
50989 toObject : function(str)
50991 if (!str || typeof(str) == 'object') {
50994 var ar = str.split('.');
50998 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
51000 throw "Module not found : " + str;
51002 Roo.each(ar, function(e) {
51003 if (typeof(o[e]) == 'undefined') {
51004 throw "Module not found : " + str;
51014 * move modules into their correct place in the tree..
51017 preBuild : function ()
51020 Roo.each(this.modules , function (obj)
51022 obj.parent = this.toObject(obj.parent);
51025 this.topModule = obj;
51029 if (!obj.parent.modules) {
51030 obj.parent.modules = new Roo.util.MixedCollection(false,
51031 function(o) { return o.order + '' }
51035 obj.parent.modules.add(obj);
51040 * make a list of modules to build.
51041 * @return {Array} list of modules.
51044 buildOrder : function()
51047 var cmp = function(a,b) {
51048 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
51051 if (!this.topModule || !this.topModule.modules) {
51052 throw "No top level modules to build";
51055 // make a flat list in order of modules to build.
51056 var mods = [ this.topModule ];
51059 // add modules to their parents..
51060 var addMod = function(m) {
51061 // Roo.debug && Roo.log(m.modKey);
51065 m.modules.keySort('ASC', cmp );
51066 m.modules.each(addMod);
51068 // not sure if this is used any more..
51070 m.finalize.name = m.name + " (clean up) ";
51071 mods.push(m.finalize);
51075 this.topModule.modules.keySort('ASC', cmp );
51076 this.topModule.modules.each(addMod);
51081 * Build the registered modules.
51082 * @param {Object} parent element.
51083 * @param {Function} optional method to call after module has been added.
51091 var mods = this.buildOrder();
51093 //this.allmods = mods;
51094 //Roo.debug && Roo.log(mods);
51096 if (!mods.length) { // should not happen
51097 throw "NO modules!!!";
51102 // flash it up as modal - so we store the mask!?
51103 Roo.MessageBox.show({ title: 'loading' });
51104 Roo.MessageBox.show({
51105 title: "Please wait...",
51106 msg: "Building Interface...",
51113 var total = mods.length;
51116 var progressRun = function() {
51117 if (!mods.length) {
51118 Roo.debug && Roo.log('hide?');
51119 Roo.MessageBox.hide();
51120 _this.topModule.fireEvent('buildcomplete', _this.topModule);
51124 var m = mods.shift();
51125 Roo.debug && Roo.log(m);
51126 if (typeof(m) == 'function') { // not sure if this is supported any more..
51128 return progressRun.defer(10, _this);
51131 Roo.MessageBox.updateProgress(
51132 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
51134 (m.name ? (' - ' + m.name) : '')
51139 var disabled = (typeof(m.disabled) == 'function') ?
51140 m.disabled.call(m.module.disabled) : m.disabled;
51144 return progressRun(); // we do not update the display!
51148 // it's a top level one..
51149 var layoutbase = new Ext.BorderLayout(document.body, {
51155 tabPosition: 'top',
51156 //resizeTabs: true,
51157 alwaysShowTabs: true,
51161 var tree = m.tree();
51162 tree.region = 'center';
51163 m.el = layoutbase.addxtype(tree);
51165 m.layout = m.panel.layout;
51166 return progressRun.defer(10, _this);
51169 var tree = m.tree();
51170 tree.region = tree.region || m.region;
51171 m.el = m.parent.el.addxtype(tree);
51172 m.fireEvent('built', m);
51174 m.layout = m.panel.layout;
51175 progressRun.defer(10, _this);
51178 progressRun.defer(1, _this);
51188 //<script type="text/javascript">
51193 * @extends Roo.LayoutDialog
51194 * A generic Login Dialog..... - only one needed in theory!?!?
51196 * Fires XComponent builder on success...
51199 * username,password, lang = for login actions.
51200 * check = 1 for periodic checking that sesion is valid.
51201 * passwordRequest = email request password
51202 * logout = 1 = to logout
51204 * Affects: (this id="????" elements)
51205 * loading (removed) (used to indicate application is loading)
51206 * loading-mask (hides) (used to hide application when it's building loading)
51212 * Myapp.login = Roo.Login({
51228 Roo.Login = function(cfg)
51234 Roo.apply(this,cfg);
51236 Roo.onReady(function() {
51242 Roo.Login.superclass.constructor.call(this, this);
51243 //this.addxtype(this.items[0]);
51249 Roo.extend(Roo.Login, Roo.LayoutDialog, {
51252 * @cfg {String} method
51253 * Method used to query for login details.
51258 * @cfg {String} url
51259 * URL to query login data. - eg. baseURL + '/Login.php'
51265 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
51270 * @property checkFails
51271 * Number of times we have attempted to get authentication check, and failed.
51276 * @property intervalID
51277 * The window interval that does the constant login checking.
51283 onLoad : function() // called on page load...
51287 if (Roo.get('loading')) { // clear any loading indicator..
51288 Roo.get('loading').remove();
51291 //this.switchLang('en'); // set the language to english..
51294 success: function(response, opts) { // check successfull...
51296 var res = this.processResponse(response);
51297 this.checkFails =0;
51298 if (!res.success) { // error!
51299 this.checkFails = 5;
51300 //console.log('call failure');
51301 return this.failure(response,opts);
51304 if (!res.data.id) { // id=0 == login failure.
51305 return this.show();
51309 //console.log(success);
51310 this.fillAuth(res.data);
51311 this.checkFails =0;
51312 Roo.XComponent.build();
51314 failure : this.show
51320 check: function(cfg) // called every so often to refresh cookie etc..
51322 if (cfg.again) { // could be undefined..
51325 this.checkFails = 0;
51328 if (this.sending) {
51329 if ( this.checkFails > 4) {
51330 Roo.MessageBox.alert("Error",
51331 "Error getting authentication status. - try reloading, or wait a while", function() {
51332 _this.sending = false;
51337 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
51340 this.sending = true;
51347 method: this.method,
51348 success: cfg.success || this.success,
51349 failure : cfg.failure || this.failure,
51359 window.onbeforeunload = function() { }; // false does not work for IE..
51369 failure : function() {
51370 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
51371 document.location = document.location.toString() + '?ts=' + Math.random();
51375 success : function() {
51376 _this.user = false;
51377 this.checkFails =0;
51379 document.location = document.location.toString() + '?ts=' + Math.random();
51386 processResponse : function (response)
51390 res = Roo.decode(response.responseText);
51392 if (typeof(res) != 'object') {
51393 res = { success : false, errorMsg : res, errors : true };
51395 if (typeof(res.success) == 'undefined') {
51396 res.success = false;
51400 res = { success : false, errorMsg : response.responseText, errors : true };
51405 success : function(response, opts) // check successfull...
51407 this.sending = false;
51408 var res = this.processResponse(response);
51409 if (!res.success) {
51410 return this.failure(response, opts);
51412 if (!res.data || !res.data.id) {
51413 return this.failure(response,opts);
51415 //console.log(res);
51416 this.fillAuth(res.data);
51418 this.checkFails =0;
51423 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
51425 this.authUser = -1;
51426 this.sending = false;
51427 var res = this.processResponse(response);
51428 //console.log(res);
51429 if ( this.checkFails > 2) {
51431 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
51432 "Error getting authentication status. - try reloading");
51435 opts.callCfg.again = true;
51436 this.check.defer(1000, this, [ opts.callCfg ]);
51442 fillAuth: function(au) {
51443 this.startAuthCheck();
51444 this.authUserId = au.id;
51445 this.authUser = au;
51446 this.lastChecked = new Date();
51447 this.fireEvent('refreshed', au);
51448 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
51449 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
51450 au.lang = au.lang || 'en';
51451 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
51452 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
51453 this.switchLang(au.lang );
51456 // open system... - -on setyp..
51457 if (this.authUserId < 0) {
51458 Roo.MessageBox.alert("Warning",
51459 "This is an open system - please set up a admin user with a password.");
51462 //Pman.onload(); // which should do nothing if it's a re-auth result...
51467 startAuthCheck : function() // starter for timeout checking..
51469 if (this.intervalID) { // timer already in place...
51473 this.intervalID = window.setInterval(function() {
51474 _this.check(false);
51475 }, 120000); // every 120 secs = 2mins..
51481 switchLang : function (lang)
51483 _T = typeof(_T) == 'undefined' ? false : _T;
51484 if (!_T || !lang.length) {
51488 if (!_T && lang != 'en') {
51489 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51493 if (typeof(_T.en) == 'undefined') {
51495 Roo.apply(_T.en, _T);
51498 if (typeof(_T[lang]) == 'undefined') {
51499 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51504 Roo.apply(_T, _T[lang]);
51505 // just need to set the text values for everything...
51507 /* this will not work ...
51511 function formLabel(name, val) {
51512 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
51515 formLabel('password', "Password"+':');
51516 formLabel('username', "Email Address"+':');
51517 formLabel('lang', "Language"+':');
51518 this.dialog.setTitle("Login");
51519 this.dialog.buttons[0].setText("Forgot Password");
51520 this.dialog.buttons[1].setText("Login");
51539 collapsible: false,
51541 center: { // needed??
51544 // tabPosition: 'top',
51547 alwaysShowTabs: false
51551 show : function(dlg)
51553 //console.log(this);
51554 this.form = this.layout.getRegion('center').activePanel.form;
51555 this.form.dialog = dlg;
51556 this.buttons[0].form = this.form;
51557 this.buttons[0].dialog = dlg;
51558 this.buttons[1].form = this.form;
51559 this.buttons[1].dialog = dlg;
51561 //this.resizeToLogo.defer(1000,this);
51562 // this is all related to resizing for logos..
51563 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
51565 // this.resizeToLogo.defer(1000,this);
51568 //var w = Ext.lib.Dom.getViewWidth() - 100;
51569 //var h = Ext.lib.Dom.getViewHeight() - 100;
51570 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
51572 if (this.disabled) {
51577 if (this.user.id < 0) { // used for inital setup situations.
51581 if (this.intervalID) {
51582 // remove the timer
51583 window.clearInterval(this.intervalID);
51584 this.intervalID = false;
51588 if (Roo.get('loading')) {
51589 Roo.get('loading').remove();
51591 if (Roo.get('loading-mask')) {
51592 Roo.get('loading-mask').hide();
51595 //incomming._node = tnode;
51597 //this.dialog.modal = !modal;
51598 //this.dialog.show();
51602 this.form.setValues({
51603 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
51604 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
51607 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
51608 if (this.form.findField('username').getValue().length > 0 ){
51609 this.form.findField('password').focus();
51611 this.form.findField('username').focus();
51619 xtype : 'ContentPanel',
51631 style : 'margin: 10px;',
51634 actionfailed : function(f, act) {
51635 // form can return { errors: .... }
51637 //act.result.errors // invalid form element list...
51638 //act.result.errorMsg// invalid form element list...
51640 this.dialog.el.unmask();
51641 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
51642 "Login failed - communication error - try again.");
51645 actioncomplete: function(re, act) {
51647 Roo.state.Manager.set(
51648 this.dialog.realm + '.username',
51649 this.findField('username').getValue()
51651 Roo.state.Manager.set(
51652 this.dialog.realm + '.lang',
51653 this.findField('lang').getValue()
51656 this.dialog.fillAuth(act.result.data);
51658 this.dialog.hide();
51660 if (Roo.get('loading-mask')) {
51661 Roo.get('loading-mask').show();
51663 Roo.XComponent.build();
51671 xtype : 'TextField',
51673 fieldLabel: "Email Address",
51676 autoCreate : {tag: "input", type: "text", size: "20"}
51679 xtype : 'TextField',
51681 fieldLabel: "Password",
51682 inputType: 'password',
51685 autoCreate : {tag: "input", type: "text", size: "20"},
51687 specialkey : function(e,ev) {
51688 if (ev.keyCode == 13) {
51689 this.form.dialog.el.mask("Logging in");
51690 this.form.doAction('submit', {
51691 url: this.form.dialog.url,
51692 method: this.form.dialog.method
51699 xtype : 'ComboBox',
51701 fieldLabel: "Language",
51704 xtype : 'SimpleStore',
51705 fields: ['lang', 'ldisp'],
51707 [ 'en', 'English' ],
51708 [ 'zh_HK' , '\u7E41\u4E2D' ],
51709 [ 'zh_CN', '\u7C21\u4E2D' ]
51713 valueField : 'lang',
51714 hiddenName: 'lang',
51716 displayField:'ldisp',
51720 triggerAction: 'all',
51721 emptyText:'Select a Language...',
51722 selectOnFocus:true,
51724 select : function(cb, rec, ix) {
51725 this.form.switchLang(rec.data.lang);
51741 text : "Forgot Password",
51743 click : function() {
51744 //console.log(this);
51745 var n = this.form.findField('username').getValue();
51747 Roo.MessageBox.alert("Error", "Fill in your email address");
51751 url: this.dialog.url,
51755 method: this.dialog.method,
51756 success: function(response, opts) { // check successfull...
51758 var res = this.dialog.processResponse(response);
51759 if (!res.success) { // error!
51760 Roo.MessageBox.alert("Error" ,
51761 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
51764 Roo.MessageBox.alert("Notice" ,
51765 "Please check you email for the Password Reset message");
51767 failure : function() {
51768 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
51781 click : function () {
51783 this.dialog.el.mask("Logging in");
51784 this.form.doAction('submit', {
51785 url: this.dialog.url,
51786 method: this.dialog.method