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} valid
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 this.valid ? this.dropAllowed : this.dropNotAllowed;
18402 notifyOver : function(dd, e, data){
18404 this.fireEvent('over', this, dd, e, data);
18405 return this.valid ? this.dropAllowed : this.dropNotAllowed;
18411 notifyOut : function(dd, e, data){
18412 this.fireEvent('out', this, dd, e, data);
18413 if(this.overClass){
18414 this.el.removeClass(this.overClass);
18421 notifyDrop : function(dd, e, data){
18422 this.success = false;
18423 this.fireEvent('drop', this, dd, e, data);
18424 return this.success;
18428 * Ext JS Library 1.1.1
18429 * Copyright(c) 2006-2007, Ext JS, LLC.
18431 * Originally Released Under LGPL - original licence link has changed is not relivant.
18434 * <script type="text/javascript">
18439 * @class Roo.dd.DragZone
18440 * @extends Roo.dd.DragSource
18441 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18442 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18444 * @param {String/HTMLElement/Element} el The container element
18445 * @param {Object} config
18447 Roo.dd.DragZone = function(el, config){
18448 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18449 if(this.containerScroll){
18450 Roo.dd.ScrollManager.register(this.el);
18454 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18456 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18457 * for auto scrolling during drag operations.
18460 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18461 * method after a failed drop (defaults to "c3daf9" - light blue)
18465 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18466 * for a valid target to drag based on the mouse down. Override this method
18467 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18468 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18469 * @param {EventObject} e The mouse down event
18470 * @return {Object} The dragData
18472 getDragData : function(e){
18473 return Roo.dd.Registry.getHandleFromEvent(e);
18477 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18478 * this.dragData.ddel
18479 * @param {Number} x The x position of the click on the dragged object
18480 * @param {Number} y The y position of the click on the dragged object
18481 * @return {Boolean} true to continue the drag, false to cancel
18483 onInitDrag : function(x, y){
18484 this.proxy.update(this.dragData.ddel.cloneNode(true));
18485 this.onStartDrag(x, y);
18490 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18492 afterRepair : function(){
18494 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18496 this.dragging = false;
18500 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18501 * the XY of this.dragData.ddel
18502 * @param {EventObject} e The mouse up event
18503 * @return {Array} The xy location (e.g. [100, 200])
18505 getRepairXY : function(e){
18506 return Roo.Element.fly(this.dragData.ddel).getXY();
18510 * Ext JS Library 1.1.1
18511 * Copyright(c) 2006-2007, Ext JS, LLC.
18513 * Originally Released Under LGPL - original licence link has changed is not relivant.
18516 * <script type="text/javascript">
18519 * @class Roo.dd.DropZone
18520 * @extends Roo.dd.DropTarget
18521 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18522 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18524 * @param {String/HTMLElement/Element} el The container element
18525 * @param {Object} config
18527 Roo.dd.DropZone = function(el, config){
18528 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18531 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18533 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18534 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18535 * provide your own custom lookup.
18536 * @param {Event} e The event
18537 * @return {Object} data The custom data
18539 getTargetFromEvent : function(e){
18540 return Roo.dd.Registry.getTargetFromEvent(e);
18544 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18545 * that it has registered. This method has no default implementation and should be overridden to provide
18546 * node-specific processing if necessary.
18547 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18548 * {@link #getTargetFromEvent} for this node)
18549 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18550 * @param {Event} e The event
18551 * @param {Object} data An object containing arbitrary data supplied by the drag source
18553 onNodeEnter : function(n, dd, e, data){
18558 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18559 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18560 * overridden to provide the proper feedback.
18561 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18562 * {@link #getTargetFromEvent} for this node)
18563 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18564 * @param {Event} e The event
18565 * @param {Object} data An object containing arbitrary data supplied by the drag source
18566 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18567 * underlying {@link Roo.dd.StatusProxy} can be updated
18569 onNodeOver : function(n, dd, e, data){
18570 return this.dropAllowed;
18574 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18575 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18576 * node-specific processing if necessary.
18577 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18578 * {@link #getTargetFromEvent} for this node)
18579 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18580 * @param {Event} e The event
18581 * @param {Object} data An object containing arbitrary data supplied by the drag source
18583 onNodeOut : function(n, dd, e, data){
18588 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18589 * the drop node. The default implementation returns false, so it should be overridden to provide the
18590 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18591 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18592 * {@link #getTargetFromEvent} for this node)
18593 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18594 * @param {Event} e The event
18595 * @param {Object} data An object containing arbitrary data supplied by the drag source
18596 * @return {Boolean} True if the drop was valid, else false
18598 onNodeDrop : function(n, dd, e, data){
18603 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18604 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18605 * it should be overridden to provide the proper feedback if necessary.
18606 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18607 * @param {Event} e The event
18608 * @param {Object} data An object containing arbitrary data supplied by the drag source
18609 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18610 * underlying {@link Roo.dd.StatusProxy} can be updated
18612 onContainerOver : function(dd, e, data){
18613 return this.dropNotAllowed;
18617 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18618 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18619 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18620 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18621 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18622 * @param {Event} e The event
18623 * @param {Object} data An object containing arbitrary data supplied by the drag source
18624 * @return {Boolean} True if the drop was valid, else false
18626 onContainerDrop : function(dd, e, data){
18631 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18632 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18633 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18634 * you should override this method and provide a custom implementation.
18635 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18636 * @param {Event} e The event
18637 * @param {Object} data An object containing arbitrary data supplied by the drag source
18638 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18639 * underlying {@link Roo.dd.StatusProxy} can be updated
18641 notifyEnter : function(dd, e, data){
18642 return this.dropNotAllowed;
18646 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18647 * This method will be called on every mouse movement while the drag source is over the drop zone.
18648 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18649 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18650 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18651 * registered node, it will call {@link #onContainerOver}.
18652 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18653 * @param {Event} e The event
18654 * @param {Object} data An object containing arbitrary data supplied by the drag source
18655 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18656 * underlying {@link Roo.dd.StatusProxy} can be updated
18658 notifyOver : function(dd, e, data){
18659 var n = this.getTargetFromEvent(e);
18660 if(!n){ // not over valid drop target
18661 if(this.lastOverNode){
18662 this.onNodeOut(this.lastOverNode, dd, e, data);
18663 this.lastOverNode = null;
18665 return this.onContainerOver(dd, e, data);
18667 if(this.lastOverNode != n){
18668 if(this.lastOverNode){
18669 this.onNodeOut(this.lastOverNode, dd, e, data);
18671 this.onNodeEnter(n, dd, e, data);
18672 this.lastOverNode = n;
18674 return this.onNodeOver(n, dd, e, data);
18678 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18679 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18680 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18681 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18682 * @param {Event} e The event
18683 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18685 notifyOut : function(dd, e, data){
18686 if(this.lastOverNode){
18687 this.onNodeOut(this.lastOverNode, dd, e, data);
18688 this.lastOverNode = null;
18693 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18694 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18695 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18696 * otherwise it will call {@link #onContainerDrop}.
18697 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18698 * @param {Event} e The event
18699 * @param {Object} data An object containing arbitrary data supplied by the drag source
18700 * @return {Boolean} True if the drop was valid, else false
18702 notifyDrop : function(dd, e, data){
18703 if(this.lastOverNode){
18704 this.onNodeOut(this.lastOverNode, dd, e, data);
18705 this.lastOverNode = null;
18707 var n = this.getTargetFromEvent(e);
18709 this.onNodeDrop(n, dd, e, data) :
18710 this.onContainerDrop(dd, e, data);
18714 triggerCacheRefresh : function(){
18715 Roo.dd.DDM.refreshCache(this.groups);
18719 * Ext JS Library 1.1.1
18720 * Copyright(c) 2006-2007, Ext JS, LLC.
18722 * Originally Released Under LGPL - original licence link has changed is not relivant.
18725 * <script type="text/javascript">
18730 * @class Roo.data.SortTypes
18732 * Defines the default sorting (casting?) comparison functions used when sorting data.
18734 Roo.data.SortTypes = {
18736 * Default sort that does nothing
18737 * @param {Mixed} s The value being converted
18738 * @return {Mixed} The comparison value
18740 none : function(s){
18745 * The regular expression used to strip tags
18749 stripTagsRE : /<\/?[^>]+>/gi,
18752 * Strips all HTML tags to sort on text only
18753 * @param {Mixed} s The value being converted
18754 * @return {String} The comparison value
18756 asText : function(s){
18757 return String(s).replace(this.stripTagsRE, "");
18761 * Strips all HTML tags to sort on text only - Case insensitive
18762 * @param {Mixed} s The value being converted
18763 * @return {String} The comparison value
18765 asUCText : function(s){
18766 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18770 * Case insensitive string
18771 * @param {Mixed} s The value being converted
18772 * @return {String} The comparison value
18774 asUCString : function(s) {
18775 return String(s).toUpperCase();
18780 * @param {Mixed} s The value being converted
18781 * @return {Number} The comparison value
18783 asDate : function(s) {
18787 if(s instanceof Date){
18788 return s.getTime();
18790 return Date.parse(String(s));
18795 * @param {Mixed} s The value being converted
18796 * @return {Float} The comparison value
18798 asFloat : function(s) {
18799 var val = parseFloat(String(s).replace(/,/g, ""));
18800 if(isNaN(val)) val = 0;
18806 * @param {Mixed} s The value being converted
18807 * @return {Number} The comparison value
18809 asInt : function(s) {
18810 var val = parseInt(String(s).replace(/,/g, ""));
18811 if(isNaN(val)) val = 0;
18816 * Ext JS Library 1.1.1
18817 * Copyright(c) 2006-2007, Ext JS, LLC.
18819 * Originally Released Under LGPL - original licence link has changed is not relivant.
18822 * <script type="text/javascript">
18826 * @class Roo.data.Record
18827 * Instances of this class encapsulate both record <em>definition</em> information, and record
18828 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18829 * to access Records cached in an {@link Roo.data.Store} object.<br>
18831 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18832 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18835 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18837 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18838 * {@link #create}. The parameters are the same.
18839 * @param {Array} data An associative Array of data values keyed by the field name.
18840 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18841 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18842 * not specified an integer id is generated.
18844 Roo.data.Record = function(data, id){
18845 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18850 * Generate a constructor for a specific record layout.
18851 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18852 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18853 * Each field definition object may contain the following properties: <ul>
18854 * <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,
18855 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18856 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18857 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18858 * is being used, then this is a string containing the javascript expression to reference the data relative to
18859 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18860 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18861 * this may be omitted.</p></li>
18862 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18863 * <ul><li>auto (Default, implies no conversion)</li>
18868 * <li>date</li></ul></p></li>
18869 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18870 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18871 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18872 * by the Reader into an object that will be stored in the Record. It is passed the
18873 * following parameters:<ul>
18874 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18876 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18878 * <br>usage:<br><pre><code>
18879 var TopicRecord = Roo.data.Record.create(
18880 {name: 'title', mapping: 'topic_title'},
18881 {name: 'author', mapping: 'username'},
18882 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18883 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18884 {name: 'lastPoster', mapping: 'user2'},
18885 {name: 'excerpt', mapping: 'post_text'}
18888 var myNewRecord = new TopicRecord({
18889 title: 'Do my job please',
18892 lastPost: new Date(),
18893 lastPoster: 'Animal',
18894 excerpt: 'No way dude!'
18896 myStore.add(myNewRecord);
18901 Roo.data.Record.create = function(o){
18902 var f = function(){
18903 f.superclass.constructor.apply(this, arguments);
18905 Roo.extend(f, Roo.data.Record);
18906 var p = f.prototype;
18907 p.fields = new Roo.util.MixedCollection(false, function(field){
18910 for(var i = 0, len = o.length; i < len; i++){
18911 p.fields.add(new Roo.data.Field(o[i]));
18913 f.getField = function(name){
18914 return p.fields.get(name);
18919 Roo.data.Record.AUTO_ID = 1000;
18920 Roo.data.Record.EDIT = 'edit';
18921 Roo.data.Record.REJECT = 'reject';
18922 Roo.data.Record.COMMIT = 'commit';
18924 Roo.data.Record.prototype = {
18926 * Readonly flag - true if this record has been modified.
18935 join : function(store){
18936 this.store = store;
18940 * Set the named field to the specified value.
18941 * @param {String} name The name of the field to set.
18942 * @param {Object} value The value to set the field to.
18944 set : function(name, value){
18945 if(this.data[name] == value){
18949 if(!this.modified){
18950 this.modified = {};
18952 if(typeof this.modified[name] == 'undefined'){
18953 this.modified[name] = this.data[name];
18955 this.data[name] = value;
18957 this.store.afterEdit(this);
18962 * Get the value of the named field.
18963 * @param {String} name The name of the field to get the value of.
18964 * @return {Object} The value of the field.
18966 get : function(name){
18967 return this.data[name];
18971 beginEdit : function(){
18972 this.editing = true;
18973 this.modified = {};
18977 cancelEdit : function(){
18978 this.editing = false;
18979 delete this.modified;
18983 endEdit : function(){
18984 this.editing = false;
18985 if(this.dirty && this.store){
18986 this.store.afterEdit(this);
18991 * Usually called by the {@link Roo.data.Store} which owns the Record.
18992 * Rejects all changes made to the Record since either creation, or the last commit operation.
18993 * Modified fields are reverted to their original values.
18995 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18996 * of reject operations.
18998 reject : function(){
18999 var m = this.modified;
19001 if(typeof m[n] != "function"){
19002 this.data[n] = m[n];
19005 this.dirty = false;
19006 delete this.modified;
19007 this.editing = false;
19009 this.store.afterReject(this);
19014 * Usually called by the {@link Roo.data.Store} which owns the Record.
19015 * Commits all changes made to the Record since either creation, or the last commit operation.
19017 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19018 * of commit operations.
19020 commit : function(){
19021 this.dirty = false;
19022 delete this.modified;
19023 this.editing = false;
19025 this.store.afterCommit(this);
19030 hasError : function(){
19031 return this.error != null;
19035 clearError : function(){
19040 * Creates a copy of this record.
19041 * @param {String} id (optional) A new record id if you don't want to use this record's id
19044 copy : function(newId) {
19045 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19049 * Ext JS Library 1.1.1
19050 * Copyright(c) 2006-2007, Ext JS, LLC.
19052 * Originally Released Under LGPL - original licence link has changed is not relivant.
19055 * <script type="text/javascript">
19061 * @class Roo.data.Store
19062 * @extends Roo.util.Observable
19063 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19064 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19066 * 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
19067 * has no knowledge of the format of the data returned by the Proxy.<br>
19069 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19070 * instances from the data object. These records are cached and made available through accessor functions.
19072 * Creates a new Store.
19073 * @param {Object} config A config object containing the objects needed for the Store to access data,
19074 * and read the data into Records.
19076 Roo.data.Store = function(config){
19077 this.data = new Roo.util.MixedCollection(false);
19078 this.data.getKey = function(o){
19081 this.baseParams = {};
19083 this.paramNames = {
19090 if(config && config.data){
19091 this.inlineData = config.data;
19092 delete config.data;
19095 Roo.apply(this, config);
19097 if(this.reader){ // reader passed
19098 this.reader = Roo.factory(this.reader, Roo.data);
19099 this.reader.xmodule = this.xmodule || false;
19100 if(!this.recordType){
19101 this.recordType = this.reader.recordType;
19103 if(this.reader.onMetaChange){
19104 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19108 if(this.recordType){
19109 this.fields = this.recordType.prototype.fields;
19111 this.modified = [];
19115 * @event datachanged
19116 * Fires when the data cache has changed, and a widget which is using this Store
19117 * as a Record cache should refresh its view.
19118 * @param {Store} this
19120 datachanged : true,
19122 * @event metachange
19123 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19124 * @param {Store} this
19125 * @param {Object} meta The JSON metadata
19130 * Fires when Records have been added to the Store
19131 * @param {Store} this
19132 * @param {Roo.data.Record[]} records The array of Records added
19133 * @param {Number} index The index at which the record(s) were added
19138 * Fires when a Record has been removed from the Store
19139 * @param {Store} this
19140 * @param {Roo.data.Record} record The Record that was removed
19141 * @param {Number} index The index at which the record was removed
19146 * Fires when a Record has been updated
19147 * @param {Store} this
19148 * @param {Roo.data.Record} record The Record that was updated
19149 * @param {String} operation The update operation being performed. Value may be one of:
19151 Roo.data.Record.EDIT
19152 Roo.data.Record.REJECT
19153 Roo.data.Record.COMMIT
19159 * Fires when the data cache has been cleared.
19160 * @param {Store} this
19164 * @event beforeload
19165 * Fires before a request is made for a new data object. If the beforeload handler returns false
19166 * the load action will be canceled.
19167 * @param {Store} this
19168 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19173 * Fires after a new set of Records has been loaded.
19174 * @param {Store} this
19175 * @param {Roo.data.Record[]} records The Records that were loaded
19176 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19180 * @event loadexception
19181 * Fires if an exception occurs in the Proxy during loading.
19182 * Called with the signature of the Proxy's "loadexception" event.
19183 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19186 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19187 * @param {Object} load options
19188 * @param {Object} jsonData from your request (normally this contains the Exception)
19190 loadexception : true
19194 this.proxy = Roo.factory(this.proxy, Roo.data);
19195 this.proxy.xmodule = this.xmodule || false;
19196 this.relayEvents(this.proxy, ["loadexception"]);
19198 this.sortToggle = {};
19200 Roo.data.Store.superclass.constructor.call(this);
19202 if(this.inlineData){
19203 this.loadData(this.inlineData);
19204 delete this.inlineData;
19207 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19209 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19210 * without a remote query - used by combo/forms at present.
19214 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19217 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19220 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19221 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19224 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19225 * on any HTTP request
19228 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19231 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19232 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19234 remoteSort : false,
19237 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19238 * loaded or when a record is removed. (defaults to false).
19240 pruneModifiedRecords : false,
19243 lastOptions : null,
19246 * Add Records to the Store and fires the add event.
19247 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19249 add : function(records){
19250 records = [].concat(records);
19251 for(var i = 0, len = records.length; i < len; i++){
19252 records[i].join(this);
19254 var index = this.data.length;
19255 this.data.addAll(records);
19256 this.fireEvent("add", this, records, index);
19260 * Remove a Record from the Store and fires the remove event.
19261 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19263 remove : function(record){
19264 var index = this.data.indexOf(record);
19265 this.data.removeAt(index);
19266 if(this.pruneModifiedRecords){
19267 this.modified.remove(record);
19269 this.fireEvent("remove", this, record, index);
19273 * Remove all Records from the Store and fires the clear event.
19275 removeAll : function(){
19277 if(this.pruneModifiedRecords){
19278 this.modified = [];
19280 this.fireEvent("clear", this);
19284 * Inserts Records to the Store at the given index and fires the add event.
19285 * @param {Number} index The start index at which to insert the passed Records.
19286 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19288 insert : function(index, records){
19289 records = [].concat(records);
19290 for(var i = 0, len = records.length; i < len; i++){
19291 this.data.insert(index, records[i]);
19292 records[i].join(this);
19294 this.fireEvent("add", this, records, index);
19298 * Get the index within the cache of the passed Record.
19299 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19300 * @return {Number} The index of the passed Record. Returns -1 if not found.
19302 indexOf : function(record){
19303 return this.data.indexOf(record);
19307 * Get the index within the cache of the Record with the passed id.
19308 * @param {String} id The id of the Record to find.
19309 * @return {Number} The index of the Record. Returns -1 if not found.
19311 indexOfId : function(id){
19312 return this.data.indexOfKey(id);
19316 * Get the Record with the specified id.
19317 * @param {String} id The id of the Record to find.
19318 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19320 getById : function(id){
19321 return this.data.key(id);
19325 * Get the Record at the specified index.
19326 * @param {Number} index The index of the Record to find.
19327 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19329 getAt : function(index){
19330 return this.data.itemAt(index);
19334 * Returns a range of Records between specified indices.
19335 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19336 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19337 * @return {Roo.data.Record[]} An array of Records
19339 getRange : function(start, end){
19340 return this.data.getRange(start, end);
19344 storeOptions : function(o){
19345 o = Roo.apply({}, o);
19348 this.lastOptions = o;
19352 * Loads the Record cache from the configured Proxy using the configured Reader.
19354 * If using remote paging, then the first load call must specify the <em>start</em>
19355 * and <em>limit</em> properties in the options.params property to establish the initial
19356 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19358 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19359 * and this call will return before the new data has been loaded. Perform any post-processing
19360 * in a callback function, or in a "load" event handler.</strong>
19362 * @param {Object} options An object containing properties which control loading options:<ul>
19363 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19364 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19365 * passed the following arguments:<ul>
19366 * <li>r : Roo.data.Record[]</li>
19367 * <li>options: Options object from the load call</li>
19368 * <li>success: Boolean success indicator</li></ul></li>
19369 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19370 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19373 load : function(options){
19374 options = options || {};
19375 if(this.fireEvent("beforeload", this, options) !== false){
19376 this.storeOptions(options);
19377 var p = Roo.apply(options.params || {}, this.baseParams);
19378 // if meta was not loaded from remote source.. try requesting it.
19379 if (!this.reader.metaFromRemote) {
19380 p._requestMeta = 1;
19382 if(this.sortInfo && this.remoteSort){
19383 var pn = this.paramNames;
19384 p[pn["sort"]] = this.sortInfo.field;
19385 p[pn["dir"]] = this.sortInfo.direction;
19387 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19392 * Reloads the Record cache from the configured Proxy using the configured Reader and
19393 * the options from the last load operation performed.
19394 * @param {Object} options (optional) An object containing properties which may override the options
19395 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19396 * the most recently used options are reused).
19398 reload : function(options){
19399 this.load(Roo.applyIf(options||{}, this.lastOptions));
19403 // Called as a callback by the Reader during a load operation.
19404 loadRecords : function(o, options, success){
19405 if(!o || success === false){
19406 if(success !== false){
19407 this.fireEvent("load", this, [], options);
19409 if(options.callback){
19410 options.callback.call(options.scope || this, [], options, false);
19414 // if data returned failure - throw an exception.
19415 if (o.success === false) {
19416 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19419 var r = o.records, t = o.totalRecords || r.length;
19420 if(!options || options.add !== true){
19421 if(this.pruneModifiedRecords){
19422 this.modified = [];
19424 for(var i = 0, len = r.length; i < len; i++){
19428 this.data = this.snapshot;
19429 delete this.snapshot;
19432 this.data.addAll(r);
19433 this.totalLength = t;
19435 this.fireEvent("datachanged", this);
19437 this.totalLength = Math.max(t, this.data.length+r.length);
19440 this.fireEvent("load", this, r, options);
19441 if(options.callback){
19442 options.callback.call(options.scope || this, r, options, true);
19447 * Loads data from a passed data block. A Reader which understands the format of the data
19448 * must have been configured in the constructor.
19449 * @param {Object} data The data block from which to read the Records. The format of the data expected
19450 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19451 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19453 loadData : function(o, append){
19454 var r = this.reader.readRecords(o);
19455 this.loadRecords(r, {add: append}, true);
19459 * Gets the number of cached records.
19461 * <em>If using paging, this may not be the total size of the dataset. If the data object
19462 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19463 * the data set size</em>
19465 getCount : function(){
19466 return this.data.length || 0;
19470 * Gets the total number of records in the dataset as returned by the server.
19472 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19473 * the dataset size</em>
19475 getTotalCount : function(){
19476 return this.totalLength || 0;
19480 * Returns the sort state of the Store as an object with two properties:
19482 field {String} The name of the field by which the Records are sorted
19483 direction {String} The sort order, "ASC" or "DESC"
19486 getSortState : function(){
19487 return this.sortInfo;
19491 applySort : function(){
19492 if(this.sortInfo && !this.remoteSort){
19493 var s = this.sortInfo, f = s.field;
19494 var st = this.fields.get(f).sortType;
19495 var fn = function(r1, r2){
19496 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19497 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19499 this.data.sort(s.direction, fn);
19500 if(this.snapshot && this.snapshot != this.data){
19501 this.snapshot.sort(s.direction, fn);
19507 * Sets the default sort column and order to be used by the next load operation.
19508 * @param {String} fieldName The name of the field to sort by.
19509 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19511 setDefaultSort : function(field, dir){
19512 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19516 * Sort the Records.
19517 * If remote sorting is used, the sort is performed on the server, and the cache is
19518 * reloaded. If local sorting is used, the cache is sorted internally.
19519 * @param {String} fieldName The name of the field to sort by.
19520 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19522 sort : function(fieldName, dir){
19523 var f = this.fields.get(fieldName);
19525 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19526 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19531 this.sortToggle[f.name] = dir;
19532 this.sortInfo = {field: f.name, direction: dir};
19533 if(!this.remoteSort){
19535 this.fireEvent("datachanged", this);
19537 this.load(this.lastOptions);
19542 * Calls the specified function for each of the Records in the cache.
19543 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19544 * Returning <em>false</em> aborts and exits the iteration.
19545 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19547 each : function(fn, scope){
19548 this.data.each(fn, scope);
19552 * Gets all records modified since the last commit. Modified records are persisted across load operations
19553 * (e.g., during paging).
19554 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19556 getModifiedRecords : function(){
19557 return this.modified;
19561 createFilterFn : function(property, value, anyMatch){
19562 if(!value.exec){ // not a regex
19563 value = String(value);
19564 if(value.length == 0){
19567 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19569 return function(r){
19570 return value.test(r.data[property]);
19575 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19576 * @param {String} property A field on your records
19577 * @param {Number} start The record index to start at (defaults to 0)
19578 * @param {Number} end The last record index to include (defaults to length - 1)
19579 * @return {Number} The sum
19581 sum : function(property, start, end){
19582 var rs = this.data.items, v = 0;
19583 start = start || 0;
19584 end = (end || end === 0) ? end : rs.length-1;
19586 for(var i = start; i <= end; i++){
19587 v += (rs[i].data[property] || 0);
19593 * Filter the records by a specified property.
19594 * @param {String} field A field on your records
19595 * @param {String/RegExp} value Either a string that the field
19596 * should start with or a RegExp to test against the field
19597 * @param {Boolean} anyMatch True to match any part not just the beginning
19599 filter : function(property, value, anyMatch){
19600 var fn = this.createFilterFn(property, value, anyMatch);
19601 return fn ? this.filterBy(fn) : this.clearFilter();
19605 * Filter by a function. The specified function will be called with each
19606 * record in this data source. If the function returns true the record is included,
19607 * otherwise it is filtered.
19608 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19609 * @param {Object} scope (optional) The scope of the function (defaults to this)
19611 filterBy : function(fn, scope){
19612 this.snapshot = this.snapshot || this.data;
19613 this.data = this.queryBy(fn, scope||this);
19614 this.fireEvent("datachanged", this);
19618 * Query the records by a specified property.
19619 * @param {String} field A field on your records
19620 * @param {String/RegExp} value Either a string that the field
19621 * should start with or a RegExp to test against the field
19622 * @param {Boolean} anyMatch True to match any part not just the beginning
19623 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19625 query : function(property, value, anyMatch){
19626 var fn = this.createFilterFn(property, value, anyMatch);
19627 return fn ? this.queryBy(fn) : this.data.clone();
19631 * Query by a function. The specified function will be called with each
19632 * record in this data source. If the function returns true the record is included
19634 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19635 * @param {Object} scope (optional) The scope of the function (defaults to this)
19636 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19638 queryBy : function(fn, scope){
19639 var data = this.snapshot || this.data;
19640 return data.filterBy(fn, scope||this);
19644 * Collects unique values for a particular dataIndex from this store.
19645 * @param {String} dataIndex The property to collect
19646 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19647 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19648 * @return {Array} An array of the unique values
19650 collect : function(dataIndex, allowNull, bypassFilter){
19651 var d = (bypassFilter === true && this.snapshot) ?
19652 this.snapshot.items : this.data.items;
19653 var v, sv, r = [], l = {};
19654 for(var i = 0, len = d.length; i < len; i++){
19655 v = d[i].data[dataIndex];
19657 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19666 * Revert to a view of the Record cache with no filtering applied.
19667 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19669 clearFilter : function(suppressEvent){
19670 if(this.snapshot && this.snapshot != this.data){
19671 this.data = this.snapshot;
19672 delete this.snapshot;
19673 if(suppressEvent !== true){
19674 this.fireEvent("datachanged", this);
19680 afterEdit : function(record){
19681 if(this.modified.indexOf(record) == -1){
19682 this.modified.push(record);
19684 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19688 afterReject : function(record){
19689 this.modified.remove(record);
19690 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19694 afterCommit : function(record){
19695 this.modified.remove(record);
19696 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19700 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19701 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19703 commitChanges : function(){
19704 var m = this.modified.slice(0);
19705 this.modified = [];
19706 for(var i = 0, len = m.length; i < len; i++){
19712 * Cancel outstanding changes on all changed records.
19714 rejectChanges : function(){
19715 var m = this.modified.slice(0);
19716 this.modified = [];
19717 for(var i = 0, len = m.length; i < len; i++){
19722 onMetaChange : function(meta, rtype, o){
19723 this.recordType = rtype;
19724 this.fields = rtype.prototype.fields;
19725 delete this.snapshot;
19726 this.sortInfo = meta.sortInfo || this.sortInfo;
19727 this.modified = [];
19728 this.fireEvent('metachange', this, this.reader.meta);
19732 * Ext JS Library 1.1.1
19733 * Copyright(c) 2006-2007, Ext JS, LLC.
19735 * Originally Released Under LGPL - original licence link has changed is not relivant.
19738 * <script type="text/javascript">
19742 * @class Roo.data.SimpleStore
19743 * @extends Roo.data.Store
19744 * Small helper class to make creating Stores from Array data easier.
19745 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19746 * @cfg {Array} fields An array of field definition objects, or field name strings.
19747 * @cfg {Array} data The multi-dimensional array of data
19749 * @param {Object} config
19751 Roo.data.SimpleStore = function(config){
19752 Roo.data.SimpleStore.superclass.constructor.call(this, {
19754 reader: new Roo.data.ArrayReader({
19757 Roo.data.Record.create(config.fields)
19759 proxy : new Roo.data.MemoryProxy(config.data)
19763 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19765 * Ext JS Library 1.1.1
19766 * Copyright(c) 2006-2007, Ext JS, LLC.
19768 * Originally Released Under LGPL - original licence link has changed is not relivant.
19771 * <script type="text/javascript">
19776 * @extends Roo.data.Store
19777 * @class Roo.data.JsonStore
19778 * Small helper class to make creating Stores for JSON data easier. <br/>
19780 var store = new Roo.data.JsonStore({
19781 url: 'get-images.php',
19783 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19786 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19787 * JsonReader and HttpProxy (unless inline data is provided).</b>
19788 * @cfg {Array} fields An array of field definition objects, or field name strings.
19790 * @param {Object} config
19792 Roo.data.JsonStore = function(c){
19793 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19794 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19795 reader: new Roo.data.JsonReader(c, c.fields)
19798 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19800 * Ext JS Library 1.1.1
19801 * Copyright(c) 2006-2007, Ext JS, LLC.
19803 * Originally Released Under LGPL - original licence link has changed is not relivant.
19806 * <script type="text/javascript">
19810 Roo.data.Field = function(config){
19811 if(typeof config == "string"){
19812 config = {name: config};
19814 Roo.apply(this, config);
19817 this.type = "auto";
19820 var st = Roo.data.SortTypes;
19821 // named sortTypes are supported, here we look them up
19822 if(typeof this.sortType == "string"){
19823 this.sortType = st[this.sortType];
19826 // set default sortType for strings and dates
19827 if(!this.sortType){
19830 this.sortType = st.asUCString;
19833 this.sortType = st.asDate;
19836 this.sortType = st.none;
19841 var stripRe = /[\$,%]/g;
19843 // prebuilt conversion function for this field, instead of
19844 // switching every time we're reading a value
19846 var cv, dateFormat = this.dateFormat;
19851 cv = function(v){ return v; };
19854 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19858 return v !== undefined && v !== null && v !== '' ?
19859 parseInt(String(v).replace(stripRe, ""), 10) : '';
19864 return v !== undefined && v !== null && v !== '' ?
19865 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19870 cv = function(v){ return v === true || v === "true" || v == 1; };
19877 if(v instanceof Date){
19881 if(dateFormat == "timestamp"){
19882 return new Date(v*1000);
19884 return Date.parseDate(v, dateFormat);
19886 var parsed = Date.parse(v);
19887 return parsed ? new Date(parsed) : null;
19896 Roo.data.Field.prototype = {
19904 * Ext JS Library 1.1.1
19905 * Copyright(c) 2006-2007, Ext JS, LLC.
19907 * Originally Released Under LGPL - original licence link has changed is not relivant.
19910 * <script type="text/javascript">
19913 // Base class for reading structured data from a data source. This class is intended to be
19914 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19917 * @class Roo.data.DataReader
19918 * Base class for reading structured data from a data source. This class is intended to be
19919 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
19922 Roo.data.DataReader = function(meta, recordType){
19926 this.recordType = recordType instanceof Array ?
19927 Roo.data.Record.create(recordType) : recordType;
19930 Roo.data.DataReader.prototype = {
19932 * Create an empty record
19933 * @param {Object} data (optional) - overlay some values
19934 * @return {Roo.data.Record} record created.
19936 newRow : function(d) {
19938 this.recordType.prototype.fields.each(function(c) {
19940 case 'int' : da[c.name] = 0; break;
19941 case 'date' : da[c.name] = new Date(); break;
19942 case 'float' : da[c.name] = 0.0; break;
19943 case 'boolean' : da[c.name] = false; break;
19944 default : da[c.name] = ""; break;
19948 return new this.recordType(Roo.apply(da, d));
19953 * Ext JS Library 1.1.1
19954 * Copyright(c) 2006-2007, Ext JS, LLC.
19956 * Originally Released Under LGPL - original licence link has changed is not relivant.
19959 * <script type="text/javascript">
19963 * @class Roo.data.DataProxy
19964 * @extends Roo.data.Observable
19965 * This class is an abstract base class for implementations which provide retrieval of
19966 * unformatted data objects.<br>
19968 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
19969 * (of the appropriate type which knows how to parse the data object) to provide a block of
19970 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
19972 * Custom implementations must implement the load method as described in
19973 * {@link Roo.data.HttpProxy#load}.
19975 Roo.data.DataProxy = function(){
19978 * @event beforeload
19979 * Fires before a network request is made to retrieve a data object.
19980 * @param {Object} This DataProxy object.
19981 * @param {Object} params The params parameter to the load function.
19986 * Fires before the load method's callback is called.
19987 * @param {Object} This DataProxy object.
19988 * @param {Object} o The data object.
19989 * @param {Object} arg The callback argument object passed to the load function.
19993 * @event loadexception
19994 * Fires if an Exception occurs during data retrieval.
19995 * @param {Object} This DataProxy object.
19996 * @param {Object} o The data object.
19997 * @param {Object} arg The callback argument object passed to the load function.
19998 * @param {Object} e The Exception.
20000 loadexception : true
20002 Roo.data.DataProxy.superclass.constructor.call(this);
20005 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20008 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20012 * Ext JS Library 1.1.1
20013 * Copyright(c) 2006-2007, Ext JS, LLC.
20015 * Originally Released Under LGPL - original licence link has changed is not relivant.
20018 * <script type="text/javascript">
20021 * @class Roo.data.MemoryProxy
20022 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20023 * to the Reader when its load method is called.
20025 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20027 Roo.data.MemoryProxy = function(data){
20031 Roo.data.MemoryProxy.superclass.constructor.call(this);
20035 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20037 * Load data from the requested source (in this case an in-memory
20038 * data object passed to the constructor), read the data object into
20039 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20040 * process that block using the passed callback.
20041 * @param {Object} params This parameter is not used by the MemoryProxy class.
20042 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20043 * object into a block of Roo.data.Records.
20044 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20045 * The function must be passed <ul>
20046 * <li>The Record block object</li>
20047 * <li>The "arg" argument from the load function</li>
20048 * <li>A boolean success indicator</li>
20050 * @param {Object} scope The scope in which to call the callback
20051 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20053 load : function(params, reader, callback, scope, arg){
20054 params = params || {};
20057 result = reader.readRecords(this.data);
20059 this.fireEvent("loadexception", this, arg, null, e);
20060 callback.call(scope, null, arg, false);
20063 callback.call(scope, result, arg, true);
20067 update : function(params, records){
20072 * Ext JS Library 1.1.1
20073 * Copyright(c) 2006-2007, Ext JS, LLC.
20075 * Originally Released Under LGPL - original licence link has changed is not relivant.
20078 * <script type="text/javascript">
20081 * @class Roo.data.HttpProxy
20082 * @extends Roo.data.DataProxy
20083 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20084 * configured to reference a certain URL.<br><br>
20086 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20087 * from which the running page was served.<br><br>
20089 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20091 * Be aware that to enable the browser to parse an XML document, the server must set
20092 * the Content-Type header in the HTTP response to "text/xml".
20094 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20095 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20096 * will be used to make the request.
20098 Roo.data.HttpProxy = function(conn){
20099 Roo.data.HttpProxy.superclass.constructor.call(this);
20100 // is conn a conn config or a real conn?
20102 this.useAjax = !conn || !conn.events;
20106 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20107 // thse are take from connection...
20110 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20113 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20114 * extra parameters to each request made by this object. (defaults to undefined)
20117 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20118 * to each request made by this object. (defaults to undefined)
20121 * @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)
20124 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20127 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20133 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20137 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20138 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20139 * a finer-grained basis than the DataProxy events.
20141 getConnection : function(){
20142 return this.useAjax ? Roo.Ajax : this.conn;
20146 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20147 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20148 * process that block using the passed callback.
20149 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20150 * for the request to the remote server.
20151 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20152 * object into a block of Roo.data.Records.
20153 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20154 * The function must be passed <ul>
20155 * <li>The Record block object</li>
20156 * <li>The "arg" argument from the load function</li>
20157 * <li>A boolean success indicator</li>
20159 * @param {Object} scope The scope in which to call the callback
20160 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20162 load : function(params, reader, callback, scope, arg){
20163 if(this.fireEvent("beforeload", this, params) !== false){
20165 params : params || {},
20167 callback : callback,
20172 callback : this.loadResponse,
20176 Roo.applyIf(o, this.conn);
20177 if(this.activeRequest){
20178 Roo.Ajax.abort(this.activeRequest);
20180 this.activeRequest = Roo.Ajax.request(o);
20182 this.conn.request(o);
20185 callback.call(scope||this, null, arg, false);
20190 loadResponse : function(o, success, response){
20191 delete this.activeRequest;
20193 this.fireEvent("loadexception", this, o, response);
20194 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20199 result = o.reader.read(response);
20201 this.fireEvent("loadexception", this, o, response, e);
20202 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20206 this.fireEvent("load", this, o, o.request.arg);
20207 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20211 update : function(dataSet){
20216 updateResponse : function(dataSet){
20221 * Ext JS Library 1.1.1
20222 * Copyright(c) 2006-2007, Ext JS, LLC.
20224 * Originally Released Under LGPL - original licence link has changed is not relivant.
20227 * <script type="text/javascript">
20231 * @class Roo.data.ScriptTagProxy
20232 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20233 * other than the originating domain of the running page.<br><br>
20235 * <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
20236 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20238 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20239 * source code that is used as the source inside a <script> tag.<br><br>
20241 * In order for the browser to process the returned data, the server must wrap the data object
20242 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20243 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20244 * depending on whether the callback name was passed:
20247 boolean scriptTag = false;
20248 String cb = request.getParameter("callback");
20251 response.setContentType("text/javascript");
20253 response.setContentType("application/x-json");
20255 Writer out = response.getWriter();
20257 out.write(cb + "(");
20259 out.print(dataBlock.toJsonString());
20266 * @param {Object} config A configuration object.
20268 Roo.data.ScriptTagProxy = function(config){
20269 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20270 Roo.apply(this, config);
20271 this.head = document.getElementsByTagName("head")[0];
20274 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20276 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20278 * @cfg {String} url The URL from which to request the data object.
20281 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20285 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20286 * the server the name of the callback function set up by the load call to process the returned data object.
20287 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20288 * javascript output which calls this named function passing the data object as its only parameter.
20290 callbackParam : "callback",
20292 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20293 * name to the request.
20298 * Load data from the configured URL, read the data object into
20299 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20300 * process that block using the passed callback.
20301 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20302 * for the request to the remote server.
20303 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20304 * object into a block of Roo.data.Records.
20305 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20306 * The function must be passed <ul>
20307 * <li>The Record block object</li>
20308 * <li>The "arg" argument from the load function</li>
20309 * <li>A boolean success indicator</li>
20311 * @param {Object} scope The scope in which to call the callback
20312 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20314 load : function(params, reader, callback, scope, arg){
20315 if(this.fireEvent("beforeload", this, params) !== false){
20317 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20319 var url = this.url;
20320 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20322 url += "&_dc=" + (new Date().getTime());
20324 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20327 cb : "stcCallback"+transId,
20328 scriptId : "stcScript"+transId,
20332 callback : callback,
20338 window[trans.cb] = function(o){
20339 conn.handleResponse(o, trans);
20342 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20344 if(this.autoAbort !== false){
20348 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20350 var script = document.createElement("script");
20351 script.setAttribute("src", url);
20352 script.setAttribute("type", "text/javascript");
20353 script.setAttribute("id", trans.scriptId);
20354 this.head.appendChild(script);
20356 this.trans = trans;
20358 callback.call(scope||this, null, arg, false);
20363 isLoading : function(){
20364 return this.trans ? true : false;
20368 * Abort the current server request.
20370 abort : function(){
20371 if(this.isLoading()){
20372 this.destroyTrans(this.trans);
20377 destroyTrans : function(trans, isLoaded){
20378 this.head.removeChild(document.getElementById(trans.scriptId));
20379 clearTimeout(trans.timeoutId);
20381 window[trans.cb] = undefined;
20383 delete window[trans.cb];
20386 // if hasn't been loaded, wait for load to remove it to prevent script error
20387 window[trans.cb] = function(){
20388 window[trans.cb] = undefined;
20390 delete window[trans.cb];
20397 handleResponse : function(o, trans){
20398 this.trans = false;
20399 this.destroyTrans(trans, true);
20402 result = trans.reader.readRecords(o);
20404 this.fireEvent("loadexception", this, o, trans.arg, e);
20405 trans.callback.call(trans.scope||window, null, trans.arg, false);
20408 this.fireEvent("load", this, o, trans.arg);
20409 trans.callback.call(trans.scope||window, result, trans.arg, true);
20413 handleFailure : function(trans){
20414 this.trans = false;
20415 this.destroyTrans(trans, false);
20416 this.fireEvent("loadexception", this, null, trans.arg);
20417 trans.callback.call(trans.scope||window, null, trans.arg, false);
20421 * Ext JS Library 1.1.1
20422 * Copyright(c) 2006-2007, Ext JS, LLC.
20424 * Originally Released Under LGPL - original licence link has changed is not relivant.
20427 * <script type="text/javascript">
20431 * @class Roo.data.JsonReader
20432 * @extends Roo.data.DataReader
20433 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20434 * based on mappings in a provided Roo.data.Record constructor.
20436 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20437 * in the reply previously.
20442 var RecordDef = Roo.data.Record.create([
20443 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20444 {name: 'occupation'} // This field will use "occupation" as the mapping.
20446 var myReader = new Roo.data.JsonReader({
20447 totalProperty: "results", // The property which contains the total dataset size (optional)
20448 root: "rows", // The property which contains an Array of row objects
20449 id: "id" // The property within each row object that provides an ID for the record (optional)
20453 * This would consume a JSON file like this:
20455 { 'results': 2, 'rows': [
20456 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20457 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20460 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20461 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20462 * paged from the remote server.
20463 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20464 * @cfg {String} root name of the property which contains the Array of row objects.
20465 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20467 * Create a new JsonReader
20468 * @param {Object} meta Metadata configuration options
20469 * @param {Object} recordType Either an Array of field definition objects,
20470 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20472 Roo.data.JsonReader = function(meta, recordType){
20475 // set some defaults:
20476 Roo.applyIf(meta, {
20477 totalProperty: 'total',
20478 successProperty : 'success',
20483 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20485 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20488 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20489 * Used by Store query builder to append _requestMeta to params.
20492 metaFromRemote : false,
20494 * This method is only used by a DataProxy which has retrieved data from a remote server.
20495 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20496 * @return {Object} data A data block which is used by an Roo.data.Store object as
20497 * a cache of Roo.data.Records.
20499 read : function(response){
20500 var json = response.responseText;
20502 var o = /* eval:var:o */ eval("("+json+")");
20504 throw {message: "JsonReader.read: Json object not found"};
20510 this.metaFromRemote = true;
20511 this.meta = o.metaData;
20512 this.recordType = Roo.data.Record.create(o.metaData.fields);
20513 this.onMetaChange(this.meta, this.recordType, o);
20515 return this.readRecords(o);
20518 // private function a store will implement
20519 onMetaChange : function(meta, recordType, o){
20526 simpleAccess: function(obj, subsc) {
20533 getJsonAccessor: function(){
20535 return function(expr) {
20537 return(re.test(expr))
20538 ? new Function("obj", "return obj." + expr)
20543 return Roo.emptyFn;
20548 * Create a data block containing Roo.data.Records from an XML document.
20549 * @param {Object} o An object which contains an Array of row objects in the property specified
20550 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20551 * which contains the total size of the dataset.
20552 * @return {Object} data A data block which is used by an Roo.data.Store object as
20553 * a cache of Roo.data.Records.
20555 readRecords : function(o){
20557 * After any data loads, the raw JSON data is available for further custom processing.
20561 var s = this.meta, Record = this.recordType,
20562 f = Record.prototype.fields, fi = f.items, fl = f.length;
20564 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20566 if(s.totalProperty) {
20567 this.getTotal = this.getJsonAccessor(s.totalProperty);
20569 if(s.successProperty) {
20570 this.getSuccess = this.getJsonAccessor(s.successProperty);
20572 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20574 var g = this.getJsonAccessor(s.id);
20575 this.getId = function(rec) {
20577 return (r === undefined || r === "") ? null : r;
20580 this.getId = function(){return null;};
20583 for(var jj = 0; jj < fl; jj++){
20585 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20586 this.ef[jj] = this.getJsonAccessor(map);
20590 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20591 if(s.totalProperty){
20592 var vt = parseInt(this.getTotal(o), 10);
20597 if(s.successProperty){
20598 var vs = this.getSuccess(o);
20599 if(vs === false || vs === 'false'){
20604 for(var i = 0; i < c; i++){
20607 var id = this.getId(n);
20608 for(var j = 0; j < fl; j++){
20610 var v = this.ef[j](n);
20612 Roo.log('missing convert for ' + f.name);
20616 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20618 var record = new Record(values, id);
20620 records[i] = record;
20625 totalRecords : totalRecords
20630 * Ext JS Library 1.1.1
20631 * Copyright(c) 2006-2007, Ext JS, LLC.
20633 * Originally Released Under LGPL - original licence link has changed is not relivant.
20636 * <script type="text/javascript">
20640 * @class Roo.data.XmlReader
20641 * @extends Roo.data.DataReader
20642 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20643 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20645 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20646 * header in the HTTP response must be set to "text/xml".</em>
20650 var RecordDef = Roo.data.Record.create([
20651 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20652 {name: 'occupation'} // This field will use "occupation" as the mapping.
20654 var myReader = new Roo.data.XmlReader({
20655 totalRecords: "results", // The element which contains the total dataset size (optional)
20656 record: "row", // The repeated element which contains row information
20657 id: "id" // The element within the row that provides an ID for the record (optional)
20661 * This would consume an XML file like this:
20665 <results>2</results>
20668 <name>Bill</name>
20669 <occupation>Gardener</occupation>
20673 <name>Ben</name>
20674 <occupation>Horticulturalist</occupation>
20678 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20679 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20680 * paged from the remote server.
20681 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20682 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20683 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20684 * a record identifier value.
20686 * Create a new XmlReader
20687 * @param {Object} meta Metadata configuration options
20688 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20689 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20690 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20692 Roo.data.XmlReader = function(meta, recordType){
20694 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20696 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20698 * This method is only used by a DataProxy which has retrieved data from a remote server.
20699 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20700 * to contain a method called 'responseXML' that returns an XML document object.
20701 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20702 * a cache of Roo.data.Records.
20704 read : function(response){
20705 var doc = response.responseXML;
20707 throw {message: "XmlReader.read: XML Document not available"};
20709 return this.readRecords(doc);
20713 * Create a data block containing Roo.data.Records from an XML document.
20714 * @param {Object} doc A parsed XML document.
20715 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20716 * a cache of Roo.data.Records.
20718 readRecords : function(doc){
20720 * After any data loads/reads, the raw XML Document is available for further custom processing.
20721 * @type XMLDocument
20723 this.xmlData = doc;
20724 var root = doc.documentElement || doc;
20725 var q = Roo.DomQuery;
20726 var recordType = this.recordType, fields = recordType.prototype.fields;
20727 var sid = this.meta.id;
20728 var totalRecords = 0, success = true;
20729 if(this.meta.totalRecords){
20730 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20733 if(this.meta.success){
20734 var sv = q.selectValue(this.meta.success, root, true);
20735 success = sv !== false && sv !== 'false';
20738 var ns = q.select(this.meta.record, root);
20739 for(var i = 0, len = ns.length; i < len; i++) {
20742 var id = sid ? q.selectValue(sid, n) : undefined;
20743 for(var j = 0, jlen = fields.length; j < jlen; j++){
20744 var f = fields.items[j];
20745 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20747 values[f.name] = v;
20749 var record = new recordType(values, id);
20751 records[records.length] = record;
20757 totalRecords : totalRecords || records.length
20762 * Ext JS Library 1.1.1
20763 * Copyright(c) 2006-2007, Ext JS, LLC.
20765 * Originally Released Under LGPL - original licence link has changed is not relivant.
20768 * <script type="text/javascript">
20772 * @class Roo.data.ArrayReader
20773 * @extends Roo.data.DataReader
20774 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20775 * Each element of that Array represents a row of data fields. The
20776 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20777 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20781 var RecordDef = Roo.data.Record.create([
20782 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20783 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20785 var myReader = new Roo.data.ArrayReader({
20786 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20790 * This would consume an Array like this:
20792 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20794 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20796 * Create a new JsonReader
20797 * @param {Object} meta Metadata configuration options.
20798 * @param {Object} recordType Either an Array of field definition objects
20799 * as specified to {@link Roo.data.Record#create},
20800 * or an {@link Roo.data.Record} object
20801 * created using {@link Roo.data.Record#create}.
20803 Roo.data.ArrayReader = function(meta, recordType){
20804 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20807 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20809 * Create a data block containing Roo.data.Records from an XML document.
20810 * @param {Object} o An Array of row objects which represents the dataset.
20811 * @return {Object} data A data block which is used by an Roo.data.Store object as
20812 * a cache of Roo.data.Records.
20814 readRecords : function(o){
20815 var sid = this.meta ? this.meta.id : null;
20816 var recordType = this.recordType, fields = recordType.prototype.fields;
20819 for(var i = 0; i < root.length; i++){
20822 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20823 for(var j = 0, jlen = fields.length; j < jlen; j++){
20824 var f = fields.items[j];
20825 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20826 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20828 values[f.name] = v;
20830 var record = new recordType(values, id);
20832 records[records.length] = record;
20836 totalRecords : records.length
20841 * Ext JS Library 1.1.1
20842 * Copyright(c) 2006-2007, Ext JS, LLC.
20844 * Originally Released Under LGPL - original licence link has changed is not relivant.
20847 * <script type="text/javascript">
20852 * @class Roo.data.Tree
20853 * @extends Roo.util.Observable
20854 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20855 * in the tree have most standard DOM functionality.
20857 * @param {Node} root (optional) The root node
20859 Roo.data.Tree = function(root){
20860 this.nodeHash = {};
20862 * The root node for this tree
20867 this.setRootNode(root);
20872 * Fires when a new child node is appended to a node in this tree.
20873 * @param {Tree} tree The owner tree
20874 * @param {Node} parent The parent node
20875 * @param {Node} node The newly appended node
20876 * @param {Number} index The index of the newly appended node
20881 * Fires when a child node is removed from a node in this tree.
20882 * @param {Tree} tree The owner tree
20883 * @param {Node} parent The parent node
20884 * @param {Node} node The child node removed
20889 * Fires when a node is moved to a new location in the tree
20890 * @param {Tree} tree The owner tree
20891 * @param {Node} node The node moved
20892 * @param {Node} oldParent The old parent of this node
20893 * @param {Node} newParent The new parent of this node
20894 * @param {Number} index The index it was moved to
20899 * Fires when a new child node is inserted in a node in this tree.
20900 * @param {Tree} tree The owner tree
20901 * @param {Node} parent The parent node
20902 * @param {Node} node The child node inserted
20903 * @param {Node} refNode The child node the node was inserted before
20907 * @event beforeappend
20908 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20909 * @param {Tree} tree The owner tree
20910 * @param {Node} parent The parent node
20911 * @param {Node} node The child node to be appended
20913 "beforeappend" : true,
20915 * @event beforeremove
20916 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20917 * @param {Tree} tree The owner tree
20918 * @param {Node} parent The parent node
20919 * @param {Node} node The child node to be removed
20921 "beforeremove" : true,
20923 * @event beforemove
20924 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
20925 * @param {Tree} tree The owner tree
20926 * @param {Node} node The node being moved
20927 * @param {Node} oldParent The parent of the node
20928 * @param {Node} newParent The new parent the node is moving to
20929 * @param {Number} index The index it is being moved to
20931 "beforemove" : true,
20933 * @event beforeinsert
20934 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
20935 * @param {Tree} tree The owner tree
20936 * @param {Node} parent The parent node
20937 * @param {Node} node The child node to be inserted
20938 * @param {Node} refNode The child node the node is being inserted before
20940 "beforeinsert" : true
20943 Roo.data.Tree.superclass.constructor.call(this);
20946 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
20947 pathSeparator: "/",
20949 proxyNodeEvent : function(){
20950 return this.fireEvent.apply(this, arguments);
20954 * Returns the root node for this tree.
20957 getRootNode : function(){
20962 * Sets the root node for this tree.
20963 * @param {Node} node
20966 setRootNode : function(node){
20968 node.ownerTree = this;
20969 node.isRoot = true;
20970 this.registerNode(node);
20975 * Gets a node in this tree by its id.
20976 * @param {String} id
20979 getNodeById : function(id){
20980 return this.nodeHash[id];
20983 registerNode : function(node){
20984 this.nodeHash[node.id] = node;
20987 unregisterNode : function(node){
20988 delete this.nodeHash[node.id];
20991 toString : function(){
20992 return "[Tree"+(this.id?" "+this.id:"")+"]";
20997 * @class Roo.data.Node
20998 * @extends Roo.util.Observable
20999 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21000 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21002 * @param {Object} attributes The attributes/config for the node
21004 Roo.data.Node = function(attributes){
21006 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21009 this.attributes = attributes || {};
21010 this.leaf = this.attributes.leaf;
21012 * The node id. @type String
21014 this.id = this.attributes.id;
21016 this.id = Roo.id(null, "ynode-");
21017 this.attributes.id = this.id;
21020 * All child nodes of this node. @type Array
21022 this.childNodes = [];
21023 if(!this.childNodes.indexOf){ // indexOf is a must
21024 this.childNodes.indexOf = function(o){
21025 for(var i = 0, len = this.length; i < len; i++){
21034 * The parent node for this node. @type Node
21036 this.parentNode = null;
21038 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21040 this.firstChild = null;
21042 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21044 this.lastChild = null;
21046 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21048 this.previousSibling = null;
21050 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21052 this.nextSibling = null;
21057 * Fires when a new child node is appended
21058 * @param {Tree} tree The owner tree
21059 * @param {Node} this This node
21060 * @param {Node} node The newly appended node
21061 * @param {Number} index The index of the newly appended node
21066 * Fires when a child node is removed
21067 * @param {Tree} tree The owner tree
21068 * @param {Node} this This node
21069 * @param {Node} node The removed node
21074 * Fires when this node is moved to a new location in the tree
21075 * @param {Tree} tree The owner tree
21076 * @param {Node} this This node
21077 * @param {Node} oldParent The old parent of this node
21078 * @param {Node} newParent The new parent of this node
21079 * @param {Number} index The index it was moved to
21084 * Fires when a new child node is inserted.
21085 * @param {Tree} tree The owner tree
21086 * @param {Node} this This node
21087 * @param {Node} node The child node inserted
21088 * @param {Node} refNode The child node the node was inserted before
21092 * @event beforeappend
21093 * Fires before a new child is appended, return false to cancel the append.
21094 * @param {Tree} tree The owner tree
21095 * @param {Node} this This node
21096 * @param {Node} node The child node to be appended
21098 "beforeappend" : true,
21100 * @event beforeremove
21101 * Fires before a child is removed, return false to cancel the remove.
21102 * @param {Tree} tree The owner tree
21103 * @param {Node} this This node
21104 * @param {Node} node The child node to be removed
21106 "beforeremove" : true,
21108 * @event beforemove
21109 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21110 * @param {Tree} tree The owner tree
21111 * @param {Node} this This node
21112 * @param {Node} oldParent The parent of this node
21113 * @param {Node} newParent The new parent this node is moving to
21114 * @param {Number} index The index it is being moved to
21116 "beforemove" : true,
21118 * @event beforeinsert
21119 * Fires before a new child is inserted, return false to cancel the insert.
21120 * @param {Tree} tree The owner tree
21121 * @param {Node} this This node
21122 * @param {Node} node The child node to be inserted
21123 * @param {Node} refNode The child node the node is being inserted before
21125 "beforeinsert" : true
21127 this.listeners = this.attributes.listeners;
21128 Roo.data.Node.superclass.constructor.call(this);
21131 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21132 fireEvent : function(evtName){
21133 // first do standard event for this node
21134 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21137 // then bubble it up to the tree if the event wasn't cancelled
21138 var ot = this.getOwnerTree();
21140 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21148 * Returns true if this node is a leaf
21149 * @return {Boolean}
21151 isLeaf : function(){
21152 return this.leaf === true;
21156 setFirstChild : function(node){
21157 this.firstChild = node;
21161 setLastChild : function(node){
21162 this.lastChild = node;
21167 * Returns true if this node is the last child of its parent
21168 * @return {Boolean}
21170 isLast : function(){
21171 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21175 * Returns true if this node is the first child of its parent
21176 * @return {Boolean}
21178 isFirst : function(){
21179 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21182 hasChildNodes : function(){
21183 return !this.isLeaf() && this.childNodes.length > 0;
21187 * Insert node(s) as the last child node of this node.
21188 * @param {Node/Array} node The node or Array of nodes to append
21189 * @return {Node} The appended node if single append, or null if an array was passed
21191 appendChild : function(node){
21193 if(node instanceof Array){
21195 }else if(arguments.length > 1){
21198 // if passed an array or multiple args do them one by one
21200 for(var i = 0, len = multi.length; i < len; i++) {
21201 this.appendChild(multi[i]);
21204 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21207 var index = this.childNodes.length;
21208 var oldParent = node.parentNode;
21209 // it's a move, make sure we move it cleanly
21211 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21214 oldParent.removeChild(node);
21216 index = this.childNodes.length;
21218 this.setFirstChild(node);
21220 this.childNodes.push(node);
21221 node.parentNode = this;
21222 var ps = this.childNodes[index-1];
21224 node.previousSibling = ps;
21225 ps.nextSibling = node;
21227 node.previousSibling = null;
21229 node.nextSibling = null;
21230 this.setLastChild(node);
21231 node.setOwnerTree(this.getOwnerTree());
21232 this.fireEvent("append", this.ownerTree, this, node, index);
21234 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21241 * Removes a child node from this node.
21242 * @param {Node} node The node to remove
21243 * @return {Node} The removed node
21245 removeChild : function(node){
21246 var index = this.childNodes.indexOf(node);
21250 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21254 // remove it from childNodes collection
21255 this.childNodes.splice(index, 1);
21258 if(node.previousSibling){
21259 node.previousSibling.nextSibling = node.nextSibling;
21261 if(node.nextSibling){
21262 node.nextSibling.previousSibling = node.previousSibling;
21265 // update child refs
21266 if(this.firstChild == node){
21267 this.setFirstChild(node.nextSibling);
21269 if(this.lastChild == node){
21270 this.setLastChild(node.previousSibling);
21273 node.setOwnerTree(null);
21274 // clear any references from the node
21275 node.parentNode = null;
21276 node.previousSibling = null;
21277 node.nextSibling = null;
21278 this.fireEvent("remove", this.ownerTree, this, node);
21283 * Inserts the first node before the second node in this nodes childNodes collection.
21284 * @param {Node} node The node to insert
21285 * @param {Node} refNode The node to insert before (if null the node is appended)
21286 * @return {Node} The inserted node
21288 insertBefore : function(node, refNode){
21289 if(!refNode){ // like standard Dom, refNode can be null for append
21290 return this.appendChild(node);
21293 if(node == refNode){
21297 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21300 var index = this.childNodes.indexOf(refNode);
21301 var oldParent = node.parentNode;
21302 var refIndex = index;
21304 // when moving internally, indexes will change after remove
21305 if(oldParent == this && this.childNodes.indexOf(node) < index){
21309 // it's a move, make sure we move it cleanly
21311 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21314 oldParent.removeChild(node);
21317 this.setFirstChild(node);
21319 this.childNodes.splice(refIndex, 0, node);
21320 node.parentNode = this;
21321 var ps = this.childNodes[refIndex-1];
21323 node.previousSibling = ps;
21324 ps.nextSibling = node;
21326 node.previousSibling = null;
21328 node.nextSibling = refNode;
21329 refNode.previousSibling = node;
21330 node.setOwnerTree(this.getOwnerTree());
21331 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21333 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21339 * Returns the child node at the specified index.
21340 * @param {Number} index
21343 item : function(index){
21344 return this.childNodes[index];
21348 * Replaces one child node in this node with another.
21349 * @param {Node} newChild The replacement node
21350 * @param {Node} oldChild The node to replace
21351 * @return {Node} The replaced node
21353 replaceChild : function(newChild, oldChild){
21354 this.insertBefore(newChild, oldChild);
21355 this.removeChild(oldChild);
21360 * Returns the index of a child node
21361 * @param {Node} node
21362 * @return {Number} The index of the node or -1 if it was not found
21364 indexOf : function(child){
21365 return this.childNodes.indexOf(child);
21369 * Returns the tree this node is in.
21372 getOwnerTree : function(){
21373 // if it doesn't have one, look for one
21374 if(!this.ownerTree){
21378 this.ownerTree = p.ownerTree;
21384 return this.ownerTree;
21388 * Returns depth of this node (the root node has a depth of 0)
21391 getDepth : function(){
21394 while(p.parentNode){
21402 setOwnerTree : function(tree){
21403 // if it's move, we need to update everyone
21404 if(tree != this.ownerTree){
21405 if(this.ownerTree){
21406 this.ownerTree.unregisterNode(this);
21408 this.ownerTree = tree;
21409 var cs = this.childNodes;
21410 for(var i = 0, len = cs.length; i < len; i++) {
21411 cs[i].setOwnerTree(tree);
21414 tree.registerNode(this);
21420 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21421 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21422 * @return {String} The path
21424 getPath : function(attr){
21425 attr = attr || "id";
21426 var p = this.parentNode;
21427 var b = [this.attributes[attr]];
21429 b.unshift(p.attributes[attr]);
21432 var sep = this.getOwnerTree().pathSeparator;
21433 return sep + b.join(sep);
21437 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21438 * function call will be the scope provided or the current node. The arguments to the function
21439 * will be the args provided or the current node. If the function returns false at any point,
21440 * the bubble is stopped.
21441 * @param {Function} fn The function to call
21442 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21443 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21445 bubble : function(fn, scope, args){
21448 if(fn.call(scope || p, args || p) === false){
21456 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21457 * function call will be the scope provided or the current node. The arguments to the function
21458 * will be the args provided or the current node. If the function returns false at any point,
21459 * the cascade is stopped on that branch.
21460 * @param {Function} fn The function to call
21461 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21462 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21464 cascade : function(fn, scope, args){
21465 if(fn.call(scope || this, args || this) !== false){
21466 var cs = this.childNodes;
21467 for(var i = 0, len = cs.length; i < len; i++) {
21468 cs[i].cascade(fn, scope, args);
21474 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21475 * function call will be the scope provided or the current node. The arguments to the function
21476 * will be the args provided or the current node. If the function returns false at any point,
21477 * the iteration stops.
21478 * @param {Function} fn The function to call
21479 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21480 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21482 eachChild : function(fn, scope, args){
21483 var cs = this.childNodes;
21484 for(var i = 0, len = cs.length; i < len; i++) {
21485 if(fn.call(scope || this, args || cs[i]) === false){
21492 * Finds the first child that has the attribute with the specified value.
21493 * @param {String} attribute The attribute name
21494 * @param {Mixed} value The value to search for
21495 * @return {Node} The found child or null if none was found
21497 findChild : function(attribute, value){
21498 var cs = this.childNodes;
21499 for(var i = 0, len = cs.length; i < len; i++) {
21500 if(cs[i].attributes[attribute] == value){
21508 * Finds the first child by a custom function. The child matches if the function passed
21510 * @param {Function} fn
21511 * @param {Object} scope (optional)
21512 * @return {Node} The found child or null if none was found
21514 findChildBy : function(fn, scope){
21515 var cs = this.childNodes;
21516 for(var i = 0, len = cs.length; i < len; i++) {
21517 if(fn.call(scope||cs[i], cs[i]) === true){
21525 * Sorts this nodes children using the supplied sort function
21526 * @param {Function} fn
21527 * @param {Object} scope (optional)
21529 sort : function(fn, scope){
21530 var cs = this.childNodes;
21531 var len = cs.length;
21533 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21535 for(var i = 0; i < len; i++){
21537 n.previousSibling = cs[i-1];
21538 n.nextSibling = cs[i+1];
21540 this.setFirstChild(n);
21543 this.setLastChild(n);
21550 * Returns true if this node is an ancestor (at any point) of the passed node.
21551 * @param {Node} node
21552 * @return {Boolean}
21554 contains : function(node){
21555 return node.isAncestor(this);
21559 * Returns true if the passed node is an ancestor (at any point) of this node.
21560 * @param {Node} node
21561 * @return {Boolean}
21563 isAncestor : function(node){
21564 var p = this.parentNode;
21574 toString : function(){
21575 return "[Node"+(this.id?" "+this.id:"")+"]";
21579 * Ext JS Library 1.1.1
21580 * Copyright(c) 2006-2007, Ext JS, LLC.
21582 * Originally Released Under LGPL - original licence link has changed is not relivant.
21585 * <script type="text/javascript">
21590 * @class Roo.ComponentMgr
21591 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21594 Roo.ComponentMgr = function(){
21595 var all = new Roo.util.MixedCollection();
21599 * Registers a component.
21600 * @param {Roo.Component} c The component
21602 register : function(c){
21607 * Unregisters a component.
21608 * @param {Roo.Component} c The component
21610 unregister : function(c){
21615 * Returns a component by id
21616 * @param {String} id The component id
21618 get : function(id){
21619 return all.get(id);
21623 * Registers a function that will be called when a specified component is added to ComponentMgr
21624 * @param {String} id The component id
21625 * @param {Funtction} fn The callback function
21626 * @param {Object} scope The scope of the callback
21628 onAvailable : function(id, fn, scope){
21629 all.on("add", function(index, o){
21631 fn.call(scope || o, o);
21632 all.un("add", fn, scope);
21639 * Ext JS Library 1.1.1
21640 * Copyright(c) 2006-2007, Ext JS, LLC.
21642 * Originally Released Under LGPL - original licence link has changed is not relivant.
21645 * <script type="text/javascript">
21649 * @class Roo.Component
21650 * @extends Roo.util.Observable
21651 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21652 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21653 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21654 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21655 * All visual components (widgets) that require rendering into a layout should subclass Component.
21657 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21658 * 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
21659 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21661 Roo.Component = function(config){
21662 config = config || {};
21663 if(config.tagName || config.dom || typeof config == "string"){ // element object
21664 config = {el: config, id: config.id || config};
21666 this.initialConfig = config;
21668 Roo.apply(this, config);
21672 * Fires after the component is disabled.
21673 * @param {Roo.Component} this
21678 * Fires after the component is enabled.
21679 * @param {Roo.Component} this
21683 * @event beforeshow
21684 * Fires before the component is shown. Return false to stop the show.
21685 * @param {Roo.Component} this
21690 * Fires after the component is shown.
21691 * @param {Roo.Component} this
21695 * @event beforehide
21696 * Fires before the component is hidden. Return false to stop the hide.
21697 * @param {Roo.Component} this
21702 * Fires after the component is hidden.
21703 * @param {Roo.Component} this
21707 * @event beforerender
21708 * Fires before the component is rendered. Return false to stop the render.
21709 * @param {Roo.Component} this
21711 beforerender : true,
21714 * Fires after the component is rendered.
21715 * @param {Roo.Component} this
21719 * @event beforedestroy
21720 * Fires before the component is destroyed. Return false to stop the destroy.
21721 * @param {Roo.Component} this
21723 beforedestroy : true,
21726 * Fires after the component is destroyed.
21727 * @param {Roo.Component} this
21732 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21734 Roo.ComponentMgr.register(this);
21735 Roo.Component.superclass.constructor.call(this);
21736 this.initComponent();
21737 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21738 this.render(this.renderTo);
21739 delete this.renderTo;
21744 Roo.Component.AUTO_ID = 1000;
21746 Roo.extend(Roo.Component, Roo.util.Observable, {
21748 * @property {Boolean} hidden
21749 * true if this component is hidden. Read-only.
21753 * true if this component is disabled. Read-only.
21757 * true if this component has been rendered. Read-only.
21761 /** @cfg {String} disableClass
21762 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21764 disabledClass : "x-item-disabled",
21765 /** @cfg {Boolean} allowDomMove
21766 * Whether the component can move the Dom node when rendering (defaults to true).
21768 allowDomMove : true,
21769 /** @cfg {String} hideMode
21770 * How this component should hidden. Supported values are
21771 * "visibility" (css visibility), "offsets" (negative offset position) and
21772 * "display" (css display) - defaults to "display".
21774 hideMode: 'display',
21777 ctype : "Roo.Component",
21779 /** @cfg {String} actionMode
21780 * which property holds the element that used for hide() / show() / disable() / enable()
21786 getActionEl : function(){
21787 return this[this.actionMode];
21790 initComponent : Roo.emptyFn,
21792 * If this is a lazy rendering component, render it to its container element.
21793 * @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.
21795 render : function(container, position){
21796 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21797 if(!container && this.el){
21798 this.el = Roo.get(this.el);
21799 container = this.el.dom.parentNode;
21800 this.allowDomMove = false;
21802 this.container = Roo.get(container);
21803 this.rendered = true;
21804 if(position !== undefined){
21805 if(typeof position == 'number'){
21806 position = this.container.dom.childNodes[position];
21808 position = Roo.getDom(position);
21811 this.onRender(this.container, position || null);
21813 this.el.addClass(this.cls);
21817 this.el.applyStyles(this.style);
21820 this.fireEvent("render", this);
21821 this.afterRender(this.container);
21833 // default function is not really useful
21834 onRender : function(ct, position){
21836 this.el = Roo.get(this.el);
21837 if(this.allowDomMove !== false){
21838 ct.dom.insertBefore(this.el.dom, position);
21844 getAutoCreate : function(){
21845 var cfg = typeof this.autoCreate == "object" ?
21846 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21847 if(this.id && !cfg.id){
21854 afterRender : Roo.emptyFn,
21857 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21858 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21860 destroy : function(){
21861 if(this.fireEvent("beforedestroy", this) !== false){
21862 this.purgeListeners();
21863 this.beforeDestroy();
21865 this.el.removeAllListeners();
21867 if(this.actionMode == "container"){
21868 this.container.remove();
21872 Roo.ComponentMgr.unregister(this);
21873 this.fireEvent("destroy", this);
21878 beforeDestroy : function(){
21883 onDestroy : function(){
21888 * Returns the underlying {@link Roo.Element}.
21889 * @return {Roo.Element} The element
21891 getEl : function(){
21896 * Returns the id of this component.
21899 getId : function(){
21904 * Try to focus this component.
21905 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21906 * @return {Roo.Component} this
21908 focus : function(selectText){
21911 if(selectText === true){
21912 this.el.dom.select();
21927 * Disable this component.
21928 * @return {Roo.Component} this
21930 disable : function(){
21934 this.disabled = true;
21935 this.fireEvent("disable", this);
21940 onDisable : function(){
21941 this.getActionEl().addClass(this.disabledClass);
21942 this.el.dom.disabled = true;
21946 * Enable this component.
21947 * @return {Roo.Component} this
21949 enable : function(){
21953 this.disabled = false;
21954 this.fireEvent("enable", this);
21959 onEnable : function(){
21960 this.getActionEl().removeClass(this.disabledClass);
21961 this.el.dom.disabled = false;
21965 * Convenience function for setting disabled/enabled by boolean.
21966 * @param {Boolean} disabled
21968 setDisabled : function(disabled){
21969 this[disabled ? "disable" : "enable"]();
21973 * Show this component.
21974 * @return {Roo.Component} this
21977 if(this.fireEvent("beforeshow", this) !== false){
21978 this.hidden = false;
21982 this.fireEvent("show", this);
21988 onShow : function(){
21989 var ae = this.getActionEl();
21990 if(this.hideMode == 'visibility'){
21991 ae.dom.style.visibility = "visible";
21992 }else if(this.hideMode == 'offsets'){
21993 ae.removeClass('x-hidden');
21995 ae.dom.style.display = "";
22000 * Hide this component.
22001 * @return {Roo.Component} this
22004 if(this.fireEvent("beforehide", this) !== false){
22005 this.hidden = true;
22009 this.fireEvent("hide", this);
22015 onHide : function(){
22016 var ae = this.getActionEl();
22017 if(this.hideMode == 'visibility'){
22018 ae.dom.style.visibility = "hidden";
22019 }else if(this.hideMode == 'offsets'){
22020 ae.addClass('x-hidden');
22022 ae.dom.style.display = "none";
22027 * Convenience function to hide or show this component by boolean.
22028 * @param {Boolean} visible True to show, false to hide
22029 * @return {Roo.Component} this
22031 setVisible: function(visible){
22041 * Returns true if this component is visible.
22043 isVisible : function(){
22044 return this.getActionEl().isVisible();
22047 cloneConfig : function(overrides){
22048 overrides = overrides || {};
22049 var id = overrides.id || Roo.id();
22050 var cfg = Roo.applyIf(overrides, this.initialConfig);
22051 cfg.id = id; // prevent dup id
22052 return new this.constructor(cfg);
22056 * Ext JS Library 1.1.1
22057 * Copyright(c) 2006-2007, Ext JS, LLC.
22059 * Originally Released Under LGPL - original licence link has changed is not relivant.
22062 * <script type="text/javascript">
22067 * @extends Roo.Element
22068 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22069 * automatic maintaining of shadow/shim positions.
22070 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22071 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22072 * you can pass a string with a CSS class name. False turns off the shadow.
22073 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22074 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22075 * @cfg {String} cls CSS class to add to the element
22076 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22077 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22079 * @param {Object} config An object with config options.
22080 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22083 Roo.Layer = function(config, existingEl){
22084 config = config || {};
22085 var dh = Roo.DomHelper;
22086 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22088 this.dom = Roo.getDom(existingEl);
22091 var o = config.dh || {tag: "div", cls: "x-layer"};
22092 this.dom = dh.append(pel, o);
22095 this.addClass(config.cls);
22097 this.constrain = config.constrain !== false;
22098 this.visibilityMode = Roo.Element.VISIBILITY;
22100 this.id = this.dom.id = config.id;
22102 this.id = Roo.id(this.dom);
22104 this.zindex = config.zindex || this.getZIndex();
22105 this.position("absolute", this.zindex);
22107 this.shadowOffset = config.shadowOffset || 4;
22108 this.shadow = new Roo.Shadow({
22109 offset : this.shadowOffset,
22110 mode : config.shadow
22113 this.shadowOffset = 0;
22115 this.useShim = config.shim !== false && Roo.useShims;
22116 this.useDisplay = config.useDisplay;
22120 var supr = Roo.Element.prototype;
22122 // shims are shared among layer to keep from having 100 iframes
22125 Roo.extend(Roo.Layer, Roo.Element, {
22127 getZIndex : function(){
22128 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22131 getShim : function(){
22138 var shim = shims.shift();
22140 shim = this.createShim();
22141 shim.enableDisplayMode('block');
22142 shim.dom.style.display = 'none';
22143 shim.dom.style.visibility = 'visible';
22145 var pn = this.dom.parentNode;
22146 if(shim.dom.parentNode != pn){
22147 pn.insertBefore(shim.dom, this.dom);
22149 shim.setStyle('z-index', this.getZIndex()-2);
22154 hideShim : function(){
22156 this.shim.setDisplayed(false);
22157 shims.push(this.shim);
22162 disableShadow : function(){
22164 this.shadowDisabled = true;
22165 this.shadow.hide();
22166 this.lastShadowOffset = this.shadowOffset;
22167 this.shadowOffset = 0;
22171 enableShadow : function(show){
22173 this.shadowDisabled = false;
22174 this.shadowOffset = this.lastShadowOffset;
22175 delete this.lastShadowOffset;
22183 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22184 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22185 sync : function(doShow){
22186 var sw = this.shadow;
22187 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22188 var sh = this.getShim();
22190 var w = this.getWidth(),
22191 h = this.getHeight();
22193 var l = this.getLeft(true),
22194 t = this.getTop(true);
22196 if(sw && !this.shadowDisabled){
22197 if(doShow && !sw.isVisible()){
22200 sw.realign(l, t, w, h);
22206 // fit the shim behind the shadow, so it is shimmed too
22207 var a = sw.adjusts, s = sh.dom.style;
22208 s.left = (Math.min(l, l+a.l))+"px";
22209 s.top = (Math.min(t, t+a.t))+"px";
22210 s.width = (w+a.w)+"px";
22211 s.height = (h+a.h)+"px";
22218 sh.setLeftTop(l, t);
22225 destroy : function(){
22228 this.shadow.hide();
22230 this.removeAllListeners();
22231 var pn = this.dom.parentNode;
22233 pn.removeChild(this.dom);
22235 Roo.Element.uncache(this.id);
22238 remove : function(){
22243 beginUpdate : function(){
22244 this.updating = true;
22248 endUpdate : function(){
22249 this.updating = false;
22254 hideUnders : function(negOffset){
22256 this.shadow.hide();
22262 constrainXY : function(){
22263 if(this.constrain){
22264 var vw = Roo.lib.Dom.getViewWidth(),
22265 vh = Roo.lib.Dom.getViewHeight();
22266 var s = Roo.get(document).getScroll();
22268 var xy = this.getXY();
22269 var x = xy[0], y = xy[1];
22270 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22271 // only move it if it needs it
22273 // first validate right/bottom
22274 if((x + w) > vw+s.left){
22275 x = vw - w - this.shadowOffset;
22278 if((y + h) > vh+s.top){
22279 y = vh - h - this.shadowOffset;
22282 // then make sure top/left isn't negative
22293 var ay = this.avoidY;
22294 if(y <= ay && (y+h) >= ay){
22300 supr.setXY.call(this, xy);
22306 isVisible : function(){
22307 return this.visible;
22311 showAction : function(){
22312 this.visible = true; // track visibility to prevent getStyle calls
22313 if(this.useDisplay === true){
22314 this.setDisplayed("");
22315 }else if(this.lastXY){
22316 supr.setXY.call(this, this.lastXY);
22317 }else if(this.lastLT){
22318 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22323 hideAction : function(){
22324 this.visible = false;
22325 if(this.useDisplay === true){
22326 this.setDisplayed(false);
22328 this.setLeftTop(-10000,-10000);
22332 // overridden Element method
22333 setVisible : function(v, a, d, c, e){
22338 var cb = function(){
22343 }.createDelegate(this);
22344 supr.setVisible.call(this, true, true, d, cb, e);
22347 this.hideUnders(true);
22356 }.createDelegate(this);
22358 supr.setVisible.call(this, v, a, d, cb, e);
22367 storeXY : function(xy){
22368 delete this.lastLT;
22372 storeLeftTop : function(left, top){
22373 delete this.lastXY;
22374 this.lastLT = [left, top];
22378 beforeFx : function(){
22379 this.beforeAction();
22380 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22384 afterFx : function(){
22385 Roo.Layer.superclass.afterFx.apply(this, arguments);
22386 this.sync(this.isVisible());
22390 beforeAction : function(){
22391 if(!this.updating && this.shadow){
22392 this.shadow.hide();
22396 // overridden Element method
22397 setLeft : function(left){
22398 this.storeLeftTop(left, this.getTop(true));
22399 supr.setLeft.apply(this, arguments);
22403 setTop : function(top){
22404 this.storeLeftTop(this.getLeft(true), top);
22405 supr.setTop.apply(this, arguments);
22409 setLeftTop : function(left, top){
22410 this.storeLeftTop(left, top);
22411 supr.setLeftTop.apply(this, arguments);
22415 setXY : function(xy, a, d, c, e){
22417 this.beforeAction();
22419 var cb = this.createCB(c);
22420 supr.setXY.call(this, xy, a, d, cb, e);
22427 createCB : function(c){
22438 // overridden Element method
22439 setX : function(x, a, d, c, e){
22440 this.setXY([x, this.getY()], a, d, c, e);
22443 // overridden Element method
22444 setY : function(y, a, d, c, e){
22445 this.setXY([this.getX(), y], a, d, c, e);
22448 // overridden Element method
22449 setSize : function(w, h, a, d, c, e){
22450 this.beforeAction();
22451 var cb = this.createCB(c);
22452 supr.setSize.call(this, w, h, a, d, cb, e);
22458 // overridden Element method
22459 setWidth : function(w, a, d, c, e){
22460 this.beforeAction();
22461 var cb = this.createCB(c);
22462 supr.setWidth.call(this, w, a, d, cb, e);
22468 // overridden Element method
22469 setHeight : function(h, a, d, c, e){
22470 this.beforeAction();
22471 var cb = this.createCB(c);
22472 supr.setHeight.call(this, h, a, d, cb, e);
22478 // overridden Element method
22479 setBounds : function(x, y, w, h, a, d, c, e){
22480 this.beforeAction();
22481 var cb = this.createCB(c);
22483 this.storeXY([x, y]);
22484 supr.setXY.call(this, [x, y]);
22485 supr.setSize.call(this, w, h, a, d, cb, e);
22488 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22494 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22495 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22496 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22497 * @param {Number} zindex The new z-index to set
22498 * @return {this} The Layer
22500 setZIndex : function(zindex){
22501 this.zindex = zindex;
22502 this.setStyle("z-index", zindex + 2);
22504 this.shadow.setZIndex(zindex + 1);
22507 this.shim.setStyle("z-index", zindex);
22513 * Ext JS Library 1.1.1
22514 * Copyright(c) 2006-2007, Ext JS, LLC.
22516 * Originally Released Under LGPL - original licence link has changed is not relivant.
22519 * <script type="text/javascript">
22524 * @class Roo.Shadow
22525 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22526 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22527 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22529 * Create a new Shadow
22530 * @param {Object} config The config object
22532 Roo.Shadow = function(config){
22533 Roo.apply(this, config);
22534 if(typeof this.mode != "string"){
22535 this.mode = this.defaultMode;
22537 var o = this.offset, a = {h: 0};
22538 var rad = Math.floor(this.offset/2);
22539 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22545 a.l -= this.offset + rad;
22546 a.t -= this.offset + rad;
22557 a.l -= (this.offset - rad);
22558 a.t -= this.offset + rad;
22560 a.w -= (this.offset - rad)*2;
22571 a.l -= (this.offset - rad);
22572 a.t -= (this.offset - rad);
22574 a.w -= (this.offset + rad + 1);
22575 a.h -= (this.offset + rad);
22584 Roo.Shadow.prototype = {
22586 * @cfg {String} mode
22587 * The shadow display mode. Supports the following options:<br />
22588 * sides: Shadow displays on both sides and bottom only<br />
22589 * frame: Shadow displays equally on all four sides<br />
22590 * drop: Traditional bottom-right drop shadow (default)
22593 * @cfg {String} offset
22594 * The number of pixels to offset the shadow from the element (defaults to 4)
22599 defaultMode: "drop",
22602 * Displays the shadow under the target element
22603 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22605 show : function(target){
22606 target = Roo.get(target);
22608 this.el = Roo.Shadow.Pool.pull();
22609 if(this.el.dom.nextSibling != target.dom){
22610 this.el.insertBefore(target);
22613 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22615 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22618 target.getLeft(true),
22619 target.getTop(true),
22623 this.el.dom.style.display = "block";
22627 * Returns true if the shadow is visible, else false
22629 isVisible : function(){
22630 return this.el ? true : false;
22634 * Direct alignment when values are already available. Show must be called at least once before
22635 * calling this method to ensure it is initialized.
22636 * @param {Number} left The target element left position
22637 * @param {Number} top The target element top position
22638 * @param {Number} width The target element width
22639 * @param {Number} height The target element height
22641 realign : function(l, t, w, h){
22645 var a = this.adjusts, d = this.el.dom, s = d.style;
22647 s.left = (l+a.l)+"px";
22648 s.top = (t+a.t)+"px";
22649 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22651 if(s.width != sws || s.height != shs){
22655 var cn = d.childNodes;
22656 var sww = Math.max(0, (sw-12))+"px";
22657 cn[0].childNodes[1].style.width = sww;
22658 cn[1].childNodes[1].style.width = sww;
22659 cn[2].childNodes[1].style.width = sww;
22660 cn[1].style.height = Math.max(0, (sh-12))+"px";
22666 * Hides this shadow
22670 this.el.dom.style.display = "none";
22671 Roo.Shadow.Pool.push(this.el);
22677 * Adjust the z-index of this shadow
22678 * @param {Number} zindex The new z-index
22680 setZIndex : function(z){
22683 this.el.setStyle("z-index", z);
22688 // Private utility class that manages the internal Shadow cache
22689 Roo.Shadow.Pool = function(){
22691 var markup = Roo.isIE ?
22692 '<div class="x-ie-shadow"></div>' :
22693 '<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>';
22696 var sh = p.shift();
22698 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22699 sh.autoBoxAdjust = false;
22704 push : function(sh){
22710 * Ext JS Library 1.1.1
22711 * Copyright(c) 2006-2007, Ext JS, LLC.
22713 * Originally Released Under LGPL - original licence link has changed is not relivant.
22716 * <script type="text/javascript">
22720 * @class Roo.BoxComponent
22721 * @extends Roo.Component
22722 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22723 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22724 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22725 * layout containers.
22727 * @param {Roo.Element/String/Object} config The configuration options.
22729 Roo.BoxComponent = function(config){
22730 Roo.Component.call(this, config);
22734 * Fires after the component is resized.
22735 * @param {Roo.Component} this
22736 * @param {Number} adjWidth The box-adjusted width that was set
22737 * @param {Number} adjHeight The box-adjusted height that was set
22738 * @param {Number} rawWidth The width that was originally specified
22739 * @param {Number} rawHeight The height that was originally specified
22744 * Fires after the component is moved.
22745 * @param {Roo.Component} this
22746 * @param {Number} x The new x position
22747 * @param {Number} y The new y position
22753 Roo.extend(Roo.BoxComponent, Roo.Component, {
22754 // private, set in afterRender to signify that the component has been rendered
22756 // private, used to defer height settings to subclasses
22757 deferHeight: false,
22758 /** @cfg {Number} width
22759 * width (optional) size of component
22761 /** @cfg {Number} height
22762 * height (optional) size of component
22766 * Sets the width and height of the component. This method fires the resize event. This method can accept
22767 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22768 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22769 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22770 * @return {Roo.BoxComponent} this
22772 setSize : function(w, h){
22773 // support for standard size objects
22774 if(typeof w == 'object'){
22779 if(!this.boxReady){
22785 // prevent recalcs when not needed
22786 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22789 this.lastSize = {width: w, height: h};
22791 var adj = this.adjustSize(w, h);
22792 var aw = adj.width, ah = adj.height;
22793 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22794 var rz = this.getResizeEl();
22795 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22796 rz.setSize(aw, ah);
22797 }else if(!this.deferHeight && ah !== undefined){
22799 }else if(aw !== undefined){
22802 this.onResize(aw, ah, w, h);
22803 this.fireEvent('resize', this, aw, ah, w, h);
22809 * Gets the current size of the component's underlying element.
22810 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22812 getSize : function(){
22813 return this.el.getSize();
22817 * Gets the current XY position of the component's underlying element.
22818 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22819 * @return {Array} The XY position of the element (e.g., [100, 200])
22821 getPosition : function(local){
22822 if(local === true){
22823 return [this.el.getLeft(true), this.el.getTop(true)];
22825 return this.xy || this.el.getXY();
22829 * Gets the current box measurements of the component's underlying element.
22830 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22831 * @returns {Object} box An object in the format {x, y, width, height}
22833 getBox : function(local){
22834 var s = this.el.getSize();
22836 s.x = this.el.getLeft(true);
22837 s.y = this.el.getTop(true);
22839 var xy = this.xy || this.el.getXY();
22847 * Sets the current box measurements of the component's underlying element.
22848 * @param {Object} box An object in the format {x, y, width, height}
22849 * @returns {Roo.BoxComponent} this
22851 updateBox : function(box){
22852 this.setSize(box.width, box.height);
22853 this.setPagePosition(box.x, box.y);
22858 getResizeEl : function(){
22859 return this.resizeEl || this.el;
22863 getPositionEl : function(){
22864 return this.positionEl || this.el;
22868 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22869 * This method fires the move event.
22870 * @param {Number} left The new left
22871 * @param {Number} top The new top
22872 * @returns {Roo.BoxComponent} this
22874 setPosition : function(x, y){
22877 if(!this.boxReady){
22880 var adj = this.adjustPosition(x, y);
22881 var ax = adj.x, ay = adj.y;
22883 var el = this.getPositionEl();
22884 if(ax !== undefined || ay !== undefined){
22885 if(ax !== undefined && ay !== undefined){
22886 el.setLeftTop(ax, ay);
22887 }else if(ax !== undefined){
22889 }else if(ay !== undefined){
22892 this.onPosition(ax, ay);
22893 this.fireEvent('move', this, ax, ay);
22899 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22900 * This method fires the move event.
22901 * @param {Number} x The new x position
22902 * @param {Number} y The new y position
22903 * @returns {Roo.BoxComponent} this
22905 setPagePosition : function(x, y){
22908 if(!this.boxReady){
22911 if(x === undefined || y === undefined){ // cannot translate undefined points
22914 var p = this.el.translatePoints(x, y);
22915 this.setPosition(p.left, p.top);
22920 onRender : function(ct, position){
22921 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
22923 this.resizeEl = Roo.get(this.resizeEl);
22925 if(this.positionEl){
22926 this.positionEl = Roo.get(this.positionEl);
22931 afterRender : function(){
22932 Roo.BoxComponent.superclass.afterRender.call(this);
22933 this.boxReady = true;
22934 this.setSize(this.width, this.height);
22935 if(this.x || this.y){
22936 this.setPosition(this.x, this.y);
22938 if(this.pageX || this.pageY){
22939 this.setPagePosition(this.pageX, this.pageY);
22944 * Force the component's size to recalculate based on the underlying element's current height and width.
22945 * @returns {Roo.BoxComponent} this
22947 syncSize : function(){
22948 delete this.lastSize;
22949 this.setSize(this.el.getWidth(), this.el.getHeight());
22954 * Called after the component is resized, this method is empty by default but can be implemented by any
22955 * subclass that needs to perform custom logic after a resize occurs.
22956 * @param {Number} adjWidth The box-adjusted width that was set
22957 * @param {Number} adjHeight The box-adjusted height that was set
22958 * @param {Number} rawWidth The width that was originally specified
22959 * @param {Number} rawHeight The height that was originally specified
22961 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
22966 * Called after the component is moved, this method is empty by default but can be implemented by any
22967 * subclass that needs to perform custom logic after a move occurs.
22968 * @param {Number} x The new x position
22969 * @param {Number} y The new y position
22971 onPosition : function(x, y){
22976 adjustSize : function(w, h){
22977 if(this.autoWidth){
22980 if(this.autoHeight){
22983 return {width : w, height: h};
22987 adjustPosition : function(x, y){
22988 return {x : x, y: y};
22992 * Ext JS Library 1.1.1
22993 * Copyright(c) 2006-2007, Ext JS, LLC.
22995 * Originally Released Under LGPL - original licence link has changed is not relivant.
22998 * <script type="text/javascript">
23003 * @class Roo.SplitBar
23004 * @extends Roo.util.Observable
23005 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23009 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23010 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23011 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23012 split.minSize = 100;
23013 split.maxSize = 600;
23014 split.animate = true;
23015 split.on('moved', splitterMoved);
23018 * Create a new SplitBar
23019 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23020 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23021 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23022 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23023 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23024 position of the SplitBar).
23026 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23029 this.el = Roo.get(dragElement, true);
23030 this.el.dom.unselectable = "on";
23032 this.resizingEl = Roo.get(resizingElement, true);
23036 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23037 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23040 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23043 * The minimum size of the resizing element. (Defaults to 0)
23049 * The maximum size of the resizing element. (Defaults to 2000)
23052 this.maxSize = 2000;
23055 * Whether to animate the transition to the new size
23058 this.animate = false;
23061 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23064 this.useShim = false;
23069 if(!existingProxy){
23071 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23073 this.proxy = Roo.get(existingProxy).dom;
23076 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23079 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23082 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23085 this.dragSpecs = {};
23088 * @private The adapter to use to positon and resize elements
23090 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23091 this.adapter.init(this);
23093 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23095 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23096 this.el.addClass("x-splitbar-h");
23099 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23100 this.el.addClass("x-splitbar-v");
23106 * Fires when the splitter is moved (alias for {@link #event-moved})
23107 * @param {Roo.SplitBar} this
23108 * @param {Number} newSize the new width or height
23113 * Fires when the splitter is moved
23114 * @param {Roo.SplitBar} this
23115 * @param {Number} newSize the new width or height
23119 * @event beforeresize
23120 * Fires before the splitter is dragged
23121 * @param {Roo.SplitBar} this
23123 "beforeresize" : true,
23125 "beforeapply" : true
23128 Roo.util.Observable.call(this);
23131 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23132 onStartProxyDrag : function(x, y){
23133 this.fireEvent("beforeresize", this);
23135 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23137 o.enableDisplayMode("block");
23138 // all splitbars share the same overlay
23139 Roo.SplitBar.prototype.overlay = o;
23141 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23142 this.overlay.show();
23143 Roo.get(this.proxy).setDisplayed("block");
23144 var size = this.adapter.getElementSize(this);
23145 this.activeMinSize = this.getMinimumSize();;
23146 this.activeMaxSize = this.getMaximumSize();;
23147 var c1 = size - this.activeMinSize;
23148 var c2 = Math.max(this.activeMaxSize - size, 0);
23149 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23150 this.dd.resetConstraints();
23151 this.dd.setXConstraint(
23152 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23153 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23155 this.dd.setYConstraint(0, 0);
23157 this.dd.resetConstraints();
23158 this.dd.setXConstraint(0, 0);
23159 this.dd.setYConstraint(
23160 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23161 this.placement == Roo.SplitBar.TOP ? c2 : c1
23164 this.dragSpecs.startSize = size;
23165 this.dragSpecs.startPoint = [x, y];
23166 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23170 * @private Called after the drag operation by the DDProxy
23172 onEndProxyDrag : function(e){
23173 Roo.get(this.proxy).setDisplayed(false);
23174 var endPoint = Roo.lib.Event.getXY(e);
23176 this.overlay.hide();
23179 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23180 newSize = this.dragSpecs.startSize +
23181 (this.placement == Roo.SplitBar.LEFT ?
23182 endPoint[0] - this.dragSpecs.startPoint[0] :
23183 this.dragSpecs.startPoint[0] - endPoint[0]
23186 newSize = this.dragSpecs.startSize +
23187 (this.placement == Roo.SplitBar.TOP ?
23188 endPoint[1] - this.dragSpecs.startPoint[1] :
23189 this.dragSpecs.startPoint[1] - endPoint[1]
23192 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23193 if(newSize != this.dragSpecs.startSize){
23194 if(this.fireEvent('beforeapply', this, newSize) !== false){
23195 this.adapter.setElementSize(this, newSize);
23196 this.fireEvent("moved", this, newSize);
23197 this.fireEvent("resize", this, newSize);
23203 * Get the adapter this SplitBar uses
23204 * @return The adapter object
23206 getAdapter : function(){
23207 return this.adapter;
23211 * Set the adapter this SplitBar uses
23212 * @param {Object} adapter A SplitBar adapter object
23214 setAdapter : function(adapter){
23215 this.adapter = adapter;
23216 this.adapter.init(this);
23220 * Gets the minimum size for the resizing element
23221 * @return {Number} The minimum size
23223 getMinimumSize : function(){
23224 return this.minSize;
23228 * Sets the minimum size for the resizing element
23229 * @param {Number} minSize The minimum size
23231 setMinimumSize : function(minSize){
23232 this.minSize = minSize;
23236 * Gets the maximum size for the resizing element
23237 * @return {Number} The maximum size
23239 getMaximumSize : function(){
23240 return this.maxSize;
23244 * Sets the maximum size for the resizing element
23245 * @param {Number} maxSize The maximum size
23247 setMaximumSize : function(maxSize){
23248 this.maxSize = maxSize;
23252 * Sets the initialize size for the resizing element
23253 * @param {Number} size The initial size
23255 setCurrentSize : function(size){
23256 var oldAnimate = this.animate;
23257 this.animate = false;
23258 this.adapter.setElementSize(this, size);
23259 this.animate = oldAnimate;
23263 * Destroy this splitbar.
23264 * @param {Boolean} removeEl True to remove the element
23266 destroy : function(removeEl){
23268 this.shim.remove();
23271 this.proxy.parentNode.removeChild(this.proxy);
23279 * @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.
23281 Roo.SplitBar.createProxy = function(dir){
23282 var proxy = new Roo.Element(document.createElement("div"));
23283 proxy.unselectable();
23284 var cls = 'x-splitbar-proxy';
23285 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23286 document.body.appendChild(proxy.dom);
23291 * @class Roo.SplitBar.BasicLayoutAdapter
23292 * Default Adapter. It assumes the splitter and resizing element are not positioned
23293 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23295 Roo.SplitBar.BasicLayoutAdapter = function(){
23298 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23299 // do nothing for now
23300 init : function(s){
23304 * Called before drag operations to get the current size of the resizing element.
23305 * @param {Roo.SplitBar} s The SplitBar using this adapter
23307 getElementSize : function(s){
23308 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23309 return s.resizingEl.getWidth();
23311 return s.resizingEl.getHeight();
23316 * Called after drag operations to set the size of the resizing element.
23317 * @param {Roo.SplitBar} s The SplitBar using this adapter
23318 * @param {Number} newSize The new size to set
23319 * @param {Function} onComplete A function to be invoked when resizing is complete
23321 setElementSize : function(s, newSize, onComplete){
23322 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23324 s.resizingEl.setWidth(newSize);
23326 onComplete(s, newSize);
23329 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23334 s.resizingEl.setHeight(newSize);
23336 onComplete(s, newSize);
23339 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23346 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23347 * @extends Roo.SplitBar.BasicLayoutAdapter
23348 * Adapter that moves the splitter element to align with the resized sizing element.
23349 * Used with an absolute positioned SplitBar.
23350 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23351 * document.body, make sure you assign an id to the body element.
23353 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23354 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23355 this.container = Roo.get(container);
23358 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23359 init : function(s){
23360 this.basic.init(s);
23363 getElementSize : function(s){
23364 return this.basic.getElementSize(s);
23367 setElementSize : function(s, newSize, onComplete){
23368 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23371 moveSplitter : function(s){
23372 var yes = Roo.SplitBar;
23373 switch(s.placement){
23375 s.el.setX(s.resizingEl.getRight());
23378 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23381 s.el.setY(s.resizingEl.getBottom());
23384 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23391 * Orientation constant - Create a vertical SplitBar
23395 Roo.SplitBar.VERTICAL = 1;
23398 * Orientation constant - Create a horizontal SplitBar
23402 Roo.SplitBar.HORIZONTAL = 2;
23405 * Placement constant - The resizing element is to the left of the splitter element
23409 Roo.SplitBar.LEFT = 1;
23412 * Placement constant - The resizing element is to the right of the splitter element
23416 Roo.SplitBar.RIGHT = 2;
23419 * Placement constant - The resizing element is positioned above the splitter element
23423 Roo.SplitBar.TOP = 3;
23426 * Placement constant - The resizing element is positioned under splitter element
23430 Roo.SplitBar.BOTTOM = 4;
23433 * Ext JS Library 1.1.1
23434 * Copyright(c) 2006-2007, Ext JS, LLC.
23436 * Originally Released Under LGPL - original licence link has changed is not relivant.
23439 * <script type="text/javascript">
23444 * @extends Roo.util.Observable
23445 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23446 * This class also supports single and multi selection modes. <br>
23447 * Create a data model bound view:
23449 var store = new Roo.data.Store(...);
23451 var view = new Roo.View({
23453 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23455 singleSelect: true,
23456 selectedClass: "ydataview-selected",
23460 // listen for node click?
23461 view.on("click", function(vw, index, node, e){
23462 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23466 dataModel.load("foobar.xml");
23468 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23470 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23471 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23473 * Note: old style constructor is still suported (container, template, config)
23476 * Create a new View
23477 * @param {Object} config The config object
23480 Roo.View = function(config, depreciated_tpl, depreciated_config){
23482 if (typeof(depreciated_tpl) == 'undefined') {
23483 // new way.. - universal constructor.
23484 Roo.apply(this, config);
23485 this.el = Roo.get(this.el);
23488 this.el = Roo.get(config);
23489 this.tpl = depreciated_tpl;
23490 Roo.apply(this, depreciated_config);
23494 if(typeof(this.tpl) == "string"){
23495 this.tpl = new Roo.Template(this.tpl);
23497 // support xtype ctors..
23498 this.tpl = new Roo.factory(this.tpl, Roo);
23502 this.tpl.compile();
23509 * @event beforeclick
23510 * Fires before a click is processed. Returns false to cancel the default action.
23511 * @param {Roo.View} this
23512 * @param {Number} index The index of the target node
23513 * @param {HTMLElement} node The target node
23514 * @param {Roo.EventObject} e The raw event object
23516 "beforeclick" : true,
23519 * Fires when a template node is clicked.
23520 * @param {Roo.View} this
23521 * @param {Number} index The index of the target node
23522 * @param {HTMLElement} node The target node
23523 * @param {Roo.EventObject} e The raw event object
23528 * Fires when a template node is double clicked.
23529 * @param {Roo.View} this
23530 * @param {Number} index The index of the target node
23531 * @param {HTMLElement} node The target node
23532 * @param {Roo.EventObject} e The raw event object
23536 * @event contextmenu
23537 * Fires when a template node is right clicked.
23538 * @param {Roo.View} this
23539 * @param {Number} index The index of the target node
23540 * @param {HTMLElement} node The target node
23541 * @param {Roo.EventObject} e The raw event object
23543 "contextmenu" : true,
23545 * @event selectionchange
23546 * Fires when the selected nodes change.
23547 * @param {Roo.View} this
23548 * @param {Array} selections Array of the selected nodes
23550 "selectionchange" : true,
23553 * @event beforeselect
23554 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23555 * @param {Roo.View} this
23556 * @param {HTMLElement} node The node to be selected
23557 * @param {Array} selections Array of currently selected nodes
23559 "beforeselect" : true
23563 "click": this.onClick,
23564 "dblclick": this.onDblClick,
23565 "contextmenu": this.onContextMenu,
23569 this.selections = [];
23571 this.cmp = new Roo.CompositeElementLite([]);
23573 this.store = Roo.factory(this.store, Roo.data);
23574 this.setStore(this.store, true);
23576 Roo.View.superclass.constructor.call(this);
23579 Roo.extend(Roo.View, Roo.util.Observable, {
23582 * @cfg {Roo.data.Store} store Data store to load data from.
23587 * @cfg {String|Roo.Element} el The container element.
23592 * @cfg {String|Roo.Template} tpl The template used by this View
23597 * @cfg {String} selectedClass The css class to add to selected nodes
23599 selectedClass : "x-view-selected",
23601 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23605 * @cfg {Boolean} multiSelect Allow multiple selection
23608 multiSelect : false,
23610 * @cfg {Boolean} singleSelect Allow single selection
23612 singleSelect: false,
23615 * Returns the element this view is bound to.
23616 * @return {Roo.Element}
23618 getEl : function(){
23623 * Refreshes the view.
23625 refresh : function(){
23627 this.clearSelections();
23628 this.el.update("");
23630 var records = this.store.getRange();
23631 if(records.length < 1){
23632 this.el.update(this.emptyText);
23635 for(var i = 0, len = records.length; i < len; i++){
23636 var data = this.prepareData(records[i].data, i, records[i]);
23637 html[html.length] = t.apply(data);
23639 this.el.update(html.join(""));
23640 this.nodes = this.el.dom.childNodes;
23641 this.updateIndexes(0);
23645 * Function to override to reformat the data that is sent to
23646 * the template for each node.
23647 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23648 * a JSON object for an UpdateManager bound view).
23650 prepareData : function(data){
23654 onUpdate : function(ds, record){
23655 this.clearSelections();
23656 var index = this.store.indexOf(record);
23657 var n = this.nodes[index];
23658 this.tpl.insertBefore(n, this.prepareData(record.data));
23659 n.parentNode.removeChild(n);
23660 this.updateIndexes(index, index);
23663 onAdd : function(ds, records, index){
23664 this.clearSelections();
23665 if(this.nodes.length == 0){
23669 var n = this.nodes[index];
23670 for(var i = 0, len = records.length; i < len; i++){
23671 var d = this.prepareData(records[i].data);
23673 this.tpl.insertBefore(n, d);
23675 this.tpl.append(this.el, d);
23678 this.updateIndexes(index);
23681 onRemove : function(ds, record, index){
23682 this.clearSelections();
23683 this.el.dom.removeChild(this.nodes[index]);
23684 this.updateIndexes(index);
23688 * Refresh an individual node.
23689 * @param {Number} index
23691 refreshNode : function(index){
23692 this.onUpdate(this.store, this.store.getAt(index));
23695 updateIndexes : function(startIndex, endIndex){
23696 var ns = this.nodes;
23697 startIndex = startIndex || 0;
23698 endIndex = endIndex || ns.length - 1;
23699 for(var i = startIndex; i <= endIndex; i++){
23700 ns[i].nodeIndex = i;
23705 * Changes the data store this view uses and refresh the view.
23706 * @param {Store} store
23708 setStore : function(store, initial){
23709 if(!initial && this.store){
23710 this.store.un("datachanged", this.refresh);
23711 this.store.un("add", this.onAdd);
23712 this.store.un("remove", this.onRemove);
23713 this.store.un("update", this.onUpdate);
23714 this.store.un("clear", this.refresh);
23718 store.on("datachanged", this.refresh, this);
23719 store.on("add", this.onAdd, this);
23720 store.on("remove", this.onRemove, this);
23721 store.on("update", this.onUpdate, this);
23722 store.on("clear", this.refresh, this);
23731 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23732 * @param {HTMLElement} node
23733 * @return {HTMLElement} The template node
23735 findItemFromChild : function(node){
23736 var el = this.el.dom;
23737 if(!node || node.parentNode == el){
23740 var p = node.parentNode;
23741 while(p && p != el){
23742 if(p.parentNode == el){
23751 onClick : function(e){
23752 var item = this.findItemFromChild(e.getTarget());
23754 var index = this.indexOf(item);
23755 if(this.onItemClick(item, index, e) !== false){
23756 this.fireEvent("click", this, index, item, e);
23759 this.clearSelections();
23764 onContextMenu : function(e){
23765 var item = this.findItemFromChild(e.getTarget());
23767 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23772 onDblClick : function(e){
23773 var item = this.findItemFromChild(e.getTarget());
23775 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23779 onItemClick : function(item, index, e){
23780 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23783 if(this.multiSelect || this.singleSelect){
23784 if(this.multiSelect && e.shiftKey && this.lastSelection){
23785 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23787 this.select(item, this.multiSelect && e.ctrlKey);
23788 this.lastSelection = item;
23790 e.preventDefault();
23796 * Get the number of selected nodes.
23799 getSelectionCount : function(){
23800 return this.selections.length;
23804 * Get the currently selected nodes.
23805 * @return {Array} An array of HTMLElements
23807 getSelectedNodes : function(){
23808 return this.selections;
23812 * Get the indexes of the selected nodes.
23815 getSelectedIndexes : function(){
23816 var indexes = [], s = this.selections;
23817 for(var i = 0, len = s.length; i < len; i++){
23818 indexes.push(s[i].nodeIndex);
23824 * Clear all selections
23825 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23827 clearSelections : function(suppressEvent){
23828 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23829 this.cmp.elements = this.selections;
23830 this.cmp.removeClass(this.selectedClass);
23831 this.selections = [];
23832 if(!suppressEvent){
23833 this.fireEvent("selectionchange", this, this.selections);
23839 * Returns true if the passed node is selected
23840 * @param {HTMLElement/Number} node The node or node index
23841 * @return {Boolean}
23843 isSelected : function(node){
23844 var s = this.selections;
23848 node = this.getNode(node);
23849 return s.indexOf(node) !== -1;
23854 * @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
23855 * @param {Boolean} keepExisting (optional) true to keep existing selections
23856 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23858 select : function(nodeInfo, keepExisting, suppressEvent){
23859 if(nodeInfo instanceof Array){
23861 this.clearSelections(true);
23863 for(var i = 0, len = nodeInfo.length; i < len; i++){
23864 this.select(nodeInfo[i], true, true);
23867 var node = this.getNode(nodeInfo);
23868 if(node && !this.isSelected(node)){
23870 this.clearSelections(true);
23872 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23873 Roo.fly(node).addClass(this.selectedClass);
23874 this.selections.push(node);
23875 if(!suppressEvent){
23876 this.fireEvent("selectionchange", this, this.selections);
23884 * Gets a template node.
23885 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23886 * @return {HTMLElement} The node or null if it wasn't found
23888 getNode : function(nodeInfo){
23889 if(typeof nodeInfo == "string"){
23890 return document.getElementById(nodeInfo);
23891 }else if(typeof nodeInfo == "number"){
23892 return this.nodes[nodeInfo];
23898 * Gets a range template nodes.
23899 * @param {Number} startIndex
23900 * @param {Number} endIndex
23901 * @return {Array} An array of nodes
23903 getNodes : function(start, end){
23904 var ns = this.nodes;
23905 start = start || 0;
23906 end = typeof end == "undefined" ? ns.length - 1 : end;
23909 for(var i = start; i <= end; i++){
23913 for(var i = start; i >= end; i--){
23921 * Finds the index of the passed node
23922 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23923 * @return {Number} The index of the node or -1
23925 indexOf : function(node){
23926 node = this.getNode(node);
23927 if(typeof node.nodeIndex == "number"){
23928 return node.nodeIndex;
23930 var ns = this.nodes;
23931 for(var i = 0, len = ns.length; i < len; i++){
23941 * Ext JS Library 1.1.1
23942 * Copyright(c) 2006-2007, Ext JS, LLC.
23944 * Originally Released Under LGPL - original licence link has changed is not relivant.
23947 * <script type="text/javascript">
23951 * @class Roo.JsonView
23952 * @extends Roo.View
23953 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
23955 var view = new Roo.JsonView({
23956 container: "my-element",
23957 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
23962 // listen for node click?
23963 view.on("click", function(vw, index, node, e){
23964 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23967 // direct load of JSON data
23968 view.load("foobar.php");
23970 // Example from my blog list
23971 var tpl = new Roo.Template(
23972 '<div class="entry">' +
23973 '<a class="entry-title" href="{link}">{title}</a>' +
23974 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
23975 "</div><hr />"
23978 var moreView = new Roo.JsonView({
23979 container : "entry-list",
23983 moreView.on("beforerender", this.sortEntries, this);
23985 url: "/blog/get-posts.php",
23986 params: "allposts=true",
23987 text: "Loading Blog Entries..."
23991 * Note: old code is supported with arguments : (container, template, config)
23995 * Create a new JsonView
23997 * @param {Object} config The config object
24000 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24003 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24005 var um = this.el.getUpdateManager();
24006 um.setRenderer(this);
24007 um.on("update", this.onLoad, this);
24008 um.on("failure", this.onLoadException, this);
24011 * @event beforerender
24012 * Fires before rendering of the downloaded JSON data.
24013 * @param {Roo.JsonView} this
24014 * @param {Object} data The JSON data loaded
24018 * Fires when data is loaded.
24019 * @param {Roo.JsonView} this
24020 * @param {Object} data The JSON data loaded
24021 * @param {Object} response The raw Connect response object
24024 * @event loadexception
24025 * Fires when loading fails.
24026 * @param {Roo.JsonView} this
24027 * @param {Object} response The raw Connect response object
24030 'beforerender' : true,
24032 'loadexception' : true
24035 Roo.extend(Roo.JsonView, Roo.View, {
24037 * @type {String} The root property in the loaded JSON object that contains the data
24042 * Refreshes the view.
24044 refresh : function(){
24045 this.clearSelections();
24046 this.el.update("");
24048 var o = this.jsonData;
24049 if(o && o.length > 0){
24050 for(var i = 0, len = o.length; i < len; i++){
24051 var data = this.prepareData(o[i], i, o);
24052 html[html.length] = this.tpl.apply(data);
24055 html.push(this.emptyText);
24057 this.el.update(html.join(""));
24058 this.nodes = this.el.dom.childNodes;
24059 this.updateIndexes(0);
24063 * 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.
24064 * @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:
24067 url: "your-url.php",
24068 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24069 callback: yourFunction,
24070 scope: yourObject, //(optional scope)
24073 text: "Loading...",
24078 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24079 * 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.
24080 * @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}
24081 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24082 * @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.
24085 var um = this.el.getUpdateManager();
24086 um.update.apply(um, arguments);
24089 render : function(el, response){
24090 this.clearSelections();
24091 this.el.update("");
24094 o = Roo.util.JSON.decode(response.responseText);
24097 o = o[this.jsonRoot];
24102 * The current JSON data or null
24105 this.beforeRender();
24110 * Get the number of records in the current JSON dataset
24113 getCount : function(){
24114 return this.jsonData ? this.jsonData.length : 0;
24118 * Returns the JSON object for the specified node(s)
24119 * @param {HTMLElement/Array} node The node or an array of nodes
24120 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24121 * you get the JSON object for the node
24123 getNodeData : function(node){
24124 if(node instanceof Array){
24126 for(var i = 0, len = node.length; i < len; i++){
24127 data.push(this.getNodeData(node[i]));
24131 return this.jsonData[this.indexOf(node)] || null;
24134 beforeRender : function(){
24135 this.snapshot = this.jsonData;
24137 this.sort.apply(this, this.sortInfo);
24139 this.fireEvent("beforerender", this, this.jsonData);
24142 onLoad : function(el, o){
24143 this.fireEvent("load", this, this.jsonData, o);
24146 onLoadException : function(el, o){
24147 this.fireEvent("loadexception", this, o);
24151 * Filter the data by a specific property.
24152 * @param {String} property A property on your JSON objects
24153 * @param {String/RegExp} value Either string that the property values
24154 * should start with, or a RegExp to test against the property
24156 filter : function(property, value){
24159 var ss = this.snapshot;
24160 if(typeof value == "string"){
24161 var vlen = value.length;
24163 this.clearFilter();
24166 value = value.toLowerCase();
24167 for(var i = 0, len = ss.length; i < len; i++){
24169 if(o[property].substr(0, vlen).toLowerCase() == value){
24173 } else if(value.exec){ // regex?
24174 for(var i = 0, len = ss.length; i < len; i++){
24176 if(value.test(o[property])){
24183 this.jsonData = data;
24189 * Filter by a function. The passed function will be called with each
24190 * object in the current dataset. If the function returns true the value is kept,
24191 * otherwise it is filtered.
24192 * @param {Function} fn
24193 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24195 filterBy : function(fn, scope){
24198 var ss = this.snapshot;
24199 for(var i = 0, len = ss.length; i < len; i++){
24201 if(fn.call(scope || this, o)){
24205 this.jsonData = data;
24211 * Clears the current filter.
24213 clearFilter : function(){
24214 if(this.snapshot && this.jsonData != this.snapshot){
24215 this.jsonData = this.snapshot;
24222 * Sorts the data for this view and refreshes it.
24223 * @param {String} property A property on your JSON objects to sort on
24224 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24225 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24227 sort : function(property, dir, sortType){
24228 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24231 var dsc = dir && dir.toLowerCase() == "desc";
24232 var f = function(o1, o2){
24233 var v1 = sortType ? sortType(o1[p]) : o1[p];
24234 var v2 = sortType ? sortType(o2[p]) : o2[p];
24237 return dsc ? +1 : -1;
24238 } else if(v1 > v2){
24239 return dsc ? -1 : +1;
24244 this.jsonData.sort(f);
24246 if(this.jsonData != this.snapshot){
24247 this.snapshot.sort(f);
24253 * Ext JS Library 1.1.1
24254 * Copyright(c) 2006-2007, Ext JS, LLC.
24256 * Originally Released Under LGPL - original licence link has changed is not relivant.
24259 * <script type="text/javascript">
24264 * @class Roo.ColorPalette
24265 * @extends Roo.Component
24266 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24267 * Here's an example of typical usage:
24269 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24270 cp.render('my-div');
24272 cp.on('select', function(palette, selColor){
24273 // do something with selColor
24277 * Create a new ColorPalette
24278 * @param {Object} config The config object
24280 Roo.ColorPalette = function(config){
24281 Roo.ColorPalette.superclass.constructor.call(this, config);
24285 * Fires when a color is selected
24286 * @param {ColorPalette} this
24287 * @param {String} color The 6-digit color hex code (without the # symbol)
24293 this.on("select", this.handler, this.scope, true);
24296 Roo.extend(Roo.ColorPalette, Roo.Component, {
24298 * @cfg {String} itemCls
24299 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24301 itemCls : "x-color-palette",
24303 * @cfg {String} value
24304 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24305 * the hex codes are case-sensitive.
24308 clickEvent:'click',
24310 ctype: "Roo.ColorPalette",
24313 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24315 allowReselect : false,
24318 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24319 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24320 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24321 * of colors with the width setting until the box is symmetrical.</p>
24322 * <p>You can override individual colors if needed:</p>
24324 var cp = new Roo.ColorPalette();
24325 cp.colors[0] = "FF0000"; // change the first box to red
24328 Or you can provide a custom array of your own for complete control:
24330 var cp = new Roo.ColorPalette();
24331 cp.colors = ["000000", "993300", "333300"];
24336 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24337 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24338 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24339 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24340 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24344 onRender : function(container, position){
24345 var t = new Roo.MasterTemplate(
24346 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24348 var c = this.colors;
24349 for(var i = 0, len = c.length; i < len; i++){
24352 var el = document.createElement("div");
24353 el.className = this.itemCls;
24355 container.dom.insertBefore(el, position);
24356 this.el = Roo.get(el);
24357 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24358 if(this.clickEvent != 'click'){
24359 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24364 afterRender : function(){
24365 Roo.ColorPalette.superclass.afterRender.call(this);
24367 var s = this.value;
24374 handleClick : function(e, t){
24375 e.preventDefault();
24376 if(!this.disabled){
24377 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24378 this.select(c.toUpperCase());
24383 * Selects the specified color in the palette (fires the select event)
24384 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24386 select : function(color){
24387 color = color.replace("#", "");
24388 if(color != this.value || this.allowReselect){
24391 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24393 el.child("a.color-"+color).addClass("x-color-palette-sel");
24394 this.value = color;
24395 this.fireEvent("select", this, color);
24400 * Ext JS Library 1.1.1
24401 * Copyright(c) 2006-2007, Ext JS, LLC.
24403 * Originally Released Under LGPL - original licence link has changed is not relivant.
24406 * <script type="text/javascript">
24410 * @class Roo.DatePicker
24411 * @extends Roo.Component
24412 * Simple date picker class.
24414 * Create a new DatePicker
24415 * @param {Object} config The config object
24417 Roo.DatePicker = function(config){
24418 Roo.DatePicker.superclass.constructor.call(this, config);
24420 this.value = config && config.value ?
24421 config.value.clearTime() : new Date().clearTime();
24426 * Fires when a date is selected
24427 * @param {DatePicker} this
24428 * @param {Date} date The selected date
24434 this.on("select", this.handler, this.scope || this);
24436 // build the disabledDatesRE
24437 if(!this.disabledDatesRE && this.disabledDates){
24438 var dd = this.disabledDates;
24440 for(var i = 0; i < dd.length; i++){
24442 if(i != dd.length-1) re += "|";
24444 this.disabledDatesRE = new RegExp(re + ")");
24448 Roo.extend(Roo.DatePicker, Roo.Component, {
24450 * @cfg {String} todayText
24451 * The text to display on the button that selects the current date (defaults to "Today")
24453 todayText : "Today",
24455 * @cfg {String} okText
24456 * The text to display on the ok button
24458 okText : " OK ", //   to give the user extra clicking room
24460 * @cfg {String} cancelText
24461 * The text to display on the cancel button
24463 cancelText : "Cancel",
24465 * @cfg {String} todayTip
24466 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24468 todayTip : "{0} (Spacebar)",
24470 * @cfg {Date} minDate
24471 * Minimum allowable date (JavaScript date object, defaults to null)
24475 * @cfg {Date} maxDate
24476 * Maximum allowable date (JavaScript date object, defaults to null)
24480 * @cfg {String} minText
24481 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24483 minText : "This date is before the minimum date",
24485 * @cfg {String} maxText
24486 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24488 maxText : "This date is after the maximum date",
24490 * @cfg {String} format
24491 * The default date format string which can be overriden for localization support. The format must be
24492 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24496 * @cfg {Array} disabledDays
24497 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24499 disabledDays : null,
24501 * @cfg {String} disabledDaysText
24502 * The tooltip to display when the date falls on a disabled day (defaults to "")
24504 disabledDaysText : "",
24506 * @cfg {RegExp} disabledDatesRE
24507 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24509 disabledDatesRE : null,
24511 * @cfg {String} disabledDatesText
24512 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24514 disabledDatesText : "",
24516 * @cfg {Boolean} constrainToViewport
24517 * True to constrain the date picker to the viewport (defaults to true)
24519 constrainToViewport : true,
24521 * @cfg {Array} monthNames
24522 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24524 monthNames : Date.monthNames,
24526 * @cfg {Array} dayNames
24527 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24529 dayNames : Date.dayNames,
24531 * @cfg {String} nextText
24532 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24534 nextText: 'Next Month (Control+Right)',
24536 * @cfg {String} prevText
24537 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24539 prevText: 'Previous Month (Control+Left)',
24541 * @cfg {String} monthYearText
24542 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24544 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24546 * @cfg {Number} startDay
24547 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24551 * @cfg {Bool} showClear
24552 * Show a clear button (usefull for date form elements that can be blank.)
24558 * Sets the value of the date field
24559 * @param {Date} value The date to set
24561 setValue : function(value){
24562 var old = this.value;
24563 this.value = value.clearTime(true);
24565 this.update(this.value);
24570 * Gets the current selected value of the date field
24571 * @return {Date} The selected date
24573 getValue : function(){
24578 focus : function(){
24580 this.update(this.activeDate);
24585 onRender : function(container, position){
24587 '<table cellspacing="0">',
24588 '<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>',
24589 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24590 var dn = this.dayNames;
24591 for(var i = 0; i < 7; i++){
24592 var d = this.startDay+i;
24596 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24598 m[m.length] = "</tr></thead><tbody><tr>";
24599 for(var i = 0; i < 42; i++) {
24600 if(i % 7 == 0 && i != 0){
24601 m[m.length] = "</tr><tr>";
24603 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24605 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24606 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24608 var el = document.createElement("div");
24609 el.className = "x-date-picker";
24610 el.innerHTML = m.join("");
24612 container.dom.insertBefore(el, position);
24614 this.el = Roo.get(el);
24615 this.eventEl = Roo.get(el.firstChild);
24617 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24618 handler: this.showPrevMonth,
24620 preventDefault:true,
24624 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24625 handler: this.showNextMonth,
24627 preventDefault:true,
24631 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24633 this.monthPicker = this.el.down('div.x-date-mp');
24634 this.monthPicker.enableDisplayMode('block');
24636 var kn = new Roo.KeyNav(this.eventEl, {
24637 "left" : function(e){
24639 this.showPrevMonth() :
24640 this.update(this.activeDate.add("d", -1));
24643 "right" : function(e){
24645 this.showNextMonth() :
24646 this.update(this.activeDate.add("d", 1));
24649 "up" : function(e){
24651 this.showNextYear() :
24652 this.update(this.activeDate.add("d", -7));
24655 "down" : function(e){
24657 this.showPrevYear() :
24658 this.update(this.activeDate.add("d", 7));
24661 "pageUp" : function(e){
24662 this.showNextMonth();
24665 "pageDown" : function(e){
24666 this.showPrevMonth();
24669 "enter" : function(e){
24670 e.stopPropagation();
24677 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24679 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24681 this.el.unselectable();
24683 this.cells = this.el.select("table.x-date-inner tbody td");
24684 this.textNodes = this.el.query("table.x-date-inner tbody span");
24686 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24688 tooltip: this.monthYearText
24691 this.mbtn.on('click', this.showMonthPicker, this);
24692 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24695 var today = (new Date()).dateFormat(this.format);
24697 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24698 if (this.showClear) {
24699 baseTb.add( new Roo.Toolbar.Fill());
24702 text: String.format(this.todayText, today),
24703 tooltip: String.format(this.todayTip, today),
24704 handler: this.selectToday,
24708 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24711 if (this.showClear) {
24713 baseTb.add( new Roo.Toolbar.Fill());
24716 cls: 'x-btn-icon x-btn-clear',
24717 handler: function() {
24719 this.fireEvent("select", this, '');
24729 this.update(this.value);
24732 createMonthPicker : function(){
24733 if(!this.monthPicker.dom.firstChild){
24734 var buf = ['<table border="0" cellspacing="0">'];
24735 for(var i = 0; i < 6; i++){
24737 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24738 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24740 '<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>' :
24741 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24745 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24747 '</button><button type="button" class="x-date-mp-cancel">',
24749 '</button></td></tr>',
24752 this.monthPicker.update(buf.join(''));
24753 this.monthPicker.on('click', this.onMonthClick, this);
24754 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24756 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24757 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24759 this.mpMonths.each(function(m, a, i){
24762 m.dom.xmonth = 5 + Math.round(i * .5);
24764 m.dom.xmonth = Math.round((i-1) * .5);
24770 showMonthPicker : function(){
24771 this.createMonthPicker();
24772 var size = this.el.getSize();
24773 this.monthPicker.setSize(size);
24774 this.monthPicker.child('table').setSize(size);
24776 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24777 this.updateMPMonth(this.mpSelMonth);
24778 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24779 this.updateMPYear(this.mpSelYear);
24781 this.monthPicker.slideIn('t', {duration:.2});
24784 updateMPYear : function(y){
24786 var ys = this.mpYears.elements;
24787 for(var i = 1; i <= 10; i++){
24788 var td = ys[i-1], y2;
24790 y2 = y + Math.round(i * .5);
24791 td.firstChild.innerHTML = y2;
24794 y2 = y - (5-Math.round(i * .5));
24795 td.firstChild.innerHTML = y2;
24798 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24802 updateMPMonth : function(sm){
24803 this.mpMonths.each(function(m, a, i){
24804 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24808 selectMPMonth: function(m){
24812 onMonthClick : function(e, t){
24814 var el = new Roo.Element(t), pn;
24815 if(el.is('button.x-date-mp-cancel')){
24816 this.hideMonthPicker();
24818 else if(el.is('button.x-date-mp-ok')){
24819 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24820 this.hideMonthPicker();
24822 else if(pn = el.up('td.x-date-mp-month', 2)){
24823 this.mpMonths.removeClass('x-date-mp-sel');
24824 pn.addClass('x-date-mp-sel');
24825 this.mpSelMonth = pn.dom.xmonth;
24827 else if(pn = el.up('td.x-date-mp-year', 2)){
24828 this.mpYears.removeClass('x-date-mp-sel');
24829 pn.addClass('x-date-mp-sel');
24830 this.mpSelYear = pn.dom.xyear;
24832 else if(el.is('a.x-date-mp-prev')){
24833 this.updateMPYear(this.mpyear-10);
24835 else if(el.is('a.x-date-mp-next')){
24836 this.updateMPYear(this.mpyear+10);
24840 onMonthDblClick : function(e, t){
24842 var el = new Roo.Element(t), pn;
24843 if(pn = el.up('td.x-date-mp-month', 2)){
24844 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24845 this.hideMonthPicker();
24847 else if(pn = el.up('td.x-date-mp-year', 2)){
24848 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24849 this.hideMonthPicker();
24853 hideMonthPicker : function(disableAnim){
24854 if(this.monthPicker){
24855 if(disableAnim === true){
24856 this.monthPicker.hide();
24858 this.monthPicker.slideOut('t', {duration:.2});
24864 showPrevMonth : function(e){
24865 this.update(this.activeDate.add("mo", -1));
24869 showNextMonth : function(e){
24870 this.update(this.activeDate.add("mo", 1));
24874 showPrevYear : function(){
24875 this.update(this.activeDate.add("y", -1));
24879 showNextYear : function(){
24880 this.update(this.activeDate.add("y", 1));
24884 handleMouseWheel : function(e){
24885 var delta = e.getWheelDelta();
24887 this.showPrevMonth();
24889 } else if(delta < 0){
24890 this.showNextMonth();
24896 handleDateClick : function(e, t){
24898 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24899 this.setValue(new Date(t.dateValue));
24900 this.fireEvent("select", this, this.value);
24905 selectToday : function(){
24906 this.setValue(new Date().clearTime());
24907 this.fireEvent("select", this, this.value);
24911 update : function(date){
24912 var vd = this.activeDate;
24913 this.activeDate = date;
24915 var t = date.getTime();
24916 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
24917 this.cells.removeClass("x-date-selected");
24918 this.cells.each(function(c){
24919 if(c.dom.firstChild.dateValue == t){
24920 c.addClass("x-date-selected");
24921 setTimeout(function(){
24922 try{c.dom.firstChild.focus();}catch(e){}
24930 var days = date.getDaysInMonth();
24931 var firstOfMonth = date.getFirstDateOfMonth();
24932 var startingPos = firstOfMonth.getDay()-this.startDay;
24934 if(startingPos <= this.startDay){
24938 var pm = date.add("mo", -1);
24939 var prevStart = pm.getDaysInMonth()-startingPos;
24941 var cells = this.cells.elements;
24942 var textEls = this.textNodes;
24943 days += startingPos;
24945 // convert everything to numbers so it's fast
24946 var day = 86400000;
24947 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
24948 var today = new Date().clearTime().getTime();
24949 var sel = date.clearTime().getTime();
24950 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
24951 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
24952 var ddMatch = this.disabledDatesRE;
24953 var ddText = this.disabledDatesText;
24954 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
24955 var ddaysText = this.disabledDaysText;
24956 var format = this.format;
24958 var setCellClass = function(cal, cell){
24960 var t = d.getTime();
24961 cell.firstChild.dateValue = t;
24963 cell.className += " x-date-today";
24964 cell.title = cal.todayText;
24967 cell.className += " x-date-selected";
24968 setTimeout(function(){
24969 try{cell.firstChild.focus();}catch(e){}
24974 cell.className = " x-date-disabled";
24975 cell.title = cal.minText;
24979 cell.className = " x-date-disabled";
24980 cell.title = cal.maxText;
24984 if(ddays.indexOf(d.getDay()) != -1){
24985 cell.title = ddaysText;
24986 cell.className = " x-date-disabled";
24989 if(ddMatch && format){
24990 var fvalue = d.dateFormat(format);
24991 if(ddMatch.test(fvalue)){
24992 cell.title = ddText.replace("%0", fvalue);
24993 cell.className = " x-date-disabled";
24999 for(; i < startingPos; i++) {
25000 textEls[i].innerHTML = (++prevStart);
25001 d.setDate(d.getDate()+1);
25002 cells[i].className = "x-date-prevday";
25003 setCellClass(this, cells[i]);
25005 for(; i < days; i++){
25006 intDay = i - startingPos + 1;
25007 textEls[i].innerHTML = (intDay);
25008 d.setDate(d.getDate()+1);
25009 cells[i].className = "x-date-active";
25010 setCellClass(this, cells[i]);
25013 for(; i < 42; i++) {
25014 textEls[i].innerHTML = (++extraDays);
25015 d.setDate(d.getDate()+1);
25016 cells[i].className = "x-date-nextday";
25017 setCellClass(this, cells[i]);
25020 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25022 if(!this.internalRender){
25023 var main = this.el.dom.firstChild;
25024 var w = main.offsetWidth;
25025 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25026 Roo.fly(main).setWidth(w);
25027 this.internalRender = true;
25028 // opera does not respect the auto grow header center column
25029 // then, after it gets a width opera refuses to recalculate
25030 // without a second pass
25031 if(Roo.isOpera && !this.secondPass){
25032 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25033 this.secondPass = true;
25034 this.update.defer(10, this, [date]);
25040 * Ext JS Library 1.1.1
25041 * Copyright(c) 2006-2007, Ext JS, LLC.
25043 * Originally Released Under LGPL - original licence link has changed is not relivant.
25046 * <script type="text/javascript">
25049 * @class Roo.TabPanel
25050 * @extends Roo.util.Observable
25051 * A lightweight tab container.
25055 // basic tabs 1, built from existing content
25056 var tabs = new Roo.TabPanel("tabs1");
25057 tabs.addTab("script", "View Script");
25058 tabs.addTab("markup", "View Markup");
25059 tabs.activate("script");
25061 // more advanced tabs, built from javascript
25062 var jtabs = new Roo.TabPanel("jtabs");
25063 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25065 // set up the UpdateManager
25066 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25067 var updater = tab2.getUpdateManager();
25068 updater.setDefaultUrl("ajax1.htm");
25069 tab2.on('activate', updater.refresh, updater, true);
25071 // Use setUrl for Ajax loading
25072 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25073 tab3.setUrl("ajax2.htm", null, true);
25076 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25079 jtabs.activate("jtabs-1");
25082 * Create a new TabPanel.
25083 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25084 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25086 Roo.TabPanel = function(container, config){
25088 * The container element for this TabPanel.
25089 * @type Roo.Element
25091 this.el = Roo.get(container, true);
25093 if(typeof config == "boolean"){
25094 this.tabPosition = config ? "bottom" : "top";
25096 Roo.apply(this, config);
25099 if(this.tabPosition == "bottom"){
25100 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25101 this.el.addClass("x-tabs-bottom");
25103 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25104 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25105 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25107 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25109 if(this.tabPosition != "bottom"){
25110 /** The body element that contains {@link Roo.TabPanelItem} bodies.
25111 * @type Roo.Element
25113 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25114 this.el.addClass("x-tabs-top");
25118 this.bodyEl.setStyle("position", "relative");
25120 this.active = null;
25121 this.activateDelegate = this.activate.createDelegate(this);
25126 * Fires when the active tab changes
25127 * @param {Roo.TabPanel} this
25128 * @param {Roo.TabPanelItem} activePanel The new active tab
25132 * @event beforetabchange
25133 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25134 * @param {Roo.TabPanel} this
25135 * @param {Object} e Set cancel to true on this object to cancel the tab change
25136 * @param {Roo.TabPanelItem} tab The tab being changed to
25138 "beforetabchange" : true
25141 Roo.EventManager.onWindowResize(this.onResize, this);
25142 this.cpad = this.el.getPadding("lr");
25143 this.hiddenCount = 0;
25145 Roo.TabPanel.superclass.constructor.call(this);
25148 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25150 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25152 tabPosition : "top",
25154 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25156 currentTabWidth : 0,
25158 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25162 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25166 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25168 preferredTabWidth : 175,
25170 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25172 resizeTabs : false,
25174 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25176 monitorResize : true,
25179 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25180 * @param {String} id The id of the div to use <b>or create</b>
25181 * @param {String} text The text for the tab
25182 * @param {String} content (optional) Content to put in the TabPanelItem body
25183 * @param {Boolean} closable (optional) True to create a close icon on the tab
25184 * @return {Roo.TabPanelItem} The created TabPanelItem
25186 addTab : function(id, text, content, closable){
25187 var item = new Roo.TabPanelItem(this, id, text, closable);
25188 this.addTabItem(item);
25190 item.setContent(content);
25196 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25197 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25198 * @return {Roo.TabPanelItem}
25200 getTab : function(id){
25201 return this.items[id];
25205 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25206 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25208 hideTab : function(id){
25209 var t = this.items[id];
25212 this.hiddenCount++;
25213 this.autoSizeTabs();
25218 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25219 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25221 unhideTab : function(id){
25222 var t = this.items[id];
25224 t.setHidden(false);
25225 this.hiddenCount--;
25226 this.autoSizeTabs();
25231 * Adds an existing {@link Roo.TabPanelItem}.
25232 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25234 addTabItem : function(item){
25235 this.items[item.id] = item;
25236 this.items.push(item);
25237 if(this.resizeTabs){
25238 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25239 this.autoSizeTabs();
25246 * Removes a {@link Roo.TabPanelItem}.
25247 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25249 removeTab : function(id){
25250 var items = this.items;
25251 var tab = items[id];
25252 if(!tab) { return; }
25253 var index = items.indexOf(tab);
25254 if(this.active == tab && items.length > 1){
25255 var newTab = this.getNextAvailable(index);
25260 this.stripEl.dom.removeChild(tab.pnode.dom);
25261 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25262 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25264 items.splice(index, 1);
25265 delete this.items[tab.id];
25266 tab.fireEvent("close", tab);
25267 tab.purgeListeners();
25268 this.autoSizeTabs();
25271 getNextAvailable : function(start){
25272 var items = this.items;
25274 // look for a next tab that will slide over to
25275 // replace the one being removed
25276 while(index < items.length){
25277 var item = items[++index];
25278 if(item && !item.isHidden()){
25282 // if one isn't found select the previous tab (on the left)
25285 var item = items[--index];
25286 if(item && !item.isHidden()){
25294 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25295 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25297 disableTab : function(id){
25298 var tab = this.items[id];
25299 if(tab && this.active != tab){
25305 * Enables a {@link Roo.TabPanelItem} that is disabled.
25306 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25308 enableTab : function(id){
25309 var tab = this.items[id];
25314 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25315 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25316 * @return {Roo.TabPanelItem} The TabPanelItem.
25318 activate : function(id){
25319 var tab = this.items[id];
25323 if(tab == this.active || tab.disabled){
25327 this.fireEvent("beforetabchange", this, e, tab);
25328 if(e.cancel !== true && !tab.disabled){
25330 this.active.hide();
25332 this.active = this.items[id];
25333 this.active.show();
25334 this.fireEvent("tabchange", this, this.active);
25340 * Gets the active {@link Roo.TabPanelItem}.
25341 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25343 getActiveTab : function(){
25344 return this.active;
25348 * Updates the tab body element to fit the height of the container element
25349 * for overflow scrolling
25350 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25352 syncHeight : function(targetHeight){
25353 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25354 var bm = this.bodyEl.getMargins();
25355 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25356 this.bodyEl.setHeight(newHeight);
25360 onResize : function(){
25361 if(this.monitorResize){
25362 this.autoSizeTabs();
25367 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25369 beginUpdate : function(){
25370 this.updating = true;
25374 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25376 endUpdate : function(){
25377 this.updating = false;
25378 this.autoSizeTabs();
25382 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25384 autoSizeTabs : function(){
25385 var count = this.items.length;
25386 var vcount = count - this.hiddenCount;
25387 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25388 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25389 var availWidth = Math.floor(w / vcount);
25390 var b = this.stripBody;
25391 if(b.getWidth() > w){
25392 var tabs = this.items;
25393 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25394 if(availWidth < this.minTabWidth){
25395 /*if(!this.sleft){ // incomplete scrolling code
25396 this.createScrollButtons();
25399 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25402 if(this.currentTabWidth < this.preferredTabWidth){
25403 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25409 * Returns the number of tabs in this TabPanel.
25412 getCount : function(){
25413 return this.items.length;
25417 * Resizes all the tabs to the passed width
25418 * @param {Number} The new width
25420 setTabWidth : function(width){
25421 this.currentTabWidth = width;
25422 for(var i = 0, len = this.items.length; i < len; i++) {
25423 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25428 * Destroys this TabPanel
25429 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25431 destroy : function(removeEl){
25432 Roo.EventManager.removeResizeListener(this.onResize, this);
25433 for(var i = 0, len = this.items.length; i < len; i++){
25434 this.items[i].purgeListeners();
25436 if(removeEl === true){
25437 this.el.update("");
25444 * @class Roo.TabPanelItem
25445 * @extends Roo.util.Observable
25446 * Represents an individual item (tab plus body) in a TabPanel.
25447 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25448 * @param {String} id The id of this TabPanelItem
25449 * @param {String} text The text for the tab of this TabPanelItem
25450 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25452 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25454 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25455 * @type Roo.TabPanel
25457 this.tabPanel = tabPanel;
25459 * The id for this TabPanelItem
25464 this.disabled = false;
25468 this.loaded = false;
25469 this.closable = closable;
25472 * The body element for this TabPanelItem.
25473 * @type Roo.Element
25475 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25476 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25477 this.bodyEl.setStyle("display", "block");
25478 this.bodyEl.setStyle("zoom", "1");
25481 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25483 this.el = Roo.get(els.el, true);
25484 this.inner = Roo.get(els.inner, true);
25485 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25486 this.pnode = Roo.get(els.el.parentNode, true);
25487 this.el.on("mousedown", this.onTabMouseDown, this);
25488 this.el.on("click", this.onTabClick, this);
25491 var c = Roo.get(els.close, true);
25492 c.dom.title = this.closeText;
25493 c.addClassOnOver("close-over");
25494 c.on("click", this.closeClick, this);
25500 * Fires when this tab becomes the active tab.
25501 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25502 * @param {Roo.TabPanelItem} this
25506 * @event beforeclose
25507 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25508 * @param {Roo.TabPanelItem} this
25509 * @param {Object} e Set cancel to true on this object to cancel the close.
25511 "beforeclose": true,
25514 * Fires when this tab is closed.
25515 * @param {Roo.TabPanelItem} this
25519 * @event deactivate
25520 * Fires when this tab is no longer the active tab.
25521 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25522 * @param {Roo.TabPanelItem} this
25524 "deactivate" : true
25526 this.hidden = false;
25528 Roo.TabPanelItem.superclass.constructor.call(this);
25531 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25532 purgeListeners : function(){
25533 Roo.util.Observable.prototype.purgeListeners.call(this);
25534 this.el.removeAllListeners();
25537 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25540 this.pnode.addClass("on");
25543 this.tabPanel.stripWrap.repaint();
25545 this.fireEvent("activate", this.tabPanel, this);
25549 * Returns true if this tab is the active tab.
25550 * @return {Boolean}
25552 isActive : function(){
25553 return this.tabPanel.getActiveTab() == this;
25557 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25560 this.pnode.removeClass("on");
25562 this.fireEvent("deactivate", this.tabPanel, this);
25565 hideAction : function(){
25566 this.bodyEl.hide();
25567 this.bodyEl.setStyle("position", "absolute");
25568 this.bodyEl.setLeft("-20000px");
25569 this.bodyEl.setTop("-20000px");
25572 showAction : function(){
25573 this.bodyEl.setStyle("position", "relative");
25574 this.bodyEl.setTop("");
25575 this.bodyEl.setLeft("");
25576 this.bodyEl.show();
25580 * Set the tooltip for the tab.
25581 * @param {String} tooltip The tab's tooltip
25583 setTooltip : function(text){
25584 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25585 this.textEl.dom.qtip = text;
25586 this.textEl.dom.removeAttribute('title');
25588 this.textEl.dom.title = text;
25592 onTabClick : function(e){
25593 e.preventDefault();
25594 this.tabPanel.activate(this.id);
25597 onTabMouseDown : function(e){
25598 e.preventDefault();
25599 this.tabPanel.activate(this.id);
25602 getWidth : function(){
25603 return this.inner.getWidth();
25606 setWidth : function(width){
25607 var iwidth = width - this.pnode.getPadding("lr");
25608 this.inner.setWidth(iwidth);
25609 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25610 this.pnode.setWidth(width);
25614 * Show or hide the tab
25615 * @param {Boolean} hidden True to hide or false to show.
25617 setHidden : function(hidden){
25618 this.hidden = hidden;
25619 this.pnode.setStyle("display", hidden ? "none" : "");
25623 * Returns true if this tab is "hidden"
25624 * @return {Boolean}
25626 isHidden : function(){
25627 return this.hidden;
25631 * Returns the text for this tab
25634 getText : function(){
25638 autoSize : function(){
25639 //this.el.beginMeasure();
25640 this.textEl.setWidth(1);
25641 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25642 //this.el.endMeasure();
25646 * Sets the text for the tab (Note: this also sets the tooltip text)
25647 * @param {String} text The tab's text and tooltip
25649 setText : function(text){
25651 this.textEl.update(text);
25652 this.setTooltip(text);
25653 if(!this.tabPanel.resizeTabs){
25658 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25660 activate : function(){
25661 this.tabPanel.activate(this.id);
25665 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25667 disable : function(){
25668 if(this.tabPanel.active != this){
25669 this.disabled = true;
25670 this.pnode.addClass("disabled");
25675 * Enables this TabPanelItem if it was previously disabled.
25677 enable : function(){
25678 this.disabled = false;
25679 this.pnode.removeClass("disabled");
25683 * Sets the content for this TabPanelItem.
25684 * @param {String} content The content
25685 * @param {Boolean} loadScripts true to look for and load scripts
25687 setContent : function(content, loadScripts){
25688 this.bodyEl.update(content, loadScripts);
25692 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25693 * @return {Roo.UpdateManager} The UpdateManager
25695 getUpdateManager : function(){
25696 return this.bodyEl.getUpdateManager();
25700 * Set a URL to be used to load the content for this TabPanelItem.
25701 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25702 * @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)
25703 * @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)
25704 * @return {Roo.UpdateManager} The UpdateManager
25706 setUrl : function(url, params, loadOnce){
25707 if(this.refreshDelegate){
25708 this.un('activate', this.refreshDelegate);
25710 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25711 this.on("activate", this.refreshDelegate);
25712 return this.bodyEl.getUpdateManager();
25716 _handleRefresh : function(url, params, loadOnce){
25717 if(!loadOnce || !this.loaded){
25718 var updater = this.bodyEl.getUpdateManager();
25719 updater.update(url, params, this._setLoaded.createDelegate(this));
25724 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25725 * Will fail silently if the setUrl method has not been called.
25726 * This does not activate the panel, just updates its content.
25728 refresh : function(){
25729 if(this.refreshDelegate){
25730 this.loaded = false;
25731 this.refreshDelegate();
25736 _setLoaded : function(){
25737 this.loaded = true;
25741 closeClick : function(e){
25744 this.fireEvent("beforeclose", this, o);
25745 if(o.cancel !== true){
25746 this.tabPanel.removeTab(this.id);
25750 * The text displayed in the tooltip for the close icon.
25753 closeText : "Close this tab"
25757 Roo.TabPanel.prototype.createStrip = function(container){
25758 var strip = document.createElement("div");
25759 strip.className = "x-tabs-wrap";
25760 container.appendChild(strip);
25764 Roo.TabPanel.prototype.createStripList = function(strip){
25765 // div wrapper for retard IE
25766 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>';
25767 return strip.firstChild.firstChild.firstChild.firstChild;
25770 Roo.TabPanel.prototype.createBody = function(container){
25771 var body = document.createElement("div");
25772 Roo.id(body, "tab-body");
25773 Roo.fly(body).addClass("x-tabs-body");
25774 container.appendChild(body);
25778 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25779 var body = Roo.getDom(id);
25781 body = document.createElement("div");
25784 Roo.fly(body).addClass("x-tabs-item-body");
25785 bodyEl.insertBefore(body, bodyEl.firstChild);
25789 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25790 var td = document.createElement("td");
25791 stripEl.appendChild(td);
25793 td.className = "x-tabs-closable";
25794 if(!this.closeTpl){
25795 this.closeTpl = new Roo.Template(
25796 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25797 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25798 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25801 var el = this.closeTpl.overwrite(td, {"text": text});
25802 var close = el.getElementsByTagName("div")[0];
25803 var inner = el.getElementsByTagName("em")[0];
25804 return {"el": el, "close": close, "inner": inner};
25807 this.tabTpl = new Roo.Template(
25808 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25809 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25812 var el = this.tabTpl.overwrite(td, {"text": text});
25813 var inner = el.getElementsByTagName("em")[0];
25814 return {"el": el, "inner": inner};
25818 * Ext JS Library 1.1.1
25819 * Copyright(c) 2006-2007, Ext JS, LLC.
25821 * Originally Released Under LGPL - original licence link has changed is not relivant.
25824 * <script type="text/javascript">
25828 * @class Roo.Button
25829 * @extends Roo.util.Observable
25830 * Simple Button class
25831 * @cfg {String} text The button text
25832 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25833 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25834 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25835 * @cfg {Object} scope The scope of the handler
25836 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25837 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25838 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25839 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25840 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25841 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25842 applies if enableToggle = true)
25843 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25844 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25845 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25847 * Create a new button
25848 * @param {Object} config The config object
25850 Roo.Button = function(renderTo, config)
25854 renderTo = config.renderTo || false;
25857 Roo.apply(this, config);
25861 * Fires when this button is clicked
25862 * @param {Button} this
25863 * @param {EventObject} e The click event
25868 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25869 * @param {Button} this
25870 * @param {Boolean} pressed
25875 * Fires when the mouse hovers over the button
25876 * @param {Button} this
25877 * @param {Event} e The event object
25879 'mouseover' : true,
25882 * Fires when the mouse exits the button
25883 * @param {Button} this
25884 * @param {Event} e The event object
25889 * Fires when the button is rendered
25890 * @param {Button} this
25895 this.menu = Roo.menu.MenuMgr.get(this.menu);
25897 // register listeners first!! - so render can be captured..
25898 Roo.util.Observable.call(this);
25900 this.render(renderTo);
25906 Roo.extend(Roo.Button, Roo.util.Observable, {
25912 * Read-only. True if this button is hidden
25917 * Read-only. True if this button is disabled
25922 * Read-only. True if this button is pressed (only if enableToggle = true)
25928 * @cfg {Number} tabIndex
25929 * The DOM tabIndex for this button (defaults to undefined)
25931 tabIndex : undefined,
25934 * @cfg {Boolean} enableToggle
25935 * True to enable pressed/not pressed toggling (defaults to false)
25937 enableToggle: false,
25939 * @cfg {Mixed} menu
25940 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
25944 * @cfg {String} menuAlign
25945 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
25947 menuAlign : "tl-bl?",
25950 * @cfg {String} iconCls
25951 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
25953 iconCls : undefined,
25955 * @cfg {String} type
25956 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
25961 menuClassTarget: 'tr',
25964 * @cfg {String} clickEvent
25965 * The type of event to map to the button's event handler (defaults to 'click')
25967 clickEvent : 'click',
25970 * @cfg {Boolean} handleMouseEvents
25971 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
25973 handleMouseEvents : true,
25976 * @cfg {String} tooltipType
25977 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
25979 tooltipType : 'qtip',
25982 * @cfg {String} cls
25983 * A CSS class to apply to the button's main element.
25987 * @cfg {Roo.Template} template (Optional)
25988 * An {@link Roo.Template} with which to create the Button's main element. This Template must
25989 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
25990 * require code modifications if required elements (e.g. a button) aren't present.
25994 render : function(renderTo){
25996 if(this.hideParent){
25997 this.parentEl = Roo.get(renderTo);
25999 if(!this.dhconfig){
26000 if(!this.template){
26001 if(!Roo.Button.buttonTemplate){
26002 // hideous table template
26003 Roo.Button.buttonTemplate = new Roo.Template(
26004 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26005 '<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>',
26006 "</tr></tbody></table>");
26008 this.template = Roo.Button.buttonTemplate;
26010 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26011 var btnEl = btn.child("button:first");
26012 btnEl.on('focus', this.onFocus, this);
26013 btnEl.on('blur', this.onBlur, this);
26015 btn.addClass(this.cls);
26018 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26021 btnEl.addClass(this.iconCls);
26023 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26026 if(this.tabIndex !== undefined){
26027 btnEl.dom.tabIndex = this.tabIndex;
26030 if(typeof this.tooltip == 'object'){
26031 Roo.QuickTips.tips(Roo.apply({
26035 btnEl.dom[this.tooltipType] = this.tooltip;
26039 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26043 this.el.dom.id = this.el.id = this.id;
26046 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26047 this.menu.on("show", this.onMenuShow, this);
26048 this.menu.on("hide", this.onMenuHide, this);
26050 btn.addClass("x-btn");
26051 if(Roo.isIE && !Roo.isIE7){
26052 this.autoWidth.defer(1, this);
26056 if(this.handleMouseEvents){
26057 btn.on("mouseover", this.onMouseOver, this);
26058 btn.on("mouseout", this.onMouseOut, this);
26059 btn.on("mousedown", this.onMouseDown, this);
26061 btn.on(this.clickEvent, this.onClick, this);
26062 //btn.on("mouseup", this.onMouseUp, this);
26069 Roo.ButtonToggleMgr.register(this);
26071 this.el.addClass("x-btn-pressed");
26074 var repeater = new Roo.util.ClickRepeater(btn,
26075 typeof this.repeat == "object" ? this.repeat : {}
26077 repeater.on("click", this.onClick, this);
26080 this.fireEvent('render', this);
26084 * Returns the button's underlying element
26085 * @return {Roo.Element} The element
26087 getEl : function(){
26092 * Destroys this Button and removes any listeners.
26094 destroy : function(){
26095 Roo.ButtonToggleMgr.unregister(this);
26096 this.el.removeAllListeners();
26097 this.purgeListeners();
26102 autoWidth : function(){
26104 this.el.setWidth("auto");
26105 if(Roo.isIE7 && Roo.isStrict){
26106 var ib = this.el.child('button');
26107 if(ib && ib.getWidth() > 20){
26109 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26114 this.el.beginMeasure();
26116 if(this.el.getWidth() < this.minWidth){
26117 this.el.setWidth(this.minWidth);
26120 this.el.endMeasure();
26127 * Assigns this button's click handler
26128 * @param {Function} handler The function to call when the button is clicked
26129 * @param {Object} scope (optional) Scope for the function passed in
26131 setHandler : function(handler, scope){
26132 this.handler = handler;
26133 this.scope = scope;
26137 * Sets this button's text
26138 * @param {String} text The button text
26140 setText : function(text){
26143 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26149 * Gets the text for this button
26150 * @return {String} The button text
26152 getText : function(){
26160 this.hidden = false;
26162 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26170 this.hidden = true;
26172 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26177 * Convenience function for boolean show/hide
26178 * @param {Boolean} visible True to show, false to hide
26180 setVisible: function(visible){
26189 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26190 * @param {Boolean} state (optional) Force a particular state
26192 toggle : function(state){
26193 state = state === undefined ? !this.pressed : state;
26194 if(state != this.pressed){
26196 this.el.addClass("x-btn-pressed");
26197 this.pressed = true;
26198 this.fireEvent("toggle", this, true);
26200 this.el.removeClass("x-btn-pressed");
26201 this.pressed = false;
26202 this.fireEvent("toggle", this, false);
26204 if(this.toggleHandler){
26205 this.toggleHandler.call(this.scope || this, this, state);
26213 focus : function(){
26214 this.el.child('button:first').focus();
26218 * Disable this button
26220 disable : function(){
26222 this.el.addClass("x-btn-disabled");
26224 this.disabled = true;
26228 * Enable this button
26230 enable : function(){
26232 this.el.removeClass("x-btn-disabled");
26234 this.disabled = false;
26238 * Convenience function for boolean enable/disable
26239 * @param {Boolean} enabled True to enable, false to disable
26241 setDisabled : function(v){
26242 this[v !== true ? "enable" : "disable"]();
26246 onClick : function(e){
26248 e.preventDefault();
26253 if(!this.disabled){
26254 if(this.enableToggle){
26257 if(this.menu && !this.menu.isVisible()){
26258 this.menu.show(this.el, this.menuAlign);
26260 this.fireEvent("click", this, e);
26262 this.el.removeClass("x-btn-over");
26263 this.handler.call(this.scope || this, this, e);
26268 onMouseOver : function(e){
26269 if(!this.disabled){
26270 this.el.addClass("x-btn-over");
26271 this.fireEvent('mouseover', this, e);
26275 onMouseOut : function(e){
26276 if(!e.within(this.el, true)){
26277 this.el.removeClass("x-btn-over");
26278 this.fireEvent('mouseout', this, e);
26282 onFocus : function(e){
26283 if(!this.disabled){
26284 this.el.addClass("x-btn-focus");
26288 onBlur : function(e){
26289 this.el.removeClass("x-btn-focus");
26292 onMouseDown : function(e){
26293 if(!this.disabled && e.button == 0){
26294 this.el.addClass("x-btn-click");
26295 Roo.get(document).on('mouseup', this.onMouseUp, this);
26299 onMouseUp : function(e){
26301 this.el.removeClass("x-btn-click");
26302 Roo.get(document).un('mouseup', this.onMouseUp, this);
26306 onMenuShow : function(e){
26307 this.el.addClass("x-btn-menu-active");
26310 onMenuHide : function(e){
26311 this.el.removeClass("x-btn-menu-active");
26315 // Private utility class used by Button
26316 Roo.ButtonToggleMgr = function(){
26319 function toggleGroup(btn, state){
26321 var g = groups[btn.toggleGroup];
26322 for(var i = 0, l = g.length; i < l; i++){
26324 g[i].toggle(false);
26331 register : function(btn){
26332 if(!btn.toggleGroup){
26335 var g = groups[btn.toggleGroup];
26337 g = groups[btn.toggleGroup] = [];
26340 btn.on("toggle", toggleGroup);
26343 unregister : function(btn){
26344 if(!btn.toggleGroup){
26347 var g = groups[btn.toggleGroup];
26350 btn.un("toggle", toggleGroup);
26356 * Ext JS Library 1.1.1
26357 * Copyright(c) 2006-2007, Ext JS, LLC.
26359 * Originally Released Under LGPL - original licence link has changed is not relivant.
26362 * <script type="text/javascript">
26366 * @class Roo.SplitButton
26367 * @extends Roo.Button
26368 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26369 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26370 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26371 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26372 * @cfg {String} arrowTooltip The title attribute of the arrow
26374 * Create a new menu button
26375 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26376 * @param {Object} config The config object
26378 Roo.SplitButton = function(renderTo, config){
26379 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26381 * @event arrowclick
26382 * Fires when this button's arrow is clicked
26383 * @param {SplitButton} this
26384 * @param {EventObject} e The click event
26386 this.addEvents({"arrowclick":true});
26389 Roo.extend(Roo.SplitButton, Roo.Button, {
26390 render : function(renderTo){
26391 // this is one sweet looking template!
26392 var tpl = new Roo.Template(
26393 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26394 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26395 '<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>',
26396 "</tbody></table></td><td>",
26397 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26398 '<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>',
26399 "</tbody></table></td></tr></table>"
26401 var btn = tpl.append(renderTo, [this.text, this.type], true);
26402 var btnEl = btn.child("button");
26404 btn.addClass(this.cls);
26407 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26410 btnEl.addClass(this.iconCls);
26412 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26416 if(this.handleMouseEvents){
26417 btn.on("mouseover", this.onMouseOver, this);
26418 btn.on("mouseout", this.onMouseOut, this);
26419 btn.on("mousedown", this.onMouseDown, this);
26420 btn.on("mouseup", this.onMouseUp, this);
26422 btn.on(this.clickEvent, this.onClick, this);
26424 if(typeof this.tooltip == 'object'){
26425 Roo.QuickTips.tips(Roo.apply({
26429 btnEl.dom[this.tooltipType] = this.tooltip;
26432 if(this.arrowTooltip){
26433 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26442 this.el.addClass("x-btn-pressed");
26444 if(Roo.isIE && !Roo.isIE7){
26445 this.autoWidth.defer(1, this);
26450 this.menu.on("show", this.onMenuShow, this);
26451 this.menu.on("hide", this.onMenuHide, this);
26453 this.fireEvent('render', this);
26457 autoWidth : function(){
26459 var tbl = this.el.child("table:first");
26460 var tbl2 = this.el.child("table:last");
26461 this.el.setWidth("auto");
26462 tbl.setWidth("auto");
26463 if(Roo.isIE7 && Roo.isStrict){
26464 var ib = this.el.child('button:first');
26465 if(ib && ib.getWidth() > 20){
26467 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26472 this.el.beginMeasure();
26474 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26475 tbl.setWidth(this.minWidth-tbl2.getWidth());
26478 this.el.endMeasure();
26481 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26485 * Sets this button's click handler
26486 * @param {Function} handler The function to call when the button is clicked
26487 * @param {Object} scope (optional) Scope for the function passed above
26489 setHandler : function(handler, scope){
26490 this.handler = handler;
26491 this.scope = scope;
26495 * Sets this button's arrow click handler
26496 * @param {Function} handler The function to call when the arrow is clicked
26497 * @param {Object} scope (optional) Scope for the function passed above
26499 setArrowHandler : function(handler, scope){
26500 this.arrowHandler = handler;
26501 this.scope = scope;
26507 focus : function(){
26509 this.el.child("button:first").focus();
26514 onClick : function(e){
26515 e.preventDefault();
26516 if(!this.disabled){
26517 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26518 if(this.menu && !this.menu.isVisible()){
26519 this.menu.show(this.el, this.menuAlign);
26521 this.fireEvent("arrowclick", this, e);
26522 if(this.arrowHandler){
26523 this.arrowHandler.call(this.scope || this, this, e);
26526 this.fireEvent("click", this, e);
26528 this.handler.call(this.scope || this, this, e);
26534 onMouseDown : function(e){
26535 if(!this.disabled){
26536 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26540 onMouseUp : function(e){
26541 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26546 // backwards compat
26547 Roo.MenuButton = Roo.SplitButton;/*
26549 * Ext JS Library 1.1.1
26550 * Copyright(c) 2006-2007, Ext JS, LLC.
26552 * Originally Released Under LGPL - original licence link has changed is not relivant.
26555 * <script type="text/javascript">
26559 * @class Roo.Toolbar
26560 * Basic Toolbar class.
26562 * Creates a new Toolbar
26563 * @param {Object} config The config object
26565 Roo.Toolbar = function(container, buttons, config)
26567 /// old consturctor format still supported..
26568 if(container instanceof Array){ // omit the container for later rendering
26569 buttons = container;
26573 if (typeof(container) == 'object' && container.xtype) {
26574 config = container;
26575 container = config.container;
26576 buttons = config.buttons; // not really - use items!!
26579 if (config && config.items) {
26580 xitems = config.items;
26581 delete config.items;
26583 Roo.apply(this, config);
26584 this.buttons = buttons;
26587 this.render(container);
26589 Roo.each(xitems, function(b) {
26595 Roo.Toolbar.prototype = {
26597 * @cfg {Roo.data.Store} items
26598 * array of button configs or elements to add
26602 * @cfg {String/HTMLElement/Element} container
26603 * The id or element that will contain the toolbar
26606 render : function(ct){
26607 this.el = Roo.get(ct);
26609 this.el.addClass(this.cls);
26611 // using a table allows for vertical alignment
26612 // 100% width is needed by Safari...
26613 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26614 this.tr = this.el.child("tr", true);
26616 this.items = new Roo.util.MixedCollection(false, function(o){
26617 return o.id || ("item" + (++autoId));
26620 this.add.apply(this, this.buttons);
26621 delete this.buttons;
26626 * Adds element(s) to the toolbar -- this function takes a variable number of
26627 * arguments of mixed type and adds them to the toolbar.
26628 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26630 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26631 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26632 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26633 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26634 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26635 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26636 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26637 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26638 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26640 * @param {Mixed} arg2
26641 * @param {Mixed} etc.
26644 var a = arguments, l = a.length;
26645 for(var i = 0; i < l; i++){
26650 _add : function(el) {
26653 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26656 if (el.applyTo){ // some kind of form field
26657 return this.addField(el);
26659 if (el.render){ // some kind of Toolbar.Item
26660 return this.addItem(el);
26662 if (typeof el == "string"){ // string
26663 if(el == "separator" || el == "-"){
26664 return this.addSeparator();
26667 return this.addSpacer();
26670 return this.addFill();
26672 return this.addText(el);
26675 if(el.tagName){ // element
26676 return this.addElement(el);
26678 if(typeof el == "object"){ // must be button config?
26679 return this.addButton(el);
26681 // and now what?!?!
26687 * Add an Xtype element
26688 * @param {Object} xtype Xtype Object
26689 * @return {Object} created Object
26691 addxtype : function(e){
26692 return this.add(e);
26696 * Returns the Element for this toolbar.
26697 * @return {Roo.Element}
26699 getEl : function(){
26705 * @return {Roo.Toolbar.Item} The separator item
26707 addSeparator : function(){
26708 return this.addItem(new Roo.Toolbar.Separator());
26712 * Adds a spacer element
26713 * @return {Roo.Toolbar.Spacer} The spacer item
26715 addSpacer : function(){
26716 return this.addItem(new Roo.Toolbar.Spacer());
26720 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26721 * @return {Roo.Toolbar.Fill} The fill item
26723 addFill : function(){
26724 return this.addItem(new Roo.Toolbar.Fill());
26728 * Adds any standard HTML element to the toolbar
26729 * @param {String/HTMLElement/Element} el The element or id of the element to add
26730 * @return {Roo.Toolbar.Item} The element's item
26732 addElement : function(el){
26733 return this.addItem(new Roo.Toolbar.Item(el));
26736 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26737 * @type Roo.util.MixedCollection
26742 * Adds any Toolbar.Item or subclass
26743 * @param {Roo.Toolbar.Item} item
26744 * @return {Roo.Toolbar.Item} The item
26746 addItem : function(item){
26747 var td = this.nextBlock();
26749 this.items.add(item);
26754 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26755 * @param {Object/Array} config A button config or array of configs
26756 * @return {Roo.Toolbar.Button/Array}
26758 addButton : function(config){
26759 if(config instanceof Array){
26761 for(var i = 0, len = config.length; i < len; i++) {
26762 buttons.push(this.addButton(config[i]));
26767 if(!(config instanceof Roo.Toolbar.Button)){
26769 new Roo.Toolbar.SplitButton(config) :
26770 new Roo.Toolbar.Button(config);
26772 var td = this.nextBlock();
26779 * Adds text to the toolbar
26780 * @param {String} text The text to add
26781 * @return {Roo.Toolbar.Item} The element's item
26783 addText : function(text){
26784 return this.addItem(new Roo.Toolbar.TextItem(text));
26788 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26789 * @param {Number} index The index where the item is to be inserted
26790 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26791 * @return {Roo.Toolbar.Button/Item}
26793 insertButton : function(index, item){
26794 if(item instanceof Array){
26796 for(var i = 0, len = item.length; i < len; i++) {
26797 buttons.push(this.insertButton(index + i, item[i]));
26801 if (!(item instanceof Roo.Toolbar.Button)){
26802 item = new Roo.Toolbar.Button(item);
26804 var td = document.createElement("td");
26805 this.tr.insertBefore(td, this.tr.childNodes[index]);
26807 this.items.insert(index, item);
26812 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26813 * @param {Object} config
26814 * @return {Roo.Toolbar.Item} The element's item
26816 addDom : function(config, returnEl){
26817 var td = this.nextBlock();
26818 Roo.DomHelper.overwrite(td, config);
26819 var ti = new Roo.Toolbar.Item(td.firstChild);
26821 this.items.add(ti);
26826 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26827 * @type Roo.util.MixedCollection
26832 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26833 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26834 * @param {Roo.form.Field} field
26835 * @return {Roo.ToolbarItem}
26839 addField : function(field) {
26840 if (!this.fields) {
26842 this.fields = new Roo.util.MixedCollection(false, function(o){
26843 return o.id || ("item" + (++autoId));
26848 var td = this.nextBlock();
26850 var ti = new Roo.Toolbar.Item(td.firstChild);
26852 this.items.add(ti);
26853 this.fields.add(field);
26864 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26865 this.el.child('div').hide();
26873 this.el.child('div').show();
26877 nextBlock : function(){
26878 var td = document.createElement("td");
26879 this.tr.appendChild(td);
26884 destroy : function(){
26885 if(this.items){ // rendered?
26886 Roo.destroy.apply(Roo, this.items.items);
26888 if(this.fields){ // rendered?
26889 Roo.destroy.apply(Roo, this.fields.items);
26891 Roo.Element.uncache(this.el, this.tr);
26896 * @class Roo.Toolbar.Item
26897 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26899 * Creates a new Item
26900 * @param {HTMLElement} el
26902 Roo.Toolbar.Item = function(el){
26903 this.el = Roo.getDom(el);
26904 this.id = Roo.id(this.el);
26905 this.hidden = false;
26908 Roo.Toolbar.Item.prototype = {
26911 * Get this item's HTML Element
26912 * @return {HTMLElement}
26914 getEl : function(){
26919 render : function(td){
26921 td.appendChild(this.el);
26925 * Removes and destroys this item.
26927 destroy : function(){
26928 this.td.parentNode.removeChild(this.td);
26935 this.hidden = false;
26936 this.td.style.display = "";
26943 this.hidden = true;
26944 this.td.style.display = "none";
26948 * Convenience function for boolean show/hide.
26949 * @param {Boolean} visible true to show/false to hide
26951 setVisible: function(visible){
26960 * Try to focus this item.
26962 focus : function(){
26963 Roo.fly(this.el).focus();
26967 * Disables this item.
26969 disable : function(){
26970 Roo.fly(this.td).addClass("x-item-disabled");
26971 this.disabled = true;
26972 this.el.disabled = true;
26976 * Enables this item.
26978 enable : function(){
26979 Roo.fly(this.td).removeClass("x-item-disabled");
26980 this.disabled = false;
26981 this.el.disabled = false;
26987 * @class Roo.Toolbar.Separator
26988 * @extends Roo.Toolbar.Item
26989 * A simple toolbar separator class
26991 * Creates a new Separator
26993 Roo.Toolbar.Separator = function(){
26994 var s = document.createElement("span");
26995 s.className = "ytb-sep";
26996 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
26998 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
26999 enable:Roo.emptyFn,
27000 disable:Roo.emptyFn,
27005 * @class Roo.Toolbar.Spacer
27006 * @extends Roo.Toolbar.Item
27007 * A simple element that adds extra horizontal space to a toolbar.
27009 * Creates a new Spacer
27011 Roo.Toolbar.Spacer = function(){
27012 var s = document.createElement("div");
27013 s.className = "ytb-spacer";
27014 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27016 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27017 enable:Roo.emptyFn,
27018 disable:Roo.emptyFn,
27023 * @class Roo.Toolbar.Fill
27024 * @extends Roo.Toolbar.Spacer
27025 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27027 * Creates a new Spacer
27029 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27031 render : function(td){
27032 td.style.width = '100%';
27033 Roo.Toolbar.Fill.superclass.render.call(this, td);
27038 * @class Roo.Toolbar.TextItem
27039 * @extends Roo.Toolbar.Item
27040 * A simple class that renders text directly into a toolbar.
27042 * Creates a new TextItem
27043 * @param {String} text
27045 Roo.Toolbar.TextItem = function(text){
27046 if (typeof(text) == 'object') {
27049 var s = document.createElement("span");
27050 s.className = "ytb-text";
27051 s.innerHTML = text;
27052 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27054 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27055 enable:Roo.emptyFn,
27056 disable:Roo.emptyFn,
27061 * @class Roo.Toolbar.Button
27062 * @extends Roo.Button
27063 * A button that renders into a toolbar.
27065 * Creates a new Button
27066 * @param {Object} config A standard {@link Roo.Button} config object
27068 Roo.Toolbar.Button = function(config){
27069 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27071 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27072 render : function(td){
27074 Roo.Toolbar.Button.superclass.render.call(this, td);
27078 * Removes and destroys this button
27080 destroy : function(){
27081 Roo.Toolbar.Button.superclass.destroy.call(this);
27082 this.td.parentNode.removeChild(this.td);
27086 * Shows this button
27089 this.hidden = false;
27090 this.td.style.display = "";
27094 * Hides this button
27097 this.hidden = true;
27098 this.td.style.display = "none";
27102 * Disables this item
27104 disable : function(){
27105 Roo.fly(this.td).addClass("x-item-disabled");
27106 this.disabled = true;
27110 * Enables this item
27112 enable : function(){
27113 Roo.fly(this.td).removeClass("x-item-disabled");
27114 this.disabled = false;
27117 // backwards compat
27118 Roo.ToolbarButton = Roo.Toolbar.Button;
27121 * @class Roo.Toolbar.SplitButton
27122 * @extends Roo.SplitButton
27123 * A menu button that renders into a toolbar.
27125 * Creates a new SplitButton
27126 * @param {Object} config A standard {@link Roo.SplitButton} config object
27128 Roo.Toolbar.SplitButton = function(config){
27129 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27131 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27132 render : function(td){
27134 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27138 * Removes and destroys this button
27140 destroy : function(){
27141 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27142 this.td.parentNode.removeChild(this.td);
27146 * Shows this button
27149 this.hidden = false;
27150 this.td.style.display = "";
27154 * Hides this button
27157 this.hidden = true;
27158 this.td.style.display = "none";
27162 // backwards compat
27163 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27165 * Ext JS Library 1.1.1
27166 * Copyright(c) 2006-2007, Ext JS, LLC.
27168 * Originally Released Under LGPL - original licence link has changed is not relivant.
27171 * <script type="text/javascript">
27175 * @class Roo.PagingToolbar
27176 * @extends Roo.Toolbar
27177 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27179 * Create a new PagingToolbar
27180 * @param {Object} config The config object
27182 Roo.PagingToolbar = function(el, ds, config)
27184 // old args format still supported... - xtype is prefered..
27185 if (typeof(el) == 'object' && el.xtype) {
27186 // created from xtype...
27188 ds = el.dataSource;
27189 el = config.container;
27192 if (config.items) {
27193 items = config.items;
27197 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27200 this.renderButtons(this.el);
27203 // supprot items array.
27205 Roo.each(items, function(e) {
27206 this.add(Roo.factory(e));
27211 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27213 * @cfg {Roo.data.Store} dataSource
27214 * The underlying data store providing the paged data
27217 * @cfg {String/HTMLElement/Element} container
27218 * container The id or element that will contain the toolbar
27221 * @cfg {Boolean} displayInfo
27222 * True to display the displayMsg (defaults to false)
27225 * @cfg {Number} pageSize
27226 * The number of records to display per page (defaults to 20)
27230 * @cfg {String} displayMsg
27231 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27233 displayMsg : 'Displaying {0} - {1} of {2}',
27235 * @cfg {String} emptyMsg
27236 * The message to display when no records are found (defaults to "No data to display")
27238 emptyMsg : 'No data to display',
27240 * Customizable piece of the default paging text (defaults to "Page")
27243 beforePageText : "Page",
27245 * Customizable piece of the default paging text (defaults to "of %0")
27248 afterPageText : "of {0}",
27250 * Customizable piece of the default paging text (defaults to "First Page")
27253 firstText : "First Page",
27255 * Customizable piece of the default paging text (defaults to "Previous Page")
27258 prevText : "Previous Page",
27260 * Customizable piece of the default paging text (defaults to "Next Page")
27263 nextText : "Next Page",
27265 * Customizable piece of the default paging text (defaults to "Last Page")
27268 lastText : "Last Page",
27270 * Customizable piece of the default paging text (defaults to "Refresh")
27273 refreshText : "Refresh",
27276 renderButtons : function(el){
27277 Roo.PagingToolbar.superclass.render.call(this, el);
27278 this.first = this.addButton({
27279 tooltip: this.firstText,
27280 cls: "x-btn-icon x-grid-page-first",
27282 handler: this.onClick.createDelegate(this, ["first"])
27284 this.prev = this.addButton({
27285 tooltip: this.prevText,
27286 cls: "x-btn-icon x-grid-page-prev",
27288 handler: this.onClick.createDelegate(this, ["prev"])
27290 //this.addSeparator();
27291 this.add(this.beforePageText);
27292 this.field = Roo.get(this.addDom({
27297 cls: "x-grid-page-number"
27299 this.field.on("keydown", this.onPagingKeydown, this);
27300 this.field.on("focus", function(){this.dom.select();});
27301 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27302 this.field.setHeight(18);
27303 //this.addSeparator();
27304 this.next = this.addButton({
27305 tooltip: this.nextText,
27306 cls: "x-btn-icon x-grid-page-next",
27308 handler: this.onClick.createDelegate(this, ["next"])
27310 this.last = this.addButton({
27311 tooltip: this.lastText,
27312 cls: "x-btn-icon x-grid-page-last",
27314 handler: this.onClick.createDelegate(this, ["last"])
27316 //this.addSeparator();
27317 this.loading = this.addButton({
27318 tooltip: this.refreshText,
27319 cls: "x-btn-icon x-grid-loading",
27320 handler: this.onClick.createDelegate(this, ["refresh"])
27323 if(this.displayInfo){
27324 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27329 updateInfo : function(){
27330 if(this.displayEl){
27331 var count = this.ds.getCount();
27332 var msg = count == 0 ?
27336 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27338 this.displayEl.update(msg);
27343 onLoad : function(ds, r, o){
27344 this.cursor = o.params ? o.params.start : 0;
27345 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27347 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27348 this.field.dom.value = ap;
27349 this.first.setDisabled(ap == 1);
27350 this.prev.setDisabled(ap == 1);
27351 this.next.setDisabled(ap == ps);
27352 this.last.setDisabled(ap == ps);
27353 this.loading.enable();
27358 getPageData : function(){
27359 var total = this.ds.getTotalCount();
27362 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27363 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27368 onLoadError : function(){
27369 this.loading.enable();
27373 onPagingKeydown : function(e){
27374 var k = e.getKey();
27375 var d = this.getPageData();
27377 var v = this.field.dom.value, pageNum;
27378 if(!v || isNaN(pageNum = parseInt(v, 10))){
27379 this.field.dom.value = d.activePage;
27382 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27383 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27386 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))
27388 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27389 this.field.dom.value = pageNum;
27390 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27393 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27395 var v = this.field.dom.value, pageNum;
27396 var increment = (e.shiftKey) ? 10 : 1;
27397 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27399 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27400 this.field.dom.value = d.activePage;
27403 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27405 this.field.dom.value = parseInt(v, 10) + increment;
27406 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27407 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27414 beforeLoad : function(){
27416 this.loading.disable();
27421 onClick : function(which){
27425 ds.load({params:{start: 0, limit: this.pageSize}});
27428 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27431 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27434 var total = ds.getTotalCount();
27435 var extra = total % this.pageSize;
27436 var lastStart = extra ? (total - extra) : total-this.pageSize;
27437 ds.load({params:{start: lastStart, limit: this.pageSize}});
27440 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27446 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27447 * @param {Roo.data.Store} store The data store to unbind
27449 unbind : function(ds){
27450 ds.un("beforeload", this.beforeLoad, this);
27451 ds.un("load", this.onLoad, this);
27452 ds.un("loadexception", this.onLoadError, this);
27453 ds.un("remove", this.updateInfo, this);
27454 ds.un("add", this.updateInfo, this);
27455 this.ds = undefined;
27459 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27460 * @param {Roo.data.Store} store The data store to bind
27462 bind : function(ds){
27463 ds.on("beforeload", this.beforeLoad, this);
27464 ds.on("load", this.onLoad, this);
27465 ds.on("loadexception", this.onLoadError, this);
27466 ds.on("remove", this.updateInfo, this);
27467 ds.on("add", this.updateInfo, this);
27472 * Ext JS Library 1.1.1
27473 * Copyright(c) 2006-2007, Ext JS, LLC.
27475 * Originally Released Under LGPL - original licence link has changed is not relivant.
27478 * <script type="text/javascript">
27482 * @class Roo.Resizable
27483 * @extends Roo.util.Observable
27484 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27485 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27486 * 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
27487 * the element will be wrapped for you automatically.</p>
27488 * <p>Here is the list of valid resize handles:</p>
27491 ------ -------------------
27500 'hd' horizontal drag
27503 * <p>Here's an example showing the creation of a typical Resizable:</p>
27505 var resizer = new Roo.Resizable("element-id", {
27513 resizer.on("resize", myHandler);
27515 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27516 * resizer.east.setDisplayed(false);</p>
27517 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27518 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27519 * resize operation's new size (defaults to [0, 0])
27520 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27521 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27522 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27523 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27524 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27525 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27526 * @cfg {Number} width The width of the element in pixels (defaults to null)
27527 * @cfg {Number} height The height of the element in pixels (defaults to null)
27528 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27529 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27530 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27531 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27532 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27533 * in favor of the handles config option (defaults to false)
27534 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27535 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27536 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27537 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27538 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27539 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27540 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27541 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27542 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27543 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27544 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27546 * Create a new resizable component
27547 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27548 * @param {Object} config configuration options
27550 Roo.Resizable = function(el, config)
27552 this.el = Roo.get(el);
27554 if(config && config.wrap){
27555 config.resizeChild = this.el;
27556 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27557 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27558 this.el.setStyle("overflow", "hidden");
27559 this.el.setPositioning(config.resizeChild.getPositioning());
27560 config.resizeChild.clearPositioning();
27561 if(!config.width || !config.height){
27562 var csize = config.resizeChild.getSize();
27563 this.el.setSize(csize.width, csize.height);
27565 if(config.pinned && !config.adjustments){
27566 config.adjustments = "auto";
27570 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27571 this.proxy.unselectable();
27572 this.proxy.enableDisplayMode('block');
27574 Roo.apply(this, config);
27577 this.disableTrackOver = true;
27578 this.el.addClass("x-resizable-pinned");
27580 // if the element isn't positioned, make it relative
27581 var position = this.el.getStyle("position");
27582 if(position != "absolute" && position != "fixed"){
27583 this.el.setStyle("position", "relative");
27585 if(!this.handles){ // no handles passed, must be legacy style
27586 this.handles = 's,e,se';
27587 if(this.multiDirectional){
27588 this.handles += ',n,w';
27591 if(this.handles == "all"){
27592 this.handles = "n s e w ne nw se sw";
27594 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27595 var ps = Roo.Resizable.positions;
27596 for(var i = 0, len = hs.length; i < len; i++){
27597 if(hs[i] && ps[hs[i]]){
27598 var pos = ps[hs[i]];
27599 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27603 this.corner = this.southeast;
27605 // updateBox = the box can move..
27606 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27607 this.updateBox = true;
27610 this.activeHandle = null;
27612 if(this.resizeChild){
27613 if(typeof this.resizeChild == "boolean"){
27614 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27616 this.resizeChild = Roo.get(this.resizeChild, true);
27620 if(this.adjustments == "auto"){
27621 var rc = this.resizeChild;
27622 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27623 if(rc && (hw || hn)){
27624 rc.position("relative");
27625 rc.setLeft(hw ? hw.el.getWidth() : 0);
27626 rc.setTop(hn ? hn.el.getHeight() : 0);
27628 this.adjustments = [
27629 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27630 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27634 if(this.draggable){
27635 this.dd = this.dynamic ?
27636 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27637 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27643 * @event beforeresize
27644 * Fired before resize is allowed. Set enabled to false to cancel resize.
27645 * @param {Roo.Resizable} this
27646 * @param {Roo.EventObject} e The mousedown event
27648 "beforeresize" : true,
27651 * Fired after a resize.
27652 * @param {Roo.Resizable} this
27653 * @param {Number} width The new width
27654 * @param {Number} height The new height
27655 * @param {Roo.EventObject} e The mouseup event
27660 if(this.width !== null && this.height !== null){
27661 this.resizeTo(this.width, this.height);
27663 this.updateChildSize();
27666 this.el.dom.style.zoom = 1;
27668 Roo.Resizable.superclass.constructor.call(this);
27671 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27672 resizeChild : false,
27673 adjustments : [0, 0],
27683 multiDirectional : false,
27684 disableTrackOver : false,
27685 easing : 'easeOutStrong',
27686 widthIncrement : 0,
27687 heightIncrement : 0,
27691 preserveRatio : false,
27692 transparent: false,
27698 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27700 constrainTo: undefined,
27702 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27704 resizeRegion: undefined,
27708 * Perform a manual resize
27709 * @param {Number} width
27710 * @param {Number} height
27712 resizeTo : function(width, height){
27713 this.el.setSize(width, height);
27714 this.updateChildSize();
27715 this.fireEvent("resize", this, width, height, null);
27719 startSizing : function(e, handle){
27720 this.fireEvent("beforeresize", this, e);
27721 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27724 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27725 this.overlay.unselectable();
27726 this.overlay.enableDisplayMode("block");
27727 this.overlay.on("mousemove", this.onMouseMove, this);
27728 this.overlay.on("mouseup", this.onMouseUp, this);
27730 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27732 this.resizing = true;
27733 this.startBox = this.el.getBox();
27734 this.startPoint = e.getXY();
27735 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27736 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27738 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27739 this.overlay.show();
27741 if(this.constrainTo) {
27742 var ct = Roo.get(this.constrainTo);
27743 this.resizeRegion = ct.getRegion().adjust(
27744 ct.getFrameWidth('t'),
27745 ct.getFrameWidth('l'),
27746 -ct.getFrameWidth('b'),
27747 -ct.getFrameWidth('r')
27751 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27753 this.proxy.setBox(this.startBox);
27755 this.proxy.setStyle('visibility', 'visible');
27761 onMouseDown : function(handle, e){
27764 this.activeHandle = handle;
27765 this.startSizing(e, handle);
27770 onMouseUp : function(e){
27771 var size = this.resizeElement();
27772 this.resizing = false;
27774 this.overlay.hide();
27776 this.fireEvent("resize", this, size.width, size.height, e);
27780 updateChildSize : function(){
27781 if(this.resizeChild){
27783 var child = this.resizeChild;
27784 var adj = this.adjustments;
27785 if(el.dom.offsetWidth){
27786 var b = el.getSize(true);
27787 child.setSize(b.width+adj[0], b.height+adj[1]);
27789 // Second call here for IE
27790 // The first call enables instant resizing and
27791 // the second call corrects scroll bars if they
27794 setTimeout(function(){
27795 if(el.dom.offsetWidth){
27796 var b = el.getSize(true);
27797 child.setSize(b.width+adj[0], b.height+adj[1]);
27805 snap : function(value, inc, min){
27806 if(!inc || !value) return value;
27807 var newValue = value;
27808 var m = value % inc;
27811 newValue = value + (inc-m);
27813 newValue = value - m;
27816 return Math.max(min, newValue);
27820 resizeElement : function(){
27821 var box = this.proxy.getBox();
27822 if(this.updateBox){
27823 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27825 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27827 this.updateChildSize();
27835 constrain : function(v, diff, m, mx){
27838 }else if(v - diff > mx){
27845 onMouseMove : function(e){
27847 try{// try catch so if something goes wrong the user doesn't get hung
27849 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27853 //var curXY = this.startPoint;
27854 var curSize = this.curSize || this.startBox;
27855 var x = this.startBox.x, y = this.startBox.y;
27856 var ox = x, oy = y;
27857 var w = curSize.width, h = curSize.height;
27858 var ow = w, oh = h;
27859 var mw = this.minWidth, mh = this.minHeight;
27860 var mxw = this.maxWidth, mxh = this.maxHeight;
27861 var wi = this.widthIncrement;
27862 var hi = this.heightIncrement;
27864 var eventXY = e.getXY();
27865 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27866 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27868 var pos = this.activeHandle.position;
27873 w = Math.min(Math.max(mw, w), mxw);
27878 h = Math.min(Math.max(mh, h), mxh);
27883 w = Math.min(Math.max(mw, w), mxw);
27884 h = Math.min(Math.max(mh, h), mxh);
27887 diffY = this.constrain(h, diffY, mh, mxh);
27894 var adiffX = Math.abs(diffX);
27895 var sub = (adiffX % wi); // how much
27896 if (sub > (wi/2)) { // far enough to snap
27897 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
27899 // remove difference..
27900 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
27904 x = Math.max(this.minX, x);
27907 diffX = this.constrain(w, diffX, mw, mxw);
27913 w = Math.min(Math.max(mw, w), mxw);
27914 diffY = this.constrain(h, diffY, mh, mxh);
27919 diffX = this.constrain(w, diffX, mw, mxw);
27920 diffY = this.constrain(h, diffY, mh, mxh);
27927 diffX = this.constrain(w, diffX, mw, mxw);
27929 h = Math.min(Math.max(mh, h), mxh);
27935 var sw = this.snap(w, wi, mw);
27936 var sh = this.snap(h, hi, mh);
27937 if(sw != w || sh != h){
27960 if(this.preserveRatio){
27965 h = Math.min(Math.max(mh, h), mxh);
27970 w = Math.min(Math.max(mw, w), mxw);
27975 w = Math.min(Math.max(mw, w), mxw);
27981 w = Math.min(Math.max(mw, w), mxw);
27987 h = Math.min(Math.max(mh, h), mxh);
27995 h = Math.min(Math.max(mh, h), mxh);
28005 h = Math.min(Math.max(mh, h), mxh);
28013 if (pos == 'hdrag') {
28016 this.proxy.setBounds(x, y, w, h);
28018 this.resizeElement();
28025 handleOver : function(){
28027 this.el.addClass("x-resizable-over");
28032 handleOut : function(){
28033 if(!this.resizing){
28034 this.el.removeClass("x-resizable-over");
28039 * Returns the element this component is bound to.
28040 * @return {Roo.Element}
28042 getEl : function(){
28047 * Returns the resizeChild element (or null).
28048 * @return {Roo.Element}
28050 getResizeChild : function(){
28051 return this.resizeChild;
28055 * Destroys this resizable. If the element was wrapped and
28056 * removeEl is not true then the element remains.
28057 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28059 destroy : function(removeEl){
28060 this.proxy.remove();
28062 this.overlay.removeAllListeners();
28063 this.overlay.remove();
28065 var ps = Roo.Resizable.positions;
28067 if(typeof ps[k] != "function" && this[ps[k]]){
28068 var h = this[ps[k]];
28069 h.el.removeAllListeners();
28074 this.el.update("");
28081 // hash to map config positions to true positions
28082 Roo.Resizable.positions = {
28083 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28088 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28090 // only initialize the template if resizable is used
28091 var tpl = Roo.DomHelper.createTemplate(
28092 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28095 Roo.Resizable.Handle.prototype.tpl = tpl;
28097 this.position = pos;
28099 // show north drag fro topdra
28100 var handlepos = pos == 'hdrag' ? 'north' : pos;
28102 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28103 if (pos == 'hdrag') {
28104 this.el.setStyle('cursor', 'pointer');
28106 this.el.unselectable();
28108 this.el.setOpacity(0);
28110 this.el.on("mousedown", this.onMouseDown, this);
28111 if(!disableTrackOver){
28112 this.el.on("mouseover", this.onMouseOver, this);
28113 this.el.on("mouseout", this.onMouseOut, this);
28118 Roo.Resizable.Handle.prototype = {
28119 afterResize : function(rz){
28123 onMouseDown : function(e){
28124 this.rz.onMouseDown(this, e);
28127 onMouseOver : function(e){
28128 this.rz.handleOver(this, e);
28131 onMouseOut : function(e){
28132 this.rz.handleOut(this, e);
28136 * Ext JS Library 1.1.1
28137 * Copyright(c) 2006-2007, Ext JS, LLC.
28139 * Originally Released Under LGPL - original licence link has changed is not relivant.
28142 * <script type="text/javascript">
28146 * @class Roo.Editor
28147 * @extends Roo.Component
28148 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28150 * Create a new Editor
28151 * @param {Roo.form.Field} field The Field object (or descendant)
28152 * @param {Object} config The config object
28154 Roo.Editor = function(field, config){
28155 Roo.Editor.superclass.constructor.call(this, config);
28156 this.field = field;
28159 * @event beforestartedit
28160 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28161 * false from the handler of this event.
28162 * @param {Editor} this
28163 * @param {Roo.Element} boundEl The underlying element bound to this editor
28164 * @param {Mixed} value The field value being set
28166 "beforestartedit" : true,
28169 * Fires when this editor is displayed
28170 * @param {Roo.Element} boundEl The underlying element bound to this editor
28171 * @param {Mixed} value The starting field value
28173 "startedit" : true,
28175 * @event beforecomplete
28176 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28177 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28178 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28179 * event will not fire since no edit actually occurred.
28180 * @param {Editor} this
28181 * @param {Mixed} value The current field value
28182 * @param {Mixed} startValue The original field value
28184 "beforecomplete" : true,
28187 * Fires after editing is complete and any changed value has been written to the underlying field.
28188 * @param {Editor} this
28189 * @param {Mixed} value The current field value
28190 * @param {Mixed} startValue The original field value
28194 * @event specialkey
28195 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28196 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28197 * @param {Roo.form.Field} this
28198 * @param {Roo.EventObject} e The event object
28200 "specialkey" : true
28204 Roo.extend(Roo.Editor, Roo.Component, {
28206 * @cfg {Boolean/String} autosize
28207 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28208 * or "height" to adopt the height only (defaults to false)
28211 * @cfg {Boolean} revertInvalid
28212 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28213 * validation fails (defaults to true)
28216 * @cfg {Boolean} ignoreNoChange
28217 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28218 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28219 * will never be ignored.
28222 * @cfg {Boolean} hideEl
28223 * False to keep the bound element visible while the editor is displayed (defaults to true)
28226 * @cfg {Mixed} value
28227 * The data value of the underlying field (defaults to "")
28231 * @cfg {String} alignment
28232 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28236 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28237 * for bottom-right shadow (defaults to "frame")
28241 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28245 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28247 completeOnEnter : false,
28249 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28251 cancelOnEsc : false,
28253 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28258 onRender : function(ct, position){
28259 this.el = new Roo.Layer({
28260 shadow: this.shadow,
28266 constrain: this.constrain
28268 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28269 if(this.field.msgTarget != 'title'){
28270 this.field.msgTarget = 'qtip';
28272 this.field.render(this.el);
28274 this.field.el.dom.setAttribute('autocomplete', 'off');
28276 this.field.on("specialkey", this.onSpecialKey, this);
28277 if(this.swallowKeys){
28278 this.field.el.swallowEvent(['keydown','keypress']);
28281 this.field.on("blur", this.onBlur, this);
28282 if(this.field.grow){
28283 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28287 onSpecialKey : function(field, e){
28288 //Roo.log('editor onSpecialKey');
28289 if(this.completeOnEnter && e.getKey() == e.ENTER){
28291 this.completeEdit();
28292 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
28295 this.fireEvent('specialkey', field, e);
28300 * Starts the editing process and shows the editor.
28301 * @param {String/HTMLElement/Element} el The element to edit
28302 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28303 * to the innerHTML of el.
28305 startEdit : function(el, value){
28307 this.completeEdit();
28309 this.boundEl = Roo.get(el);
28310 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28311 if(!this.rendered){
28312 this.render(this.parentEl || document.body);
28314 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28317 this.startValue = v;
28318 this.field.setValue(v);
28320 var sz = this.boundEl.getSize();
28321 switch(this.autoSize){
28323 this.setSize(sz.width, "");
28326 this.setSize("", sz.height);
28329 this.setSize(sz.width, sz.height);
28332 this.el.alignTo(this.boundEl, this.alignment);
28333 this.editing = true;
28335 Roo.QuickTips.disable();
28341 * Sets the height and width of this editor.
28342 * @param {Number} width The new width
28343 * @param {Number} height The new height
28345 setSize : function(w, h){
28346 this.field.setSize(w, h);
28353 * Realigns the editor to the bound field based on the current alignment config value.
28355 realign : function(){
28356 this.el.alignTo(this.boundEl, this.alignment);
28360 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28361 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28363 completeEdit : function(remainVisible){
28367 var v = this.getValue();
28368 if(this.revertInvalid !== false && !this.field.isValid()){
28369 v = this.startValue;
28370 this.cancelEdit(true);
28372 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28373 this.editing = false;
28377 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28378 this.editing = false;
28379 if(this.updateEl && this.boundEl){
28380 this.boundEl.update(v);
28382 if(remainVisible !== true){
28385 this.fireEvent("complete", this, v, this.startValue);
28390 onShow : function(){
28392 if(this.hideEl !== false){
28393 this.boundEl.hide();
28396 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28397 this.fixIEFocus = true;
28398 this.deferredFocus.defer(50, this);
28400 this.field.focus();
28402 this.fireEvent("startedit", this.boundEl, this.startValue);
28405 deferredFocus : function(){
28407 this.field.focus();
28412 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28413 * reverted to the original starting value.
28414 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28415 * cancel (defaults to false)
28417 cancelEdit : function(remainVisible){
28419 this.setValue(this.startValue);
28420 if(remainVisible !== true){
28427 onBlur : function(){
28428 if(this.allowBlur !== true && this.editing){
28429 this.completeEdit();
28434 onHide : function(){
28436 this.completeEdit();
28440 if(this.field.collapse){
28441 this.field.collapse();
28444 if(this.hideEl !== false){
28445 this.boundEl.show();
28448 Roo.QuickTips.enable();
28453 * Sets the data value of the editor
28454 * @param {Mixed} value Any valid value supported by the underlying field
28456 setValue : function(v){
28457 this.field.setValue(v);
28461 * Gets the data value of the editor
28462 * @return {Mixed} The data value
28464 getValue : function(){
28465 return this.field.getValue();
28469 * Ext JS Library 1.1.1
28470 * Copyright(c) 2006-2007, Ext JS, LLC.
28472 * Originally Released Under LGPL - original licence link has changed is not relivant.
28475 * <script type="text/javascript">
28479 * @class Roo.BasicDialog
28480 * @extends Roo.util.Observable
28481 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28483 var dlg = new Roo.BasicDialog("my-dlg", {
28492 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28493 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28494 dlg.addButton('Cancel', dlg.hide, dlg);
28497 <b>A Dialog should always be a direct child of the body element.</b>
28498 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28499 * @cfg {String} title Default text to display in the title bar (defaults to null)
28500 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28501 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28502 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28503 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28504 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28505 * (defaults to null with no animation)
28506 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28507 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28508 * property for valid values (defaults to 'all')
28509 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28510 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28511 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28512 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28513 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28514 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28515 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28516 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28517 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28518 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28519 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28520 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28521 * draggable = true (defaults to false)
28522 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28523 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28524 * shadow (defaults to false)
28525 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28526 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28527 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28528 * @cfg {Array} buttons Array of buttons
28529 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28531 * Create a new BasicDialog.
28532 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28533 * @param {Object} config Configuration options
28535 Roo.BasicDialog = function(el, config){
28536 this.el = Roo.get(el);
28537 var dh = Roo.DomHelper;
28538 if(!this.el && config && config.autoCreate){
28539 if(typeof config.autoCreate == "object"){
28540 if(!config.autoCreate.id){
28541 config.autoCreate.id = el;
28543 this.el = dh.append(document.body,
28544 config.autoCreate, true);
28546 this.el = dh.append(document.body,
28547 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28551 el.setDisplayed(true);
28552 el.hide = this.hideAction;
28554 el.addClass("x-dlg");
28556 Roo.apply(this, config);
28558 this.proxy = el.createProxy("x-dlg-proxy");
28559 this.proxy.hide = this.hideAction;
28560 this.proxy.setOpacity(.5);
28564 el.setWidth(config.width);
28567 el.setHeight(config.height);
28569 this.size = el.getSize();
28570 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28571 this.xy = [config.x,config.y];
28573 this.xy = el.getCenterXY(true);
28575 /** The header element @type Roo.Element */
28576 this.header = el.child("> .x-dlg-hd");
28577 /** The body element @type Roo.Element */
28578 this.body = el.child("> .x-dlg-bd");
28579 /** The footer element @type Roo.Element */
28580 this.footer = el.child("> .x-dlg-ft");
28583 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28586 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28589 this.header.unselectable();
28591 this.header.update(this.title);
28593 // this element allows the dialog to be focused for keyboard event
28594 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28595 this.focusEl.swallowEvent("click", true);
28597 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28599 // wrap the body and footer for special rendering
28600 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28602 this.bwrap.dom.appendChild(this.footer.dom);
28605 this.bg = this.el.createChild({
28606 tag: "div", cls:"x-dlg-bg",
28607 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28609 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28612 if(this.autoScroll !== false && !this.autoTabs){
28613 this.body.setStyle("overflow", "auto");
28616 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28618 if(this.closable !== false){
28619 this.el.addClass("x-dlg-closable");
28620 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28621 this.close.on("click", this.closeClick, this);
28622 this.close.addClassOnOver("x-dlg-close-over");
28624 if(this.collapsible !== false){
28625 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28626 this.collapseBtn.on("click", this.collapseClick, this);
28627 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28628 this.header.on("dblclick", this.collapseClick, this);
28630 if(this.resizable !== false){
28631 this.el.addClass("x-dlg-resizable");
28632 this.resizer = new Roo.Resizable(el, {
28633 minWidth: this.minWidth || 80,
28634 minHeight:this.minHeight || 80,
28635 handles: this.resizeHandles || "all",
28638 this.resizer.on("beforeresize", this.beforeResize, this);
28639 this.resizer.on("resize", this.onResize, this);
28641 if(this.draggable !== false){
28642 el.addClass("x-dlg-draggable");
28643 if (!this.proxyDrag) {
28644 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28647 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28649 dd.setHandleElId(this.header.id);
28650 dd.endDrag = this.endMove.createDelegate(this);
28651 dd.startDrag = this.startMove.createDelegate(this);
28652 dd.onDrag = this.onDrag.createDelegate(this);
28657 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28658 this.mask.enableDisplayMode("block");
28660 this.el.addClass("x-dlg-modal");
28663 this.shadow = new Roo.Shadow({
28664 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28665 offset : this.shadowOffset
28668 this.shadowOffset = 0;
28670 if(Roo.useShims && this.shim !== false){
28671 this.shim = this.el.createShim();
28672 this.shim.hide = this.hideAction;
28680 if (this.buttons) {
28681 var bts= this.buttons;
28683 Roo.each(bts, function(b) {
28692 * Fires when a key is pressed
28693 * @param {Roo.BasicDialog} this
28694 * @param {Roo.EventObject} e
28699 * Fires when this dialog is moved by the user.
28700 * @param {Roo.BasicDialog} this
28701 * @param {Number} x The new page X
28702 * @param {Number} y The new page Y
28707 * Fires when this dialog is resized by the user.
28708 * @param {Roo.BasicDialog} this
28709 * @param {Number} width The new width
28710 * @param {Number} height The new height
28714 * @event beforehide
28715 * Fires before this dialog is hidden.
28716 * @param {Roo.BasicDialog} this
28718 "beforehide" : true,
28721 * Fires when this dialog is hidden.
28722 * @param {Roo.BasicDialog} this
28726 * @event beforeshow
28727 * Fires before this dialog is shown.
28728 * @param {Roo.BasicDialog} this
28730 "beforeshow" : true,
28733 * Fires when this dialog is shown.
28734 * @param {Roo.BasicDialog} this
28738 el.on("keydown", this.onKeyDown, this);
28739 el.on("mousedown", this.toFront, this);
28740 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28742 Roo.DialogManager.register(this);
28743 Roo.BasicDialog.superclass.constructor.call(this);
28746 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28747 shadowOffset: Roo.isIE ? 6 : 5,
28750 minButtonWidth: 75,
28751 defaultButton: null,
28752 buttonAlign: "right",
28757 * Sets the dialog title text
28758 * @param {String} text The title text to display
28759 * @return {Roo.BasicDialog} this
28761 setTitle : function(text){
28762 this.header.update(text);
28767 closeClick : function(){
28772 collapseClick : function(){
28773 this[this.collapsed ? "expand" : "collapse"]();
28777 * Collapses the dialog to its minimized state (only the title bar is visible).
28778 * Equivalent to the user clicking the collapse dialog button.
28780 collapse : function(){
28781 if(!this.collapsed){
28782 this.collapsed = true;
28783 this.el.addClass("x-dlg-collapsed");
28784 this.restoreHeight = this.el.getHeight();
28785 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28790 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28791 * clicking the expand dialog button.
28793 expand : function(){
28794 if(this.collapsed){
28795 this.collapsed = false;
28796 this.el.removeClass("x-dlg-collapsed");
28797 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28802 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28803 * @return {Roo.TabPanel} The tabs component
28805 initTabs : function(){
28806 var tabs = this.getTabs();
28807 while(tabs.getTab(0)){
28810 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28812 tabs.addTab(Roo.id(dom), dom.title);
28820 beforeResize : function(){
28821 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28825 onResize : function(){
28826 this.refreshSize();
28827 this.syncBodyHeight();
28828 this.adjustAssets();
28830 this.fireEvent("resize", this, this.size.width, this.size.height);
28834 onKeyDown : function(e){
28835 if(this.isVisible()){
28836 this.fireEvent("keydown", this, e);
28841 * Resizes the dialog.
28842 * @param {Number} width
28843 * @param {Number} height
28844 * @return {Roo.BasicDialog} this
28846 resizeTo : function(width, height){
28847 this.el.setSize(width, height);
28848 this.size = {width: width, height: height};
28849 this.syncBodyHeight();
28850 if(this.fixedcenter){
28853 if(this.isVisible()){
28854 this.constrainXY();
28855 this.adjustAssets();
28857 this.fireEvent("resize", this, width, height);
28863 * Resizes the dialog to fit the specified content size.
28864 * @param {Number} width
28865 * @param {Number} height
28866 * @return {Roo.BasicDialog} this
28868 setContentSize : function(w, h){
28869 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28870 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28871 //if(!this.el.isBorderBox()){
28872 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28873 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28876 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28877 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28879 this.resizeTo(w, h);
28884 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28885 * executed in response to a particular key being pressed while the dialog is active.
28886 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28887 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28888 * @param {Function} fn The function to call
28889 * @param {Object} scope (optional) The scope of the function
28890 * @return {Roo.BasicDialog} this
28892 addKeyListener : function(key, fn, scope){
28893 var keyCode, shift, ctrl, alt;
28894 if(typeof key == "object" && !(key instanceof Array)){
28895 keyCode = key["key"];
28896 shift = key["shift"];
28897 ctrl = key["ctrl"];
28902 var handler = function(dlg, e){
28903 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
28904 var k = e.getKey();
28905 if(keyCode instanceof Array){
28906 for(var i = 0, len = keyCode.length; i < len; i++){
28907 if(keyCode[i] == k){
28908 fn.call(scope || window, dlg, k, e);
28914 fn.call(scope || window, dlg, k, e);
28919 this.on("keydown", handler);
28924 * Returns the TabPanel component (creates it if it doesn't exist).
28925 * Note: If you wish to simply check for the existence of tabs without creating them,
28926 * check for a null 'tabs' property.
28927 * @return {Roo.TabPanel} The tabs component
28929 getTabs : function(){
28931 this.el.addClass("x-dlg-auto-tabs");
28932 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
28933 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
28939 * Adds a button to the footer section of the dialog.
28940 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28941 * object or a valid Roo.DomHelper element config
28942 * @param {Function} handler The function called when the button is clicked
28943 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
28944 * @return {Roo.Button} The new button
28946 addButton : function(config, handler, scope){
28947 var dh = Roo.DomHelper;
28949 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
28951 if(!this.btnContainer){
28952 var tb = this.footer.createChild({
28954 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
28955 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28957 this.btnContainer = tb.firstChild.firstChild.firstChild;
28962 minWidth: this.minButtonWidth,
28965 if(typeof config == "string"){
28966 bconfig.text = config;
28969 bconfig.dhconfig = config;
28971 Roo.apply(bconfig, config);
28975 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
28976 bconfig.position = Math.max(0, bconfig.position);
28977 fc = this.btnContainer.childNodes[bconfig.position];
28980 var btn = new Roo.Button(
28982 this.btnContainer.insertBefore(document.createElement("td"),fc)
28983 : this.btnContainer.appendChild(document.createElement("td")),
28984 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
28987 this.syncBodyHeight();
28990 * Array of all the buttons that have been added to this dialog via addButton
28995 this.buttons.push(btn);
29000 * Sets the default button to be focused when the dialog is displayed.
29001 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29002 * @return {Roo.BasicDialog} this
29004 setDefaultButton : function(btn){
29005 this.defaultButton = btn;
29010 getHeaderFooterHeight : function(safe){
29013 height += this.header.getHeight();
29016 var fm = this.footer.getMargins();
29017 height += (this.footer.getHeight()+fm.top+fm.bottom);
29019 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29020 height += this.centerBg.getPadding("tb");
29025 syncBodyHeight : function(){
29026 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29027 var height = this.size.height - this.getHeaderFooterHeight(false);
29028 bd.setHeight(height-bd.getMargins("tb"));
29029 var hh = this.header.getHeight();
29030 var h = this.size.height-hh;
29032 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29033 bw.setHeight(h-cb.getPadding("tb"));
29034 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29035 bd.setWidth(bw.getWidth(true));
29037 this.tabs.syncHeight();
29039 this.tabs.el.repaint();
29045 * Restores the previous state of the dialog if Roo.state is configured.
29046 * @return {Roo.BasicDialog} this
29048 restoreState : function(){
29049 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29050 if(box && box.width){
29051 this.xy = [box.x, box.y];
29052 this.resizeTo(box.width, box.height);
29058 beforeShow : function(){
29060 if(this.fixedcenter){
29061 this.xy = this.el.getCenterXY(true);
29064 Roo.get(document.body).addClass("x-body-masked");
29065 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29068 this.constrainXY();
29072 animShow : function(){
29073 var b = Roo.get(this.animateTarget).getBox();
29074 this.proxy.setSize(b.width, b.height);
29075 this.proxy.setLocation(b.x, b.y);
29077 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29078 true, .35, this.showEl.createDelegate(this));
29082 * Shows the dialog.
29083 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29084 * @return {Roo.BasicDialog} this
29086 show : function(animateTarget){
29087 if (this.fireEvent("beforeshow", this) === false){
29090 if(this.syncHeightBeforeShow){
29091 this.syncBodyHeight();
29092 }else if(this.firstShow){
29093 this.firstShow = false;
29094 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29096 this.animateTarget = animateTarget || this.animateTarget;
29097 if(!this.el.isVisible()){
29099 if(this.animateTarget && Roo.get(this.animateTarget)){
29109 showEl : function(){
29111 this.el.setXY(this.xy);
29113 this.adjustAssets(true);
29116 // IE peekaboo bug - fix found by Dave Fenwick
29120 this.fireEvent("show", this);
29124 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29125 * dialog itself will receive focus.
29127 focus : function(){
29128 if(this.defaultButton){
29129 this.defaultButton.focus();
29131 this.focusEl.focus();
29136 constrainXY : function(){
29137 if(this.constraintoviewport !== false){
29138 if(!this.viewSize){
29139 if(this.container){
29140 var s = this.container.getSize();
29141 this.viewSize = [s.width, s.height];
29143 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29146 var s = Roo.get(this.container||document).getScroll();
29148 var x = this.xy[0], y = this.xy[1];
29149 var w = this.size.width, h = this.size.height;
29150 var vw = this.viewSize[0], vh = this.viewSize[1];
29151 // only move it if it needs it
29153 // first validate right/bottom
29154 if(x + w > vw+s.left){
29158 if(y + h > vh+s.top){
29162 // then make sure top/left isn't negative
29174 if(this.isVisible()){
29175 this.el.setLocation(x, y);
29176 this.adjustAssets();
29183 onDrag : function(){
29184 if(!this.proxyDrag){
29185 this.xy = this.el.getXY();
29186 this.adjustAssets();
29191 adjustAssets : function(doShow){
29192 var x = this.xy[0], y = this.xy[1];
29193 var w = this.size.width, h = this.size.height;
29194 if(doShow === true){
29196 this.shadow.show(this.el);
29202 if(this.shadow && this.shadow.isVisible()){
29203 this.shadow.show(this.el);
29205 if(this.shim && this.shim.isVisible()){
29206 this.shim.setBounds(x, y, w, h);
29211 adjustViewport : function(w, h){
29213 w = Roo.lib.Dom.getViewWidth();
29214 h = Roo.lib.Dom.getViewHeight();
29217 this.viewSize = [w, h];
29218 if(this.modal && this.mask.isVisible()){
29219 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29220 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29222 if(this.isVisible()){
29223 this.constrainXY();
29228 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29229 * shadow, proxy, mask, etc.) Also removes all event listeners.
29230 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29232 destroy : function(removeEl){
29233 if(this.isVisible()){
29234 this.animateTarget = null;
29237 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29239 this.tabs.destroy(removeEl);
29252 for(var i = 0, len = this.buttons.length; i < len; i++){
29253 this.buttons[i].destroy();
29256 this.el.removeAllListeners();
29257 if(removeEl === true){
29258 this.el.update("");
29261 Roo.DialogManager.unregister(this);
29265 startMove : function(){
29266 if(this.proxyDrag){
29269 if(this.constraintoviewport !== false){
29270 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29275 endMove : function(){
29276 if(!this.proxyDrag){
29277 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29279 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29282 this.refreshSize();
29283 this.adjustAssets();
29285 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29289 * Brings this dialog to the front of any other visible dialogs
29290 * @return {Roo.BasicDialog} this
29292 toFront : function(){
29293 Roo.DialogManager.bringToFront(this);
29298 * Sends this dialog to the back (under) of any other visible dialogs
29299 * @return {Roo.BasicDialog} this
29301 toBack : function(){
29302 Roo.DialogManager.sendToBack(this);
29307 * Centers this dialog in the viewport
29308 * @return {Roo.BasicDialog} this
29310 center : function(){
29311 var xy = this.el.getCenterXY(true);
29312 this.moveTo(xy[0], xy[1]);
29317 * Moves the dialog's top-left corner to the specified point
29318 * @param {Number} x
29319 * @param {Number} y
29320 * @return {Roo.BasicDialog} this
29322 moveTo : function(x, y){
29324 if(this.isVisible()){
29325 this.el.setXY(this.xy);
29326 this.adjustAssets();
29332 * Aligns the dialog to the specified element
29333 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29334 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29335 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29336 * @return {Roo.BasicDialog} this
29338 alignTo : function(element, position, offsets){
29339 this.xy = this.el.getAlignToXY(element, position, offsets);
29340 if(this.isVisible()){
29341 this.el.setXY(this.xy);
29342 this.adjustAssets();
29348 * Anchors an element to another element and realigns it when the window is resized.
29349 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29350 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29351 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29352 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29353 * is a number, it is used as the buffer delay (defaults to 50ms).
29354 * @return {Roo.BasicDialog} this
29356 anchorTo : function(el, alignment, offsets, monitorScroll){
29357 var action = function(){
29358 this.alignTo(el, alignment, offsets);
29360 Roo.EventManager.onWindowResize(action, this);
29361 var tm = typeof monitorScroll;
29362 if(tm != 'undefined'){
29363 Roo.EventManager.on(window, 'scroll', action, this,
29364 {buffer: tm == 'number' ? monitorScroll : 50});
29371 * Returns true if the dialog is visible
29372 * @return {Boolean}
29374 isVisible : function(){
29375 return this.el.isVisible();
29379 animHide : function(callback){
29380 var b = Roo.get(this.animateTarget).getBox();
29382 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29384 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29385 this.hideEl.createDelegate(this, [callback]));
29389 * Hides the dialog.
29390 * @param {Function} callback (optional) Function to call when the dialog is hidden
29391 * @return {Roo.BasicDialog} this
29393 hide : function(callback){
29394 if (this.fireEvent("beforehide", this) === false){
29398 this.shadow.hide();
29403 // sometimes animateTarget seems to get set.. causing problems...
29404 // this just double checks..
29405 if(this.animateTarget && Roo.get(this.animateTarget)) {
29406 this.animHide(callback);
29409 this.hideEl(callback);
29415 hideEl : function(callback){
29419 Roo.get(document.body).removeClass("x-body-masked");
29421 this.fireEvent("hide", this);
29422 if(typeof callback == "function"){
29428 hideAction : function(){
29429 this.setLeft("-10000px");
29430 this.setTop("-10000px");
29431 this.setStyle("visibility", "hidden");
29435 refreshSize : function(){
29436 this.size = this.el.getSize();
29437 this.xy = this.el.getXY();
29438 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29442 // z-index is managed by the DialogManager and may be overwritten at any time
29443 setZIndex : function(index){
29445 this.mask.setStyle("z-index", index);
29448 this.shim.setStyle("z-index", ++index);
29451 this.shadow.setZIndex(++index);
29453 this.el.setStyle("z-index", ++index);
29455 this.proxy.setStyle("z-index", ++index);
29458 this.resizer.proxy.setStyle("z-index", ++index);
29461 this.lastZIndex = index;
29465 * Returns the element for this dialog
29466 * @return {Roo.Element} The underlying dialog Element
29468 getEl : function(){
29474 * @class Roo.DialogManager
29475 * Provides global access to BasicDialogs that have been created and
29476 * support for z-indexing (layering) multiple open dialogs.
29478 Roo.DialogManager = function(){
29480 var accessList = [];
29484 var sortDialogs = function(d1, d2){
29485 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29489 var orderDialogs = function(){
29490 accessList.sort(sortDialogs);
29491 var seed = Roo.DialogManager.zseed;
29492 for(var i = 0, len = accessList.length; i < len; i++){
29493 var dlg = accessList[i];
29495 dlg.setZIndex(seed + (i*10));
29502 * The starting z-index for BasicDialogs (defaults to 9000)
29503 * @type Number The z-index value
29508 register : function(dlg){
29509 list[dlg.id] = dlg;
29510 accessList.push(dlg);
29514 unregister : function(dlg){
29515 delete list[dlg.id];
29518 if(!accessList.indexOf){
29519 for( i = 0, len = accessList.length; i < len; i++){
29520 if(accessList[i] == dlg){
29521 accessList.splice(i, 1);
29526 i = accessList.indexOf(dlg);
29528 accessList.splice(i, 1);
29534 * Gets a registered dialog by id
29535 * @param {String/Object} id The id of the dialog or a dialog
29536 * @return {Roo.BasicDialog} this
29538 get : function(id){
29539 return typeof id == "object" ? id : list[id];
29543 * Brings the specified dialog to the front
29544 * @param {String/Object} dlg The id of the dialog or a dialog
29545 * @return {Roo.BasicDialog} this
29547 bringToFront : function(dlg){
29548 dlg = this.get(dlg);
29551 dlg._lastAccess = new Date().getTime();
29558 * Sends the specified dialog to the back
29559 * @param {String/Object} dlg The id of the dialog or a dialog
29560 * @return {Roo.BasicDialog} this
29562 sendToBack : function(dlg){
29563 dlg = this.get(dlg);
29564 dlg._lastAccess = -(new Date().getTime());
29570 * Hides all dialogs
29572 hideAll : function(){
29573 for(var id in list){
29574 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29583 * @class Roo.LayoutDialog
29584 * @extends Roo.BasicDialog
29585 * Dialog which provides adjustments for working with a layout in a Dialog.
29586 * Add your necessary layout config options to the dialog's config.<br>
29587 * Example usage (including a nested layout):
29590 dialog = new Roo.LayoutDialog("download-dlg", {
29599 // layout config merges with the dialog config
29601 tabPosition: "top",
29602 alwaysShowTabs: true
29605 dialog.addKeyListener(27, dialog.hide, dialog);
29606 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29607 dialog.addButton("Build It!", this.getDownload, this);
29609 // we can even add nested layouts
29610 var innerLayout = new Roo.BorderLayout("dl-inner", {
29620 innerLayout.beginUpdate();
29621 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29622 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29623 innerLayout.endUpdate(true);
29625 var layout = dialog.getLayout();
29626 layout.beginUpdate();
29627 layout.add("center", new Roo.ContentPanel("standard-panel",
29628 {title: "Download the Source", fitToFrame:true}));
29629 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29630 {title: "Build your own roo.js"}));
29631 layout.getRegion("center").showPanel(sp);
29632 layout.endUpdate();
29636 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29637 * @param {Object} config configuration options
29639 Roo.LayoutDialog = function(el, cfg){
29642 if (typeof(cfg) == 'undefined') {
29643 config = Roo.apply({}, el);
29644 // not sure why we use documentElement here.. - it should always be body.
29645 // IE7 borks horribly if we use documentElement.
29646 el = Roo.get( Roo.isIE ? (document.body || document.documentElement) : (document.documentElement || document.body) ).createChild();
29647 //config.autoCreate = true;
29651 config.autoTabs = false;
29652 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29653 this.body.setStyle({overflow:"hidden", position:"relative"});
29654 this.layout = new Roo.BorderLayout(this.body.dom, config);
29655 this.layout.monitorWindowResize = false;
29656 this.el.addClass("x-dlg-auto-layout");
29657 // fix case when center region overwrites center function
29658 this.center = Roo.BasicDialog.prototype.center;
29659 this.on("show", this.layout.layout, this.layout, true);
29660 if (config.items) {
29661 var xitems = config.items;
29662 delete config.items;
29663 Roo.each(xitems, this.addxtype, this);
29668 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29670 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29673 endUpdate : function(){
29674 this.layout.endUpdate();
29678 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29681 beginUpdate : function(){
29682 this.layout.beginUpdate();
29686 * Get the BorderLayout for this dialog
29687 * @return {Roo.BorderLayout}
29689 getLayout : function(){
29690 return this.layout;
29693 showEl : function(){
29694 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29696 this.layout.layout();
29701 // Use the syncHeightBeforeShow config option to control this automatically
29702 syncBodyHeight : function(){
29703 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29704 if(this.layout){this.layout.layout();}
29708 * Add an xtype element (actually adds to the layout.)
29709 * @return {Object} xdata xtype object data.
29712 addxtype : function(c) {
29713 return this.layout.addxtype(c);
29717 * Ext JS Library 1.1.1
29718 * Copyright(c) 2006-2007, Ext JS, LLC.
29720 * Originally Released Under LGPL - original licence link has changed is not relivant.
29723 * <script type="text/javascript">
29727 * @class Roo.MessageBox
29728 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29732 Roo.Msg.alert('Status', 'Changes saved successfully.');
29734 // Prompt for user data:
29735 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29737 // process text value...
29741 // Show a dialog using config options:
29743 title:'Save Changes?',
29744 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29745 buttons: Roo.Msg.YESNOCANCEL,
29752 Roo.MessageBox = function(){
29753 var dlg, opt, mask, waitTimer;
29754 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29755 var buttons, activeTextEl, bwidth;
29758 var handleButton = function(button){
29760 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29764 var handleHide = function(){
29765 if(opt && opt.cls){
29766 dlg.el.removeClass(opt.cls);
29769 Roo.TaskMgr.stop(waitTimer);
29775 var updateButtons = function(b){
29778 buttons["ok"].hide();
29779 buttons["cancel"].hide();
29780 buttons["yes"].hide();
29781 buttons["no"].hide();
29782 dlg.footer.dom.style.display = 'none';
29785 dlg.footer.dom.style.display = '';
29786 for(var k in buttons){
29787 if(typeof buttons[k] != "function"){
29790 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29791 width += buttons[k].el.getWidth()+15;
29801 var handleEsc = function(d, k, e){
29802 if(opt && opt.closable !== false){
29812 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29813 * @return {Roo.BasicDialog} The BasicDialog element
29815 getDialog : function(){
29817 dlg = new Roo.BasicDialog("x-msg-box", {
29822 constraintoviewport:false,
29824 collapsible : false,
29827 width:400, height:100,
29828 buttonAlign:"center",
29829 closeClick : function(){
29830 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29831 handleButton("no");
29833 handleButton("cancel");
29837 dlg.on("hide", handleHide);
29839 dlg.addKeyListener(27, handleEsc);
29841 var bt = this.buttonText;
29842 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29843 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29844 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29845 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29846 bodyEl = dlg.body.createChild({
29848 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>'
29850 msgEl = bodyEl.dom.firstChild;
29851 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29852 textboxEl.enableDisplayMode();
29853 textboxEl.addKeyListener([10,13], function(){
29854 if(dlg.isVisible() && opt && opt.buttons){
29855 if(opt.buttons.ok){
29856 handleButton("ok");
29857 }else if(opt.buttons.yes){
29858 handleButton("yes");
29862 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29863 textareaEl.enableDisplayMode();
29864 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29865 progressEl.enableDisplayMode();
29866 var pf = progressEl.dom.firstChild;
29868 pp = Roo.get(pf.firstChild);
29869 pp.setHeight(pf.offsetHeight);
29877 * Updates the message box body text
29878 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29879 * the XHTML-compliant non-breaking space character '&#160;')
29880 * @return {Roo.MessageBox} This message box
29882 updateText : function(text){
29883 if(!dlg.isVisible() && !opt.width){
29884 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29886 msgEl.innerHTML = text || ' ';
29887 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29888 Math.max(opt.minWidth || this.minWidth, bwidth));
29890 activeTextEl.setWidth(w);
29892 if(dlg.isVisible()){
29893 dlg.fixedcenter = false;
29895 dlg.setContentSize(w, bodyEl.getHeight());
29896 if(dlg.isVisible()){
29897 dlg.fixedcenter = true;
29903 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
29904 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
29905 * @param {Number} value Any number between 0 and 1 (e.g., .5)
29906 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
29907 * @return {Roo.MessageBox} This message box
29909 updateProgress : function(value, text){
29911 this.updateText(text);
29913 if (pp) { // weird bug on my firefox - for some reason this is not defined
29914 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
29920 * Returns true if the message box is currently displayed
29921 * @return {Boolean} True if the message box is visible, else false
29923 isVisible : function(){
29924 return dlg && dlg.isVisible();
29928 * Hides the message box if it is displayed
29931 if(this.isVisible()){
29937 * Displays a new message box, or reinitializes an existing message box, based on the config options
29938 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
29939 * The following config object properties are supported:
29941 Property Type Description
29942 ---------- --------------- ------------------------------------------------------------------------------------
29943 animEl String/Element An id or Element from which the message box should animate as it opens and
29944 closes (defaults to undefined)
29945 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
29946 cancel:'Bar'}), or false to not show any buttons (defaults to false)
29947 closable Boolean False to hide the top-right close button (defaults to true). Note that
29948 progress and wait dialogs will ignore this property and always hide the
29949 close button as they can only be closed programmatically.
29950 cls String A custom CSS class to apply to the message box element
29951 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
29952 displayed (defaults to 75)
29953 fn Function A callback function to execute after closing the dialog. The arguments to the
29954 function will be btn (the name of the button that was clicked, if applicable,
29955 e.g. "ok"), and text (the value of the active text field, if applicable).
29956 Progress and wait dialogs will ignore this option since they do not respond to
29957 user actions and can only be closed programmatically, so any required function
29958 should be called by the same code after it closes the dialog.
29959 icon String A CSS class that provides a background image to be used as an icon for
29960 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
29961 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
29962 minWidth Number The minimum width in pixels of the message box (defaults to 100)
29963 modal Boolean False to allow user interaction with the page while the message box is
29964 displayed (defaults to true)
29965 msg String A string that will replace the existing message box body text (defaults
29966 to the XHTML-compliant non-breaking space character ' ')
29967 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
29968 progress Boolean True to display a progress bar (defaults to false)
29969 progressText String The text to display inside the progress bar if progress = true (defaults to '')
29970 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
29971 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
29972 title String The title text
29973 value String The string value to set into the active textbox element if displayed
29974 wait Boolean True to display a progress bar (defaults to false)
29975 width Number The width of the dialog in pixels
29982 msg: 'Please enter your address:',
29984 buttons: Roo.MessageBox.OKCANCEL,
29987 animEl: 'addAddressBtn'
29990 * @param {Object} config Configuration options
29991 * @return {Roo.MessageBox} This message box
29993 show : function(options){
29994 if(this.isVisible()){
29997 var d = this.getDialog();
29999 d.setTitle(opt.title || " ");
30000 d.close.setDisplayed(opt.closable !== false);
30001 activeTextEl = textboxEl;
30002 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30007 textareaEl.setHeight(typeof opt.multiline == "number" ?
30008 opt.multiline : this.defaultTextHeight);
30009 activeTextEl = textareaEl;
30018 progressEl.setDisplayed(opt.progress === true);
30019 this.updateProgress(0);
30020 activeTextEl.dom.value = opt.value || "";
30022 dlg.setDefaultButton(activeTextEl);
30024 var bs = opt.buttons;
30027 db = buttons["ok"];
30028 }else if(bs && bs.yes){
30029 db = buttons["yes"];
30031 dlg.setDefaultButton(db);
30033 bwidth = updateButtons(opt.buttons);
30034 this.updateText(opt.msg);
30036 d.el.addClass(opt.cls);
30038 d.proxyDrag = opt.proxyDrag === true;
30039 d.modal = opt.modal !== false;
30040 d.mask = opt.modal !== false ? mask : false;
30041 if(!d.isVisible()){
30042 // force it to the end of the z-index stack so it gets a cursor in FF
30043 document.body.appendChild(dlg.el.dom);
30044 d.animateTarget = null;
30045 d.show(options.animEl);
30051 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30052 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30053 * and closing the message box when the process is complete.
30054 * @param {String} title The title bar text
30055 * @param {String} msg The message box body text
30056 * @return {Roo.MessageBox} This message box
30058 progress : function(title, msg){
30065 minWidth: this.minProgressWidth,
30072 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30073 * If a callback function is passed it will be called after the user clicks the button, and the
30074 * id of the button that was clicked will be passed as the only parameter to the callback
30075 * (could also be the top-right close button).
30076 * @param {String} title The title bar text
30077 * @param {String} msg The message box body text
30078 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30079 * @param {Object} scope (optional) The scope of the callback function
30080 * @return {Roo.MessageBox} This message box
30082 alert : function(title, msg, fn, scope){
30095 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30096 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30097 * You are responsible for closing the message box when the process is complete.
30098 * @param {String} msg The message box body text
30099 * @param {String} title (optional) The title bar text
30100 * @return {Roo.MessageBox} This message box
30102 wait : function(msg, title){
30113 waitTimer = Roo.TaskMgr.start({
30115 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30123 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30124 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30125 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30126 * @param {String} title The title bar text
30127 * @param {String} msg The message box body text
30128 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30129 * @param {Object} scope (optional) The scope of the callback function
30130 * @return {Roo.MessageBox} This message box
30132 confirm : function(title, msg, fn, scope){
30136 buttons: this.YESNO,
30145 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30146 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30147 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30148 * (could also be the top-right close button) and the text that was entered will be passed as the two
30149 * parameters to the callback.
30150 * @param {String} title The title bar text
30151 * @param {String} msg The message box body text
30152 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30153 * @param {Object} scope (optional) The scope of the callback function
30154 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30155 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30156 * @return {Roo.MessageBox} This message box
30158 prompt : function(title, msg, fn, scope, multiline){
30162 buttons: this.OKCANCEL,
30167 multiline: multiline,
30174 * Button config that displays a single OK button
30179 * Button config that displays Yes and No buttons
30182 YESNO : {yes:true, no:true},
30184 * Button config that displays OK and Cancel buttons
30187 OKCANCEL : {ok:true, cancel:true},
30189 * Button config that displays Yes, No and Cancel buttons
30192 YESNOCANCEL : {yes:true, no:true, cancel:true},
30195 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30198 defaultTextHeight : 75,
30200 * The maximum width in pixels of the message box (defaults to 600)
30205 * The minimum width in pixels of the message box (defaults to 100)
30210 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30211 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30214 minProgressWidth : 250,
30216 * An object containing the default button text strings that can be overriden for localized language support.
30217 * Supported properties are: ok, cancel, yes and no.
30218 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30231 * Shorthand for {@link Roo.MessageBox}
30233 Roo.Msg = Roo.MessageBox;/*
30235 * Ext JS Library 1.1.1
30236 * Copyright(c) 2006-2007, Ext JS, LLC.
30238 * Originally Released Under LGPL - original licence link has changed is not relivant.
30241 * <script type="text/javascript">
30244 * @class Roo.QuickTips
30245 * Provides attractive and customizable tooltips for any element.
30248 Roo.QuickTips = function(){
30249 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30250 var ce, bd, xy, dd;
30251 var visible = false, disabled = true, inited = false;
30252 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30254 var onOver = function(e){
30258 var t = e.getTarget();
30259 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30262 if(ce && t == ce.el){
30263 clearTimeout(hideProc);
30266 if(t && tagEls[t.id]){
30267 tagEls[t.id].el = t;
30268 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30271 var ttp, et = Roo.fly(t);
30272 var ns = cfg.namespace;
30273 if(tm.interceptTitles && t.title){
30276 t.removeAttribute("title");
30277 e.preventDefault();
30279 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30282 showProc = show.defer(tm.showDelay, tm, [{
30285 width: et.getAttributeNS(ns, cfg.width),
30286 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30287 title: et.getAttributeNS(ns, cfg.title),
30288 cls: et.getAttributeNS(ns, cfg.cls)
30293 var onOut = function(e){
30294 clearTimeout(showProc);
30295 var t = e.getTarget();
30296 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30297 hideProc = setTimeout(hide, tm.hideDelay);
30301 var onMove = function(e){
30307 if(tm.trackMouse && ce){
30312 var onDown = function(e){
30313 clearTimeout(showProc);
30314 clearTimeout(hideProc);
30316 if(tm.hideOnClick){
30319 tm.enable.defer(100, tm);
30324 var getPad = function(){
30325 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30328 var show = function(o){
30332 clearTimeout(dismissProc);
30334 if(removeCls){ // in case manually hidden
30335 el.removeClass(removeCls);
30339 el.addClass(ce.cls);
30340 removeCls = ce.cls;
30343 tipTitle.update(ce.title);
30346 tipTitle.update('');
30349 el.dom.style.width = tm.maxWidth+'px';
30350 //tipBody.dom.style.width = '';
30351 tipBodyText.update(o.text);
30352 var p = getPad(), w = ce.width;
30354 var td = tipBodyText.dom;
30355 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30356 if(aw > tm.maxWidth){
30358 }else if(aw < tm.minWidth){
30364 //tipBody.setWidth(w);
30365 el.setWidth(parseInt(w, 10) + p);
30366 if(ce.autoHide === false){
30367 close.setDisplayed(true);
30372 close.setDisplayed(false);
30378 el.avoidY = xy[1]-18;
30383 el.setStyle("visibility", "visible");
30384 el.fadeIn({callback: afterShow});
30390 var afterShow = function(){
30394 if(tm.autoDismiss && ce.autoHide !== false){
30395 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30400 var hide = function(noanim){
30401 clearTimeout(dismissProc);
30402 clearTimeout(hideProc);
30404 if(el.isVisible()){
30406 if(noanim !== true && tm.animate){
30407 el.fadeOut({callback: afterHide});
30414 var afterHide = function(){
30417 el.removeClass(removeCls);
30424 * @cfg {Number} minWidth
30425 * The minimum width of the quick tip (defaults to 40)
30429 * @cfg {Number} maxWidth
30430 * The maximum width of the quick tip (defaults to 300)
30434 * @cfg {Boolean} interceptTitles
30435 * True to automatically use the element's DOM title value if available (defaults to false)
30437 interceptTitles : false,
30439 * @cfg {Boolean} trackMouse
30440 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30442 trackMouse : false,
30444 * @cfg {Boolean} hideOnClick
30445 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30447 hideOnClick : true,
30449 * @cfg {Number} showDelay
30450 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30454 * @cfg {Number} hideDelay
30455 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30459 * @cfg {Boolean} autoHide
30460 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30461 * Used in conjunction with hideDelay.
30466 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30467 * (defaults to true). Used in conjunction with autoDismissDelay.
30469 autoDismiss : true,
30472 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30474 autoDismissDelay : 5000,
30476 * @cfg {Boolean} animate
30477 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30482 * @cfg {String} title
30483 * Title text to display (defaults to ''). This can be any valid HTML markup.
30487 * @cfg {String} text
30488 * Body text to display (defaults to ''). This can be any valid HTML markup.
30492 * @cfg {String} cls
30493 * A CSS class to apply to the base quick tip element (defaults to '').
30497 * @cfg {Number} width
30498 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30499 * minWidth or maxWidth.
30504 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30505 * or display QuickTips in a page.
30508 tm = Roo.QuickTips;
30509 cfg = tm.tagConfig;
30511 if(!Roo.isReady){ // allow calling of init() before onReady
30512 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30515 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30516 el.fxDefaults = {stopFx: true};
30517 // maximum custom styling
30518 //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>');
30519 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>');
30520 tipTitle = el.child('h3');
30521 tipTitle.enableDisplayMode("block");
30522 tipBody = el.child('div.x-tip-bd');
30523 tipBodyText = el.child('div.x-tip-bd-inner');
30524 //bdLeft = el.child('div.x-tip-bd-left');
30525 //bdRight = el.child('div.x-tip-bd-right');
30526 close = el.child('div.x-tip-close');
30527 close.enableDisplayMode("block");
30528 close.on("click", hide);
30529 var d = Roo.get(document);
30530 d.on("mousedown", onDown);
30531 d.on("mouseover", onOver);
30532 d.on("mouseout", onOut);
30533 d.on("mousemove", onMove);
30534 esc = d.addKeyListener(27, hide);
30537 dd = el.initDD("default", null, {
30538 onDrag : function(){
30542 dd.setHandleElId(tipTitle.id);
30551 * Configures a new quick tip instance and assigns it to a target element. The following config options
30554 Property Type Description
30555 ---------- --------------------- ------------------------------------------------------------------------
30556 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30558 * @param {Object} config The config object
30560 register : function(config){
30561 var cs = config instanceof Array ? config : arguments;
30562 for(var i = 0, len = cs.length; i < len; i++) {
30564 var target = c.target;
30566 if(target instanceof Array){
30567 for(var j = 0, jlen = target.length; j < jlen; j++){
30568 tagEls[target[j]] = c;
30571 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30578 * Removes this quick tip from its element and destroys it.
30579 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30581 unregister : function(el){
30582 delete tagEls[Roo.id(el)];
30586 * Enable this quick tip.
30588 enable : function(){
30589 if(inited && disabled){
30591 if(locks.length < 1){
30598 * Disable this quick tip.
30600 disable : function(){
30602 clearTimeout(showProc);
30603 clearTimeout(hideProc);
30604 clearTimeout(dismissProc);
30612 * Returns true if the quick tip is enabled, else false.
30614 isEnabled : function(){
30621 attribute : "qtip",
30631 // backwards compat
30632 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30634 * Ext JS Library 1.1.1
30635 * Copyright(c) 2006-2007, Ext JS, LLC.
30637 * Originally Released Under LGPL - original licence link has changed is not relivant.
30640 * <script type="text/javascript">
30645 * @class Roo.tree.TreePanel
30646 * @extends Roo.data.Tree
30648 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30649 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30650 * @cfg {Boolean} enableDD true to enable drag and drop
30651 * @cfg {Boolean} enableDrag true to enable just drag
30652 * @cfg {Boolean} enableDrop true to enable just drop
30653 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30654 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30655 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30656 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30657 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30658 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30659 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30660 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30661 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30662 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30663 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30664 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30665 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30666 * @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>
30667 * @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>
30670 * @param {String/HTMLElement/Element} el The container element
30671 * @param {Object} config
30673 Roo.tree.TreePanel = function(el, config){
30675 var loader = false;
30677 root = config.root;
30678 delete config.root;
30680 if (config.loader) {
30681 loader = config.loader;
30682 delete config.loader;
30685 Roo.apply(this, config);
30686 Roo.tree.TreePanel.superclass.constructor.call(this);
30687 this.el = Roo.get(el);
30688 this.el.addClass('x-tree');
30689 //console.log(root);
30691 this.setRootNode( Roo.factory(root, Roo.tree));
30694 this.loader = Roo.factory(loader, Roo.tree);
30697 * Read-only. The id of the container element becomes this TreePanel's id.
30699 this.id = this.el.id;
30702 * @event beforeload
30703 * Fires before a node is loaded, return false to cancel
30704 * @param {Node} node The node being loaded
30706 "beforeload" : true,
30709 * Fires when a node is loaded
30710 * @param {Node} node The node that was loaded
30714 * @event textchange
30715 * Fires when the text for a node is changed
30716 * @param {Node} node The node
30717 * @param {String} text The new text
30718 * @param {String} oldText The old text
30720 "textchange" : true,
30722 * @event beforeexpand
30723 * Fires before a node is expanded, return false to cancel.
30724 * @param {Node} node The node
30725 * @param {Boolean} deep
30726 * @param {Boolean} anim
30728 "beforeexpand" : true,
30730 * @event beforecollapse
30731 * Fires before a node is collapsed, return false to cancel.
30732 * @param {Node} node The node
30733 * @param {Boolean} deep
30734 * @param {Boolean} anim
30736 "beforecollapse" : true,
30739 * Fires when a node is expanded
30740 * @param {Node} node The node
30744 * @event disabledchange
30745 * Fires when the disabled status of a node changes
30746 * @param {Node} node The node
30747 * @param {Boolean} disabled
30749 "disabledchange" : true,
30752 * Fires when a node is collapsed
30753 * @param {Node} node The node
30757 * @event beforeclick
30758 * Fires before click processing on a node. Return false to cancel the default action.
30759 * @param {Node} node The node
30760 * @param {Roo.EventObject} e The event object
30762 "beforeclick":true,
30764 * @event checkchange
30765 * Fires when a node with a checkbox's checked property changes
30766 * @param {Node} this This node
30767 * @param {Boolean} checked
30769 "checkchange":true,
30772 * Fires when a node is clicked
30773 * @param {Node} node The node
30774 * @param {Roo.EventObject} e The event object
30779 * Fires when a node is double clicked
30780 * @param {Node} node The node
30781 * @param {Roo.EventObject} e The event object
30785 * @event contextmenu
30786 * Fires when a node is right clicked
30787 * @param {Node} node The node
30788 * @param {Roo.EventObject} e The event object
30790 "contextmenu":true,
30792 * @event beforechildrenrendered
30793 * Fires right before the child nodes for a node are rendered
30794 * @param {Node} node The node
30796 "beforechildrenrendered":true,
30799 * Fires when a node starts being dragged
30800 * @param {Roo.tree.TreePanel} this
30801 * @param {Roo.tree.TreeNode} node
30802 * @param {event} e The raw browser event
30804 "startdrag" : true,
30807 * Fires when a drag operation is complete
30808 * @param {Roo.tree.TreePanel} this
30809 * @param {Roo.tree.TreeNode} node
30810 * @param {event} e The raw browser event
30815 * Fires when a dragged node is dropped on a valid DD target
30816 * @param {Roo.tree.TreePanel} this
30817 * @param {Roo.tree.TreeNode} node
30818 * @param {DD} dd The dd it was dropped on
30819 * @param {event} e The raw browser event
30823 * @event beforenodedrop
30824 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30825 * passed to handlers has the following properties:<br />
30826 * <ul style="padding:5px;padding-left:16px;">
30827 * <li>tree - The TreePanel</li>
30828 * <li>target - The node being targeted for the drop</li>
30829 * <li>data - The drag data from the drag source</li>
30830 * <li>point - The point of the drop - append, above or below</li>
30831 * <li>source - The drag source</li>
30832 * <li>rawEvent - Raw mouse event</li>
30833 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30834 * to be inserted by setting them on this object.</li>
30835 * <li>cancel - Set this to true to cancel the drop.</li>
30837 * @param {Object} dropEvent
30839 "beforenodedrop" : true,
30842 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30843 * passed to handlers has the following properties:<br />
30844 * <ul style="padding:5px;padding-left:16px;">
30845 * <li>tree - The TreePanel</li>
30846 * <li>target - The node being targeted for the drop</li>
30847 * <li>data - The drag data from the drag source</li>
30848 * <li>point - The point of the drop - append, above or below</li>
30849 * <li>source - The drag source</li>
30850 * <li>rawEvent - Raw mouse event</li>
30851 * <li>dropNode - Dropped node(s).</li>
30853 * @param {Object} dropEvent
30857 * @event nodedragover
30858 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30859 * passed to handlers has the following properties:<br />
30860 * <ul style="padding:5px;padding-left:16px;">
30861 * <li>tree - The TreePanel</li>
30862 * <li>target - The node being targeted for the drop</li>
30863 * <li>data - The drag data from the drag source</li>
30864 * <li>point - The point of the drop - append, above or below</li>
30865 * <li>source - The drag source</li>
30866 * <li>rawEvent - Raw mouse event</li>
30867 * <li>dropNode - Drop node(s) provided by the source.</li>
30868 * <li>cancel - Set this to true to signal drop not allowed.</li>
30870 * @param {Object} dragOverEvent
30872 "nodedragover" : true
30875 if(this.singleExpand){
30876 this.on("beforeexpand", this.restrictExpand, this);
30879 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30880 rootVisible : true,
30881 animate: Roo.enableFx,
30884 hlDrop : Roo.enableFx,
30888 rendererTip: false,
30890 restrictExpand : function(node){
30891 var p = node.parentNode;
30893 if(p.expandedChild && p.expandedChild.parentNode == p){
30894 p.expandedChild.collapse();
30896 p.expandedChild = node;
30900 // private override
30901 setRootNode : function(node){
30902 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
30903 if(!this.rootVisible){
30904 node.ui = new Roo.tree.RootTreeNodeUI(node);
30910 * Returns the container element for this TreePanel
30912 getEl : function(){
30917 * Returns the default TreeLoader for this TreePanel
30919 getLoader : function(){
30920 return this.loader;
30926 expandAll : function(){
30927 this.root.expand(true);
30931 * Collapse all nodes
30933 collapseAll : function(){
30934 this.root.collapse(true);
30938 * Returns the selection model used by this TreePanel
30940 getSelectionModel : function(){
30941 if(!this.selModel){
30942 this.selModel = new Roo.tree.DefaultSelectionModel();
30944 return this.selModel;
30948 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
30949 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
30950 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
30953 getChecked : function(a, startNode){
30954 startNode = startNode || this.root;
30956 var f = function(){
30957 if(this.attributes.checked){
30958 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
30961 startNode.cascade(f);
30966 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30967 * @param {String} path
30968 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30969 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
30970 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
30972 expandPath : function(path, attr, callback){
30973 attr = attr || "id";
30974 var keys = path.split(this.pathSeparator);
30975 var curNode = this.root;
30976 if(curNode.attributes[attr] != keys[1]){ // invalid root
30978 callback(false, null);
30983 var f = function(){
30984 if(++index == keys.length){
30986 callback(true, curNode);
30990 var c = curNode.findChild(attr, keys[index]);
30993 callback(false, curNode);
30998 c.expand(false, false, f);
31000 curNode.expand(false, false, f);
31004 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31005 * @param {String} path
31006 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31007 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31008 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31010 selectPath : function(path, attr, callback){
31011 attr = attr || "id";
31012 var keys = path.split(this.pathSeparator);
31013 var v = keys.pop();
31014 if(keys.length > 0){
31015 var f = function(success, node){
31016 if(success && node){
31017 var n = node.findChild(attr, v);
31023 }else if(callback){
31024 callback(false, n);
31028 callback(false, n);
31032 this.expandPath(keys.join(this.pathSeparator), attr, f);
31034 this.root.select();
31036 callback(true, this.root);
31041 getTreeEl : function(){
31046 * Trigger rendering of this TreePanel
31048 render : function(){
31049 if (this.innerCt) {
31050 return this; // stop it rendering more than once!!
31053 this.innerCt = this.el.createChild({tag:"ul",
31054 cls:"x-tree-root-ct " +
31055 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31057 if(this.containerScroll){
31058 Roo.dd.ScrollManager.register(this.el);
31060 if((this.enableDD || this.enableDrop) && !this.dropZone){
31062 * The dropZone used by this tree if drop is enabled
31063 * @type Roo.tree.TreeDropZone
31065 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31066 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31069 if((this.enableDD || this.enableDrag) && !this.dragZone){
31071 * The dragZone used by this tree if drag is enabled
31072 * @type Roo.tree.TreeDragZone
31074 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31075 ddGroup: this.ddGroup || "TreeDD",
31076 scroll: this.ddScroll
31079 this.getSelectionModel().init(this);
31081 console.log("ROOT not set in tree");
31084 this.root.render();
31085 if(!this.rootVisible){
31086 this.root.renderChildren();
31092 * Ext JS Library 1.1.1
31093 * Copyright(c) 2006-2007, Ext JS, LLC.
31095 * Originally Released Under LGPL - original licence link has changed is not relivant.
31098 * <script type="text/javascript">
31103 * @class Roo.tree.DefaultSelectionModel
31104 * @extends Roo.util.Observable
31105 * The default single selection for a TreePanel.
31107 Roo.tree.DefaultSelectionModel = function(){
31108 this.selNode = null;
31112 * @event selectionchange
31113 * Fires when the selected node changes
31114 * @param {DefaultSelectionModel} this
31115 * @param {TreeNode} node the new selection
31117 "selectionchange" : true,
31120 * @event beforeselect
31121 * Fires before the selected node changes, return false to cancel the change
31122 * @param {DefaultSelectionModel} this
31123 * @param {TreeNode} node the new selection
31124 * @param {TreeNode} node the old selection
31126 "beforeselect" : true
31130 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31131 init : function(tree){
31133 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31134 tree.on("click", this.onNodeClick, this);
31137 onNodeClick : function(node, e){
31138 if (e.ctrlKey && this.selNode == node) {
31139 this.unselect(node);
31147 * @param {TreeNode} node The node to select
31148 * @return {TreeNode} The selected node
31150 select : function(node){
31151 var last = this.selNode;
31152 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31154 last.ui.onSelectedChange(false);
31156 this.selNode = node;
31157 node.ui.onSelectedChange(true);
31158 this.fireEvent("selectionchange", this, node, last);
31165 * @param {TreeNode} node The node to unselect
31167 unselect : function(node){
31168 if(this.selNode == node){
31169 this.clearSelections();
31174 * Clear all selections
31176 clearSelections : function(){
31177 var n = this.selNode;
31179 n.ui.onSelectedChange(false);
31180 this.selNode = null;
31181 this.fireEvent("selectionchange", this, null);
31187 * Get the selected node
31188 * @return {TreeNode} The selected node
31190 getSelectedNode : function(){
31191 return this.selNode;
31195 * Returns true if the node is selected
31196 * @param {TreeNode} node The node to check
31197 * @return {Boolean}
31199 isSelected : function(node){
31200 return this.selNode == node;
31204 * Selects the node above the selected node in the tree, intelligently walking the nodes
31205 * @return TreeNode The new selection
31207 selectPrevious : function(){
31208 var s = this.selNode || this.lastSelNode;
31212 var ps = s.previousSibling;
31214 if(!ps.isExpanded() || ps.childNodes.length < 1){
31215 return this.select(ps);
31217 var lc = ps.lastChild;
31218 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31221 return this.select(lc);
31223 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31224 return this.select(s.parentNode);
31230 * Selects the node above the selected node in the tree, intelligently walking the nodes
31231 * @return TreeNode The new selection
31233 selectNext : function(){
31234 var s = this.selNode || this.lastSelNode;
31238 if(s.firstChild && s.isExpanded()){
31239 return this.select(s.firstChild);
31240 }else if(s.nextSibling){
31241 return this.select(s.nextSibling);
31242 }else if(s.parentNode){
31244 s.parentNode.bubble(function(){
31245 if(this.nextSibling){
31246 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31255 onKeyDown : function(e){
31256 var s = this.selNode || this.lastSelNode;
31257 // undesirable, but required
31262 var k = e.getKey();
31270 this.selectPrevious();
31273 e.preventDefault();
31274 if(s.hasChildNodes()){
31275 if(!s.isExpanded()){
31277 }else if(s.firstChild){
31278 this.select(s.firstChild, e);
31283 e.preventDefault();
31284 if(s.hasChildNodes() && s.isExpanded()){
31286 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31287 this.select(s.parentNode, e);
31295 * @class Roo.tree.MultiSelectionModel
31296 * @extends Roo.util.Observable
31297 * Multi selection for a TreePanel.
31299 Roo.tree.MultiSelectionModel = function(){
31300 this.selNodes = [];
31304 * @event selectionchange
31305 * Fires when the selected nodes change
31306 * @param {MultiSelectionModel} this
31307 * @param {Array} nodes Array of the selected nodes
31309 "selectionchange" : true
31313 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31314 init : function(tree){
31316 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31317 tree.on("click", this.onNodeClick, this);
31320 onNodeClick : function(node, e){
31321 this.select(node, e, e.ctrlKey);
31326 * @param {TreeNode} node The node to select
31327 * @param {EventObject} e (optional) An event associated with the selection
31328 * @param {Boolean} keepExisting True to retain existing selections
31329 * @return {TreeNode} The selected node
31331 select : function(node, e, keepExisting){
31332 if(keepExisting !== true){
31333 this.clearSelections(true);
31335 if(this.isSelected(node)){
31336 this.lastSelNode = node;
31339 this.selNodes.push(node);
31340 this.selMap[node.id] = node;
31341 this.lastSelNode = node;
31342 node.ui.onSelectedChange(true);
31343 this.fireEvent("selectionchange", this, this.selNodes);
31349 * @param {TreeNode} node The node to unselect
31351 unselect : function(node){
31352 if(this.selMap[node.id]){
31353 node.ui.onSelectedChange(false);
31354 var sn = this.selNodes;
31357 index = sn.indexOf(node);
31359 for(var i = 0, len = sn.length; i < len; i++){
31367 this.selNodes.splice(index, 1);
31369 delete this.selMap[node.id];
31370 this.fireEvent("selectionchange", this, this.selNodes);
31375 * Clear all selections
31377 clearSelections : function(suppressEvent){
31378 var sn = this.selNodes;
31380 for(var i = 0, len = sn.length; i < len; i++){
31381 sn[i].ui.onSelectedChange(false);
31383 this.selNodes = [];
31385 if(suppressEvent !== true){
31386 this.fireEvent("selectionchange", this, this.selNodes);
31392 * Returns true if the node is selected
31393 * @param {TreeNode} node The node to check
31394 * @return {Boolean}
31396 isSelected : function(node){
31397 return this.selMap[node.id] ? true : false;
31401 * Returns an array of the selected nodes
31404 getSelectedNodes : function(){
31405 return this.selNodes;
31408 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31410 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31412 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31415 * Ext JS Library 1.1.1
31416 * Copyright(c) 2006-2007, Ext JS, LLC.
31418 * Originally Released Under LGPL - original licence link has changed is not relivant.
31421 * <script type="text/javascript">
31425 * @class Roo.tree.TreeNode
31426 * @extends Roo.data.Node
31427 * @cfg {String} text The text for this node
31428 * @cfg {Boolean} expanded true to start the node expanded
31429 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31430 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31431 * @cfg {Boolean} disabled true to start the node disabled
31432 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31433 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31434 * @cfg {String} cls A css class to be added to the node
31435 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31436 * @cfg {String} href URL of the link used for the node (defaults to #)
31437 * @cfg {String} hrefTarget target frame for the link
31438 * @cfg {String} qtip An Ext QuickTip for the node
31439 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31440 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31441 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31442 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31443 * (defaults to undefined with no checkbox rendered)
31445 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31447 Roo.tree.TreeNode = function(attributes){
31448 attributes = attributes || {};
31449 if(typeof attributes == "string"){
31450 attributes = {text: attributes};
31452 this.childrenRendered = false;
31453 this.rendered = false;
31454 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31455 this.expanded = attributes.expanded === true;
31456 this.isTarget = attributes.isTarget !== false;
31457 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31458 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31461 * Read-only. The text for this node. To change it use setText().
31464 this.text = attributes.text;
31466 * True if this node is disabled.
31469 this.disabled = attributes.disabled === true;
31473 * @event textchange
31474 * Fires when the text for this node is changed
31475 * @param {Node} this This node
31476 * @param {String} text The new text
31477 * @param {String} oldText The old text
31479 "textchange" : true,
31481 * @event beforeexpand
31482 * Fires before this node is expanded, return false to cancel.
31483 * @param {Node} this This node
31484 * @param {Boolean} deep
31485 * @param {Boolean} anim
31487 "beforeexpand" : true,
31489 * @event beforecollapse
31490 * Fires before this node is collapsed, return false to cancel.
31491 * @param {Node} this This node
31492 * @param {Boolean} deep
31493 * @param {Boolean} anim
31495 "beforecollapse" : true,
31498 * Fires when this node is expanded
31499 * @param {Node} this This node
31503 * @event disabledchange
31504 * Fires when the disabled status of this node changes
31505 * @param {Node} this This node
31506 * @param {Boolean} disabled
31508 "disabledchange" : true,
31511 * Fires when this node is collapsed
31512 * @param {Node} this This node
31516 * @event beforeclick
31517 * Fires before click processing. Return false to cancel the default action.
31518 * @param {Node} this This node
31519 * @param {Roo.EventObject} e The event object
31521 "beforeclick":true,
31523 * @event checkchange
31524 * Fires when a node with a checkbox's checked property changes
31525 * @param {Node} this This node
31526 * @param {Boolean} checked
31528 "checkchange":true,
31531 * Fires when this node is clicked
31532 * @param {Node} this This node
31533 * @param {Roo.EventObject} e The event object
31538 * Fires when this node is double clicked
31539 * @param {Node} this This node
31540 * @param {Roo.EventObject} e The event object
31544 * @event contextmenu
31545 * Fires when this node is right clicked
31546 * @param {Node} this This node
31547 * @param {Roo.EventObject} e The event object
31549 "contextmenu":true,
31551 * @event beforechildrenrendered
31552 * Fires right before the child nodes for this node are rendered
31553 * @param {Node} this This node
31555 "beforechildrenrendered":true
31558 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31561 * Read-only. The UI for this node
31564 this.ui = new uiClass(this);
31566 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31567 preventHScroll: true,
31569 * Returns true if this node is expanded
31570 * @return {Boolean}
31572 isExpanded : function(){
31573 return this.expanded;
31577 * Returns the UI object for this node
31578 * @return {TreeNodeUI}
31580 getUI : function(){
31584 // private override
31585 setFirstChild : function(node){
31586 var of = this.firstChild;
31587 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31588 if(this.childrenRendered && of && node != of){
31589 of.renderIndent(true, true);
31592 this.renderIndent(true, true);
31596 // private override
31597 setLastChild : function(node){
31598 var ol = this.lastChild;
31599 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31600 if(this.childrenRendered && ol && node != ol){
31601 ol.renderIndent(true, true);
31604 this.renderIndent(true, true);
31608 // these methods are overridden to provide lazy rendering support
31609 // private override
31610 appendChild : function(){
31611 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31612 if(node && this.childrenRendered){
31615 this.ui.updateExpandIcon();
31619 // private override
31620 removeChild : function(node){
31621 this.ownerTree.getSelectionModel().unselect(node);
31622 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31623 // if it's been rendered remove dom node
31624 if(this.childrenRendered){
31627 if(this.childNodes.length < 1){
31628 this.collapse(false, false);
31630 this.ui.updateExpandIcon();
31632 if(!this.firstChild) {
31633 this.childrenRendered = false;
31638 // private override
31639 insertBefore : function(node, refNode){
31640 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31641 if(newNode && refNode && this.childrenRendered){
31644 this.ui.updateExpandIcon();
31649 * Sets the text for this node
31650 * @param {String} text
31652 setText : function(text){
31653 var oldText = this.text;
31655 this.attributes.text = text;
31656 if(this.rendered){ // event without subscribing
31657 this.ui.onTextChange(this, text, oldText);
31659 this.fireEvent("textchange", this, text, oldText);
31663 * Triggers selection of this node
31665 select : function(){
31666 this.getOwnerTree().getSelectionModel().select(this);
31670 * Triggers deselection of this node
31672 unselect : function(){
31673 this.getOwnerTree().getSelectionModel().unselect(this);
31677 * Returns true if this node is selected
31678 * @return {Boolean}
31680 isSelected : function(){
31681 return this.getOwnerTree().getSelectionModel().isSelected(this);
31685 * Expand this node.
31686 * @param {Boolean} deep (optional) True to expand all children as well
31687 * @param {Boolean} anim (optional) false to cancel the default animation
31688 * @param {Function} callback (optional) A callback to be called when
31689 * expanding this node completes (does not wait for deep expand to complete).
31690 * Called with 1 parameter, this node.
31692 expand : function(deep, anim, callback){
31693 if(!this.expanded){
31694 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31697 if(!this.childrenRendered){
31698 this.renderChildren();
31700 this.expanded = true;
31701 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31702 this.ui.animExpand(function(){
31703 this.fireEvent("expand", this);
31704 if(typeof callback == "function"){
31708 this.expandChildNodes(true);
31710 }.createDelegate(this));
31714 this.fireEvent("expand", this);
31715 if(typeof callback == "function"){
31720 if(typeof callback == "function"){
31725 this.expandChildNodes(true);
31729 isHiddenRoot : function(){
31730 return this.isRoot && !this.getOwnerTree().rootVisible;
31734 * Collapse this node.
31735 * @param {Boolean} deep (optional) True to collapse all children as well
31736 * @param {Boolean} anim (optional) false to cancel the default animation
31738 collapse : function(deep, anim){
31739 if(this.expanded && !this.isHiddenRoot()){
31740 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31743 this.expanded = false;
31744 if((this.getOwnerTree().animate && anim !== false) || anim){
31745 this.ui.animCollapse(function(){
31746 this.fireEvent("collapse", this);
31748 this.collapseChildNodes(true);
31750 }.createDelegate(this));
31753 this.ui.collapse();
31754 this.fireEvent("collapse", this);
31758 var cs = this.childNodes;
31759 for(var i = 0, len = cs.length; i < len; i++) {
31760 cs[i].collapse(true, false);
31766 delayedExpand : function(delay){
31767 if(!this.expandProcId){
31768 this.expandProcId = this.expand.defer(delay, this);
31773 cancelExpand : function(){
31774 if(this.expandProcId){
31775 clearTimeout(this.expandProcId);
31777 this.expandProcId = false;
31781 * Toggles expanded/collapsed state of the node
31783 toggle : function(){
31792 * Ensures all parent nodes are expanded
31794 ensureVisible : function(callback){
31795 var tree = this.getOwnerTree();
31796 tree.expandPath(this.parentNode.getPath(), false, function(){
31797 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31798 Roo.callback(callback);
31799 }.createDelegate(this));
31803 * Expand all child nodes
31804 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31806 expandChildNodes : function(deep){
31807 var cs = this.childNodes;
31808 for(var i = 0, len = cs.length; i < len; i++) {
31809 cs[i].expand(deep);
31814 * Collapse all child nodes
31815 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31817 collapseChildNodes : function(deep){
31818 var cs = this.childNodes;
31819 for(var i = 0, len = cs.length; i < len; i++) {
31820 cs[i].collapse(deep);
31825 * Disables this node
31827 disable : function(){
31828 this.disabled = true;
31830 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31831 this.ui.onDisableChange(this, true);
31833 this.fireEvent("disabledchange", this, true);
31837 * Enables this node
31839 enable : function(){
31840 this.disabled = false;
31841 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31842 this.ui.onDisableChange(this, false);
31844 this.fireEvent("disabledchange", this, false);
31848 renderChildren : function(suppressEvent){
31849 if(suppressEvent !== false){
31850 this.fireEvent("beforechildrenrendered", this);
31852 var cs = this.childNodes;
31853 for(var i = 0, len = cs.length; i < len; i++){
31854 cs[i].render(true);
31856 this.childrenRendered = true;
31860 sort : function(fn, scope){
31861 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31862 if(this.childrenRendered){
31863 var cs = this.childNodes;
31864 for(var i = 0, len = cs.length; i < len; i++){
31865 cs[i].render(true);
31871 render : function(bulkRender){
31872 this.ui.render(bulkRender);
31873 if(!this.rendered){
31874 this.rendered = true;
31876 this.expanded = false;
31877 this.expand(false, false);
31883 renderIndent : function(deep, refresh){
31885 this.ui.childIndent = null;
31887 this.ui.renderIndent();
31888 if(deep === true && this.childrenRendered){
31889 var cs = this.childNodes;
31890 for(var i = 0, len = cs.length; i < len; i++){
31891 cs[i].renderIndent(true, refresh);
31897 * Ext JS Library 1.1.1
31898 * Copyright(c) 2006-2007, Ext JS, LLC.
31900 * Originally Released Under LGPL - original licence link has changed is not relivant.
31903 * <script type="text/javascript">
31907 * @class Roo.tree.AsyncTreeNode
31908 * @extends Roo.tree.TreeNode
31909 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
31911 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31913 Roo.tree.AsyncTreeNode = function(config){
31914 this.loaded = false;
31915 this.loading = false;
31916 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
31918 * @event beforeload
31919 * Fires before this node is loaded, return false to cancel
31920 * @param {Node} this This node
31922 this.addEvents({'beforeload':true, 'load': true});
31925 * Fires when this node is loaded
31926 * @param {Node} this This node
31929 * The loader used by this node (defaults to using the tree's defined loader)
31934 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
31935 expand : function(deep, anim, callback){
31936 if(this.loading){ // if an async load is already running, waiting til it's done
31938 var f = function(){
31939 if(!this.loading){ // done loading
31940 clearInterval(timer);
31941 this.expand(deep, anim, callback);
31943 }.createDelegate(this);
31944 timer = setInterval(f, 200);
31948 if(this.fireEvent("beforeload", this) === false){
31951 this.loading = true;
31952 this.ui.beforeLoad(this);
31953 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
31955 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
31959 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
31963 * Returns true if this node is currently loading
31964 * @return {Boolean}
31966 isLoading : function(){
31967 return this.loading;
31970 loadComplete : function(deep, anim, callback){
31971 this.loading = false;
31972 this.loaded = true;
31973 this.ui.afterLoad(this);
31974 this.fireEvent("load", this);
31975 this.expand(deep, anim, callback);
31979 * Returns true if this node has been loaded
31980 * @return {Boolean}
31982 isLoaded : function(){
31983 return this.loaded;
31986 hasChildNodes : function(){
31987 if(!this.isLeaf() && !this.loaded){
31990 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
31995 * Trigger a reload for this node
31996 * @param {Function} callback
31998 reload : function(callback){
31999 this.collapse(false, false);
32000 while(this.firstChild){
32001 this.removeChild(this.firstChild);
32003 this.childrenRendered = false;
32004 this.loaded = false;
32005 if(this.isHiddenRoot()){
32006 this.expanded = false;
32008 this.expand(false, false, callback);
32012 * Ext JS Library 1.1.1
32013 * Copyright(c) 2006-2007, Ext JS, LLC.
32015 * Originally Released Under LGPL - original licence link has changed is not relivant.
32018 * <script type="text/javascript">
32022 * @class Roo.tree.TreeNodeUI
32024 * @param {Object} node The node to render
32025 * The TreeNode UI implementation is separate from the
32026 * tree implementation. Unless you are customizing the tree UI,
32027 * you should never have to use this directly.
32029 Roo.tree.TreeNodeUI = function(node){
32031 this.rendered = false;
32032 this.animating = false;
32033 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32036 Roo.tree.TreeNodeUI.prototype = {
32037 removeChild : function(node){
32039 this.ctNode.removeChild(node.ui.getEl());
32043 beforeLoad : function(){
32044 this.addClass("x-tree-node-loading");
32047 afterLoad : function(){
32048 this.removeClass("x-tree-node-loading");
32051 onTextChange : function(node, text, oldText){
32053 this.textNode.innerHTML = text;
32057 onDisableChange : function(node, state){
32058 this.disabled = state;
32060 this.addClass("x-tree-node-disabled");
32062 this.removeClass("x-tree-node-disabled");
32066 onSelectedChange : function(state){
32069 this.addClass("x-tree-selected");
32072 this.removeClass("x-tree-selected");
32076 onMove : function(tree, node, oldParent, newParent, index, refNode){
32077 this.childIndent = null;
32079 var targetNode = newParent.ui.getContainer();
32080 if(!targetNode){//target not rendered
32081 this.holder = document.createElement("div");
32082 this.holder.appendChild(this.wrap);
32085 var insertBefore = refNode ? refNode.ui.getEl() : null;
32087 targetNode.insertBefore(this.wrap, insertBefore);
32089 targetNode.appendChild(this.wrap);
32091 this.node.renderIndent(true);
32095 addClass : function(cls){
32097 Roo.fly(this.elNode).addClass(cls);
32101 removeClass : function(cls){
32103 Roo.fly(this.elNode).removeClass(cls);
32107 remove : function(){
32109 this.holder = document.createElement("div");
32110 this.holder.appendChild(this.wrap);
32114 fireEvent : function(){
32115 return this.node.fireEvent.apply(this.node, arguments);
32118 initEvents : function(){
32119 this.node.on("move", this.onMove, this);
32120 var E = Roo.EventManager;
32121 var a = this.anchor;
32123 var el = Roo.fly(a, '_treeui');
32125 if(Roo.isOpera){ // opera render bug ignores the CSS
32126 el.setStyle("text-decoration", "none");
32129 el.on("click", this.onClick, this);
32130 el.on("dblclick", this.onDblClick, this);
32133 Roo.EventManager.on(this.checkbox,
32134 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32137 el.on("contextmenu", this.onContextMenu, this);
32139 var icon = Roo.fly(this.iconNode);
32140 icon.on("click", this.onClick, this);
32141 icon.on("dblclick", this.onDblClick, this);
32142 icon.on("contextmenu", this.onContextMenu, this);
32143 E.on(this.ecNode, "click", this.ecClick, this, true);
32145 if(this.node.disabled){
32146 this.addClass("x-tree-node-disabled");
32148 if(this.node.hidden){
32149 this.addClass("x-tree-node-disabled");
32151 var ot = this.node.getOwnerTree();
32152 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32153 if(dd && (!this.node.isRoot || ot.rootVisible)){
32154 Roo.dd.Registry.register(this.elNode, {
32156 handles: this.getDDHandles(),
32162 getDDHandles : function(){
32163 return [this.iconNode, this.textNode];
32168 this.wrap.style.display = "none";
32174 this.wrap.style.display = "";
32178 onContextMenu : function(e){
32179 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32180 e.preventDefault();
32182 this.fireEvent("contextmenu", this.node, e);
32186 onClick : function(e){
32191 if(this.fireEvent("beforeclick", this.node, e) !== false){
32192 if(!this.disabled && this.node.attributes.href){
32193 this.fireEvent("click", this.node, e);
32196 e.preventDefault();
32201 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32202 this.node.toggle();
32205 this.fireEvent("click", this.node, e);
32211 onDblClick : function(e){
32212 e.preventDefault();
32217 this.toggleCheck();
32219 if(!this.animating && this.node.hasChildNodes()){
32220 this.node.toggle();
32222 this.fireEvent("dblclick", this.node, e);
32225 onCheckChange : function(){
32226 var checked = this.checkbox.checked;
32227 this.node.attributes.checked = checked;
32228 this.fireEvent('checkchange', this.node, checked);
32231 ecClick : function(e){
32232 if(!this.animating && this.node.hasChildNodes()){
32233 this.node.toggle();
32237 startDrop : function(){
32238 this.dropping = true;
32241 // delayed drop so the click event doesn't get fired on a drop
32242 endDrop : function(){
32243 setTimeout(function(){
32244 this.dropping = false;
32245 }.createDelegate(this), 50);
32248 expand : function(){
32249 this.updateExpandIcon();
32250 this.ctNode.style.display = "";
32253 focus : function(){
32254 if(!this.node.preventHScroll){
32255 try{this.anchor.focus();
32257 }else if(!Roo.isIE){
32259 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32260 var l = noscroll.scrollLeft;
32261 this.anchor.focus();
32262 noscroll.scrollLeft = l;
32267 toggleCheck : function(value){
32268 var cb = this.checkbox;
32270 cb.checked = (value === undefined ? !cb.checked : value);
32276 this.anchor.blur();
32280 animExpand : function(callback){
32281 var ct = Roo.get(this.ctNode);
32283 if(!this.node.hasChildNodes()){
32284 this.updateExpandIcon();
32285 this.ctNode.style.display = "";
32286 Roo.callback(callback);
32289 this.animating = true;
32290 this.updateExpandIcon();
32293 callback : function(){
32294 this.animating = false;
32295 Roo.callback(callback);
32298 duration: this.node.ownerTree.duration || .25
32302 highlight : function(){
32303 var tree = this.node.getOwnerTree();
32304 Roo.fly(this.wrap).highlight(
32305 tree.hlColor || "C3DAF9",
32306 {endColor: tree.hlBaseColor}
32310 collapse : function(){
32311 this.updateExpandIcon();
32312 this.ctNode.style.display = "none";
32315 animCollapse : function(callback){
32316 var ct = Roo.get(this.ctNode);
32317 ct.enableDisplayMode('block');
32320 this.animating = true;
32321 this.updateExpandIcon();
32324 callback : function(){
32325 this.animating = false;
32326 Roo.callback(callback);
32329 duration: this.node.ownerTree.duration || .25
32333 getContainer : function(){
32334 return this.ctNode;
32337 getEl : function(){
32341 appendDDGhost : function(ghostNode){
32342 ghostNode.appendChild(this.elNode.cloneNode(true));
32345 getDDRepairXY : function(){
32346 return Roo.lib.Dom.getXY(this.iconNode);
32349 onRender : function(){
32353 render : function(bulkRender){
32354 var n = this.node, a = n.attributes;
32355 var targetNode = n.parentNode ?
32356 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32358 if(!this.rendered){
32359 this.rendered = true;
32361 this.renderElements(n, a, targetNode, bulkRender);
32364 if(this.textNode.setAttributeNS){
32365 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32367 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32370 this.textNode.setAttribute("ext:qtip", a.qtip);
32372 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32375 }else if(a.qtipCfg){
32376 a.qtipCfg.target = Roo.id(this.textNode);
32377 Roo.QuickTips.register(a.qtipCfg);
32380 if(!this.node.expanded){
32381 this.updateExpandIcon();
32384 if(bulkRender === true) {
32385 targetNode.appendChild(this.wrap);
32390 renderElements : function(n, a, targetNode, bulkRender){
32391 // add some indent caching, this helps performance when rendering a large tree
32392 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32393 var t = n.getOwnerTree();
32394 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32395 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32396 var cb = typeof a.checked == 'boolean';
32397 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32398 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32399 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32400 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32401 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32402 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32403 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32404 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32405 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32406 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32409 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32410 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32411 n.nextSibling.ui.getEl(), buf.join(""));
32413 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32416 this.elNode = this.wrap.childNodes[0];
32417 this.ctNode = this.wrap.childNodes[1];
32418 var cs = this.elNode.childNodes;
32419 this.indentNode = cs[0];
32420 this.ecNode = cs[1];
32421 this.iconNode = cs[2];
32424 this.checkbox = cs[3];
32427 this.anchor = cs[index];
32428 this.textNode = cs[index].firstChild;
32431 getAnchor : function(){
32432 return this.anchor;
32435 getTextEl : function(){
32436 return this.textNode;
32439 getIconEl : function(){
32440 return this.iconNode;
32443 isChecked : function(){
32444 return this.checkbox ? this.checkbox.checked : false;
32447 updateExpandIcon : function(){
32449 var n = this.node, c1, c2;
32450 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32451 var hasChild = n.hasChildNodes();
32455 c1 = "x-tree-node-collapsed";
32456 c2 = "x-tree-node-expanded";
32459 c1 = "x-tree-node-expanded";
32460 c2 = "x-tree-node-collapsed";
32463 this.removeClass("x-tree-node-leaf");
32464 this.wasLeaf = false;
32466 if(this.c1 != c1 || this.c2 != c2){
32467 Roo.fly(this.elNode).replaceClass(c1, c2);
32468 this.c1 = c1; this.c2 = c2;
32472 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32475 this.wasLeaf = true;
32478 var ecc = "x-tree-ec-icon "+cls;
32479 if(this.ecc != ecc){
32480 this.ecNode.className = ecc;
32486 getChildIndent : function(){
32487 if(!this.childIndent){
32491 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32493 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32495 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32500 this.childIndent = buf.join("");
32502 return this.childIndent;
32505 renderIndent : function(){
32508 var p = this.node.parentNode;
32510 indent = p.ui.getChildIndent();
32512 if(this.indentMarkup != indent){ // don't rerender if not required
32513 this.indentNode.innerHTML = indent;
32514 this.indentMarkup = indent;
32516 this.updateExpandIcon();
32521 Roo.tree.RootTreeNodeUI = function(){
32522 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32524 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32525 render : function(){
32526 if(!this.rendered){
32527 var targetNode = this.node.ownerTree.innerCt.dom;
32528 this.node.expanded = true;
32529 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32530 this.wrap = this.ctNode = targetNode.firstChild;
32533 collapse : function(){
32535 expand : function(){
32539 * Ext JS Library 1.1.1
32540 * Copyright(c) 2006-2007, Ext JS, LLC.
32542 * Originally Released Under LGPL - original licence link has changed is not relivant.
32545 * <script type="text/javascript">
32548 * @class Roo.tree.TreeLoader
32549 * @extends Roo.util.Observable
32550 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32551 * nodes from a specified URL. The response must be a javascript Array definition
32552 * who's elements are node definition objects. eg:
32554 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32555 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32558 * A server request is sent, and child nodes are loaded only when a node is expanded.
32559 * The loading node's id is passed to the server under the parameter name "node" to
32560 * enable the server to produce the correct child nodes.
32562 * To pass extra parameters, an event handler may be attached to the "beforeload"
32563 * event, and the parameters specified in the TreeLoader's baseParams property:
32565 myTreeLoader.on("beforeload", function(treeLoader, node) {
32566 this.baseParams.category = node.attributes.category;
32569 * This would pass an HTTP parameter called "category" to the server containing
32570 * the value of the Node's "category" attribute.
32572 * Creates a new Treeloader.
32573 * @param {Object} config A config object containing config properties.
32575 Roo.tree.TreeLoader = function(config){
32576 this.baseParams = {};
32577 this.requestMethod = "POST";
32578 Roo.apply(this, config);
32583 * @event beforeload
32584 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32585 * @param {Object} This TreeLoader object.
32586 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32587 * @param {Object} callback The callback function specified in the {@link #load} call.
32592 * Fires when the node has been successfuly loaded.
32593 * @param {Object} This TreeLoader object.
32594 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32595 * @param {Object} response The response object containing the data from the server.
32599 * @event loadexception
32600 * Fires if the network request failed.
32601 * @param {Object} This TreeLoader object.
32602 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32603 * @param {Object} response The response object containing the data from the server.
32605 loadexception : true,
32608 * Fires before a node is created, enabling you to return custom Node types
32609 * @param {Object} This TreeLoader object.
32610 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32615 Roo.tree.TreeLoader.superclass.constructor.call(this);
32618 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32620 * @cfg {String} dataUrl The URL from which to request a Json string which
32621 * specifies an array of node definition object representing the child nodes
32625 * @cfg {Object} baseParams (optional) An object containing properties which
32626 * specify HTTP parameters to be passed to each request for child nodes.
32629 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32630 * created by this loader. If the attributes sent by the server have an attribute in this object,
32631 * they take priority.
32634 * @cfg {Object} uiProviders (optional) An object containing properties which
32636 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32637 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32638 * <i>uiProvider</i> attribute of a returned child node is a string rather
32639 * than a reference to a TreeNodeUI implementation, this that string value
32640 * is used as a property name in the uiProviders object. You can define the provider named
32641 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32646 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32647 * child nodes before loading.
32649 clearOnLoad : true,
32652 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32653 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32654 * Grid query { data : [ .....] }
32659 * @cfg {String} queryParam (optional)
32660 * Name of the query as it will be passed on the querystring (defaults to 'node')
32661 * eg. the request will be ?node=[id]
32668 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32669 * This is called automatically when a node is expanded, but may be used to reload
32670 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32671 * @param {Roo.tree.TreeNode} node
32672 * @param {Function} callback
32674 load : function(node, callback){
32675 if(this.clearOnLoad){
32676 while(node.firstChild){
32677 node.removeChild(node.firstChild);
32680 if(node.attributes.children){ // preloaded json children
32681 var cs = node.attributes.children;
32682 for(var i = 0, len = cs.length; i < len; i++){
32683 node.appendChild(this.createNode(cs[i]));
32685 if(typeof callback == "function"){
32688 }else if(this.dataUrl){
32689 this.requestData(node, callback);
32693 getParams: function(node){
32694 var buf = [], bp = this.baseParams;
32695 for(var key in bp){
32696 if(typeof bp[key] != "function"){
32697 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32700 var n = this.queryParam === false ? 'node' : this.queryParam;
32701 buf.push(n + "=", encodeURIComponent(node.id));
32702 return buf.join("");
32705 requestData : function(node, callback){
32706 if(this.fireEvent("beforeload", this, node, callback) !== false){
32707 this.transId = Roo.Ajax.request({
32708 method:this.requestMethod,
32709 url: this.dataUrl||this.url,
32710 success: this.handleResponse,
32711 failure: this.handleFailure,
32713 argument: {callback: callback, node: node},
32714 params: this.getParams(node)
32717 // if the load is cancelled, make sure we notify
32718 // the node that we are done
32719 if(typeof callback == "function"){
32725 isLoading : function(){
32726 return this.transId ? true : false;
32729 abort : function(){
32730 if(this.isLoading()){
32731 Roo.Ajax.abort(this.transId);
32736 createNode : function(attr){
32737 // apply baseAttrs, nice idea Corey!
32738 if(this.baseAttrs){
32739 Roo.applyIf(attr, this.baseAttrs);
32741 if(this.applyLoader !== false){
32742 attr.loader = this;
32744 // uiProvider = depreciated..
32746 if(typeof(attr.uiProvider) == 'string'){
32747 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32748 /** eval:var:attr */ eval(attr.uiProvider);
32750 if(typeof(this.uiProviders['default']) != 'undefined') {
32751 attr.uiProvider = this.uiProviders['default'];
32754 this.fireEvent('create', this, attr);
32756 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32758 new Roo.tree.TreeNode(attr) :
32759 new Roo.tree.AsyncTreeNode(attr));
32762 processResponse : function(response, node, callback){
32763 var json = response.responseText;
32766 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32767 if (this.root !== false) {
32771 for(var i = 0, len = o.length; i < len; i++){
32772 var n = this.createNode(o[i]);
32774 node.appendChild(n);
32777 if(typeof callback == "function"){
32778 callback(this, node);
32781 this.handleFailure(response);
32785 handleResponse : function(response){
32786 this.transId = false;
32787 var a = response.argument;
32788 this.processResponse(response, a.node, a.callback);
32789 this.fireEvent("load", this, a.node, response);
32792 handleFailure : function(response){
32793 this.transId = false;
32794 var a = response.argument;
32795 this.fireEvent("loadexception", this, a.node, response);
32796 if(typeof a.callback == "function"){
32797 a.callback(this, a.node);
32802 * Ext JS Library 1.1.1
32803 * Copyright(c) 2006-2007, Ext JS, LLC.
32805 * Originally Released Under LGPL - original licence link has changed is not relivant.
32808 * <script type="text/javascript">
32812 * @class Roo.tree.TreeFilter
32813 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32814 * @param {TreePanel} tree
32815 * @param {Object} config (optional)
32817 Roo.tree.TreeFilter = function(tree, config){
32819 this.filtered = {};
32820 Roo.apply(this, config);
32823 Roo.tree.TreeFilter.prototype = {
32830 * Filter the data by a specific attribute.
32831 * @param {String/RegExp} value Either string that the attribute value
32832 * should start with or a RegExp to test against the attribute
32833 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32834 * @param {TreeNode} startNode (optional) The node to start the filter at.
32836 filter : function(value, attr, startNode){
32837 attr = attr || "text";
32839 if(typeof value == "string"){
32840 var vlen = value.length;
32841 // auto clear empty filter
32842 if(vlen == 0 && this.clearBlank){
32846 value = value.toLowerCase();
32848 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32850 }else if(value.exec){ // regex?
32852 return value.test(n.attributes[attr]);
32855 throw 'Illegal filter type, must be string or regex';
32857 this.filterBy(f, null, startNode);
32861 * Filter by a function. The passed function will be called with each
32862 * node in the tree (or from the startNode). If the function returns true, the node is kept
32863 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32864 * @param {Function} fn The filter function
32865 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32867 filterBy : function(fn, scope, startNode){
32868 startNode = startNode || this.tree.root;
32869 if(this.autoClear){
32872 var af = this.filtered, rv = this.reverse;
32873 var f = function(n){
32874 if(n == startNode){
32880 var m = fn.call(scope || n, n);
32888 startNode.cascade(f);
32891 if(typeof id != "function"){
32893 if(n && n.parentNode){
32894 n.parentNode.removeChild(n);
32902 * Clears the current filter. Note: with the "remove" option
32903 * set a filter cannot be cleared.
32905 clear : function(){
32907 var af = this.filtered;
32909 if(typeof id != "function"){
32916 this.filtered = {};
32921 * Ext JS Library 1.1.1
32922 * Copyright(c) 2006-2007, Ext JS, LLC.
32924 * Originally Released Under LGPL - original licence link has changed is not relivant.
32927 * <script type="text/javascript">
32932 * @class Roo.tree.TreeSorter
32933 * Provides sorting of nodes in a TreePanel
32935 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
32936 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
32937 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
32938 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
32939 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
32940 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
32942 * @param {TreePanel} tree
32943 * @param {Object} config
32945 Roo.tree.TreeSorter = function(tree, config){
32946 Roo.apply(this, config);
32947 tree.on("beforechildrenrendered", this.doSort, this);
32948 tree.on("append", this.updateSort, this);
32949 tree.on("insert", this.updateSort, this);
32951 var dsc = this.dir && this.dir.toLowerCase() == "desc";
32952 var p = this.property || "text";
32953 var sortType = this.sortType;
32954 var fs = this.folderSort;
32955 var cs = this.caseSensitive === true;
32956 var leafAttr = this.leafAttr || 'leaf';
32958 this.sortFn = function(n1, n2){
32960 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
32963 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
32967 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
32968 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
32970 return dsc ? +1 : -1;
32972 return dsc ? -1 : +1;
32979 Roo.tree.TreeSorter.prototype = {
32980 doSort : function(node){
32981 node.sort(this.sortFn);
32984 compareNodes : function(n1, n2){
32985 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
32988 updateSort : function(tree, node){
32989 if(node.childrenRendered){
32990 this.doSort.defer(1, this, [node]);
32995 * Ext JS Library 1.1.1
32996 * Copyright(c) 2006-2007, Ext JS, LLC.
32998 * Originally Released Under LGPL - original licence link has changed is not relivant.
33001 * <script type="text/javascript">
33004 if(Roo.dd.DropZone){
33006 Roo.tree.TreeDropZone = function(tree, config){
33007 this.allowParentInsert = false;
33008 this.allowContainerDrop = false;
33009 this.appendOnly = false;
33010 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33012 this.lastInsertClass = "x-tree-no-status";
33013 this.dragOverData = {};
33016 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33017 ddGroup : "TreeDD",
33019 expandDelay : 1000,
33021 expandNode : function(node){
33022 if(node.hasChildNodes() && !node.isExpanded()){
33023 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33027 queueExpand : function(node){
33028 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33031 cancelExpand : function(){
33032 if(this.expandProcId){
33033 clearTimeout(this.expandProcId);
33034 this.expandProcId = false;
33038 isValidDropPoint : function(n, pt, dd, e, data){
33039 if(!n || !data){ return false; }
33040 var targetNode = n.node;
33041 var dropNode = data.node;
33042 // default drop rules
33043 if(!(targetNode && targetNode.isTarget && pt)){
33046 if(pt == "append" && targetNode.allowChildren === false){
33049 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33052 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33055 // reuse the object
33056 var overEvent = this.dragOverData;
33057 overEvent.tree = this.tree;
33058 overEvent.target = targetNode;
33059 overEvent.data = data;
33060 overEvent.point = pt;
33061 overEvent.source = dd;
33062 overEvent.rawEvent = e;
33063 overEvent.dropNode = dropNode;
33064 overEvent.cancel = false;
33065 var result = this.tree.fireEvent("nodedragover", overEvent);
33066 return overEvent.cancel === false && result !== false;
33069 getDropPoint : function(e, n, dd){
33072 return tn.allowChildren !== false ? "append" : false; // always append for root
33074 var dragEl = n.ddel;
33075 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33076 var y = Roo.lib.Event.getPageY(e);
33077 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33079 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33080 var noAppend = tn.allowChildren === false;
33081 if(this.appendOnly || tn.parentNode.allowChildren === false){
33082 return noAppend ? false : "append";
33084 var noBelow = false;
33085 if(!this.allowParentInsert){
33086 noBelow = tn.hasChildNodes() && tn.isExpanded();
33088 var q = (b - t) / (noAppend ? 2 : 3);
33089 if(y >= t && y < (t + q)){
33091 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33098 onNodeEnter : function(n, dd, e, data){
33099 this.cancelExpand();
33102 onNodeOver : function(n, dd, e, data){
33103 var pt = this.getDropPoint(e, n, dd);
33106 // auto node expand check
33107 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33108 this.queueExpand(node);
33109 }else if(pt != "append"){
33110 this.cancelExpand();
33113 // set the insert point style on the target node
33114 var returnCls = this.dropNotAllowed;
33115 if(this.isValidDropPoint(n, pt, dd, e, data)){
33120 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33121 cls = "x-tree-drag-insert-above";
33122 }else if(pt == "below"){
33123 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33124 cls = "x-tree-drag-insert-below";
33126 returnCls = "x-tree-drop-ok-append";
33127 cls = "x-tree-drag-append";
33129 if(this.lastInsertClass != cls){
33130 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33131 this.lastInsertClass = cls;
33138 onNodeOut : function(n, dd, e, data){
33139 this.cancelExpand();
33140 this.removeDropIndicators(n);
33143 onNodeDrop : function(n, dd, e, data){
33144 var point = this.getDropPoint(e, n, dd);
33145 var targetNode = n.node;
33146 targetNode.ui.startDrop();
33147 if(!this.isValidDropPoint(n, point, dd, e, data)){
33148 targetNode.ui.endDrop();
33151 // first try to find the drop node
33152 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33155 target: targetNode,
33160 dropNode: dropNode,
33163 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33164 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33165 targetNode.ui.endDrop();
33168 // allow target changing
33169 targetNode = dropEvent.target;
33170 if(point == "append" && !targetNode.isExpanded()){
33171 targetNode.expand(false, null, function(){
33172 this.completeDrop(dropEvent);
33173 }.createDelegate(this));
33175 this.completeDrop(dropEvent);
33180 completeDrop : function(de){
33181 var ns = de.dropNode, p = de.point, t = de.target;
33182 if(!(ns instanceof Array)){
33186 for(var i = 0, len = ns.length; i < len; i++){
33189 t.parentNode.insertBefore(n, t);
33190 }else if(p == "below"){
33191 t.parentNode.insertBefore(n, t.nextSibling);
33197 if(this.tree.hlDrop){
33201 this.tree.fireEvent("nodedrop", de);
33204 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33205 if(this.tree.hlDrop){
33206 dropNode.ui.focus();
33207 dropNode.ui.highlight();
33209 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33212 getTree : function(){
33216 removeDropIndicators : function(n){
33219 Roo.fly(el).removeClass([
33220 "x-tree-drag-insert-above",
33221 "x-tree-drag-insert-below",
33222 "x-tree-drag-append"]);
33223 this.lastInsertClass = "_noclass";
33227 beforeDragDrop : function(target, e, id){
33228 this.cancelExpand();
33232 afterRepair : function(data){
33233 if(data && Roo.enableFx){
33234 data.node.ui.highlight();
33243 * Ext JS Library 1.1.1
33244 * Copyright(c) 2006-2007, Ext JS, LLC.
33246 * Originally Released Under LGPL - original licence link has changed is not relivant.
33249 * <script type="text/javascript">
33253 if(Roo.dd.DragZone){
33254 Roo.tree.TreeDragZone = function(tree, config){
33255 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33259 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33260 ddGroup : "TreeDD",
33262 onBeforeDrag : function(data, e){
33264 return n && n.draggable && !n.disabled;
33267 onInitDrag : function(e){
33268 var data = this.dragData;
33269 this.tree.getSelectionModel().select(data.node);
33270 this.proxy.update("");
33271 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33272 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33275 getRepairXY : function(e, data){
33276 return data.node.ui.getDDRepairXY();
33279 onEndDrag : function(data, e){
33280 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33283 onValidDrop : function(dd, e, id){
33284 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33288 beforeInvalidDrop : function(e, id){
33289 // this scrolls the original position back into view
33290 var sm = this.tree.getSelectionModel();
33291 sm.clearSelections();
33292 sm.select(this.dragData.node);
33297 * Ext JS Library 1.1.1
33298 * Copyright(c) 2006-2007, Ext JS, LLC.
33300 * Originally Released Under LGPL - original licence link has changed is not relivant.
33303 * <script type="text/javascript">
33306 * @class Roo.tree.TreeEditor
33307 * @extends Roo.Editor
33308 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33309 * as the editor field.
33311 * @param {TreePanel} tree
33312 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33314 Roo.tree.TreeEditor = function(tree, config){
33315 config = config || {};
33316 var field = config.events ? config : new Roo.form.TextField(config);
33317 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33321 tree.on('beforeclick', this.beforeNodeClick, this);
33322 tree.getTreeEl().on('mousedown', this.hide, this);
33323 this.on('complete', this.updateNode, this);
33324 this.on('beforestartedit', this.fitToTree, this);
33325 this.on('startedit', this.bindScroll, this, {delay:10});
33326 this.on('specialkey', this.onSpecialKey, this);
33329 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33331 * @cfg {String} alignment
33332 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33338 * @cfg {Boolean} hideEl
33339 * True to hide the bound element while the editor is displayed (defaults to false)
33343 * @cfg {String} cls
33344 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33346 cls: "x-small-editor x-tree-editor",
33348 * @cfg {Boolean} shim
33349 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33355 * @cfg {Number} maxWidth
33356 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33357 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33358 * scroll and client offsets into account prior to each edit.
33365 fitToTree : function(ed, el){
33366 var td = this.tree.getTreeEl().dom, nd = el.dom;
33367 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33368 td.scrollLeft = nd.offsetLeft;
33372 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33373 this.setSize(w, '');
33377 triggerEdit : function(node){
33378 this.completeEdit();
33379 this.editNode = node;
33380 this.startEdit(node.ui.textNode, node.text);
33384 bindScroll : function(){
33385 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33389 beforeNodeClick : function(node, e){
33390 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33391 this.lastClick = new Date();
33392 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33394 this.triggerEdit(node);
33400 updateNode : function(ed, value){
33401 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33402 this.editNode.setText(value);
33406 onHide : function(){
33407 Roo.tree.TreeEditor.superclass.onHide.call(this);
33409 this.editNode.ui.focus();
33414 onSpecialKey : function(field, e){
33415 var k = e.getKey();
33419 }else if(k == e.ENTER && !e.hasModifier()){
33421 this.completeEdit();
33424 });//<Script type="text/javascript">
33427 * Ext JS Library 1.1.1
33428 * Copyright(c) 2006-2007, Ext JS, LLC.
33430 * Originally Released Under LGPL - original licence link has changed is not relivant.
33433 * <script type="text/javascript">
33437 * Not documented??? - probably should be...
33440 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33441 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33443 renderElements : function(n, a, targetNode, bulkRender){
33444 //consel.log("renderElements?");
33445 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33447 var t = n.getOwnerTree();
33448 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33450 var cols = t.columns;
33451 var bw = t.borderWidth;
33453 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33454 var cb = typeof a.checked == "boolean";
33455 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33456 var colcls = 'x-t-' + tid + '-c0';
33458 '<li class="x-tree-node">',
33461 '<div class="x-tree-node-el ', a.cls,'">',
33463 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33466 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33467 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33468 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33469 (a.icon ? ' x-tree-node-inline-icon' : ''),
33470 (a.iconCls ? ' '+a.iconCls : ''),
33471 '" unselectable="on" />',
33472 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33473 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33475 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33476 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33477 '<span unselectable="on" qtip="' + tx + '">',
33481 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33482 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33484 for(var i = 1, len = cols.length; i < len; i++){
33486 colcls = 'x-t-' + tid + '-c' +i;
33487 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33488 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33489 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33495 '<div class="x-clear"></div></div>',
33496 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33499 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33500 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33501 n.nextSibling.ui.getEl(), buf.join(""));
33503 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33505 var el = this.wrap.firstChild;
33507 this.elNode = el.firstChild;
33508 this.ranchor = el.childNodes[1];
33509 this.ctNode = this.wrap.childNodes[1];
33510 var cs = el.firstChild.childNodes;
33511 this.indentNode = cs[0];
33512 this.ecNode = cs[1];
33513 this.iconNode = cs[2];
33516 this.checkbox = cs[3];
33519 this.anchor = cs[index];
33521 this.textNode = cs[index].firstChild;
33523 //el.on("click", this.onClick, this);
33524 //el.on("dblclick", this.onDblClick, this);
33527 // console.log(this);
33529 initEvents : function(){
33530 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33533 var a = this.ranchor;
33535 var el = Roo.get(a);
33537 if(Roo.isOpera){ // opera render bug ignores the CSS
33538 el.setStyle("text-decoration", "none");
33541 el.on("click", this.onClick, this);
33542 el.on("dblclick", this.onDblClick, this);
33543 el.on("contextmenu", this.onContextMenu, this);
33547 /*onSelectedChange : function(state){
33550 this.addClass("x-tree-selected");
33553 this.removeClass("x-tree-selected");
33556 addClass : function(cls){
33558 Roo.fly(this.elRow).addClass(cls);
33564 removeClass : function(cls){
33566 Roo.fly(this.elRow).removeClass(cls);
33572 });//<Script type="text/javascript">
33576 * Ext JS Library 1.1.1
33577 * Copyright(c) 2006-2007, Ext JS, LLC.
33579 * Originally Released Under LGPL - original licence link has changed is not relivant.
33582 * <script type="text/javascript">
33587 * @class Roo.tree.ColumnTree
33588 * @extends Roo.data.TreePanel
33589 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33590 * @cfg {int} borderWidth compined right/left border allowance
33592 * @param {String/HTMLElement/Element} el The container element
33593 * @param {Object} config
33595 Roo.tree.ColumnTree = function(el, config)
33597 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33601 * Fire this event on a container when it resizes
33602 * @param {int} w Width
33603 * @param {int} h Height
33607 this.on('resize', this.onResize, this);
33610 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33614 borderWidth: Roo.isBorderBox ? 0 : 2,
33617 render : function(){
33618 // add the header.....
33620 Roo.tree.ColumnTree.superclass.render.apply(this);
33622 this.el.addClass('x-column-tree');
33624 this.headers = this.el.createChild(
33625 {cls:'x-tree-headers'},this.innerCt.dom);
33627 var cols = this.columns, c;
33628 var totalWidth = 0;
33630 var len = cols.length;
33631 for(var i = 0; i < len; i++){
33633 totalWidth += c.width;
33634 this.headEls.push(this.headers.createChild({
33635 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33637 cls:'x-tree-hd-text',
33640 style:'width:'+(c.width-this.borderWidth)+'px;'
33643 this.headers.createChild({cls:'x-clear'});
33644 // prevent floats from wrapping when clipped
33645 this.headers.setWidth(totalWidth);
33646 //this.innerCt.setWidth(totalWidth);
33647 this.innerCt.setStyle({ overflow: 'auto' });
33648 this.onResize(this.width, this.height);
33652 onResize : function(w,h)
33657 this.innerCt.setWidth(this.width);
33658 this.innerCt.setHeight(this.height-20);
33661 var cols = this.columns, c;
33662 var totalWidth = 0;
33664 var len = cols.length;
33665 for(var i = 0; i < len; i++){
33667 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33668 // it's the expander..
33669 expEl = this.headEls[i];
33672 totalWidth += c.width;
33676 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33678 this.headers.setWidth(w-20);
33687 * Ext JS Library 1.1.1
33688 * Copyright(c) 2006-2007, Ext JS, LLC.
33690 * Originally Released Under LGPL - original licence link has changed is not relivant.
33693 * <script type="text/javascript">
33697 * @class Roo.menu.Menu
33698 * @extends Roo.util.Observable
33699 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33700 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33702 * Creates a new Menu
33703 * @param {Object} config Configuration options
33705 Roo.menu.Menu = function(config){
33706 Roo.apply(this, config);
33707 this.id = this.id || Roo.id();
33710 * @event beforeshow
33711 * Fires before this menu is displayed
33712 * @param {Roo.menu.Menu} this
33716 * @event beforehide
33717 * Fires before this menu is hidden
33718 * @param {Roo.menu.Menu} this
33723 * Fires after this menu is displayed
33724 * @param {Roo.menu.Menu} this
33729 * Fires after this menu is hidden
33730 * @param {Roo.menu.Menu} this
33735 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33736 * @param {Roo.menu.Menu} this
33737 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33738 * @param {Roo.EventObject} e
33743 * Fires when the mouse is hovering over this menu
33744 * @param {Roo.menu.Menu} this
33745 * @param {Roo.EventObject} e
33746 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33751 * Fires when the mouse exits this menu
33752 * @param {Roo.menu.Menu} this
33753 * @param {Roo.EventObject} e
33754 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33759 * Fires when a menu item contained in this menu is clicked
33760 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33761 * @param {Roo.EventObject} e
33765 if (this.registerMenu) {
33766 Roo.menu.MenuMgr.register(this);
33769 var mis = this.items;
33770 this.items = new Roo.util.MixedCollection();
33772 this.add.apply(this, mis);
33776 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33778 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33782 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33783 * for bottom-right shadow (defaults to "sides")
33787 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33788 * this menu (defaults to "tl-tr?")
33790 subMenuAlign : "tl-tr?",
33792 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33793 * relative to its element of origin (defaults to "tl-bl?")
33795 defaultAlign : "tl-bl?",
33797 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33799 allowOtherMenus : false,
33801 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33803 registerMenu : true,
33808 render : function(){
33812 var el = this.el = new Roo.Layer({
33814 shadow:this.shadow,
33816 parentEl: this.parentEl || document.body,
33820 this.keyNav = new Roo.menu.MenuNav(this);
33823 el.addClass("x-menu-plain");
33826 el.addClass(this.cls);
33828 // generic focus element
33829 this.focusEl = el.createChild({
33830 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33832 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33833 ul.on("click", this.onClick, this);
33834 ul.on("mouseover", this.onMouseOver, this);
33835 ul.on("mouseout", this.onMouseOut, this);
33836 this.items.each(function(item){
33837 var li = document.createElement("li");
33838 li.className = "x-menu-list-item";
33839 ul.dom.appendChild(li);
33840 item.render(li, this);
33847 autoWidth : function(){
33848 var el = this.el, ul = this.ul;
33852 var w = this.width;
33855 }else if(Roo.isIE){
33856 el.setWidth(this.minWidth);
33857 var t = el.dom.offsetWidth; // force recalc
33858 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33863 delayAutoWidth : function(){
33866 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33868 this.awTask.delay(20);
33873 findTargetItem : function(e){
33874 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33875 if(t && t.menuItemId){
33876 return this.items.get(t.menuItemId);
33881 onClick : function(e){
33883 if(t = this.findTargetItem(e)){
33885 this.fireEvent("click", this, t, e);
33890 setActiveItem : function(item, autoExpand){
33891 if(item != this.activeItem){
33892 if(this.activeItem){
33893 this.activeItem.deactivate();
33895 this.activeItem = item;
33896 item.activate(autoExpand);
33897 }else if(autoExpand){
33903 tryActivate : function(start, step){
33904 var items = this.items;
33905 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
33906 var item = items.get(i);
33907 if(!item.disabled && item.canActivate){
33908 this.setActiveItem(item, false);
33916 onMouseOver : function(e){
33918 if(t = this.findTargetItem(e)){
33919 if(t.canActivate && !t.disabled){
33920 this.setActiveItem(t, true);
33923 this.fireEvent("mouseover", this, e, t);
33927 onMouseOut : function(e){
33929 if(t = this.findTargetItem(e)){
33930 if(t == this.activeItem && t.shouldDeactivate(e)){
33931 this.activeItem.deactivate();
33932 delete this.activeItem;
33935 this.fireEvent("mouseout", this, e, t);
33939 * Read-only. Returns true if the menu is currently displayed, else false.
33942 isVisible : function(){
33943 return this.el && !this.hidden;
33947 * Displays this menu relative to another element
33948 * @param {String/HTMLElement/Roo.Element} element The element to align to
33949 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
33950 * the element (defaults to this.defaultAlign)
33951 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33953 show : function(el, pos, parentMenu){
33954 this.parentMenu = parentMenu;
33958 this.fireEvent("beforeshow", this);
33959 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
33963 * Displays this menu at a specific xy position
33964 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
33965 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33967 showAt : function(xy, parentMenu, /* private: */_e){
33968 this.parentMenu = parentMenu;
33973 this.fireEvent("beforeshow", this);
33974 xy = this.el.adjustForConstraints(xy);
33978 this.hidden = false;
33980 this.fireEvent("show", this);
33983 focus : function(){
33985 this.doFocus.defer(50, this);
33989 doFocus : function(){
33991 this.focusEl.focus();
33996 * Hides this menu and optionally all parent menus
33997 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
33999 hide : function(deep){
34000 if(this.el && this.isVisible()){
34001 this.fireEvent("beforehide", this);
34002 if(this.activeItem){
34003 this.activeItem.deactivate();
34004 this.activeItem = null;
34007 this.hidden = true;
34008 this.fireEvent("hide", this);
34010 if(deep === true && this.parentMenu){
34011 this.parentMenu.hide(true);
34016 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34017 * Any of the following are valid:
34019 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34020 * <li>An HTMLElement object which will be converted to a menu item</li>
34021 * <li>A menu item config object that will be created as a new menu item</li>
34022 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34023 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34028 var menu = new Roo.menu.Menu();
34030 // Create a menu item to add by reference
34031 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34033 // Add a bunch of items at once using different methods.
34034 // Only the last item added will be returned.
34035 var item = menu.add(
34036 menuItem, // add existing item by ref
34037 'Dynamic Item', // new TextItem
34038 '-', // new separator
34039 { text: 'Config Item' } // new item by config
34042 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34043 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34046 var a = arguments, l = a.length, item;
34047 for(var i = 0; i < l; i++){
34049 if ((typeof(el) == "object") && el.xtype && el.xns) {
34050 el = Roo.factory(el, Roo.menu);
34053 if(el.render){ // some kind of Item
34054 item = this.addItem(el);
34055 }else if(typeof el == "string"){ // string
34056 if(el == "separator" || el == "-"){
34057 item = this.addSeparator();
34059 item = this.addText(el);
34061 }else if(el.tagName || el.el){ // element
34062 item = this.addElement(el);
34063 }else if(typeof el == "object"){ // must be menu item config?
34064 item = this.addMenuItem(el);
34071 * Returns this menu's underlying {@link Roo.Element} object
34072 * @return {Roo.Element} The element
34074 getEl : function(){
34082 * Adds a separator bar to the menu
34083 * @return {Roo.menu.Item} The menu item that was added
34085 addSeparator : function(){
34086 return this.addItem(new Roo.menu.Separator());
34090 * Adds an {@link Roo.Element} object to the menu
34091 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34092 * @return {Roo.menu.Item} The menu item that was added
34094 addElement : function(el){
34095 return this.addItem(new Roo.menu.BaseItem(el));
34099 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34100 * @param {Roo.menu.Item} item The menu item to add
34101 * @return {Roo.menu.Item} The menu item that was added
34103 addItem : function(item){
34104 this.items.add(item);
34106 var li = document.createElement("li");
34107 li.className = "x-menu-list-item";
34108 this.ul.dom.appendChild(li);
34109 item.render(li, this);
34110 this.delayAutoWidth();
34116 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34117 * @param {Object} config A MenuItem config object
34118 * @return {Roo.menu.Item} The menu item that was added
34120 addMenuItem : function(config){
34121 if(!(config instanceof Roo.menu.Item)){
34122 if(typeof config.checked == "boolean"){ // must be check menu item config?
34123 config = new Roo.menu.CheckItem(config);
34125 config = new Roo.menu.Item(config);
34128 return this.addItem(config);
34132 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34133 * @param {String} text The text to display in the menu item
34134 * @return {Roo.menu.Item} The menu item that was added
34136 addText : function(text){
34137 return this.addItem(new Roo.menu.TextItem({ text : text }));
34141 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34142 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34143 * @param {Roo.menu.Item} item The menu item to add
34144 * @return {Roo.menu.Item} The menu item that was added
34146 insert : function(index, item){
34147 this.items.insert(index, item);
34149 var li = document.createElement("li");
34150 li.className = "x-menu-list-item";
34151 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34152 item.render(li, this);
34153 this.delayAutoWidth();
34159 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34160 * @param {Roo.menu.Item} item The menu item to remove
34162 remove : function(item){
34163 this.items.removeKey(item.id);
34168 * Removes and destroys all items in the menu
34170 removeAll : function(){
34172 while(f = this.items.first()){
34178 // MenuNav is a private utility class used internally by the Menu
34179 Roo.menu.MenuNav = function(menu){
34180 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34181 this.scope = this.menu = menu;
34184 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34185 doRelay : function(e, h){
34186 var k = e.getKey();
34187 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34188 this.menu.tryActivate(0, 1);
34191 return h.call(this.scope || this, e, this.menu);
34194 up : function(e, m){
34195 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34196 m.tryActivate(m.items.length-1, -1);
34200 down : function(e, m){
34201 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34202 m.tryActivate(0, 1);
34206 right : function(e, m){
34208 m.activeItem.expandMenu(true);
34212 left : function(e, m){
34214 if(m.parentMenu && m.parentMenu.activeItem){
34215 m.parentMenu.activeItem.activate();
34219 enter : function(e, m){
34221 e.stopPropagation();
34222 m.activeItem.onClick(e);
34223 m.fireEvent("click", this, m.activeItem);
34229 * Ext JS Library 1.1.1
34230 * Copyright(c) 2006-2007, Ext JS, LLC.
34232 * Originally Released Under LGPL - original licence link has changed is not relivant.
34235 * <script type="text/javascript">
34239 * @class Roo.menu.MenuMgr
34240 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34243 Roo.menu.MenuMgr = function(){
34244 var menus, active, groups = {}, attached = false, lastShow = new Date();
34246 // private - called when first menu is created
34249 active = new Roo.util.MixedCollection();
34250 Roo.get(document).addKeyListener(27, function(){
34251 if(active.length > 0){
34258 function hideAll(){
34259 if(active && active.length > 0){
34260 var c = active.clone();
34261 c.each(function(m){
34268 function onHide(m){
34270 if(active.length < 1){
34271 Roo.get(document).un("mousedown", onMouseDown);
34277 function onShow(m){
34278 var last = active.last();
34279 lastShow = new Date();
34282 Roo.get(document).on("mousedown", onMouseDown);
34286 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34287 m.parentMenu.activeChild = m;
34288 }else if(last && last.isVisible()){
34289 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34294 function onBeforeHide(m){
34296 m.activeChild.hide();
34298 if(m.autoHideTimer){
34299 clearTimeout(m.autoHideTimer);
34300 delete m.autoHideTimer;
34305 function onBeforeShow(m){
34306 var pm = m.parentMenu;
34307 if(!pm && !m.allowOtherMenus){
34309 }else if(pm && pm.activeChild && active != m){
34310 pm.activeChild.hide();
34315 function onMouseDown(e){
34316 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34322 function onBeforeCheck(mi, state){
34324 var g = groups[mi.group];
34325 for(var i = 0, l = g.length; i < l; i++){
34327 g[i].setChecked(false);
34336 * Hides all menus that are currently visible
34338 hideAll : function(){
34343 register : function(menu){
34347 menus[menu.id] = menu;
34348 menu.on("beforehide", onBeforeHide);
34349 menu.on("hide", onHide);
34350 menu.on("beforeshow", onBeforeShow);
34351 menu.on("show", onShow);
34352 var g = menu.group;
34353 if(g && menu.events["checkchange"]){
34357 groups[g].push(menu);
34358 menu.on("checkchange", onCheck);
34363 * Returns a {@link Roo.menu.Menu} object
34364 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34365 * be used to generate and return a new Menu instance.
34367 get : function(menu){
34368 if(typeof menu == "string"){ // menu id
34369 return menus[menu];
34370 }else if(menu.events){ // menu instance
34372 }else if(typeof menu.length == 'number'){ // array of menu items?
34373 return new Roo.menu.Menu({items:menu});
34374 }else{ // otherwise, must be a config
34375 return new Roo.menu.Menu(menu);
34380 unregister : function(menu){
34381 delete menus[menu.id];
34382 menu.un("beforehide", onBeforeHide);
34383 menu.un("hide", onHide);
34384 menu.un("beforeshow", onBeforeShow);
34385 menu.un("show", onShow);
34386 var g = menu.group;
34387 if(g && menu.events["checkchange"]){
34388 groups[g].remove(menu);
34389 menu.un("checkchange", onCheck);
34394 registerCheckable : function(menuItem){
34395 var g = menuItem.group;
34400 groups[g].push(menuItem);
34401 menuItem.on("beforecheckchange", onBeforeCheck);
34406 unregisterCheckable : function(menuItem){
34407 var g = menuItem.group;
34409 groups[g].remove(menuItem);
34410 menuItem.un("beforecheckchange", onBeforeCheck);
34416 * Ext JS Library 1.1.1
34417 * Copyright(c) 2006-2007, Ext JS, LLC.
34419 * Originally Released Under LGPL - original licence link has changed is not relivant.
34422 * <script type="text/javascript">
34427 * @class Roo.menu.BaseItem
34428 * @extends Roo.Component
34429 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34430 * management and base configuration options shared by all menu components.
34432 * Creates a new BaseItem
34433 * @param {Object} config Configuration options
34435 Roo.menu.BaseItem = function(config){
34436 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34441 * Fires when this item is clicked
34442 * @param {Roo.menu.BaseItem} this
34443 * @param {Roo.EventObject} e
34448 * Fires when this item is activated
34449 * @param {Roo.menu.BaseItem} this
34453 * @event deactivate
34454 * Fires when this item is deactivated
34455 * @param {Roo.menu.BaseItem} this
34461 this.on("click", this.handler, this.scope, true);
34465 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34467 * @cfg {Function} handler
34468 * A function that will handle the click event of this menu item (defaults to undefined)
34471 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34473 canActivate : false,
34475 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34477 activeClass : "x-menu-item-active",
34479 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34481 hideOnClick : true,
34483 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34488 ctype: "Roo.menu.BaseItem",
34491 actionMode : "container",
34494 render : function(container, parentMenu){
34495 this.parentMenu = parentMenu;
34496 Roo.menu.BaseItem.superclass.render.call(this, container);
34497 this.container.menuItemId = this.id;
34501 onRender : function(container, position){
34502 this.el = Roo.get(this.el);
34503 container.dom.appendChild(this.el.dom);
34507 onClick : function(e){
34508 if(!this.disabled && this.fireEvent("click", this, e) !== false
34509 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34510 this.handleClick(e);
34517 activate : function(){
34521 var li = this.container;
34522 li.addClass(this.activeClass);
34523 this.region = li.getRegion().adjust(2, 2, -2, -2);
34524 this.fireEvent("activate", this);
34529 deactivate : function(){
34530 this.container.removeClass(this.activeClass);
34531 this.fireEvent("deactivate", this);
34535 shouldDeactivate : function(e){
34536 return !this.region || !this.region.contains(e.getPoint());
34540 handleClick : function(e){
34541 if(this.hideOnClick){
34542 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34547 expandMenu : function(autoActivate){
34552 hideMenu : function(){
34557 * Ext JS Library 1.1.1
34558 * Copyright(c) 2006-2007, Ext JS, LLC.
34560 * Originally Released Under LGPL - original licence link has changed is not relivant.
34563 * <script type="text/javascript">
34567 * @class Roo.menu.Adapter
34568 * @extends Roo.menu.BaseItem
34569 * 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.
34570 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34572 * Creates a new Adapter
34573 * @param {Object} config Configuration options
34575 Roo.menu.Adapter = function(component, config){
34576 Roo.menu.Adapter.superclass.constructor.call(this, config);
34577 this.component = component;
34579 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34581 canActivate : true,
34584 onRender : function(container, position){
34585 this.component.render(container);
34586 this.el = this.component.getEl();
34590 activate : function(){
34594 this.component.focus();
34595 this.fireEvent("activate", this);
34600 deactivate : function(){
34601 this.fireEvent("deactivate", this);
34605 disable : function(){
34606 this.component.disable();
34607 Roo.menu.Adapter.superclass.disable.call(this);
34611 enable : function(){
34612 this.component.enable();
34613 Roo.menu.Adapter.superclass.enable.call(this);
34617 * Ext JS Library 1.1.1
34618 * Copyright(c) 2006-2007, Ext JS, LLC.
34620 * Originally Released Under LGPL - original licence link has changed is not relivant.
34623 * <script type="text/javascript">
34627 * @class Roo.menu.TextItem
34628 * @extends Roo.menu.BaseItem
34629 * Adds a static text string to a menu, usually used as either a heading or group separator.
34630 * Note: old style constructor with text is still supported.
34633 * Creates a new TextItem
34634 * @param {Object} cfg Configuration
34636 Roo.menu.TextItem = function(cfg){
34637 if (typeof(cfg) == 'string') {
34640 Roo.apply(this,cfg);
34643 Roo.menu.TextItem.superclass.constructor.call(this);
34646 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34648 * @cfg {Boolean} text Text to show on item.
34653 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34655 hideOnClick : false,
34657 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34659 itemCls : "x-menu-text",
34662 onRender : function(){
34663 var s = document.createElement("span");
34664 s.className = this.itemCls;
34665 s.innerHTML = this.text;
34667 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34671 * Ext JS Library 1.1.1
34672 * Copyright(c) 2006-2007, Ext JS, LLC.
34674 * Originally Released Under LGPL - original licence link has changed is not relivant.
34677 * <script type="text/javascript">
34681 * @class Roo.menu.Separator
34682 * @extends Roo.menu.BaseItem
34683 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34684 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34686 * @param {Object} config Configuration options
34688 Roo.menu.Separator = function(config){
34689 Roo.menu.Separator.superclass.constructor.call(this, config);
34692 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34694 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34696 itemCls : "x-menu-sep",
34698 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34700 hideOnClick : false,
34703 onRender : function(li){
34704 var s = document.createElement("span");
34705 s.className = this.itemCls;
34706 s.innerHTML = " ";
34708 li.addClass("x-menu-sep-li");
34709 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34713 * Ext JS Library 1.1.1
34714 * Copyright(c) 2006-2007, Ext JS, LLC.
34716 * Originally Released Under LGPL - original licence link has changed is not relivant.
34719 * <script type="text/javascript">
34722 * @class Roo.menu.Item
34723 * @extends Roo.menu.BaseItem
34724 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34725 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34726 * activation and click handling.
34728 * Creates a new Item
34729 * @param {Object} config Configuration options
34731 Roo.menu.Item = function(config){
34732 Roo.menu.Item.superclass.constructor.call(this, config);
34734 this.menu = Roo.menu.MenuMgr.get(this.menu);
34737 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34740 * @cfg {String} text
34741 * The text to show on the menu item.
34745 * @cfg {String} HTML to render in menu
34746 * The text to show on the menu item (HTML version).
34750 * @cfg {String} icon
34751 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34755 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34757 itemCls : "x-menu-item",
34759 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34761 canActivate : true,
34763 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34766 // doc'd in BaseItem
34770 ctype: "Roo.menu.Item",
34773 onRender : function(container, position){
34774 var el = document.createElement("a");
34775 el.hideFocus = true;
34776 el.unselectable = "on";
34777 el.href = this.href || "#";
34778 if(this.hrefTarget){
34779 el.target = this.hrefTarget;
34781 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34783 var html = this.html.length ? this.html : String.format('{0}',this.text);
34785 el.innerHTML = String.format(
34786 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
34787 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
34789 Roo.menu.Item.superclass.onRender.call(this, container, position);
34793 * Sets the text to display in this menu item
34794 * @param {String} text The text to display
34795 * @param {Boolean} isHTML true to indicate text is pure html.
34797 setText : function(text, isHTML){
34805 var html = this.html.length ? this.html : String.format('{0}',this.text);
34807 this.el.update(String.format(
34808 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
34809 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34810 this.parentMenu.autoWidth();
34815 handleClick : function(e){
34816 if(!this.href){ // if no link defined, stop the event automatically
34819 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34823 activate : function(autoExpand){
34824 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34834 shouldDeactivate : function(e){
34835 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34836 if(this.menu && this.menu.isVisible()){
34837 return !this.menu.getEl().getRegion().contains(e.getPoint());
34845 deactivate : function(){
34846 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34851 expandMenu : function(autoActivate){
34852 if(!this.disabled && this.menu){
34853 clearTimeout(this.hideTimer);
34854 delete this.hideTimer;
34855 if(!this.menu.isVisible() && !this.showTimer){
34856 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34857 }else if (this.menu.isVisible() && autoActivate){
34858 this.menu.tryActivate(0, 1);
34864 deferExpand : function(autoActivate){
34865 delete this.showTimer;
34866 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34868 this.menu.tryActivate(0, 1);
34873 hideMenu : function(){
34874 clearTimeout(this.showTimer);
34875 delete this.showTimer;
34876 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34877 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34882 deferHide : function(){
34883 delete this.hideTimer;
34888 * Ext JS Library 1.1.1
34889 * Copyright(c) 2006-2007, Ext JS, LLC.
34891 * Originally Released Under LGPL - original licence link has changed is not relivant.
34894 * <script type="text/javascript">
34898 * @class Roo.menu.CheckItem
34899 * @extends Roo.menu.Item
34900 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
34902 * Creates a new CheckItem
34903 * @param {Object} config Configuration options
34905 Roo.menu.CheckItem = function(config){
34906 Roo.menu.CheckItem.superclass.constructor.call(this, config);
34909 * @event beforecheckchange
34910 * Fires before the checked value is set, providing an opportunity to cancel if needed
34911 * @param {Roo.menu.CheckItem} this
34912 * @param {Boolean} checked The new checked value that will be set
34914 "beforecheckchange" : true,
34916 * @event checkchange
34917 * Fires after the checked value has been set
34918 * @param {Roo.menu.CheckItem} this
34919 * @param {Boolean} checked The checked value that was set
34921 "checkchange" : true
34923 if(this.checkHandler){
34924 this.on('checkchange', this.checkHandler, this.scope);
34927 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
34929 * @cfg {String} group
34930 * All check items with the same group name will automatically be grouped into a single-select
34931 * radio button group (defaults to '')
34934 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
34936 itemCls : "x-menu-item x-menu-check-item",
34938 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
34940 groupClass : "x-menu-group-item",
34943 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
34944 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
34945 * initialized with checked = true will be rendered as checked.
34950 ctype: "Roo.menu.CheckItem",
34953 onRender : function(c){
34954 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
34956 this.el.addClass(this.groupClass);
34958 Roo.menu.MenuMgr.registerCheckable(this);
34960 this.checked = false;
34961 this.setChecked(true, true);
34966 destroy : function(){
34968 Roo.menu.MenuMgr.unregisterCheckable(this);
34970 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
34974 * Set the checked state of this item
34975 * @param {Boolean} checked The new checked value
34976 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
34978 setChecked : function(state, suppressEvent){
34979 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
34980 if(this.container){
34981 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
34983 this.checked = state;
34984 if(suppressEvent !== true){
34985 this.fireEvent("checkchange", this, state);
34991 handleClick : function(e){
34992 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
34993 this.setChecked(!this.checked);
34995 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
34999 * Ext JS Library 1.1.1
35000 * Copyright(c) 2006-2007, Ext JS, LLC.
35002 * Originally Released Under LGPL - original licence link has changed is not relivant.
35005 * <script type="text/javascript">
35009 * @class Roo.menu.DateItem
35010 * @extends Roo.menu.Adapter
35011 * A menu item that wraps the {@link Roo.DatPicker} component.
35013 * Creates a new DateItem
35014 * @param {Object} config Configuration options
35016 Roo.menu.DateItem = function(config){
35017 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35018 /** The Roo.DatePicker object @type Roo.DatePicker */
35019 this.picker = this.component;
35020 this.addEvents({select: true});
35022 this.picker.on("render", function(picker){
35023 picker.getEl().swallowEvent("click");
35024 picker.container.addClass("x-menu-date-item");
35027 this.picker.on("select", this.onSelect, this);
35030 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35032 onSelect : function(picker, date){
35033 this.fireEvent("select", this, date, picker);
35034 Roo.menu.DateItem.superclass.handleClick.call(this);
35038 * Ext JS Library 1.1.1
35039 * Copyright(c) 2006-2007, Ext JS, LLC.
35041 * Originally Released Under LGPL - original licence link has changed is not relivant.
35044 * <script type="text/javascript">
35048 * @class Roo.menu.ColorItem
35049 * @extends Roo.menu.Adapter
35050 * A menu item that wraps the {@link Roo.ColorPalette} component.
35052 * Creates a new ColorItem
35053 * @param {Object} config Configuration options
35055 Roo.menu.ColorItem = function(config){
35056 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35057 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35058 this.palette = this.component;
35059 this.relayEvents(this.palette, ["select"]);
35060 if(this.selectHandler){
35061 this.on('select', this.selectHandler, this.scope);
35064 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35066 * Ext JS Library 1.1.1
35067 * Copyright(c) 2006-2007, Ext JS, LLC.
35069 * Originally Released Under LGPL - original licence link has changed is not relivant.
35072 * <script type="text/javascript">
35077 * @class Roo.menu.DateMenu
35078 * @extends Roo.menu.Menu
35079 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35081 * Creates a new DateMenu
35082 * @param {Object} config Configuration options
35084 Roo.menu.DateMenu = function(config){
35085 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35087 var di = new Roo.menu.DateItem(config);
35090 * The {@link Roo.DatePicker} instance for this DateMenu
35093 this.picker = di.picker;
35096 * @param {DatePicker} picker
35097 * @param {Date} date
35099 this.relayEvents(di, ["select"]);
35101 this.on('beforeshow', function(){
35103 this.picker.hideMonthPicker(true);
35107 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35111 * Ext JS Library 1.1.1
35112 * Copyright(c) 2006-2007, Ext JS, LLC.
35114 * Originally Released Under LGPL - original licence link has changed is not relivant.
35117 * <script type="text/javascript">
35122 * @class Roo.menu.ColorMenu
35123 * @extends Roo.menu.Menu
35124 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35126 * Creates a new ColorMenu
35127 * @param {Object} config Configuration options
35129 Roo.menu.ColorMenu = function(config){
35130 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35132 var ci = new Roo.menu.ColorItem(config);
35135 * The {@link Roo.ColorPalette} instance for this ColorMenu
35136 * @type ColorPalette
35138 this.palette = ci.palette;
35141 * @param {ColorPalette} palette
35142 * @param {String} color
35144 this.relayEvents(ci, ["select"]);
35146 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35148 * Ext JS Library 1.1.1
35149 * Copyright(c) 2006-2007, Ext JS, LLC.
35151 * Originally Released Under LGPL - original licence link has changed is not relivant.
35154 * <script type="text/javascript">
35158 * @class Roo.form.Field
35159 * @extends Roo.BoxComponent
35160 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35162 * Creates a new Field
35163 * @param {Object} config Configuration options
35165 Roo.form.Field = function(config){
35166 Roo.form.Field.superclass.constructor.call(this, config);
35169 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35171 * @cfg {String} fieldLabel Label to use when rendering a form.
35174 * @cfg {String} qtip Mouse over tip
35178 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35180 invalidClass : "x-form-invalid",
35182 * @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")
35184 invalidText : "The value in this field is invalid",
35186 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35188 focusClass : "x-form-focus",
35190 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35191 automatic validation (defaults to "keyup").
35193 validationEvent : "keyup",
35195 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35197 validateOnBlur : true,
35199 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35201 validationDelay : 250,
35203 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35204 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35206 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35208 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35210 fieldClass : "x-form-field",
35212 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35215 ----------- ----------------------------------------------------------------------
35216 qtip Display a quick tip when the user hovers over the field
35217 title Display a default browser title attribute popup
35218 under Add a block div beneath the field containing the error text
35219 side Add an error icon to the right of the field with a popup on hover
35220 [element id] Add the error text directly to the innerHTML of the specified element
35223 msgTarget : 'qtip',
35225 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35230 * @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.
35235 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35240 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35242 inputType : undefined,
35245 * @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).
35247 tabIndex : undefined,
35250 isFormField : true,
35255 * @property {Roo.Element} fieldEl
35256 * Element Containing the rendered Field (with label etc.)
35259 * @cfg {Mixed} value A value to initialize this field with.
35264 * @cfg {String} name The field's HTML name attribute.
35267 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35271 initComponent : function(){
35272 Roo.form.Field.superclass.initComponent.call(this);
35276 * Fires when this field receives input focus.
35277 * @param {Roo.form.Field} this
35282 * Fires when this field loses input focus.
35283 * @param {Roo.form.Field} this
35287 * @event specialkey
35288 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35289 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35290 * @param {Roo.form.Field} this
35291 * @param {Roo.EventObject} e The event object
35296 * Fires just before the field blurs if the field value has changed.
35297 * @param {Roo.form.Field} this
35298 * @param {Mixed} newValue The new value
35299 * @param {Mixed} oldValue The original value
35304 * Fires after the field has been marked as invalid.
35305 * @param {Roo.form.Field} this
35306 * @param {String} msg The validation message
35311 * Fires after the field has been validated with no errors.
35312 * @param {Roo.form.Field} this
35317 * Fires after the key up
35318 * @param {Roo.form.Field} this
35319 * @param {Roo.EventObject} e The event Object
35326 * Returns the name attribute of the field if available
35327 * @return {String} name The field name
35329 getName: function(){
35330 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35334 onRender : function(ct, position){
35335 Roo.form.Field.superclass.onRender.call(this, ct, position);
35337 var cfg = this.getAutoCreate();
35339 cfg.name = this.name || this.id;
35341 if(this.inputType){
35342 cfg.type = this.inputType;
35344 this.el = ct.createChild(cfg, position);
35346 var type = this.el.dom.type;
35348 if(type == 'password'){
35351 this.el.addClass('x-form-'+type);
35354 this.el.dom.readOnly = true;
35356 if(this.tabIndex !== undefined){
35357 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35360 this.el.addClass([this.fieldClass, this.cls]);
35365 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35366 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35367 * @return {Roo.form.Field} this
35369 applyTo : function(target){
35370 this.allowDomMove = false;
35371 this.el = Roo.get(target);
35372 this.render(this.el.dom.parentNode);
35377 initValue : function(){
35378 if(this.value !== undefined){
35379 this.setValue(this.value);
35380 }else if(this.el.dom.value.length > 0){
35381 this.setValue(this.el.dom.value);
35386 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35388 isDirty : function() {
35389 if(this.disabled) {
35392 return String(this.getValue()) !== String(this.originalValue);
35396 afterRender : function(){
35397 Roo.form.Field.superclass.afterRender.call(this);
35402 fireKey : function(e){
35403 //Roo.log('field ' + e.getKey());
35404 if(e.isNavKeyPress()){
35405 this.fireEvent("specialkey", this, e);
35410 * Resets the current field value to the originally loaded value and clears any validation messages
35412 reset : function(){
35413 this.setValue(this.originalValue);
35414 this.clearInvalid();
35418 initEvents : function(){
35419 // safari killled keypress - so keydown is now used..
35420 this.el.on("keydown" , this.fireKey, this);
35421 this.el.on("focus", this.onFocus, this);
35422 this.el.on("blur", this.onBlur, this);
35423 this.el.relayEvent('keyup', this);
35425 // reference to original value for reset
35426 this.originalValue = this.getValue();
35430 onFocus : function(){
35431 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35432 this.el.addClass(this.focusClass);
35434 if(!this.hasFocus){
35435 this.hasFocus = true;
35436 this.startValue = this.getValue();
35437 this.fireEvent("focus", this);
35441 beforeBlur : Roo.emptyFn,
35444 onBlur : function(){
35446 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35447 this.el.removeClass(this.focusClass);
35449 this.hasFocus = false;
35450 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35453 var v = this.getValue();
35454 if(String(v) !== String(this.startValue)){
35455 this.fireEvent('change', this, v, this.startValue);
35457 this.fireEvent("blur", this);
35461 * Returns whether or not the field value is currently valid
35462 * @param {Boolean} preventMark True to disable marking the field invalid
35463 * @return {Boolean} True if the value is valid, else false
35465 isValid : function(preventMark){
35469 var restore = this.preventMark;
35470 this.preventMark = preventMark === true;
35471 var v = this.validateValue(this.processValue(this.getRawValue()));
35472 this.preventMark = restore;
35477 * Validates the field value
35478 * @return {Boolean} True if the value is valid, else false
35480 validate : function(){
35481 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35482 this.clearInvalid();
35488 processValue : function(value){
35493 // Subclasses should provide the validation implementation by overriding this
35494 validateValue : function(value){
35499 * Mark this field as invalid
35500 * @param {String} msg The validation message
35502 markInvalid : function(msg){
35503 if(!this.rendered || this.preventMark){ // not rendered
35506 this.el.addClass(this.invalidClass);
35507 msg = msg || this.invalidText;
35508 switch(this.msgTarget){
35510 this.el.dom.qtip = msg;
35511 this.el.dom.qclass = 'x-form-invalid-tip';
35512 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35513 Roo.QuickTips.enable();
35517 this.el.dom.title = msg;
35521 var elp = this.el.findParent('.x-form-element', 5, true);
35522 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35523 this.errorEl.setWidth(elp.getWidth(true)-20);
35525 this.errorEl.update(msg);
35526 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35529 if(!this.errorIcon){
35530 var elp = this.el.findParent('.x-form-element', 5, true);
35531 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35533 this.alignErrorIcon();
35534 this.errorIcon.dom.qtip = msg;
35535 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35536 this.errorIcon.show();
35537 this.on('resize', this.alignErrorIcon, this);
35540 var t = Roo.getDom(this.msgTarget);
35542 t.style.display = this.msgDisplay;
35545 this.fireEvent('invalid', this, msg);
35549 alignErrorIcon : function(){
35550 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35554 * Clear any invalid styles/messages for this field
35556 clearInvalid : function(){
35557 if(!this.rendered || this.preventMark){ // not rendered
35560 this.el.removeClass(this.invalidClass);
35561 switch(this.msgTarget){
35563 this.el.dom.qtip = '';
35566 this.el.dom.title = '';
35570 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35574 if(this.errorIcon){
35575 this.errorIcon.dom.qtip = '';
35576 this.errorIcon.hide();
35577 this.un('resize', this.alignErrorIcon, this);
35581 var t = Roo.getDom(this.msgTarget);
35583 t.style.display = 'none';
35586 this.fireEvent('valid', this);
35590 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35591 * @return {Mixed} value The field value
35593 getRawValue : function(){
35594 var v = this.el.getValue();
35595 if(v === this.emptyText){
35602 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35603 * @return {Mixed} value The field value
35605 getValue : function(){
35606 var v = this.el.getValue();
35607 if(v === this.emptyText || v === undefined){
35614 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35615 * @param {Mixed} value The value to set
35617 setRawValue : function(v){
35618 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35622 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35623 * @param {Mixed} value The value to set
35625 setValue : function(v){
35628 this.el.dom.value = (v === null || v === undefined ? '' : v);
35633 adjustSize : function(w, h){
35634 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35635 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35639 adjustWidth : function(tag, w){
35640 tag = tag.toLowerCase();
35641 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35642 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35643 if(tag == 'input'){
35646 if(tag = 'textarea'){
35649 }else if(Roo.isOpera){
35650 if(tag == 'input'){
35653 if(tag = 'textarea'){
35663 // anything other than normal should be considered experimental
35664 Roo.form.Field.msgFx = {
35666 show: function(msgEl, f){
35667 msgEl.setDisplayed('block');
35670 hide : function(msgEl, f){
35671 msgEl.setDisplayed(false).update('');
35676 show: function(msgEl, f){
35677 msgEl.slideIn('t', {stopFx:true});
35680 hide : function(msgEl, f){
35681 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35686 show: function(msgEl, f){
35687 msgEl.fixDisplay();
35688 msgEl.alignTo(f.el, 'tl-tr');
35689 msgEl.slideIn('l', {stopFx:true});
35692 hide : function(msgEl, f){
35693 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35698 * Ext JS Library 1.1.1
35699 * Copyright(c) 2006-2007, Ext JS, LLC.
35701 * Originally Released Under LGPL - original licence link has changed is not relivant.
35704 * <script type="text/javascript">
35709 * @class Roo.form.TextField
35710 * @extends Roo.form.Field
35711 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35712 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35714 * Creates a new TextField
35715 * @param {Object} config Configuration options
35717 Roo.form.TextField = function(config){
35718 Roo.form.TextField.superclass.constructor.call(this, config);
35722 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35723 * according to the default logic, but this event provides a hook for the developer to apply additional
35724 * logic at runtime to resize the field if needed.
35725 * @param {Roo.form.Field} this This text field
35726 * @param {Number} width The new field width
35732 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35734 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35738 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35742 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35746 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35750 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35754 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35756 disableKeyFilter : false,
35758 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35762 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35766 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35768 maxLength : Number.MAX_VALUE,
35770 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35772 minLengthText : "The minimum length for this field is {0}",
35774 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35776 maxLengthText : "The maximum length for this field is {0}",
35778 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35780 selectOnFocus : false,
35782 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35784 blankText : "This field is required",
35786 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35787 * If available, this function will be called only after the basic validators all return true, and will be passed the
35788 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35792 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35793 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35794 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35798 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35802 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35806 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35807 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35809 emptyClass : 'x-form-empty-field',
35812 initEvents : function(){
35813 Roo.form.TextField.superclass.initEvents.call(this);
35814 if(this.validationEvent == 'keyup'){
35815 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35816 this.el.on('keyup', this.filterValidation, this);
35818 else if(this.validationEvent !== false){
35819 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35821 if(this.selectOnFocus || this.emptyText){
35822 this.on("focus", this.preFocus, this);
35823 if(this.emptyText){
35824 this.on('blur', this.postBlur, this);
35825 this.applyEmptyText();
35828 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35829 this.el.on("keypress", this.filterKeys, this);
35832 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35833 this.el.on("click", this.autoSize, this);
35837 processValue : function(value){
35838 if(this.stripCharsRe){
35839 var newValue = value.replace(this.stripCharsRe, '');
35840 if(newValue !== value){
35841 this.setRawValue(newValue);
35848 filterValidation : function(e){
35849 if(!e.isNavKeyPress()){
35850 this.validationTask.delay(this.validationDelay);
35855 onKeyUp : function(e){
35856 if(!e.isNavKeyPress()){
35862 * Resets the current field value to the originally-loaded value and clears any validation messages.
35863 * Also adds emptyText and emptyClass if the original value was blank.
35865 reset : function(){
35866 Roo.form.TextField.superclass.reset.call(this);
35867 this.applyEmptyText();
35870 applyEmptyText : function(){
35871 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35872 this.setRawValue(this.emptyText);
35873 this.el.addClass(this.emptyClass);
35878 preFocus : function(){
35879 if(this.emptyText){
35880 if(this.el.dom.value == this.emptyText){
35881 this.setRawValue('');
35883 this.el.removeClass(this.emptyClass);
35885 if(this.selectOnFocus){
35886 this.el.dom.select();
35891 postBlur : function(){
35892 this.applyEmptyText();
35896 filterKeys : function(e){
35897 var k = e.getKey();
35898 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
35901 var c = e.getCharCode(), cc = String.fromCharCode(c);
35902 if(Roo.isIE && (e.isSpecialKey() || !cc)){
35905 if(!this.maskRe.test(cc)){
35910 setValue : function(v){
35911 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
35912 this.el.removeClass(this.emptyClass);
35914 Roo.form.TextField.superclass.setValue.apply(this, arguments);
35915 this.applyEmptyText();
35920 * Validates a value according to the field's validation rules and marks the field as invalid
35921 * if the validation fails
35922 * @param {Mixed} value The value to validate
35923 * @return {Boolean} True if the value is valid, else false
35925 validateValue : function(value){
35926 if(value.length < 1 || value === this.emptyText){ // if it's blank
35927 if(this.allowBlank){
35928 this.clearInvalid();
35931 this.markInvalid(this.blankText);
35935 if(value.length < this.minLength){
35936 this.markInvalid(String.format(this.minLengthText, this.minLength));
35939 if(value.length > this.maxLength){
35940 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
35944 var vt = Roo.form.VTypes;
35945 if(!vt[this.vtype](value, this)){
35946 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
35950 if(typeof this.validator == "function"){
35951 var msg = this.validator(value);
35953 this.markInvalid(msg);
35957 if(this.regex && !this.regex.test(value)){
35958 this.markInvalid(this.regexText);
35965 * Selects text in this field
35966 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
35967 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
35969 selectText : function(start, end){
35970 var v = this.getRawValue();
35972 start = start === undefined ? 0 : start;
35973 end = end === undefined ? v.length : end;
35974 var d = this.el.dom;
35975 if(d.setSelectionRange){
35976 d.setSelectionRange(start, end);
35977 }else if(d.createTextRange){
35978 var range = d.createTextRange();
35979 range.moveStart("character", start);
35980 range.moveEnd("character", v.length-end);
35987 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
35988 * This only takes effect if grow = true, and fires the autosize event.
35990 autoSize : function(){
35991 if(!this.grow || !this.rendered){
35995 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
35998 var v = el.dom.value;
35999 var d = document.createElement('div');
36000 d.appendChild(document.createTextNode(v));
36004 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36005 this.el.setWidth(w);
36006 this.fireEvent("autosize", this, w);
36010 * Ext JS Library 1.1.1
36011 * Copyright(c) 2006-2007, Ext JS, LLC.
36013 * Originally Released Under LGPL - original licence link has changed is not relivant.
36016 * <script type="text/javascript">
36020 * @class Roo.form.Hidden
36021 * @extends Roo.form.TextField
36022 * Simple Hidden element used on forms
36024 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36027 * Creates a new Hidden form element.
36028 * @param {Object} config Configuration options
36033 // easy hidden field...
36034 Roo.form.Hidden = function(config){
36035 Roo.form.Hidden.superclass.constructor.call(this, config);
36038 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36040 inputType: 'hidden',
36043 labelSeparator: '',
36045 itemCls : 'x-form-item-display-none'
36053 * Ext JS Library 1.1.1
36054 * Copyright(c) 2006-2007, Ext JS, LLC.
36056 * Originally Released Under LGPL - original licence link has changed is not relivant.
36059 * <script type="text/javascript">
36063 * @class Roo.form.TriggerField
36064 * @extends Roo.form.TextField
36065 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36066 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36067 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36068 * for which you can provide a custom implementation. For example:
36070 var trigger = new Roo.form.TriggerField();
36071 trigger.onTriggerClick = myTriggerFn;
36072 trigger.applyTo('my-field');
36075 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36076 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36077 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36078 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36080 * Create a new TriggerField.
36081 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36082 * to the base TextField)
36084 Roo.form.TriggerField = function(config){
36085 this.mimicing = false;
36086 Roo.form.TriggerField.superclass.constructor.call(this, config);
36089 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36091 * @cfg {String} triggerClass A CSS class to apply to the trigger
36094 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36095 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36097 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36099 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36103 /** @cfg {Boolean} grow @hide */
36104 /** @cfg {Number} growMin @hide */
36105 /** @cfg {Number} growMax @hide */
36111 autoSize: Roo.emptyFn,
36115 deferHeight : true,
36118 actionMode : 'wrap',
36120 onResize : function(w, h){
36121 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36122 if(typeof w == 'number'){
36123 var x = w - this.trigger.getWidth();
36124 this.el.setWidth(this.adjustWidth('input', x));
36125 this.trigger.setStyle('left', x+'px');
36130 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36133 getResizeEl : function(){
36138 getPositionEl : function(){
36143 alignErrorIcon : function(){
36144 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36148 onRender : function(ct, position){
36149 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36150 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36151 this.trigger = this.wrap.createChild(this.triggerConfig ||
36152 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36153 if(this.hideTrigger){
36154 this.trigger.setDisplayed(false);
36156 this.initTrigger();
36158 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36163 initTrigger : function(){
36164 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36165 this.trigger.addClassOnOver('x-form-trigger-over');
36166 this.trigger.addClassOnClick('x-form-trigger-click');
36170 onDestroy : function(){
36172 this.trigger.removeAllListeners();
36173 this.trigger.remove();
36176 this.wrap.remove();
36178 Roo.form.TriggerField.superclass.onDestroy.call(this);
36182 onFocus : function(){
36183 Roo.form.TriggerField.superclass.onFocus.call(this);
36184 if(!this.mimicing){
36185 this.wrap.addClass('x-trigger-wrap-focus');
36186 this.mimicing = true;
36187 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36188 if(this.monitorTab){
36189 this.el.on("keydown", this.checkTab, this);
36195 checkTab : function(e){
36196 if(e.getKey() == e.TAB){
36197 this.triggerBlur();
36202 onBlur : function(){
36207 mimicBlur : function(e, t){
36208 if(!this.wrap.contains(t) && this.validateBlur()){
36209 this.triggerBlur();
36214 triggerBlur : function(){
36215 this.mimicing = false;
36216 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36217 if(this.monitorTab){
36218 this.el.un("keydown", this.checkTab, this);
36220 this.wrap.removeClass('x-trigger-wrap-focus');
36221 Roo.form.TriggerField.superclass.onBlur.call(this);
36225 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36226 validateBlur : function(e, t){
36231 onDisable : function(){
36232 Roo.form.TriggerField.superclass.onDisable.call(this);
36234 this.wrap.addClass('x-item-disabled');
36239 onEnable : function(){
36240 Roo.form.TriggerField.superclass.onEnable.call(this);
36242 this.wrap.removeClass('x-item-disabled');
36247 onShow : function(){
36248 var ae = this.getActionEl();
36251 ae.dom.style.display = '';
36252 ae.dom.style.visibility = 'visible';
36258 onHide : function(){
36259 var ae = this.getActionEl();
36260 ae.dom.style.display = 'none';
36264 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36265 * by an implementing function.
36267 * @param {EventObject} e
36269 onTriggerClick : Roo.emptyFn
36272 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36273 // to be extended by an implementing class. For an example of implementing this class, see the custom
36274 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36275 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36276 initComponent : function(){
36277 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36279 this.triggerConfig = {
36280 tag:'span', cls:'x-form-twin-triggers', cn:[
36281 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36282 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36286 getTrigger : function(index){
36287 return this.triggers[index];
36290 initTrigger : function(){
36291 var ts = this.trigger.select('.x-form-trigger', true);
36292 this.wrap.setStyle('overflow', 'hidden');
36293 var triggerField = this;
36294 ts.each(function(t, all, index){
36295 t.hide = function(){
36296 var w = triggerField.wrap.getWidth();
36297 this.dom.style.display = 'none';
36298 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36300 t.show = function(){
36301 var w = triggerField.wrap.getWidth();
36302 this.dom.style.display = '';
36303 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36305 var triggerIndex = 'Trigger'+(index+1);
36307 if(this['hide'+triggerIndex]){
36308 t.dom.style.display = 'none';
36310 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36311 t.addClassOnOver('x-form-trigger-over');
36312 t.addClassOnClick('x-form-trigger-click');
36314 this.triggers = ts.elements;
36317 onTrigger1Click : Roo.emptyFn,
36318 onTrigger2Click : Roo.emptyFn
36321 * Ext JS Library 1.1.1
36322 * Copyright(c) 2006-2007, Ext JS, LLC.
36324 * Originally Released Under LGPL - original licence link has changed is not relivant.
36327 * <script type="text/javascript">
36331 * @class Roo.form.TextArea
36332 * @extends Roo.form.TextField
36333 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36334 * support for auto-sizing.
36336 * Creates a new TextArea
36337 * @param {Object} config Configuration options
36339 Roo.form.TextArea = function(config){
36340 Roo.form.TextArea.superclass.constructor.call(this, config);
36341 // these are provided exchanges for backwards compat
36342 // minHeight/maxHeight were replaced by growMin/growMax to be
36343 // compatible with TextField growing config values
36344 if(this.minHeight !== undefined){
36345 this.growMin = this.minHeight;
36347 if(this.maxHeight !== undefined){
36348 this.growMax = this.maxHeight;
36352 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36354 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36358 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36362 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36363 * in the field (equivalent to setting overflow: hidden, defaults to false)
36365 preventScrollbars: false,
36367 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36368 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36372 onRender : function(ct, position){
36374 this.defaultAutoCreate = {
36376 style:"width:300px;height:60px;",
36377 autocomplete: "off"
36380 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36382 this.textSizeEl = Roo.DomHelper.append(document.body, {
36383 tag: "pre", cls: "x-form-grow-sizer"
36385 if(this.preventScrollbars){
36386 this.el.setStyle("overflow", "hidden");
36388 this.el.setHeight(this.growMin);
36392 onDestroy : function(){
36393 if(this.textSizeEl){
36394 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36396 Roo.form.TextArea.superclass.onDestroy.call(this);
36400 onKeyUp : function(e){
36401 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36407 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36408 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36410 autoSize : function(){
36411 if(!this.grow || !this.textSizeEl){
36415 var v = el.dom.value;
36416 var ts = this.textSizeEl;
36419 ts.appendChild(document.createTextNode(v));
36422 Roo.fly(ts).setWidth(this.el.getWidth());
36424 v = "  ";
36427 v = v.replace(/\n/g, '<p> </p>');
36429 v += " \n ";
36432 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36433 if(h != this.lastHeight){
36434 this.lastHeight = h;
36435 this.el.setHeight(h);
36436 this.fireEvent("autosize", this, h);
36441 * Ext JS Library 1.1.1
36442 * Copyright(c) 2006-2007, Ext JS, LLC.
36444 * Originally Released Under LGPL - original licence link has changed is not relivant.
36447 * <script type="text/javascript">
36452 * @class Roo.form.NumberField
36453 * @extends Roo.form.TextField
36454 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36456 * Creates a new NumberField
36457 * @param {Object} config Configuration options
36459 Roo.form.NumberField = function(config){
36460 Roo.form.NumberField.superclass.constructor.call(this, config);
36463 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36465 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36467 fieldClass: "x-form-field x-form-num-field",
36469 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36471 allowDecimals : true,
36473 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36475 decimalSeparator : ".",
36477 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36479 decimalPrecision : 2,
36481 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36483 allowNegative : true,
36485 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36487 minValue : Number.NEGATIVE_INFINITY,
36489 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36491 maxValue : Number.MAX_VALUE,
36493 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36495 minText : "The minimum value for this field is {0}",
36497 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36499 maxText : "The maximum value for this field is {0}",
36501 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36502 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36504 nanText : "{0} is not a valid number",
36507 initEvents : function(){
36508 Roo.form.NumberField.superclass.initEvents.call(this);
36509 var allowed = "0123456789";
36510 if(this.allowDecimals){
36511 allowed += this.decimalSeparator;
36513 if(this.allowNegative){
36516 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36517 var keyPress = function(e){
36518 var k = e.getKey();
36519 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36522 var c = e.getCharCode();
36523 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36527 this.el.on("keypress", keyPress, this);
36531 validateValue : function(value){
36532 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36535 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36538 var num = this.parseValue(value);
36540 this.markInvalid(String.format(this.nanText, value));
36543 if(num < this.minValue){
36544 this.markInvalid(String.format(this.minText, this.minValue));
36547 if(num > this.maxValue){
36548 this.markInvalid(String.format(this.maxText, this.maxValue));
36554 getValue : function(){
36555 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36559 parseValue : function(value){
36560 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36561 return isNaN(value) ? '' : value;
36565 fixPrecision : function(value){
36566 var nan = isNaN(value);
36567 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36568 return nan ? '' : value;
36570 return parseFloat(value).toFixed(this.decimalPrecision);
36573 setValue : function(v){
36574 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36578 decimalPrecisionFcn : function(v){
36579 return Math.floor(v);
36582 beforeBlur : function(){
36583 var v = this.parseValue(this.getRawValue());
36585 this.setValue(this.fixPrecision(v));
36590 * Ext JS Library 1.1.1
36591 * Copyright(c) 2006-2007, Ext JS, LLC.
36593 * Originally Released Under LGPL - original licence link has changed is not relivant.
36596 * <script type="text/javascript">
36600 * @class Roo.form.DateField
36601 * @extends Roo.form.TriggerField
36602 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36604 * Create a new DateField
36605 * @param {Object} config
36607 Roo.form.DateField = function(config){
36608 Roo.form.DateField.superclass.constructor.call(this, config);
36614 * Fires when a date is selected
36615 * @param {Roo.form.DateField} combo This combo box
36616 * @param {Date} date The date selected
36623 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36624 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36625 this.ddMatch = null;
36626 if(this.disabledDates){
36627 var dd = this.disabledDates;
36629 for(var i = 0; i < dd.length; i++){
36631 if(i != dd.length-1) re += "|";
36633 this.ddMatch = new RegExp(re + ")");
36637 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36639 * @cfg {String} format
36640 * The default date format string which can be overriden for localization support. The format must be
36641 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36645 * @cfg {String} altFormats
36646 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36647 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36649 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36651 * @cfg {Array} disabledDays
36652 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36654 disabledDays : null,
36656 * @cfg {String} disabledDaysText
36657 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36659 disabledDaysText : "Disabled",
36661 * @cfg {Array} disabledDates
36662 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36663 * expression so they are very powerful. Some examples:
36665 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36666 * <li>["03/08", "09/16"] would disable those days for every year</li>
36667 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36668 * <li>["03/../2006"] would disable every day in March 2006</li>
36669 * <li>["^03"] would disable every day in every March</li>
36671 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36672 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36674 disabledDates : null,
36676 * @cfg {String} disabledDatesText
36677 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36679 disabledDatesText : "Disabled",
36681 * @cfg {Date/String} minValue
36682 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36683 * valid format (defaults to null).
36687 * @cfg {Date/String} maxValue
36688 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36689 * valid format (defaults to null).
36693 * @cfg {String} minText
36694 * The error text to display when the date in the cell is before minValue (defaults to
36695 * 'The date in this field must be after {minValue}').
36697 minText : "The date in this field must be equal to or after {0}",
36699 * @cfg {String} maxText
36700 * The error text to display when the date in the cell is after maxValue (defaults to
36701 * 'The date in this field must be before {maxValue}').
36703 maxText : "The date in this field must be equal to or before {0}",
36705 * @cfg {String} invalidText
36706 * The error text to display when the date in the field is invalid (defaults to
36707 * '{value} is not a valid date - it must be in the format {format}').
36709 invalidText : "{0} is not a valid date - it must be in the format {1}",
36711 * @cfg {String} triggerClass
36712 * An additional CSS class used to style the trigger button. The trigger will always get the
36713 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36714 * which displays a calendar icon).
36716 triggerClass : 'x-form-date-trigger',
36720 * @cfg {bool} useIso
36721 * if enabled, then the date field will use a hidden field to store the
36722 * real value as iso formated date. default (false)
36726 * @cfg {String/Object} autoCreate
36727 * A DomHelper element spec, or true for a default element spec (defaults to
36728 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36731 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36734 hiddenField: false,
36736 onRender : function(ct, position)
36738 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36740 this.el.dom.removeAttribute('name');
36741 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36743 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36744 // prevent input submission
36745 this.hiddenName = this.name;
36752 validateValue : function(value)
36754 value = this.formatDate(value);
36755 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36758 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36761 var svalue = value;
36762 value = this.parseDate(value);
36764 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36767 var time = value.getTime();
36768 if(this.minValue && time < this.minValue.getTime()){
36769 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36772 if(this.maxValue && time > this.maxValue.getTime()){
36773 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36776 if(this.disabledDays){
36777 var day = value.getDay();
36778 for(var i = 0; i < this.disabledDays.length; i++) {
36779 if(day === this.disabledDays[i]){
36780 this.markInvalid(this.disabledDaysText);
36785 var fvalue = this.formatDate(value);
36786 if(this.ddMatch && this.ddMatch.test(fvalue)){
36787 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36794 // Provides logic to override the default TriggerField.validateBlur which just returns true
36795 validateBlur : function(){
36796 return !this.menu || !this.menu.isVisible();
36800 * Returns the current date value of the date field.
36801 * @return {Date} The date value
36803 getValue : function(){
36805 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36809 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36810 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36811 * (the default format used is "m/d/y").
36814 //All of these calls set the same date value (May 4, 2006)
36816 //Pass a date object:
36817 var dt = new Date('5/4/06');
36818 dateField.setValue(dt);
36820 //Pass a date string (default format):
36821 dateField.setValue('5/4/06');
36823 //Pass a date string (custom format):
36824 dateField.format = 'Y-m-d';
36825 dateField.setValue('2006-5-4');
36827 * @param {String/Date} date The date or valid date string
36829 setValue : function(date){
36830 if (this.hiddenField) {
36831 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36833 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36837 parseDate : function(value){
36838 if(!value || value instanceof Date){
36841 var v = Date.parseDate(value, this.format);
36842 if(!v && this.altFormats){
36843 if(!this.altFormatsArray){
36844 this.altFormatsArray = this.altFormats.split("|");
36846 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36847 v = Date.parseDate(value, this.altFormatsArray[i]);
36854 formatDate : function(date, fmt){
36855 return (!date || !(date instanceof Date)) ?
36856 date : date.dateFormat(fmt || this.format);
36861 select: function(m, d){
36863 this.fireEvent('select', this, d);
36865 show : function(){ // retain focus styling
36869 this.focus.defer(10, this);
36870 var ml = this.menuListeners;
36871 this.menu.un("select", ml.select, this);
36872 this.menu.un("show", ml.show, this);
36873 this.menu.un("hide", ml.hide, this);
36878 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36879 onTriggerClick : function(){
36883 if(this.menu == null){
36884 this.menu = new Roo.menu.DateMenu();
36886 Roo.apply(this.menu.picker, {
36887 showClear: this.allowBlank,
36888 minDate : this.minValue,
36889 maxDate : this.maxValue,
36890 disabledDatesRE : this.ddMatch,
36891 disabledDatesText : this.disabledDatesText,
36892 disabledDays : this.disabledDays,
36893 disabledDaysText : this.disabledDaysText,
36894 format : this.format,
36895 minText : String.format(this.minText, this.formatDate(this.minValue)),
36896 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
36898 this.menu.on(Roo.apply({}, this.menuListeners, {
36901 this.menu.picker.setValue(this.getValue() || new Date());
36902 this.menu.show(this.el, "tl-bl?");
36905 beforeBlur : function(){
36906 var v = this.parseDate(this.getRawValue());
36912 /** @cfg {Boolean} grow @hide */
36913 /** @cfg {Number} growMin @hide */
36914 /** @cfg {Number} growMax @hide */
36921 * Ext JS Library 1.1.1
36922 * Copyright(c) 2006-2007, Ext JS, LLC.
36924 * Originally Released Under LGPL - original licence link has changed is not relivant.
36927 * <script type="text/javascript">
36932 * @class Roo.form.ComboBox
36933 * @extends Roo.form.TriggerField
36934 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
36936 * Create a new ComboBox.
36937 * @param {Object} config Configuration options
36939 Roo.form.ComboBox = function(config){
36940 Roo.form.ComboBox.superclass.constructor.call(this, config);
36944 * Fires when the dropdown list is expanded
36945 * @param {Roo.form.ComboBox} combo This combo box
36950 * Fires when the dropdown list is collapsed
36951 * @param {Roo.form.ComboBox} combo This combo box
36955 * @event beforeselect
36956 * Fires before a list item is selected. Return false to cancel the selection.
36957 * @param {Roo.form.ComboBox} combo This combo box
36958 * @param {Roo.data.Record} record The data record returned from the underlying store
36959 * @param {Number} index The index of the selected item in the dropdown list
36961 'beforeselect' : true,
36964 * Fires when a list item is selected
36965 * @param {Roo.form.ComboBox} combo This combo box
36966 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
36967 * @param {Number} index The index of the selected item in the dropdown list
36971 * @event beforequery
36972 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
36973 * The event object passed has these properties:
36974 * @param {Roo.form.ComboBox} combo This combo box
36975 * @param {String} query The query
36976 * @param {Boolean} forceAll true to force "all" query
36977 * @param {Boolean} cancel true to cancel the query
36978 * @param {Object} e The query event object
36980 'beforequery': true,
36983 * Fires when the 'add' icon is pressed (add a listener to enable add button)
36984 * @param {Roo.form.ComboBox} combo This combo box
36989 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
36990 * @param {Roo.form.ComboBox} combo This combo box
36991 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
36997 if(this.transform){
36998 this.allowDomMove = false;
36999 var s = Roo.getDom(this.transform);
37000 if(!this.hiddenName){
37001 this.hiddenName = s.name;
37004 this.mode = 'local';
37005 var d = [], opts = s.options;
37006 for(var i = 0, len = opts.length;i < len; i++){
37008 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37010 this.value = value;
37012 d.push([value, o.text]);
37014 this.store = new Roo.data.SimpleStore({
37016 fields: ['value', 'text'],
37019 this.valueField = 'value';
37020 this.displayField = 'text';
37022 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37023 if(!this.lazyRender){
37024 this.target = true;
37025 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37026 s.parentNode.removeChild(s); // remove it
37027 this.render(this.el.parentNode);
37029 s.parentNode.removeChild(s); // remove it
37034 this.store = Roo.factory(this.store, Roo.data);
37037 this.selectedIndex = -1;
37038 if(this.mode == 'local'){
37039 if(config.queryDelay === undefined){
37040 this.queryDelay = 10;
37042 if(config.minChars === undefined){
37048 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37050 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37053 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37054 * rendering into an Roo.Editor, defaults to false)
37057 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37058 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37061 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37064 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37065 * the dropdown list (defaults to undefined, with no header element)
37069 * @cfg {String/Roo.Template} tpl The template to use to render the output
37073 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37075 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37077 listWidth: undefined,
37079 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37080 * mode = 'remote' or 'text' if mode = 'local')
37082 displayField: undefined,
37084 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37085 * mode = 'remote' or 'value' if mode = 'local').
37086 * Note: use of a valueField requires the user make a selection
37087 * in order for a value to be mapped.
37089 valueField: undefined,
37091 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37092 * field's data value (defaults to the underlying DOM element's name)
37094 hiddenName: undefined,
37096 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37100 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37102 selectedClass: 'x-combo-selected',
37104 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37105 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37106 * which displays a downward arrow icon).
37108 triggerClass : 'x-form-arrow-trigger',
37110 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37114 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37115 * anchor positions (defaults to 'tl-bl')
37117 listAlign: 'tl-bl?',
37119 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37123 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37124 * query specified by the allQuery config option (defaults to 'query')
37126 triggerAction: 'query',
37128 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37129 * (defaults to 4, does not apply if editable = false)
37133 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37134 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37138 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37139 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37143 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37144 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37148 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37149 * when editable = true (defaults to false)
37151 selectOnFocus:false,
37153 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37155 queryParam: 'query',
37157 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37158 * when mode = 'remote' (defaults to 'Loading...')
37160 loadingText: 'Loading...',
37162 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37166 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37170 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37171 * traditional select (defaults to true)
37175 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37179 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37183 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37184 * listWidth has a higher value)
37188 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37189 * allow the user to set arbitrary text into the field (defaults to false)
37191 forceSelection:false,
37193 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37194 * if typeAhead = true (defaults to 250)
37196 typeAheadDelay : 250,
37198 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37199 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37201 valueNotFoundText : undefined,
37203 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37205 blockFocus : false,
37208 * @cfg {Boolean} disableClear Disable showing of clear button.
37210 disableClear : false,
37212 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37214 alwaysQuery : false,
37222 onRender : function(ct, position){
37223 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37224 if(this.hiddenName){
37225 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37227 this.hiddenField.value =
37228 this.hiddenValue !== undefined ? this.hiddenValue :
37229 this.value !== undefined ? this.value : '';
37231 // prevent input submission
37232 this.el.dom.removeAttribute('name');
37235 this.el.dom.setAttribute('autocomplete', 'off');
37238 var cls = 'x-combo-list';
37240 this.list = new Roo.Layer({
37241 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37244 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37245 this.list.setWidth(lw);
37246 this.list.swallowEvent('mousewheel');
37247 this.assetHeight = 0;
37250 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37251 this.assetHeight += this.header.getHeight();
37254 this.innerList = this.list.createChild({cls:cls+'-inner'});
37255 this.innerList.on('mouseover', this.onViewOver, this);
37256 this.innerList.on('mousemove', this.onViewMove, this);
37257 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37259 if(this.allowBlank && !this.pageSize && !this.disableClear){
37260 this.footer = this.list.createChild({cls:cls+'-ft'});
37261 this.pageTb = new Roo.Toolbar(this.footer);
37265 this.footer = this.list.createChild({cls:cls+'-ft'});
37266 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37267 {pageSize: this.pageSize});
37271 if (this.pageTb && this.allowBlank && !this.disableClear) {
37273 this.pageTb.add(new Roo.Toolbar.Fill(), {
37274 cls: 'x-btn-icon x-btn-clear',
37276 handler: function()
37279 _this.clearValue();
37280 _this.onSelect(false, -1);
37285 this.assetHeight += this.footer.getHeight();
37290 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37293 this.view = new Roo.View(this.innerList, this.tpl, {
37294 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37297 this.view.on('click', this.onViewClick, this);
37299 this.store.on('beforeload', this.onBeforeLoad, this);
37300 this.store.on('load', this.onLoad, this);
37301 this.store.on('loadexception', this.collapse, this);
37303 if(this.resizable){
37304 this.resizer = new Roo.Resizable(this.list, {
37305 pinned:true, handles:'se'
37307 this.resizer.on('resize', function(r, w, h){
37308 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37309 this.listWidth = w;
37310 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37311 this.restrictHeight();
37313 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37315 if(!this.editable){
37316 this.editable = true;
37317 this.setEditable(false);
37321 if (typeof(this.events.add.listeners) != 'undefined') {
37323 this.addicon = this.wrap.createChild(
37324 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37326 this.addicon.on('click', function(e) {
37327 this.fireEvent('add', this);
37330 if (typeof(this.events.edit.listeners) != 'undefined') {
37332 this.editicon = this.wrap.createChild(
37333 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37334 if (this.addicon) {
37335 this.editicon.setStyle('margin-left', '40px');
37337 this.editicon.on('click', function(e) {
37339 // we fire even if inothing is selected..
37340 this.fireEvent('edit', this, this.lastData );
37350 initEvents : function(){
37351 Roo.form.ComboBox.superclass.initEvents.call(this);
37353 this.keyNav = new Roo.KeyNav(this.el, {
37354 "up" : function(e){
37355 this.inKeyMode = true;
37359 "down" : function(e){
37360 if(!this.isExpanded()){
37361 this.onTriggerClick();
37363 this.inKeyMode = true;
37368 "enter" : function(e){
37369 this.onViewClick();
37373 "esc" : function(e){
37377 "tab" : function(e){
37378 this.onViewClick(false);
37384 doRelay : function(foo, bar, hname){
37385 if(hname == 'down' || this.scope.isExpanded()){
37386 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37393 this.queryDelay = Math.max(this.queryDelay || 10,
37394 this.mode == 'local' ? 10 : 250);
37395 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37396 if(this.typeAhead){
37397 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37399 if(this.editable !== false){
37400 this.el.on("keyup", this.onKeyUp, this);
37402 if(this.forceSelection){
37403 this.on('blur', this.doForce, this);
37407 onDestroy : function(){
37409 this.view.setStore(null);
37410 this.view.el.removeAllListeners();
37411 this.view.el.remove();
37412 this.view.purgeListeners();
37415 this.list.destroy();
37418 this.store.un('beforeload', this.onBeforeLoad, this);
37419 this.store.un('load', this.onLoad, this);
37420 this.store.un('loadexception', this.collapse, this);
37422 Roo.form.ComboBox.superclass.onDestroy.call(this);
37426 fireKey : function(e){
37427 if(e.isNavKeyPress() && !this.list.isVisible()){
37428 this.fireEvent("specialkey", this, e);
37433 onResize: function(w, h){
37434 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37436 if(typeof w != 'number'){
37437 // we do not handle it!?!?
37440 var tw = this.trigger.getWidth();
37441 tw += this.addicon ? this.addicon.getWidth() : 0;
37442 tw += this.editicon ? this.editicon.getWidth() : 0;
37444 this.el.setWidth( this.adjustWidth('input', x));
37446 this.trigger.setStyle('left', x+'px');
37448 if(this.list && this.listWidth === undefined){
37449 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37450 this.list.setWidth(lw);
37451 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37459 * Allow or prevent the user from directly editing the field text. If false is passed,
37460 * the user will only be able to select from the items defined in the dropdown list. This method
37461 * is the runtime equivalent of setting the 'editable' config option at config time.
37462 * @param {Boolean} value True to allow the user to directly edit the field text
37464 setEditable : function(value){
37465 if(value == this.editable){
37468 this.editable = value;
37470 this.el.dom.setAttribute('readOnly', true);
37471 this.el.on('mousedown', this.onTriggerClick, this);
37472 this.el.addClass('x-combo-noedit');
37474 this.el.dom.setAttribute('readOnly', false);
37475 this.el.un('mousedown', this.onTriggerClick, this);
37476 this.el.removeClass('x-combo-noedit');
37481 onBeforeLoad : function(){
37482 if(!this.hasFocus){
37485 this.innerList.update(this.loadingText ?
37486 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37487 this.restrictHeight();
37488 this.selectedIndex = -1;
37492 onLoad : function(){
37493 if(!this.hasFocus){
37496 if(this.store.getCount() > 0){
37498 this.restrictHeight();
37499 if(this.lastQuery == this.allQuery){
37501 this.el.dom.select();
37503 if(!this.selectByValue(this.value, true)){
37504 this.select(0, true);
37508 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37509 this.taTask.delay(this.typeAheadDelay);
37513 this.onEmptyResults();
37519 onTypeAhead : function(){
37520 if(this.store.getCount() > 0){
37521 var r = this.store.getAt(0);
37522 var newValue = r.data[this.displayField];
37523 var len = newValue.length;
37524 var selStart = this.getRawValue().length;
37525 if(selStart != len){
37526 this.setRawValue(newValue);
37527 this.selectText(selStart, newValue.length);
37533 onSelect : function(record, index){
37534 if(this.fireEvent('beforeselect', this, record, index) !== false){
37535 this.setFromData(index > -1 ? record.data : false);
37537 this.fireEvent('select', this, record, index);
37542 * Returns the currently selected field value or empty string if no value is set.
37543 * @return {String} value The selected value
37545 getValue : function(){
37546 if(this.valueField){
37547 return typeof this.value != 'undefined' ? this.value : '';
37549 return Roo.form.ComboBox.superclass.getValue.call(this);
37554 * Clears any text/value currently set in the field
37556 clearValue : function(){
37557 if(this.hiddenField){
37558 this.hiddenField.value = '';
37561 this.setRawValue('');
37562 this.lastSelectionText = '';
37563 this.applyEmptyText();
37567 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37568 * will be displayed in the field. If the value does not match the data value of an existing item,
37569 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37570 * Otherwise the field will be blank (although the value will still be set).
37571 * @param {String} value The value to match
37573 setValue : function(v){
37575 if(this.valueField){
37576 var r = this.findRecord(this.valueField, v);
37578 text = r.data[this.displayField];
37579 }else if(this.valueNotFoundText !== undefined){
37580 text = this.valueNotFoundText;
37583 this.lastSelectionText = text;
37584 if(this.hiddenField){
37585 this.hiddenField.value = v;
37587 Roo.form.ComboBox.superclass.setValue.call(this, text);
37591 * @property {Object} the last set data for the element
37596 * Sets the value of the field based on a object which is related to the record format for the store.
37597 * @param {Object} value the value to set as. or false on reset?
37599 setFromData : function(o){
37600 var dv = ''; // display value
37601 var vv = ''; // value value..
37603 if (this.displayField) {
37604 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37606 // this is an error condition!!!
37607 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37610 if(this.valueField){
37611 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37613 if(this.hiddenField){
37614 this.hiddenField.value = vv;
37616 this.lastSelectionText = dv;
37617 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37621 // no hidden field.. - we store the value in 'value', but still display
37622 // display field!!!!
37623 this.lastSelectionText = dv;
37624 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37630 reset : function(){
37631 // overridden so that last data is reset..
37632 this.setValue(this.originalValue);
37633 this.clearInvalid();
37634 this.lastData = false;
37637 findRecord : function(prop, value){
37639 if(this.store.getCount() > 0){
37640 this.store.each(function(r){
37641 if(r.data[prop] == value){
37651 onViewMove : function(e, t){
37652 this.inKeyMode = false;
37656 onViewOver : function(e, t){
37657 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37660 var item = this.view.findItemFromChild(t);
37662 var index = this.view.indexOf(item);
37663 this.select(index, false);
37668 onViewClick : function(doFocus){
37669 var index = this.view.getSelectedIndexes()[0];
37670 var r = this.store.getAt(index);
37672 this.onSelect(r, index);
37674 if(doFocus !== false && !this.blockFocus){
37680 restrictHeight : function(){
37681 this.innerList.dom.style.height = '';
37682 var inner = this.innerList.dom;
37683 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37684 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37685 this.list.beginUpdate();
37686 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37687 this.list.alignTo(this.el, this.listAlign);
37688 this.list.endUpdate();
37692 onEmptyResults : function(){
37697 * Returns true if the dropdown list is expanded, else false.
37699 isExpanded : function(){
37700 return this.list.isVisible();
37704 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37705 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37706 * @param {String} value The data value of the item to select
37707 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37708 * selected item if it is not currently in view (defaults to true)
37709 * @return {Boolean} True if the value matched an item in the list, else false
37711 selectByValue : function(v, scrollIntoView){
37712 if(v !== undefined && v !== null){
37713 var r = this.findRecord(this.valueField || this.displayField, v);
37715 this.select(this.store.indexOf(r), scrollIntoView);
37723 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37724 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37725 * @param {Number} index The zero-based index of the list item to select
37726 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37727 * selected item if it is not currently in view (defaults to true)
37729 select : function(index, scrollIntoView){
37730 this.selectedIndex = index;
37731 this.view.select(index);
37732 if(scrollIntoView !== false){
37733 var el = this.view.getNode(index);
37735 this.innerList.scrollChildIntoView(el, false);
37741 selectNext : function(){
37742 var ct = this.store.getCount();
37744 if(this.selectedIndex == -1){
37746 }else if(this.selectedIndex < ct-1){
37747 this.select(this.selectedIndex+1);
37753 selectPrev : function(){
37754 var ct = this.store.getCount();
37756 if(this.selectedIndex == -1){
37758 }else if(this.selectedIndex != 0){
37759 this.select(this.selectedIndex-1);
37765 onKeyUp : function(e){
37766 if(this.editable !== false && !e.isSpecialKey()){
37767 this.lastKey = e.getKey();
37768 this.dqTask.delay(this.queryDelay);
37773 validateBlur : function(){
37774 return !this.list || !this.list.isVisible();
37778 initQuery : function(){
37779 this.doQuery(this.getRawValue());
37783 doForce : function(){
37784 if(this.el.dom.value.length > 0){
37785 this.el.dom.value =
37786 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37787 this.applyEmptyText();
37792 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37793 * query allowing the query action to be canceled if needed.
37794 * @param {String} query The SQL query to execute
37795 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37796 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37797 * saved in the current store (defaults to false)
37799 doQuery : function(q, forceAll){
37800 if(q === undefined || q === null){
37805 forceAll: forceAll,
37809 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37813 forceAll = qe.forceAll;
37814 if(forceAll === true || (q.length >= this.minChars)){
37815 if(this.lastQuery != q || this.alwaysQuery){
37816 this.lastQuery = q;
37817 if(this.mode == 'local'){
37818 this.selectedIndex = -1;
37820 this.store.clearFilter();
37822 this.store.filter(this.displayField, q);
37826 this.store.baseParams[this.queryParam] = q;
37828 params: this.getParams(q)
37833 this.selectedIndex = -1;
37840 getParams : function(q){
37842 //p[this.queryParam] = q;
37845 p.limit = this.pageSize;
37851 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37853 collapse : function(){
37854 if(!this.isExpanded()){
37858 Roo.get(document).un('mousedown', this.collapseIf, this);
37859 Roo.get(document).un('mousewheel', this.collapseIf, this);
37860 if (!this.editable) {
37861 Roo.get(document).un('keydown', this.listKeyPress, this);
37863 this.fireEvent('collapse', this);
37867 collapseIf : function(e){
37868 if(!e.within(this.wrap) && !e.within(this.list)){
37874 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37876 expand : function(){
37877 if(this.isExpanded() || !this.hasFocus){
37880 this.list.alignTo(this.el, this.listAlign);
37882 Roo.get(document).on('mousedown', this.collapseIf, this);
37883 Roo.get(document).on('mousewheel', this.collapseIf, this);
37884 if (!this.editable) {
37885 Roo.get(document).on('keydown', this.listKeyPress, this);
37888 this.fireEvent('expand', this);
37892 // Implements the default empty TriggerField.onTriggerClick function
37893 onTriggerClick : function(){
37897 if(this.isExpanded()){
37899 if (!this.blockFocus) {
37904 this.hasFocus = true;
37905 if(this.triggerAction == 'all') {
37906 this.doQuery(this.allQuery, true);
37908 this.doQuery(this.getRawValue());
37910 if (!this.blockFocus) {
37915 listKeyPress : function(e)
37917 //Roo.log('listkeypress');
37918 // scroll to first matching element based on key pres..
37919 if (e.isSpecialKey()) {
37922 var k = String.fromCharCode(e.getKey()).toUpperCase();
37925 var csel = this.view.getSelectedNodes();
37926 var cselitem = false;
37928 var ix = this.view.indexOf(csel[0]);
37929 cselitem = this.store.getAt(ix);
37930 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
37936 this.store.each(function(v) {
37938 // start at existing selection.
37939 if (cselitem.id == v.id) {
37945 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
37946 match = this.store.indexOf(v);
37951 if (match === false) {
37952 return true; // no more action?
37955 this.view.select(match);
37956 var sn = Roo.get(this.view.getSelectedNodes()[0])
37957 sn.scrollIntoView(sn.dom.parentNode, false);
37961 * @cfg {Boolean} grow
37965 * @cfg {Number} growMin
37969 * @cfg {Number} growMax
37978 * Ext JS Library 1.1.1
37979 * Copyright(c) 2006-2007, Ext JS, LLC.
37981 * Originally Released Under LGPL - original licence link has changed is not relivant.
37984 * <script type="text/javascript">
37987 * @class Roo.form.Checkbox
37988 * @extends Roo.form.Field
37989 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
37991 * Creates a new Checkbox
37992 * @param {Object} config Configuration options
37994 Roo.form.Checkbox = function(config){
37995 Roo.form.Checkbox.superclass.constructor.call(this, config);
37999 * Fires when the checkbox is checked or unchecked.
38000 * @param {Roo.form.Checkbox} this This checkbox
38001 * @param {Boolean} checked The new checked value
38007 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38009 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38011 focusClass : undefined,
38013 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38015 fieldClass: "x-form-field",
38017 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38021 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38022 * {tag: "input", type: "checkbox", autocomplete: "off"})
38024 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38026 * @cfg {String} boxLabel The text that appears beside the checkbox
38030 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38034 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38036 valueOff: '0', // value when not checked..
38038 actionMode : 'viewEl',
38041 itemCls : 'x-menu-check-item x-form-item',
38042 groupClass : 'x-menu-group-item',
38043 inputType : 'hidden',
38046 inSetChecked: false, // check that we are not calling self...
38048 inputElement: false, // real input element?
38049 basedOn: false, // ????
38051 isFormField: true, // not sure where this is needed!!!!
38053 onResize : function(){
38054 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38055 if(!this.boxLabel){
38056 this.el.alignTo(this.wrap, 'c-c');
38060 initEvents : function(){
38061 Roo.form.Checkbox.superclass.initEvents.call(this);
38062 this.el.on("click", this.onClick, this);
38063 this.el.on("change", this.onClick, this);
38067 getResizeEl : function(){
38071 getPositionEl : function(){
38076 onRender : function(ct, position){
38077 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38079 if(this.inputValue !== undefined){
38080 this.el.dom.value = this.inputValue;
38083 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38084 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38085 var viewEl = this.wrap.createChild({
38086 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38087 this.viewEl = viewEl;
38088 this.wrap.on('click', this.onClick, this);
38090 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38091 this.el.on('propertychange', this.setFromHidden, this); //ie
38096 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38097 // viewEl.on('click', this.onClick, this);
38099 //if(this.checked){
38100 this.setChecked(this.checked);
38102 //this.checked = this.el.dom;
38108 initValue : Roo.emptyFn,
38111 * Returns the checked state of the checkbox.
38112 * @return {Boolean} True if checked, else false
38114 getValue : function(){
38116 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38118 return this.valueOff;
38123 onClick : function(){
38124 this.setChecked(!this.checked);
38126 //if(this.el.dom.checked != this.checked){
38127 // this.setValue(this.el.dom.checked);
38132 * Sets the checked state of the checkbox.
38133 * On is always based on a string comparison between inputValue and the param.
38134 * @param {Boolean/String} value - the value to set
38135 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38137 setValue : function(v,suppressEvent){
38140 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38141 //if(this.el && this.el.dom){
38142 // this.el.dom.checked = this.checked;
38143 // this.el.dom.defaultChecked = this.checked;
38145 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38146 //this.fireEvent("check", this, this.checked);
38149 setChecked : function(state,suppressEvent)
38151 if (this.inSetChecked) {
38152 this.checked = state;
38158 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38160 this.checked = state;
38161 if(suppressEvent !== true){
38162 this.fireEvent('check', this, state);
38164 this.inSetChecked = true;
38165 this.el.dom.value = state ? this.inputValue : this.valueOff;
38166 this.inSetChecked = false;
38169 // handle setting of hidden value by some other method!!?!?
38170 setFromHidden: function()
38175 //console.log("SET FROM HIDDEN");
38176 //alert('setFrom hidden');
38177 this.setValue(this.el.dom.value);
38180 onDestroy : function()
38183 Roo.get(this.viewEl).remove();
38186 Roo.form.Checkbox.superclass.onDestroy.call(this);
38191 * Ext JS Library 1.1.1
38192 * Copyright(c) 2006-2007, Ext JS, LLC.
38194 * Originally Released Under LGPL - original licence link has changed is not relivant.
38197 * <script type="text/javascript">
38201 * @class Roo.form.Radio
38202 * @extends Roo.form.Checkbox
38203 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38204 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38206 * Creates a new Radio
38207 * @param {Object} config Configuration options
38209 Roo.form.Radio = function(){
38210 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38212 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38213 inputType: 'radio',
38216 * If this radio is part of a group, it will return the selected value
38219 getGroupValue : function(){
38220 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38222 });//<script type="text/javascript">
38225 * Ext JS Library 1.1.1
38226 * Copyright(c) 2006-2007, Ext JS, LLC.
38227 * licensing@extjs.com
38229 * http://www.extjs.com/license
38235 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38236 * - IE ? - no idea how much works there.
38244 * @class Ext.form.HtmlEditor
38245 * @extends Ext.form.Field
38246 * Provides a lightweight HTML Editor component.
38247 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38249 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38250 * supported by this editor.</b><br/><br/>
38251 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38252 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38254 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38256 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38260 * @cfg {String} createLinkText The default text for the create link prompt
38262 createLinkText : 'Please enter the URL for the link:',
38264 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38266 defaultLinkValue : 'http:/'+'/',
38272 // private properties
38273 validationEvent : false,
38275 initialized : false,
38277 sourceEditMode : false,
38278 onFocus : Roo.emptyFn,
38280 hideMode:'offsets',
38281 defaultAutoCreate : {
38283 style:"width:500px;height:300px;",
38284 autocomplete: "off"
38288 initComponent : function(){
38291 * @event initialize
38292 * Fires when the editor is fully initialized (including the iframe)
38293 * @param {HtmlEditor} this
38298 * Fires when the editor is first receives the focus. Any insertion must wait
38299 * until after this event.
38300 * @param {HtmlEditor} this
38304 * @event beforesync
38305 * Fires before the textarea is updated with content from the editor iframe. Return false
38306 * to cancel the sync.
38307 * @param {HtmlEditor} this
38308 * @param {String} html
38312 * @event beforepush
38313 * Fires before the iframe editor is updated with content from the textarea. Return false
38314 * to cancel the push.
38315 * @param {HtmlEditor} this
38316 * @param {String} html
38321 * Fires when the textarea is updated with content from the editor iframe.
38322 * @param {HtmlEditor} this
38323 * @param {String} html
38328 * Fires when the iframe editor is updated with content from the textarea.
38329 * @param {HtmlEditor} this
38330 * @param {String} html
38334 * @event editmodechange
38335 * Fires when the editor switches edit modes
38336 * @param {HtmlEditor} this
38337 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38339 editmodechange: true,
38341 * @event editorevent
38342 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38343 * @param {HtmlEditor} this
38350 * Protected method that will not generally be called directly. It
38351 * is called when the editor creates its toolbar. Override this method if you need to
38352 * add custom toolbar buttons.
38353 * @param {HtmlEditor} editor
38355 createToolbar : function(editor){
38356 if (!editor.toolbars || !editor.toolbars.length) {
38357 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38360 for (var i =0 ; i < editor.toolbars.length;i++) {
38361 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38362 editor.toolbars[i].init(editor);
38369 * Protected method that will not generally be called directly. It
38370 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38371 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38373 getDocMarkup : function(){
38374 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
38378 onRender : function(ct, position){
38379 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38380 this.el.dom.style.border = '0 none';
38381 this.el.dom.setAttribute('tabIndex', -1);
38382 this.el.addClass('x-hidden');
38383 if(Roo.isIE){ // fix IE 1px bogus margin
38384 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38386 this.wrap = this.el.wrap({
38387 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38390 this.frameId = Roo.id();
38391 this.createToolbar(this);
38398 var iframe = this.wrap.createChild({
38401 name: this.frameId,
38402 frameBorder : 'no',
38403 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38406 // console.log(iframe);
38407 //this.wrap.dom.appendChild(iframe);
38409 this.iframe = iframe.dom;
38411 this.assignDocWin();
38413 this.doc.designMode = 'on';
38416 this.doc.write(this.getDocMarkup());
38420 var task = { // must defer to wait for browser to be ready
38422 //console.log("run task?" + this.doc.readyState);
38423 this.assignDocWin();
38424 if(this.doc.body || this.doc.readyState == 'complete'){
38426 this.doc.designMode="on";
38430 Roo.TaskMgr.stop(task);
38431 this.initEditor.defer(10, this);
38438 Roo.TaskMgr.start(task);
38441 this.setSize(this.el.getSize());
38446 onResize : function(w, h){
38447 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38448 if(this.el && this.iframe){
38449 if(typeof w == 'number'){
38450 var aw = w - this.wrap.getFrameWidth('lr');
38451 this.el.setWidth(this.adjustWidth('textarea', aw));
38452 this.iframe.style.width = aw + 'px';
38454 if(typeof h == 'number'){
38456 for (var i =0; i < this.toolbars.length;i++) {
38457 // fixme - ask toolbars for heights?
38458 tbh += this.toolbars[i].tb.el.getHeight();
38464 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38465 this.el.setHeight(this.adjustWidth('textarea', ah));
38466 this.iframe.style.height = ah + 'px';
38468 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38475 * Toggles the editor between standard and source edit mode.
38476 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38478 toggleSourceEdit : function(sourceEditMode){
38480 this.sourceEditMode = sourceEditMode === true;
38482 if(this.sourceEditMode){
38485 this.iframe.className = 'x-hidden';
38486 this.el.removeClass('x-hidden');
38487 this.el.dom.removeAttribute('tabIndex');
38492 this.iframe.className = '';
38493 this.el.addClass('x-hidden');
38494 this.el.dom.setAttribute('tabIndex', -1);
38497 this.setSize(this.wrap.getSize());
38498 this.fireEvent('editmodechange', this, this.sourceEditMode);
38501 // private used internally
38502 createLink : function(){
38503 var url = prompt(this.createLinkText, this.defaultLinkValue);
38504 if(url && url != 'http:/'+'/'){
38505 this.relayCmd('createlink', url);
38509 // private (for BoxComponent)
38510 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38512 // private (for BoxComponent)
38513 getResizeEl : function(){
38517 // private (for BoxComponent)
38518 getPositionEl : function(){
38523 initEvents : function(){
38524 this.originalValue = this.getValue();
38528 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38531 markInvalid : Roo.emptyFn,
38533 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38536 clearInvalid : Roo.emptyFn,
38538 setValue : function(v){
38539 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38544 * Protected method that will not generally be called directly. If you need/want
38545 * custom HTML cleanup, this is the method you should override.
38546 * @param {String} html The HTML to be cleaned
38547 * return {String} The cleaned HTML
38549 cleanHtml : function(html){
38550 html = String(html);
38551 if(html.length > 5){
38552 if(Roo.isSafari){ // strip safari nonsense
38553 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38556 if(html == ' '){
38563 * Protected method that will not generally be called directly. Syncs the contents
38564 * of the editor iframe with the textarea.
38566 syncValue : function(){
38567 if(this.initialized){
38568 var bd = (this.doc.body || this.doc.documentElement);
38569 var html = bd.innerHTML;
38571 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38572 var m = bs.match(/text-align:(.*?);/i);
38574 html = '<div style="'+m[0]+'">' + html + '</div>';
38577 html = this.cleanHtml(html);
38578 if(this.fireEvent('beforesync', this, html) !== false){
38579 this.el.dom.value = html;
38580 this.fireEvent('sync', this, html);
38586 * Protected method that will not generally be called directly. Pushes the value of the textarea
38587 * into the iframe editor.
38589 pushValue : function(){
38590 if(this.initialized){
38591 var v = this.el.dom.value;
38595 if(this.fireEvent('beforepush', this, v) !== false){
38596 (this.doc.body || this.doc.documentElement).innerHTML = v;
38597 this.fireEvent('push', this, v);
38603 deferFocus : function(){
38604 this.focus.defer(10, this);
38608 focus : function(){
38609 if(this.win && !this.sourceEditMode){
38616 assignDocWin: function()
38618 var iframe = this.iframe;
38621 this.doc = iframe.contentWindow.document;
38622 this.win = iframe.contentWindow;
38624 if (!Roo.get(this.frameId)) {
38627 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38628 this.win = Roo.get(this.frameId).dom.contentWindow;
38633 initEditor : function(){
38634 //console.log("INIT EDITOR");
38635 this.assignDocWin();
38639 this.doc.designMode="on";
38641 this.doc.write(this.getDocMarkup());
38644 var dbody = (this.doc.body || this.doc.documentElement);
38645 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38646 // this copies styles from the containing element into thsi one..
38647 // not sure why we need all of this..
38648 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38649 ss['background-attachment'] = 'fixed'; // w3c
38650 dbody.bgProperties = 'fixed'; // ie
38651 Roo.DomHelper.applyStyles(dbody, ss);
38652 Roo.EventManager.on(this.doc, {
38653 'mousedown': this.onEditorEvent,
38654 'dblclick': this.onEditorEvent,
38655 'click': this.onEditorEvent,
38656 'keyup': this.onEditorEvent,
38661 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
38663 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38664 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38666 this.initialized = true;
38668 this.fireEvent('initialize', this);
38673 onDestroy : function(){
38679 for (var i =0; i < this.toolbars.length;i++) {
38680 // fixme - ask toolbars for heights?
38681 this.toolbars[i].onDestroy();
38684 this.wrap.dom.innerHTML = '';
38685 this.wrap.remove();
38690 onFirstFocus : function(){
38692 this.assignDocWin();
38695 this.activated = true;
38696 for (var i =0; i < this.toolbars.length;i++) {
38697 this.toolbars[i].onFirstFocus();
38700 if(Roo.isGecko){ // prevent silly gecko errors
38702 var s = this.win.getSelection();
38703 if(!s.focusNode || s.focusNode.nodeType != 3){
38704 var r = s.getRangeAt(0);
38705 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38710 this.execCmd('useCSS', true);
38711 this.execCmd('styleWithCSS', false);
38714 this.fireEvent('activate', this);
38718 adjustFont: function(btn){
38719 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38720 //if(Roo.isSafari){ // safari
38723 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38724 if(Roo.isSafari){ // safari
38725 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38726 v = (v < 10) ? 10 : v;
38727 v = (v > 48) ? 48 : v;
38728 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38733 v = Math.max(1, v+adjust);
38735 this.execCmd('FontSize', v );
38738 onEditorEvent : function(e){
38739 this.fireEvent('editorevent', this, e);
38740 // this.updateToolbar();
38744 insertTag : function(tg)
38746 // could be a bit smarter... -> wrap the current selected tRoo..
38748 this.execCmd("formatblock", tg);
38752 insertText : function(txt)
38756 range = this.createRange();
38757 range.deleteContents();
38758 //alert(Sender.getAttribute('label'));
38760 range.insertNode(this.doc.createTextNode(txt));
38764 relayBtnCmd : function(btn){
38765 this.relayCmd(btn.cmd);
38769 * Executes a Midas editor command on the editor document and performs necessary focus and
38770 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38771 * @param {String} cmd The Midas command
38772 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38774 relayCmd : function(cmd, value){
38776 this.execCmd(cmd, value);
38777 this.fireEvent('editorevent', this);
38778 //this.updateToolbar();
38783 * Executes a Midas editor command directly on the editor document.
38784 * For visual commands, you should use {@link #relayCmd} instead.
38785 * <b>This should only be called after the editor is initialized.</b>
38786 * @param {String} cmd The Midas command
38787 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38789 execCmd : function(cmd, value){
38790 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38796 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38798 * @param {String} text
38800 insertAtCursor : function(text){
38801 if(!this.activated){
38806 var r = this.doc.selection.createRange();
38813 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
38815 this.execCmd('InsertHTML', text);
38820 mozKeyPress : function(e){
38822 var c = e.getCharCode(), cmd;
38825 c = String.fromCharCode(c).toLowerCase();
38836 this.cleanUpPaste.defer(100, this);
38844 e.preventDefault();
38852 fixKeys : function(){ // load time branching for fastest keydown performance
38854 return function(e){
38855 var k = e.getKey(), r;
38858 r = this.doc.selection.createRange();
38861 r.pasteHTML('    ');
38868 r = this.doc.selection.createRange();
38870 var target = r.parentElement();
38871 if(!target || target.tagName.toLowerCase() != 'li'){
38873 r.pasteHTML('<br />');
38879 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38880 this.cleanUpPaste.defer(100, this);
38886 }else if(Roo.isOpera){
38887 return function(e){
38888 var k = e.getKey();
38892 this.execCmd('InsertHTML','    ');
38895 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38896 this.cleanUpPaste.defer(100, this);
38901 }else if(Roo.isSafari){
38902 return function(e){
38903 var k = e.getKey();
38907 this.execCmd('InsertText','\t');
38911 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38912 this.cleanUpPaste.defer(100, this);
38920 getAllAncestors: function()
38922 var p = this.getSelectedNode();
38925 a.push(p); // push blank onto stack..
38926 p = this.getParentElement();
38930 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
38934 a.push(this.doc.body);
38938 lastSelNode : false,
38941 getSelection : function()
38943 this.assignDocWin();
38944 return Roo.isIE ? this.doc.selection : this.win.getSelection();
38947 getSelectedNode: function()
38949 // this may only work on Gecko!!!
38951 // should we cache this!!!!
38956 var range = this.createRange(this.getSelection());
38959 var parent = range.parentElement();
38961 var testRange = range.duplicate();
38962 testRange.moveToElementText(parent);
38963 if (testRange.inRange(range)) {
38966 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
38969 parent = parent.parentElement;
38975 var ar = range.endContainer.childNodes;
38977 ar = range.commonAncestorContainer.childNodes;
38978 //alert(ar.length);
38981 var other_nodes = [];
38982 var has_other_nodes = false;
38983 for (var i=0;i<ar.length;i++) {
38984 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
38987 // fullly contained node.
38989 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
38994 // probably selected..
38995 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
38996 other_nodes.push(ar[i]);
38999 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39004 has_other_nodes = true;
39006 if (!nodes.length && other_nodes.length) {
39007 nodes= other_nodes;
39009 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39015 createRange: function(sel)
39017 // this has strange effects when using with
39018 // top toolbar - not sure if it's a great idea.
39019 //this.editor.contentWindow.focus();
39020 if (typeof sel != "undefined") {
39022 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39024 return this.doc.createRange();
39027 return this.doc.createRange();
39030 getParentElement: function()
39033 this.assignDocWin();
39034 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39036 var range = this.createRange(sel);
39039 var p = range.commonAncestorContainer;
39040 while (p.nodeType == 3) { // text node
39052 // BC Hacks - cause I cant work out what i was trying to do..
39053 rangeIntersectsNode : function(range, node)
39055 var nodeRange = node.ownerDocument.createRange();
39057 nodeRange.selectNode(node);
39060 nodeRange.selectNodeContents(node);
39063 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
39064 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
39066 rangeCompareNode : function(range, node) {
39067 var nodeRange = node.ownerDocument.createRange();
39069 nodeRange.selectNode(node);
39071 nodeRange.selectNodeContents(node);
39073 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
39074 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
39076 if (nodeIsBefore && !nodeIsAfter)
39078 if (!nodeIsBefore && nodeIsAfter)
39080 if (nodeIsBefore && nodeIsAfter)
39086 // private? - in a new class?
39087 cleanUpPaste : function()
39089 // cleans up the whole document..
39090 // console.log('cleanuppaste');
39091 this.cleanUpChildren(this.doc.body)
39095 cleanUpChildren : function (n)
39097 if (!n.childNodes.length) {
39100 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39101 this.cleanUpChild(n.childNodes[i]);
39108 cleanUpChild : function (node)
39110 //console.log(node);
39111 if (node.nodeName == "#text") {
39112 // clean up silly Windows -- stuff?
39115 if (node.nodeName == "#comment") {
39116 node.parentNode.removeChild(node);
39117 // clean up silly Windows -- stuff?
39121 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39123 node.parentNode.removeChild(node);
39127 if (!node.attributes || !node.attributes.length) {
39128 this.cleanUpChildren(node);
39132 function cleanAttr(n,v)
39135 if (v.match(/^\./) || v.match(/^\//)) {
39138 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39141 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39142 node.removeAttribute(n);
39146 function cleanStyle(n,v)
39148 if (v.match(/expression/)) { //XSS?? should we even bother..
39149 node.removeAttribute(n);
39154 var parts = v.split(/;/);
39155 Roo.each(parts, function(p) {
39156 p = p.replace(/\s+/g,'');
39160 var l = p.split(':').shift().replace(/\s+/g,'');
39162 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39163 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39164 node.removeAttribute(n);
39173 for (var i = node.attributes.length-1; i > -1 ; i--) {
39174 var a = node.attributes[i];
39176 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39177 node.removeAttribute(a.name);
39180 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39181 cleanAttr(a.name,a.value); // fixme..
39184 if (a.name == 'style') {
39185 cleanStyle(a.name,a.value);
39187 /// clean up MS crap..
39188 if (a.name == 'class') {
39189 if (a.value.match(/^Mso/)) {
39190 node.className = '';
39200 this.cleanUpChildren(node);
39206 // hide stuff that is not compatible
39220 * @event specialkey
39224 * @cfg {String} fieldClass @hide
39227 * @cfg {String} focusClass @hide
39230 * @cfg {String} autoCreate @hide
39233 * @cfg {String} inputType @hide
39236 * @cfg {String} invalidClass @hide
39239 * @cfg {String} invalidText @hide
39242 * @cfg {String} msgFx @hide
39245 * @cfg {String} validateOnBlur @hide
39249 Roo.form.HtmlEditor.white = [
39250 'area', 'br', 'img', 'input', 'hr', 'wbr',
39252 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39253 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39254 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39255 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39256 'table', 'ul', 'xmp',
39258 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39261 'dir', 'menu', 'ol', 'ul', 'dl',
39267 Roo.form.HtmlEditor.black = [
39268 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39270 'base', 'basefont', 'bgsound', 'blink', 'body',
39271 'frame', 'frameset', 'head', 'html', 'ilayer',
39272 'iframe', 'layer', 'link', 'meta', 'object',
39273 'script', 'style' ,'title', 'xml' // clean later..
39275 Roo.form.HtmlEditor.clean = [
39276 'script', 'style', 'title', 'xml'
39281 Roo.form.HtmlEditor.ablack = [
39285 Roo.form.HtmlEditor.aclean = [
39286 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39290 Roo.form.HtmlEditor.pwhite= [
39291 'http', 'https', 'mailto'
39294 Roo.form.HtmlEditor.cwhite= [
39299 // <script type="text/javascript">
39302 * Ext JS Library 1.1.1
39303 * Copyright(c) 2006-2007, Ext JS, LLC.
39309 * @class Roo.form.HtmlEditorToolbar1
39314 new Roo.form.HtmlEditor({
39317 new Roo.form.HtmlEditorToolbar1({
39318 disable : { fonts: 1 , format: 1, ..., ... , ...],
39324 * @cfg {Object} disable List of elements to disable..
39325 * @cfg {Array} btns List of additional buttons.
39329 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39332 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39335 Roo.apply(this, config);
39336 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39337 // dont call parent... till later.
39340 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39348 * @cfg {Object} disable List of toolbar elements to disable
39353 * @cfg {Array} fontFamilies An array of available font families
39371 // "á" , ?? a acute?
39376 "°" // , // degrees
39378 // "é" , // e ecute
39379 // "ú" , // u ecute?
39382 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39383 "input:submit", "input:button", "select", "textarea", "label" ],
39386 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39388 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39391 * @cfg {String} defaultFont default font to use.
39393 defaultFont: 'tahoma',
39395 fontSelect : false,
39398 formatCombo : false,
39400 init : function(editor)
39402 this.editor = editor;
39405 var fid = editor.frameId;
39407 function btn(id, toggle, handler){
39408 var xid = fid + '-'+ id ;
39412 cls : 'x-btn-icon x-edit-'+id,
39413 enableToggle:toggle !== false,
39414 scope: editor, // was editor...
39415 handler:handler||editor.relayBtnCmd,
39416 clickEvent:'mousedown',
39417 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39424 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
39426 // stop form submits
39427 tb.el.on('click', function(e){
39428 e.preventDefault(); // what does this do?
39431 if(!this.disable.font && !Roo.isSafari){
39432 /* why no safari for fonts
39433 editor.fontSelect = tb.el.createChild({
39436 cls:'x-font-select',
39437 html: editor.createFontOptions()
39439 editor.fontSelect.on('change', function(){
39440 var font = editor.fontSelect.dom.value;
39441 editor.relayCmd('fontname', font);
39442 editor.deferFocus();
39445 editor.fontSelect.dom,
39450 if(!this.disable.formats){
39451 this.formatCombo = new Roo.form.ComboBox({
39452 store: new Roo.data.SimpleStore({
39455 data : this.formats // from states.js
39458 //autoCreate : {tag: "div", size: "20"},
39459 displayField:'tag',
39463 triggerAction: 'all',
39464 emptyText:'Add tag',
39465 selectOnFocus:true,
39468 'select': function(c, r, i) {
39469 editor.insertTag(r.get('tag'));
39475 tb.addField(this.formatCombo);
39479 if(!this.disable.format){
39486 if(!this.disable.fontSize){
39491 btn('increasefontsize', false, editor.adjustFont),
39492 btn('decreasefontsize', false, editor.adjustFont)
39497 if(this.disable.colors){
39500 id:editor.frameId +'-forecolor',
39501 cls:'x-btn-icon x-edit-forecolor',
39502 clickEvent:'mousedown',
39503 tooltip: this.buttonTips['forecolor'] || undefined,
39505 menu : new Roo.menu.ColorMenu({
39506 allowReselect: true,
39507 focus: Roo.emptyFn,
39510 selectHandler: function(cp, color){
39511 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
39512 editor.deferFocus();
39515 clickEvent:'mousedown'
39518 id:editor.frameId +'backcolor',
39519 cls:'x-btn-icon x-edit-backcolor',
39520 clickEvent:'mousedown',
39521 tooltip: this.buttonTips['backcolor'] || undefined,
39523 menu : new Roo.menu.ColorMenu({
39524 focus: Roo.emptyFn,
39527 allowReselect: true,
39528 selectHandler: function(cp, color){
39530 editor.execCmd('useCSS', false);
39531 editor.execCmd('hilitecolor', color);
39532 editor.execCmd('useCSS', true);
39533 editor.deferFocus();
39535 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
39536 Roo.isSafari || Roo.isIE ? '#'+color : color);
39537 editor.deferFocus();
39541 clickEvent:'mousedown'
39546 // now add all the items...
39549 if(!this.disable.alignments){
39552 btn('justifyleft'),
39553 btn('justifycenter'),
39554 btn('justifyright')
39558 //if(!Roo.isSafari){
39559 if(!this.disable.links){
39562 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
39566 if(!this.disable.lists){
39569 btn('insertorderedlist'),
39570 btn('insertunorderedlist')
39573 if(!this.disable.sourceEdit){
39576 btn('sourceedit', true, function(btn){
39577 this.toggleSourceEdit(btn.pressed);
39584 // special menu.. - needs to be tidied up..
39585 if (!this.disable.special) {
39588 cls: 'x-edit-none',
39593 for (var i =0; i < this.specialChars.length; i++) {
39594 smenu.menu.items.push({
39596 html: this.specialChars[i],
39597 handler: function(a,b) {
39598 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
39611 for(var i =0; i< this.btns.length;i++) {
39612 var b = this.btns[i];
39613 b.cls = 'x-edit-none';
39622 // disable everything...
39624 this.tb.items.each(function(item){
39625 if(item.id != editor.frameId+ '-sourceedit'){
39629 this.rendered = true;
39631 // the all the btns;
39632 editor.on('editorevent', this.updateToolbar, this);
39633 // other toolbars need to implement this..
39634 //editor.on('editmodechange', this.updateToolbar, this);
39640 * Protected method that will not generally be called directly. It triggers
39641 * a toolbar update by reading the markup state of the current selection in the editor.
39643 updateToolbar: function(){
39645 if(!this.editor.activated){
39646 this.editor.onFirstFocus();
39650 var btns = this.tb.items.map,
39651 doc = this.editor.doc,
39652 frameId = this.editor.frameId;
39654 if(!this.disable.font && !Roo.isSafari){
39656 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39657 if(name != this.fontSelect.dom.value){
39658 this.fontSelect.dom.value = name;
39662 if(!this.disable.format){
39663 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39664 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39665 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39667 if(!this.disable.alignments){
39668 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39669 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39670 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39672 if(!Roo.isSafari && !this.disable.lists){
39673 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39674 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39677 var ans = this.editor.getAllAncestors();
39678 if (this.formatCombo) {
39681 var store = this.formatCombo.store;
39682 this.formatCombo.setValue("");
39683 for (var i =0; i < ans.length;i++) {
39684 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
39686 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39694 // hides menus... - so this cant be on a menu...
39695 Roo.menu.MenuMgr.hideAll();
39697 //this.editorsyncValue();
39701 createFontOptions : function(){
39702 var buf = [], fs = this.fontFamilies, ff, lc;
39703 for(var i = 0, len = fs.length; i< len; i++){
39705 lc = ff.toLowerCase();
39707 '<option value="',lc,'" style="font-family:',ff,';"',
39708 (this.defaultFont == lc ? ' selected="true">' : '>'),
39713 return buf.join('');
39716 toggleSourceEdit : function(sourceEditMode){
39717 if(sourceEditMode === undefined){
39718 sourceEditMode = !this.sourceEditMode;
39720 this.sourceEditMode = sourceEditMode === true;
39721 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39722 // just toggle the button?
39723 if(btn.pressed !== this.editor.sourceEditMode){
39724 btn.toggle(this.editor.sourceEditMode);
39728 if(this.sourceEditMode){
39729 this.tb.items.each(function(item){
39730 if(item.cmd != 'sourceedit'){
39736 if(this.initialized){
39737 this.tb.items.each(function(item){
39743 // tell the editor that it's been pressed..
39744 this.editor.toggleSourceEdit(sourceEditMode);
39748 * Object collection of toolbar tooltips for the buttons in the editor. The key
39749 * is the command id associated with that button and the value is a valid QuickTips object.
39754 title: 'Bold (Ctrl+B)',
39755 text: 'Make the selected text bold.',
39756 cls: 'x-html-editor-tip'
39759 title: 'Italic (Ctrl+I)',
39760 text: 'Make the selected text italic.',
39761 cls: 'x-html-editor-tip'
39769 title: 'Bold (Ctrl+B)',
39770 text: 'Make the selected text bold.',
39771 cls: 'x-html-editor-tip'
39774 title: 'Italic (Ctrl+I)',
39775 text: 'Make the selected text italic.',
39776 cls: 'x-html-editor-tip'
39779 title: 'Underline (Ctrl+U)',
39780 text: 'Underline the selected text.',
39781 cls: 'x-html-editor-tip'
39783 increasefontsize : {
39784 title: 'Grow Text',
39785 text: 'Increase the font size.',
39786 cls: 'x-html-editor-tip'
39788 decreasefontsize : {
39789 title: 'Shrink Text',
39790 text: 'Decrease the font size.',
39791 cls: 'x-html-editor-tip'
39794 title: 'Text Highlight Color',
39795 text: 'Change the background color of the selected text.',
39796 cls: 'x-html-editor-tip'
39799 title: 'Font Color',
39800 text: 'Change the color of the selected text.',
39801 cls: 'x-html-editor-tip'
39804 title: 'Align Text Left',
39805 text: 'Align text to the left.',
39806 cls: 'x-html-editor-tip'
39809 title: 'Center Text',
39810 text: 'Center text in the editor.',
39811 cls: 'x-html-editor-tip'
39814 title: 'Align Text Right',
39815 text: 'Align text to the right.',
39816 cls: 'x-html-editor-tip'
39818 insertunorderedlist : {
39819 title: 'Bullet List',
39820 text: 'Start a bulleted list.',
39821 cls: 'x-html-editor-tip'
39823 insertorderedlist : {
39824 title: 'Numbered List',
39825 text: 'Start a numbered list.',
39826 cls: 'x-html-editor-tip'
39829 title: 'Hyperlink',
39830 text: 'Make the selected text a hyperlink.',
39831 cls: 'x-html-editor-tip'
39834 title: 'Source Edit',
39835 text: 'Switch to source editing mode.',
39836 cls: 'x-html-editor-tip'
39840 onDestroy : function(){
39843 this.tb.items.each(function(item){
39845 item.menu.removeAll();
39847 item.menu.el.destroy();
39855 onFirstFocus: function() {
39856 this.tb.items.each(function(item){
39865 // <script type="text/javascript">
39868 * Ext JS Library 1.1.1
39869 * Copyright(c) 2006-2007, Ext JS, LLC.
39876 * @class Roo.form.HtmlEditor.ToolbarContext
39881 new Roo.form.HtmlEditor({
39884 new Roo.form.HtmlEditor.ToolbarStandard(),
39885 new Roo.form.HtmlEditor.ToolbarContext()
39890 * @config : {Object} disable List of elements to disable.. (not done yet.)
39895 Roo.form.HtmlEditor.ToolbarContext = function(config)
39898 Roo.apply(this, config);
39899 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39900 // dont call parent... till later.
39902 Roo.form.HtmlEditor.ToolbarContext.types = {
39914 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
39976 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
39981 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40045 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40053 * @cfg {Object} disable List of toolbar elements to disable
40062 init : function(editor)
40064 this.editor = editor;
40067 var fid = editor.frameId;
40069 function btn(id, toggle, handler){
40070 var xid = fid + '-'+ id ;
40074 cls : 'x-btn-icon x-edit-'+id,
40075 enableToggle:toggle !== false,
40076 scope: editor, // was editor...
40077 handler:handler||editor.relayBtnCmd,
40078 clickEvent:'mousedown',
40079 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40083 // create a new element.
40084 var wdiv = editor.wrap.createChild({
40086 }, editor.wrap.dom.firstChild.nextSibling, true);
40088 // can we do this more than once??
40090 // stop form submits
40093 // disable everything...
40094 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40095 this.toolbars = {};
40097 for (var i in ty) {
40099 this.toolbars[i] = this.buildToolbar(ty[i],i);
40101 this.tb = this.toolbars.BODY;
40105 this.rendered = true;
40107 // the all the btns;
40108 editor.on('editorevent', this.updateToolbar, this);
40109 // other toolbars need to implement this..
40110 //editor.on('editmodechange', this.updateToolbar, this);
40116 * Protected method that will not generally be called directly. It triggers
40117 * a toolbar update by reading the markup state of the current selection in the editor.
40119 updateToolbar: function(){
40121 if(!this.editor.activated){
40122 this.editor.onFirstFocus();
40127 var ans = this.editor.getAllAncestors();
40130 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40131 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40132 sel = sel ? sel : this.editor.doc.body;
40133 sel = sel.tagName.length ? sel : this.editor.doc.body;
40134 var tn = sel.tagName.toUpperCase();
40135 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40136 tn = sel.tagName.toUpperCase();
40137 if (this.tb.name == tn) {
40138 return; // no change
40141 ///console.log("show: " + tn);
40142 this.tb = this.toolbars[tn];
40144 this.tb.fields.each(function(e) {
40145 e.setValue(sel.getAttribute(e.name));
40147 this.tb.selectedNode = sel;
40150 Roo.menu.MenuMgr.hideAll();
40152 //this.editorsyncValue();
40157 onDestroy : function(){
40160 this.tb.items.each(function(item){
40162 item.menu.removeAll();
40164 item.menu.el.destroy();
40172 onFirstFocus: function() {
40173 // need to do this for all the toolbars..
40174 this.tb.items.each(function(item){
40178 buildToolbar: function(tlist, nm)
40180 var editor = this.editor;
40181 // create a new element.
40182 var wdiv = editor.wrap.createChild({
40184 }, editor.wrap.dom.firstChild.nextSibling, true);
40187 var tb = new Roo.Toolbar(wdiv);
40188 tb.add(nm+ ": ");
40189 for (var i in tlist) {
40190 var item = tlist[i];
40191 tb.add(item.title + ": ");
40196 tb.addField( new Roo.form.ComboBox({
40197 store: new Roo.data.SimpleStore({
40200 data : item.opts // from states.js
40203 displayField:'val',
40207 triggerAction: 'all',
40208 emptyText:'Select',
40209 selectOnFocus:true,
40210 width: item.width ? item.width : 130,
40212 'select': function(c, r, i) {
40213 tb.selectedNode.setAttribute(c.name, r.get('val'));
40224 tb.addField( new Roo.form.TextField({
40227 //allowBlank:false,
40232 tb.addField( new Roo.form.TextField({
40238 'change' : function(f, nv, ov) {
40239 tb.selectedNode.setAttribute(f.name, nv);
40245 tb.el.on('click', function(e){
40246 e.preventDefault(); // what does this do?
40248 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40251 // dont need to disable them... as they will get hidden
40268 * Ext JS Library 1.1.1
40269 * Copyright(c) 2006-2007, Ext JS, LLC.
40271 * Originally Released Under LGPL - original licence link has changed is not relivant.
40274 * <script type="text/javascript">
40278 * @class Roo.form.BasicForm
40279 * @extends Roo.util.Observable
40280 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
40282 * @param {String/HTMLElement/Roo.Element} el The form element or its id
40283 * @param {Object} config Configuration options
40285 Roo.form.BasicForm = function(el, config){
40286 this.allItems = [];
40287 this.childForms = [];
40288 Roo.apply(this, config);
40290 * The Roo.form.Field items in this form.
40291 * @type MixedCollection
40295 this.items = new Roo.util.MixedCollection(false, function(o){
40296 return o.id || (o.id = Roo.id());
40300 * @event beforeaction
40301 * Fires before any action is performed. Return false to cancel the action.
40302 * @param {Form} this
40303 * @param {Action} action The action to be performed
40305 beforeaction: true,
40307 * @event actionfailed
40308 * Fires when an action fails.
40309 * @param {Form} this
40310 * @param {Action} action The action that failed
40312 actionfailed : true,
40314 * @event actioncomplete
40315 * Fires when an action is completed.
40316 * @param {Form} this
40317 * @param {Action} action The action that completed
40319 actioncomplete : true
40324 Roo.form.BasicForm.superclass.constructor.call(this);
40327 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
40329 * @cfg {String} method
40330 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
40333 * @cfg {DataReader} reader
40334 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
40335 * This is optional as there is built-in support for processing JSON.
40338 * @cfg {DataReader} errorReader
40339 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
40340 * This is completely optional as there is built-in support for processing JSON.
40343 * @cfg {String} url
40344 * The URL to use for form actions if one isn't supplied in the action options.
40347 * @cfg {Boolean} fileUpload
40348 * Set to true if this form is a file upload.
40351 * @cfg {Object} baseParams
40352 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
40355 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
40360 activeAction : null,
40363 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
40364 * or setValues() data instead of when the form was first created.
40366 trackResetOnLoad : false,
40370 * childForms - used for multi-tab forms
40373 childForms : false,
40376 * allItems - full list of fields.
40382 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
40383 * element by passing it or its id or mask the form itself by passing in true.
40386 waitMsgTarget : undefined,
40389 initEl : function(el){
40390 this.el = Roo.get(el);
40391 this.id = this.el.id || Roo.id();
40392 this.el.on('submit', this.onSubmit, this);
40393 this.el.addClass('x-form');
40397 onSubmit : function(e){
40402 * Returns true if client-side validation on the form is successful.
40405 isValid : function(){
40407 this.items.each(function(f){
40416 * Returns true if any fields in this form have changed since their original load.
40419 isDirty : function(){
40421 this.items.each(function(f){
40431 * Performs a predefined action (submit or load) or custom actions you define on this form.
40432 * @param {String} actionName The name of the action type
40433 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
40434 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
40435 * accept other config options):
40437 Property Type Description
40438 ---------------- --------------- ----------------------------------------------------------------------------------
40439 url String The url for the action (defaults to the form's url)
40440 method String The form method to use (defaults to the form's method, or POST if not defined)
40441 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
40442 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
40443 validate the form on the client (defaults to false)
40445 * @return {BasicForm} this
40447 doAction : function(action, options){
40448 if(typeof action == 'string'){
40449 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
40451 if(this.fireEvent('beforeaction', this, action) !== false){
40452 this.beforeAction(action);
40453 action.run.defer(100, action);
40459 * Shortcut to do a submit action.
40460 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40461 * @return {BasicForm} this
40463 submit : function(options){
40464 this.doAction('submit', options);
40469 * Shortcut to do a load action.
40470 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40471 * @return {BasicForm} this
40473 load : function(options){
40474 this.doAction('load', options);
40479 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
40480 * @param {Record} record The record to edit
40481 * @return {BasicForm} this
40483 updateRecord : function(record){
40484 record.beginEdit();
40485 var fs = record.fields;
40486 fs.each(function(f){
40487 var field = this.findField(f.name);
40489 record.set(f.name, field.getValue());
40497 * Loads an Roo.data.Record into this form.
40498 * @param {Record} record The record to load
40499 * @return {BasicForm} this
40501 loadRecord : function(record){
40502 this.setValues(record.data);
40507 beforeAction : function(action){
40508 var o = action.options;
40510 if(this.waitMsgTarget === true){
40511 this.el.mask(o.waitMsg, 'x-mask-loading');
40512 }else if(this.waitMsgTarget){
40513 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
40514 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
40516 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
40522 afterAction : function(action, success){
40523 this.activeAction = null;
40524 var o = action.options;
40526 if(this.waitMsgTarget === true){
40528 }else if(this.waitMsgTarget){
40529 this.waitMsgTarget.unmask();
40531 Roo.MessageBox.updateProgress(1);
40532 Roo.MessageBox.hide();
40539 Roo.callback(o.success, o.scope, [this, action]);
40540 this.fireEvent('actioncomplete', this, action);
40542 Roo.callback(o.failure, o.scope, [this, action]);
40543 this.fireEvent('actionfailed', this, action);
40548 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
40549 * @param {String} id The value to search for
40552 findField : function(id){
40553 var field = this.items.get(id);
40555 this.items.each(function(f){
40556 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
40562 return field || null;
40566 * Add a secondary form to this one,
40567 * Used to provide tabbed forms. One form is primary, with hidden values
40568 * which mirror the elements from the other forms.
40570 * @param {Roo.form.Form} form to add.
40573 addForm : function(form)
40576 if (this.childForms.indexOf(form) > -1) {
40580 this.childForms.push(form);
40582 Roo.each(form.allItems, function (fe) {
40584 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
40585 if (this.findField(n)) { // already added..
40588 var add = new Roo.form.Hidden({
40591 add.render(this.el);
40598 * Mark fields in this form invalid in bulk.
40599 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
40600 * @return {BasicForm} this
40602 markInvalid : function(errors){
40603 if(errors instanceof Array){
40604 for(var i = 0, len = errors.length; i < len; i++){
40605 var fieldError = errors[i];
40606 var f = this.findField(fieldError.id);
40608 f.markInvalid(fieldError.msg);
40614 if(typeof errors[id] != 'function' && (field = this.findField(id))){
40615 field.markInvalid(errors[id]);
40619 Roo.each(this.childForms || [], function (f) {
40620 f.markInvalid(errors);
40627 * Set values for fields in this form in bulk.
40628 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40629 * @return {BasicForm} this
40631 setValues : function(values){
40632 if(values instanceof Array){ // array of objects
40633 for(var i = 0, len = values.length; i < len; i++){
40635 var f = this.findField(v.id);
40637 f.setValue(v.value);
40638 if(this.trackResetOnLoad){
40639 f.originalValue = f.getValue();
40643 }else{ // object hash
40646 if(typeof values[id] != 'function' && (field = this.findField(id))){
40648 if (field.setFromData &&
40649 field.valueField &&
40650 field.displayField &&
40651 // combos' with local stores can
40652 // be queried via setValue()
40653 // to set their value..
40654 (field.store && !field.store.isLocal)
40658 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40659 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40660 field.setFromData(sd);
40663 field.setValue(values[id]);
40667 if(this.trackResetOnLoad){
40668 field.originalValue = field.getValue();
40674 Roo.each(this.childForms || [], function (f) {
40675 f.setValues(values);
40682 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40683 * they are returned as an array.
40684 * @param {Boolean} asString
40687 getValues : function(asString){
40688 if (this.childForms) {
40689 // copy values from the child forms
40690 Roo.each(this.childForms, function (f) {
40691 this.setValues(f.getValues());
40697 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40698 if(asString === true){
40701 return Roo.urlDecode(fs);
40705 * Returns the fields in this form as an object with key/value pairs.
40706 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
40709 getFieldValues : function()
40711 if (this.childForms) {
40712 // copy values from the child forms
40713 Roo.each(this.childForms, function (f) {
40714 this.setValues(f.getValues());
40719 this.items.each(function(f){
40720 if (!f.getName()) {
40723 var v = f.getValue();
40724 if ((typeof(v) == 'object') && f.getRawValue) {
40725 v = f.getRawValue() ; // dates..
40727 ret[f.getName()] = v;
40734 * Clears all invalid messages in this form.
40735 * @return {BasicForm} this
40737 clearInvalid : function(){
40738 this.items.each(function(f){
40742 Roo.each(this.childForms || [], function (f) {
40751 * Resets this form.
40752 * @return {BasicForm} this
40754 reset : function(){
40755 this.items.each(function(f){
40759 Roo.each(this.childForms || [], function (f) {
40768 * Add Roo.form components to this form.
40769 * @param {Field} field1
40770 * @param {Field} field2 (optional)
40771 * @param {Field} etc (optional)
40772 * @return {BasicForm} this
40775 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40781 * Removes a field from the items collection (does NOT remove its markup).
40782 * @param {Field} field
40783 * @return {BasicForm} this
40785 remove : function(field){
40786 this.items.remove(field);
40791 * Looks at the fields in this form, checks them for an id attribute,
40792 * and calls applyTo on the existing dom element with that id.
40793 * @return {BasicForm} this
40795 render : function(){
40796 this.items.each(function(f){
40797 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40805 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40806 * @param {Object} values
40807 * @return {BasicForm} this
40809 applyToFields : function(o){
40810 this.items.each(function(f){
40817 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40818 * @param {Object} values
40819 * @return {BasicForm} this
40821 applyIfToFields : function(o){
40822 this.items.each(function(f){
40830 Roo.BasicForm = Roo.form.BasicForm;/*
40832 * Ext JS Library 1.1.1
40833 * Copyright(c) 2006-2007, Ext JS, LLC.
40835 * Originally Released Under LGPL - original licence link has changed is not relivant.
40838 * <script type="text/javascript">
40842 * @class Roo.form.Form
40843 * @extends Roo.form.BasicForm
40844 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40846 * @param {Object} config Configuration options
40848 Roo.form.Form = function(config){
40850 if (config.items) {
40851 xitems = config.items;
40852 delete config.items;
40856 Roo.form.Form.superclass.constructor.call(this, null, config);
40857 this.url = this.url || this.action;
40859 this.root = new Roo.form.Layout(Roo.applyIf({
40863 this.active = this.root;
40865 * Array of all the buttons that have been added to this form via {@link addButton}
40869 this.allItems = [];
40872 * @event clientvalidation
40873 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40874 * @param {Form} this
40875 * @param {Boolean} valid true if the form has passed client-side validation
40877 clientvalidation: true,
40880 * Fires when the form is rendered
40881 * @param {Roo.form.Form} form
40886 if (this.progressUrl) {
40887 // push a hidden field onto the list of fields..
40891 name : 'UPLOAD_IDENTIFIER'
40896 Roo.each(xitems, this.addxtype, this);
40902 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
40904 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
40907 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
40910 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
40912 buttonAlign:'center',
40915 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
40920 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
40921 * This property cascades to child containers if not set.
40926 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
40927 * fires a looping event with that state. This is required to bind buttons to the valid
40928 * state using the config value formBind:true on the button.
40930 monitorValid : false,
40933 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
40938 * @cfg {String} progressUrl - Url to return progress data
40941 progressUrl : false,
40944 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
40945 * fields are added and the column is closed. If no fields are passed the column remains open
40946 * until end() is called.
40947 * @param {Object} config The config to pass to the column
40948 * @param {Field} field1 (optional)
40949 * @param {Field} field2 (optional)
40950 * @param {Field} etc (optional)
40951 * @return Column The column container object
40953 column : function(c){
40954 var col = new Roo.form.Column(c);
40956 if(arguments.length > 1){ // duplicate code required because of Opera
40957 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40964 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
40965 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
40966 * until end() is called.
40967 * @param {Object} config The config to pass to the fieldset
40968 * @param {Field} field1 (optional)
40969 * @param {Field} field2 (optional)
40970 * @param {Field} etc (optional)
40971 * @return FieldSet The fieldset container object
40973 fieldset : function(c){
40974 var fs = new Roo.form.FieldSet(c);
40976 if(arguments.length > 1){ // duplicate code required because of Opera
40977 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40984 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
40985 * fields are added and the container is closed. If no fields are passed the container remains open
40986 * until end() is called.
40987 * @param {Object} config The config to pass to the Layout
40988 * @param {Field} field1 (optional)
40989 * @param {Field} field2 (optional)
40990 * @param {Field} etc (optional)
40991 * @return Layout The container object
40993 container : function(c){
40994 var l = new Roo.form.Layout(c);
40996 if(arguments.length > 1){ // duplicate code required because of Opera
40997 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41004 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41005 * @param {Object} container A Roo.form.Layout or subclass of Layout
41006 * @return {Form} this
41008 start : function(c){
41009 // cascade label info
41010 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41011 this.active.stack.push(c);
41012 c.ownerCt = this.active;
41018 * Closes the current open container
41019 * @return {Form} this
41022 if(this.active == this.root){
41025 this.active = this.active.ownerCt;
41030 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41031 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41032 * as the label of the field.
41033 * @param {Field} field1
41034 * @param {Field} field2 (optional)
41035 * @param {Field} etc. (optional)
41036 * @return {Form} this
41039 this.active.stack.push.apply(this.active.stack, arguments);
41040 this.allItems.push.apply(this.allItems,arguments);
41042 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41043 if(a[i].isFormField){
41048 Roo.form.Form.superclass.add.apply(this, r);
41058 * Find any element that has been added to a form, using it's ID or name
41059 * This can include framesets, columns etc. along with regular fields..
41060 * @param {String} id - id or name to find.
41062 * @return {Element} e - or false if nothing found.
41064 findbyId : function(id)
41070 Ext.each(this.allItems, function(f){
41071 if (f.id == id || f.name == id ){
41082 * Render this form into the passed container. This should only be called once!
41083 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41084 * @return {Form} this
41086 render : function(ct)
41092 var o = this.autoCreate || {
41094 method : this.method || 'POST',
41095 id : this.id || Roo.id()
41097 this.initEl(ct.createChild(o));
41099 this.root.render(this.el);
41103 this.items.each(function(f){
41104 f.render('x-form-el-'+f.id);
41107 if(this.buttons.length > 0){
41108 // tables are required to maintain order and for correct IE layout
41109 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41110 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41111 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41113 var tr = tb.getElementsByTagName('tr')[0];
41114 for(var i = 0, len = this.buttons.length; i < len; i++) {
41115 var b = this.buttons[i];
41116 var td = document.createElement('td');
41117 td.className = 'x-form-btn-td';
41118 b.render(tr.appendChild(td));
41121 if(this.monitorValid){ // initialize after render
41122 this.startMonitoring();
41124 this.fireEvent('rendered', this);
41129 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41130 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41131 * object or a valid Roo.DomHelper element config
41132 * @param {Function} handler The function called when the button is clicked
41133 * @param {Object} scope (optional) The scope of the handler function
41134 * @return {Roo.Button}
41136 addButton : function(config, handler, scope){
41140 minWidth: this.minButtonWidth,
41143 if(typeof config == "string"){
41146 Roo.apply(bc, config);
41148 var btn = new Roo.Button(null, bc);
41149 this.buttons.push(btn);
41154 * Adds a series of form elements (using the xtype property as the factory method.
41155 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41156 * @param {Object} config
41159 addxtype : function()
41161 var ar = Array.prototype.slice.call(arguments, 0);
41163 for(var i = 0; i < ar.length; i++) {
41165 continue; // skip -- if this happends something invalid got sent, we
41166 // should ignore it, as basically that interface element will not show up
41167 // and that should be pretty obvious!!
41170 if (Roo.form[ar[i].xtype]) {
41172 var fe = Roo.factory(ar[i], Roo.form);
41178 fe.store.form = this;
41183 this.allItems.push(fe);
41184 if (fe.items && fe.addxtype) {
41185 fe.addxtype.apply(fe, fe.items);
41195 // console.log('adding ' + ar[i].xtype);
41197 if (ar[i].xtype == 'Button') {
41198 //console.log('adding button');
41199 //console.log(ar[i]);
41200 this.addButton(ar[i]);
41201 this.allItems.push(fe);
41205 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
41206 alert('end is not supported on xtype any more, use items');
41208 // //console.log('adding end');
41216 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
41217 * option "monitorValid"
41219 startMonitoring : function(){
41222 Roo.TaskMgr.start({
41223 run : this.bindHandler,
41224 interval : this.monitorPoll || 200,
41231 * Stops monitoring of the valid state of this form
41233 stopMonitoring : function(){
41234 this.bound = false;
41238 bindHandler : function(){
41240 return false; // stops binding
41243 this.items.each(function(f){
41244 if(!f.isValid(true)){
41249 for(var i = 0, len = this.buttons.length; i < len; i++){
41250 var btn = this.buttons[i];
41251 if(btn.formBind === true && btn.disabled === valid){
41252 btn.setDisabled(!valid);
41255 this.fireEvent('clientvalidation', this, valid);
41269 Roo.Form = Roo.form.Form;
41272 * Ext JS Library 1.1.1
41273 * Copyright(c) 2006-2007, Ext JS, LLC.
41275 * Originally Released Under LGPL - original licence link has changed is not relivant.
41278 * <script type="text/javascript">
41282 * @class Roo.form.Action
41283 * Internal Class used to handle form actions
41285 * @param {Roo.form.BasicForm} el The form element or its id
41286 * @param {Object} config Configuration options
41290 // define the action interface
41291 Roo.form.Action = function(form, options){
41293 this.options = options || {};
41296 * Client Validation Failed
41299 Roo.form.Action.CLIENT_INVALID = 'client';
41301 * Server Validation Failed
41304 Roo.form.Action.SERVER_INVALID = 'server';
41306 * Connect to Server Failed
41309 Roo.form.Action.CONNECT_FAILURE = 'connect';
41311 * Reading Data from Server Failed
41314 Roo.form.Action.LOAD_FAILURE = 'load';
41316 Roo.form.Action.prototype = {
41318 failureType : undefined,
41319 response : undefined,
41320 result : undefined,
41322 // interface method
41323 run : function(options){
41327 // interface method
41328 success : function(response){
41332 // interface method
41333 handleResponse : function(response){
41337 // default connection failure
41338 failure : function(response){
41339 this.response = response;
41340 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41341 this.form.afterAction(this, false);
41344 processResponse : function(response){
41345 this.response = response;
41346 if(!response.responseText){
41349 this.result = this.handleResponse(response);
41350 return this.result;
41353 // utility functions used internally
41354 getUrl : function(appendParams){
41355 var url = this.options.url || this.form.url || this.form.el.dom.action;
41357 var p = this.getParams();
41359 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
41365 getMethod : function(){
41366 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
41369 getParams : function(){
41370 var bp = this.form.baseParams;
41371 var p = this.options.params;
41373 if(typeof p == "object"){
41374 p = Roo.urlEncode(Roo.applyIf(p, bp));
41375 }else if(typeof p == 'string' && bp){
41376 p += '&' + Roo.urlEncode(bp);
41379 p = Roo.urlEncode(bp);
41384 createCallback : function(){
41386 success: this.success,
41387 failure: this.failure,
41389 timeout: (this.form.timeout*1000),
41390 upload: this.form.fileUpload ? this.success : undefined
41395 Roo.form.Action.Submit = function(form, options){
41396 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
41399 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
41402 haveProgress : false,
41403 uploadComplete : false,
41405 // uploadProgress indicator.
41406 uploadProgress : function()
41408 if (!this.form.progressUrl) {
41412 if (!this.haveProgress) {
41413 Roo.MessageBox.progress("Uploading", "Uploading");
41415 if (this.uploadComplete) {
41416 Roo.MessageBox.hide();
41420 this.haveProgress = true;
41422 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
41424 var c = new Roo.data.Connection();
41426 url : this.form.progressUrl,
41431 success : function(req){
41432 //console.log(data);
41436 rdata = Roo.decode(req.responseText)
41438 Roo.log("Invalid data from server..");
41442 if (!rdata || !rdata.success) {
41446 var data = rdata.data;
41448 if (this.uploadComplete) {
41449 Roo.MessageBox.hide();
41454 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
41455 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
41458 this.uploadProgress.defer(2000,this);
41461 failure: function(data) {
41462 Roo.log('progress url failed ');
41473 // run get Values on the form, so it syncs any secondary forms.
41474 this.form.getValues();
41476 var o = this.options;
41477 var method = this.getMethod();
41478 var isPost = method == 'POST';
41479 if(o.clientValidation === false || this.form.isValid()){
41481 if (this.form.progressUrl) {
41482 this.form.findField('UPLOAD_IDENTIFIER').setValue(
41483 (new Date() * 1) + '' + Math.random());
41487 Roo.Ajax.request(Roo.apply(this.createCallback(), {
41488 form:this.form.el.dom,
41489 url:this.getUrl(!isPost),
41491 params:isPost ? this.getParams() : null,
41492 isUpload: this.form.fileUpload
41495 this.uploadProgress();
41497 }else if (o.clientValidation !== false){ // client validation failed
41498 this.failureType = Roo.form.Action.CLIENT_INVALID;
41499 this.form.afterAction(this, false);
41503 success : function(response)
41505 this.uploadComplete= true;
41506 if (this.haveProgress) {
41507 Roo.MessageBox.hide();
41510 var result = this.processResponse(response);
41511 if(result === true || result.success){
41512 this.form.afterAction(this, true);
41516 this.form.markInvalid(result.errors);
41517 this.failureType = Roo.form.Action.SERVER_INVALID;
41519 this.form.afterAction(this, false);
41521 failure : function(response)
41523 this.uploadComplete= true;
41524 if (this.haveProgress) {
41525 Roo.MessageBox.hide();
41528 this.response = response;
41529 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41530 this.form.afterAction(this, false);
41533 handleResponse : function(response){
41534 if(this.form.errorReader){
41535 var rs = this.form.errorReader.read(response);
41538 for(var i = 0, len = rs.records.length; i < len; i++) {
41539 var r = rs.records[i];
41540 errors[i] = r.data;
41543 if(errors.length < 1){
41547 success : rs.success,
41553 ret = Roo.decode(response.responseText);
41557 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
41567 Roo.form.Action.Load = function(form, options){
41568 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
41569 this.reader = this.form.reader;
41572 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
41576 Roo.Ajax.request(Roo.apply(
41577 this.createCallback(), {
41578 method:this.getMethod(),
41579 url:this.getUrl(false),
41580 params:this.getParams()
41584 success : function(response){
41585 var result = this.processResponse(response);
41586 if(result === true || !result.success || !result.data){
41587 this.failureType = Roo.form.Action.LOAD_FAILURE;
41588 this.form.afterAction(this, false);
41591 this.form.clearInvalid();
41592 this.form.setValues(result.data);
41593 this.form.afterAction(this, true);
41596 handleResponse : function(response){
41597 if(this.form.reader){
41598 var rs = this.form.reader.read(response);
41599 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
41601 success : rs.success,
41605 return Roo.decode(response.responseText);
41609 Roo.form.Action.ACTION_TYPES = {
41610 'load' : Roo.form.Action.Load,
41611 'submit' : Roo.form.Action.Submit
41614 * Ext JS Library 1.1.1
41615 * Copyright(c) 2006-2007, Ext JS, LLC.
41617 * Originally Released Under LGPL - original licence link has changed is not relivant.
41620 * <script type="text/javascript">
41624 * @class Roo.form.Layout
41625 * @extends Roo.Component
41626 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
41628 * @param {Object} config Configuration options
41630 Roo.form.Layout = function(config){
41632 if (config.items) {
41633 xitems = config.items;
41634 delete config.items;
41636 Roo.form.Layout.superclass.constructor.call(this, config);
41638 Roo.each(xitems, this.addxtype, this);
41642 Roo.extend(Roo.form.Layout, Roo.Component, {
41644 * @cfg {String/Object} autoCreate
41645 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
41648 * @cfg {String/Object/Function} style
41649 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
41650 * a function which returns such a specification.
41653 * @cfg {String} labelAlign
41654 * Valid values are "left," "top" and "right" (defaults to "left")
41657 * @cfg {Number} labelWidth
41658 * Fixed width in pixels of all field labels (defaults to undefined)
41661 * @cfg {Boolean} clear
41662 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
41666 * @cfg {String} labelSeparator
41667 * The separator to use after field labels (defaults to ':')
41669 labelSeparator : ':',
41671 * @cfg {Boolean} hideLabels
41672 * True to suppress the display of field labels in this layout (defaults to false)
41674 hideLabels : false,
41677 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
41682 onRender : function(ct, position){
41683 if(this.el){ // from markup
41684 this.el = Roo.get(this.el);
41685 }else { // generate
41686 var cfg = this.getAutoCreate();
41687 this.el = ct.createChild(cfg, position);
41690 this.el.applyStyles(this.style);
41692 if(this.labelAlign){
41693 this.el.addClass('x-form-label-'+this.labelAlign);
41695 if(this.hideLabels){
41696 this.labelStyle = "display:none";
41697 this.elementStyle = "padding-left:0;";
41699 if(typeof this.labelWidth == 'number'){
41700 this.labelStyle = "width:"+this.labelWidth+"px;";
41701 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
41703 if(this.labelAlign == 'top'){
41704 this.labelStyle = "width:auto;";
41705 this.elementStyle = "padding-left:0;";
41708 var stack = this.stack;
41709 var slen = stack.length;
41711 if(!this.fieldTpl){
41712 var t = new Roo.Template(
41713 '<div class="x-form-item {5}">',
41714 '<label for="{0}" style="{2}">{1}{4}</label>',
41715 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41717 '</div><div class="x-form-clear-left"></div>'
41719 t.disableFormats = true;
41721 Roo.form.Layout.prototype.fieldTpl = t;
41723 for(var i = 0; i < slen; i++) {
41724 if(stack[i].isFormField){
41725 this.renderField(stack[i]);
41727 this.renderComponent(stack[i]);
41732 this.el.createChild({cls:'x-form-clear'});
41737 renderField : function(f){
41738 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
41741 f.labelStyle||this.labelStyle||'', //2
41742 this.elementStyle||'', //3
41743 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
41744 f.itemCls||this.itemCls||'' //5
41745 ], true).getPrevSibling());
41749 renderComponent : function(c){
41750 c.render(c.isLayout ? this.el : this.el.createChild());
41753 * Adds a object form elements (using the xtype property as the factory method.)
41754 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
41755 * @param {Object} config
41757 addxtype : function(o)
41759 // create the lement.
41760 o.form = this.form;
41761 var fe = Roo.factory(o, Roo.form);
41762 this.form.allItems.push(fe);
41763 this.stack.push(fe);
41765 if (fe.isFormField) {
41766 this.form.items.add(fe);
41774 * @class Roo.form.Column
41775 * @extends Roo.form.Layout
41776 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41778 * @param {Object} config Configuration options
41780 Roo.form.Column = function(config){
41781 Roo.form.Column.superclass.constructor.call(this, config);
41784 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41786 * @cfg {Number/String} width
41787 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41790 * @cfg {String/Object} autoCreate
41791 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41795 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41798 onRender : function(ct, position){
41799 Roo.form.Column.superclass.onRender.call(this, ct, position);
41801 this.el.setWidth(this.width);
41808 * @class Roo.form.Row
41809 * @extends Roo.form.Layout
41810 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41812 * @param {Object} config Configuration options
41816 Roo.form.Row = function(config){
41817 Roo.form.Row.superclass.constructor.call(this, config);
41820 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41822 * @cfg {Number/String} width
41823 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41826 * @cfg {Number/String} height
41827 * The fixed height of the column in pixels or CSS value (defaults to "auto")
41829 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41833 onRender : function(ct, position){
41834 //console.log('row render');
41836 var t = new Roo.Template(
41837 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
41838 '<label for="{0}" style="{2}">{1}{4}</label>',
41839 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41843 t.disableFormats = true;
41845 Roo.form.Layout.prototype.rowTpl = t;
41847 this.fieldTpl = this.rowTpl;
41849 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
41850 var labelWidth = 100;
41852 if ((this.labelAlign != 'top')) {
41853 if (typeof this.labelWidth == 'number') {
41854 labelWidth = this.labelWidth
41856 this.padWidth = 20 + labelWidth;
41860 Roo.form.Column.superclass.onRender.call(this, ct, position);
41862 this.el.setWidth(this.width);
41865 this.el.setHeight(this.height);
41870 renderField : function(f){
41871 f.fieldEl = this.fieldTpl.append(this.el, [
41872 f.id, f.fieldLabel,
41873 f.labelStyle||this.labelStyle||'',
41874 this.elementStyle||'',
41875 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
41876 f.itemCls||this.itemCls||'',
41877 f.width ? f.width + this.padWidth : 160 + this.padWidth
41884 * @class Roo.form.FieldSet
41885 * @extends Roo.form.Layout
41886 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
41888 * @param {Object} config Configuration options
41890 Roo.form.FieldSet = function(config){
41891 Roo.form.FieldSet.superclass.constructor.call(this, config);
41894 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
41896 * @cfg {String} legend
41897 * The text to display as the legend for the FieldSet (defaults to '')
41900 * @cfg {String/Object} autoCreate
41901 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
41905 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
41908 onRender : function(ct, position){
41909 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
41911 this.setLegend(this.legend);
41916 setLegend : function(text){
41918 this.el.child('legend').update(text);
41923 * Ext JS Library 1.1.1
41924 * Copyright(c) 2006-2007, Ext JS, LLC.
41926 * Originally Released Under LGPL - original licence link has changed is not relivant.
41929 * <script type="text/javascript">
41932 * @class Roo.form.VTypes
41933 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
41936 Roo.form.VTypes = function(){
41937 // closure these in so they are only created once.
41938 var alpha = /^[a-zA-Z_]+$/;
41939 var alphanum = /^[a-zA-Z0-9_]+$/;
41940 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
41941 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
41943 // All these messages and functions are configurable
41946 * The function used to validate email addresses
41947 * @param {String} value The email address
41949 'email' : function(v){
41950 return email.test(v);
41953 * The error text to display when the email validation function returns false
41956 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
41958 * The keystroke filter mask to be applied on email input
41961 'emailMask' : /[a-z0-9_\.\-@]/i,
41964 * The function used to validate URLs
41965 * @param {String} value The URL
41967 'url' : function(v){
41968 return url.test(v);
41971 * The error text to display when the url validation function returns false
41974 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
41977 * The function used to validate alpha values
41978 * @param {String} value The value
41980 'alpha' : function(v){
41981 return alpha.test(v);
41984 * The error text to display when the alpha validation function returns false
41987 'alphaText' : 'This field should only contain letters and _',
41989 * The keystroke filter mask to be applied on alpha input
41992 'alphaMask' : /[a-z_]/i,
41995 * The function used to validate alphanumeric values
41996 * @param {String} value The value
41998 'alphanum' : function(v){
41999 return alphanum.test(v);
42002 * The error text to display when the alphanumeric validation function returns false
42005 'alphanumText' : 'This field should only contain letters, numbers and _',
42007 * The keystroke filter mask to be applied on alphanumeric input
42010 'alphanumMask' : /[a-z0-9_]/i
42012 }();//<script type="text/javascript">
42015 * @class Roo.form.FCKeditor
42016 * @extends Roo.form.TextArea
42017 * Wrapper around the FCKEditor http://www.fckeditor.net
42019 * Creates a new FCKeditor
42020 * @param {Object} config Configuration options
42022 Roo.form.FCKeditor = function(config){
42023 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42026 * @event editorinit
42027 * Fired when the editor is initialized - you can add extra handlers here..
42028 * @param {FCKeditor} this
42029 * @param {Object} the FCK object.
42036 Roo.form.FCKeditor.editors = { };
42037 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42039 //defaultAutoCreate : {
42040 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42044 * @cfg {Object} fck options - see fck manual for details.
42049 * @cfg {Object} fck toolbar set (Basic or Default)
42051 toolbarSet : 'Basic',
42053 * @cfg {Object} fck BasePath
42055 basePath : '/fckeditor/',
42063 onRender : function(ct, position)
42066 this.defaultAutoCreate = {
42068 style:"width:300px;height:60px;",
42069 autocomplete: "off"
42072 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42075 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42076 if(this.preventScrollbars){
42077 this.el.setStyle("overflow", "hidden");
42079 this.el.setHeight(this.growMin);
42082 //console.log('onrender' + this.getId() );
42083 Roo.form.FCKeditor.editors[this.getId()] = this;
42086 this.replaceTextarea() ;
42090 getEditor : function() {
42091 return this.fckEditor;
42094 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42095 * @param {Mixed} value The value to set
42099 setValue : function(value)
42101 //console.log('setValue: ' + value);
42103 if(typeof(value) == 'undefined') { // not sure why this is happending...
42106 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42108 //if(!this.el || !this.getEditor()) {
42109 // this.value = value;
42110 //this.setValue.defer(100,this,[value]);
42114 if(!this.getEditor()) {
42118 this.getEditor().SetData(value);
42125 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42126 * @return {Mixed} value The field value
42128 getValue : function()
42131 if (this.frame && this.frame.dom.style.display == 'none') {
42132 return Roo.form.FCKeditor.superclass.getValue.call(this);
42135 if(!this.el || !this.getEditor()) {
42137 // this.getValue.defer(100,this);
42142 var value=this.getEditor().GetData();
42143 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42144 return Roo.form.FCKeditor.superclass.getValue.call(this);
42150 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42151 * @return {Mixed} value The field value
42153 getRawValue : function()
42155 if (this.frame && this.frame.dom.style.display == 'none') {
42156 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42159 if(!this.el || !this.getEditor()) {
42160 //this.getRawValue.defer(100,this);
42167 var value=this.getEditor().GetData();
42168 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
42169 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42173 setSize : function(w,h) {
42177 //if (this.frame && this.frame.dom.style.display == 'none') {
42178 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42181 //if(!this.el || !this.getEditor()) {
42182 // this.setSize.defer(100,this, [w,h]);
42188 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42190 this.frame.dom.setAttribute('width', w);
42191 this.frame.dom.setAttribute('height', h);
42192 this.frame.setSize(w,h);
42196 toggleSourceEdit : function(value) {
42200 this.el.dom.style.display = value ? '' : 'none';
42201 this.frame.dom.style.display = value ? 'none' : '';
42206 focus: function(tag)
42208 if (this.frame.dom.style.display == 'none') {
42209 return Roo.form.FCKeditor.superclass.focus.call(this);
42211 if(!this.el || !this.getEditor()) {
42212 this.focus.defer(100,this, [tag]);
42219 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
42220 this.getEditor().Focus();
42222 if (!this.getEditor().Selection.GetSelection()) {
42223 this.focus.defer(100,this, [tag]);
42228 var r = this.getEditor().EditorDocument.createRange();
42229 r.setStart(tgs[0],0);
42230 r.setEnd(tgs[0],0);
42231 this.getEditor().Selection.GetSelection().removeAllRanges();
42232 this.getEditor().Selection.GetSelection().addRange(r);
42233 this.getEditor().Focus();
42240 replaceTextarea : function()
42242 if ( document.getElementById( this.getId() + '___Frame' ) )
42244 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
42246 // We must check the elements firstly using the Id and then the name.
42247 var oTextarea = document.getElementById( this.getId() );
42249 var colElementsByName = document.getElementsByName( this.getId() ) ;
42251 oTextarea.style.display = 'none' ;
42253 if ( oTextarea.tabIndex ) {
42254 this.TabIndex = oTextarea.tabIndex ;
42257 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
42258 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
42259 this.frame = Roo.get(this.getId() + '___Frame')
42262 _getConfigHtml : function()
42266 for ( var o in this.fckconfig ) {
42267 sConfig += sConfig.length > 0 ? '&' : '';
42268 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
42271 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
42275 _getIFrameHtml : function()
42277 var sFile = 'fckeditor.html' ;
42278 /* no idea what this is about..
42281 if ( (/fcksource=true/i).test( window.top.location.search ) )
42282 sFile = 'fckeditor.original.html' ;
42287 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
42288 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
42291 var html = '<iframe id="' + this.getId() +
42292 '___Frame" src="' + sLink +
42293 '" width="' + this.width +
42294 '" height="' + this.height + '"' +
42295 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
42296 ' frameborder="0" scrolling="no"></iframe>' ;
42301 _insertHtmlBefore : function( html, element )
42303 if ( element.insertAdjacentHTML ) {
42305 element.insertAdjacentHTML( 'beforeBegin', html ) ;
42307 var oRange = document.createRange() ;
42308 oRange.setStartBefore( element ) ;
42309 var oFragment = oRange.createContextualFragment( html );
42310 element.parentNode.insertBefore( oFragment, element ) ;
42323 //Roo.reg('fckeditor', Roo.form.FCKeditor);
42325 function FCKeditor_OnComplete(editorInstance){
42326 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
42327 f.fckEditor = editorInstance;
42328 //console.log("loaded");
42329 f.fireEvent('editorinit', f, editorInstance);
42349 //<script type="text/javascript">
42351 * @class Roo.form.GridField
42352 * @extends Roo.form.Field
42353 * Embed a grid (or editable grid into a form)
42356 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
42358 * xgrid.store = Roo.data.Store
42359 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
42360 * xgrid.store.reader = Roo.data.JsonReader
42364 * Creates a new GridField
42365 * @param {Object} config Configuration options
42367 Roo.form.GridField = function(config){
42368 Roo.form.GridField.superclass.constructor.call(this, config);
42372 Roo.extend(Roo.form.GridField, Roo.form.Field, {
42374 * @cfg {Number} width - used to restrict width of grid..
42378 * @cfg {Number} height - used to restrict height of grid..
42382 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
42388 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42389 * {tag: "input", type: "checkbox", autocomplete: "off"})
42391 // defaultAutoCreate : { tag: 'div' },
42392 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42394 * @cfg {String} addTitle Text to include for adding a title.
42398 onResize : function(){
42399 Roo.form.Field.superclass.onResize.apply(this, arguments);
42402 initEvents : function(){
42403 // Roo.form.Checkbox.superclass.initEvents.call(this);
42404 // has no events...
42409 getResizeEl : function(){
42413 getPositionEl : function(){
42418 onRender : function(ct, position){
42420 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
42421 var style = this.style;
42424 Roo.form.GridField.superclass.onRender.call(this, ct, position);
42425 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
42426 this.viewEl = this.wrap.createChild({ tag: 'div' });
42428 this.viewEl.applyStyles(style);
42431 this.viewEl.setWidth(this.width);
42434 this.viewEl.setHeight(this.height);
42436 //if(this.inputValue !== undefined){
42437 //this.setValue(this.value);
42440 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
42443 this.grid.render();
42444 this.grid.getDataSource().on('remove', this.refreshValue, this);
42445 this.grid.getDataSource().on('update', this.refreshValue, this);
42446 this.grid.on('afteredit', this.refreshValue, this);
42452 * Sets the value of the item.
42453 * @param {String} either an object or a string..
42455 setValue : function(v){
42457 v = v || []; // empty set..
42458 // this does not seem smart - it really only affects memoryproxy grids..
42459 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
42460 var ds = this.grid.getDataSource();
42461 // assumes a json reader..
42463 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
42464 ds.loadData( data);
42466 Roo.form.GridField.superclass.setValue.call(this, v);
42467 this.refreshValue();
42468 // should load data in the grid really....
42472 refreshValue: function() {
42474 this.grid.getDataSource().each(function(r) {
42477 this.el.dom.value = Roo.encode(val);
42485 * Ext JS Library 1.1.1
42486 * Copyright(c) 2006-2007, Ext JS, LLC.
42488 * Originally Released Under LGPL - original licence link has changed is not relivant.
42491 * <script type="text/javascript">
42494 * @class Roo.form.DisplayField
42495 * @extends Roo.form.Field
42496 * A generic Field to display non-editable data.
42498 * Creates a new Display Field item.
42499 * @param {Object} config Configuration options
42501 Roo.form.DisplayField = function(config){
42502 Roo.form.DisplayField.superclass.constructor.call(this, config);
42506 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
42507 inputType: 'hidden',
42513 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42515 focusClass : undefined,
42517 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42519 fieldClass: 'x-form-field',
42522 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
42524 valueRenderer: undefined,
42528 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42529 * {tag: "input", type: "checkbox", autocomplete: "off"})
42532 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42534 onResize : function(){
42535 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
42539 initEvents : function(){
42540 // Roo.form.Checkbox.superclass.initEvents.call(this);
42541 // has no events...
42546 getResizeEl : function(){
42550 getPositionEl : function(){
42555 onRender : function(ct, position){
42557 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
42558 //if(this.inputValue !== undefined){
42559 this.wrap = this.el.wrap();
42561 this.viewEl = this.wrap.createChild({ tag: 'div'});
42563 if (this.bodyStyle) {
42564 this.viewEl.applyStyles(this.bodyStyle);
42566 //this.viewEl.setStyle('padding', '2px');
42568 this.setValue(this.value);
42573 initValue : Roo.emptyFn,
42578 onClick : function(){
42583 * Sets the checked state of the checkbox.
42584 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
42586 setValue : function(v){
42588 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
42589 // this might be called before we have a dom element..
42590 if (!this.viewEl) {
42593 this.viewEl.dom.innerHTML = html;
42594 Roo.form.DisplayField.superclass.setValue.call(this, v);
42597 });//<script type="text/javasscript">
42601 * @class Roo.DDView
42602 * A DnD enabled version of Roo.View.
42603 * @param {Element/String} container The Element in which to create the View.
42604 * @param {String} tpl The template string used to create the markup for each element of the View
42605 * @param {Object} config The configuration properties. These include all the config options of
42606 * {@link Roo.View} plus some specific to this class.<br>
42608 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
42609 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
42611 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
42612 .x-view-drag-insert-above {
42613 border-top:1px dotted #3366cc;
42615 .x-view-drag-insert-below {
42616 border-bottom:1px dotted #3366cc;
42622 Roo.DDView = function(container, tpl, config) {
42623 Roo.DDView.superclass.constructor.apply(this, arguments);
42624 this.getEl().setStyle("outline", "0px none");
42625 this.getEl().unselectable();
42626 if (this.dragGroup) {
42627 this.setDraggable(this.dragGroup.split(","));
42629 if (this.dropGroup) {
42630 this.setDroppable(this.dropGroup.split(","));
42632 if (this.deletable) {
42633 this.setDeletable();
42635 this.isDirtyFlag = false;
42641 Roo.extend(Roo.DDView, Roo.View, {
42642 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
42643 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
42644 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
42645 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
42649 reset: Roo.emptyFn,
42651 clearInvalid: Roo.form.Field.prototype.clearInvalid,
42653 validate: function() {
42657 destroy: function() {
42658 this.purgeListeners();
42659 this.getEl.removeAllListeners();
42660 this.getEl().remove();
42661 if (this.dragZone) {
42662 if (this.dragZone.destroy) {
42663 this.dragZone.destroy();
42666 if (this.dropZone) {
42667 if (this.dropZone.destroy) {
42668 this.dropZone.destroy();
42673 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
42674 getName: function() {
42678 /** Loads the View from a JSON string representing the Records to put into the Store. */
42679 setValue: function(v) {
42681 throw "DDView.setValue(). DDView must be constructed with a valid Store";
42684 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
42685 this.store.proxy = new Roo.data.MemoryProxy(data);
42689 /** @return {String} a parenthesised list of the ids of the Records in the View. */
42690 getValue: function() {
42692 this.store.each(function(rec) {
42693 result += rec.id + ',';
42695 return result.substr(0, result.length - 1) + ')';
42698 getIds: function() {
42699 var i = 0, result = new Array(this.store.getCount());
42700 this.store.each(function(rec) {
42701 result[i++] = rec.id;
42706 isDirty: function() {
42707 return this.isDirtyFlag;
42711 * Part of the Roo.dd.DropZone interface. If no target node is found, the
42712 * whole Element becomes the target, and this causes the drop gesture to append.
42714 getTargetFromEvent : function(e) {
42715 var target = e.getTarget();
42716 while ((target !== null) && (target.parentNode != this.el.dom)) {
42717 target = target.parentNode;
42720 target = this.el.dom.lastChild || this.el.dom;
42726 * Create the drag data which consists of an object which has the property "ddel" as
42727 * the drag proxy element.
42729 getDragData : function(e) {
42730 var target = this.findItemFromChild(e.getTarget());
42732 this.handleSelection(e);
42733 var selNodes = this.getSelectedNodes();
42736 copy: this.copy || (this.allowCopy && e.ctrlKey),
42740 var selectedIndices = this.getSelectedIndexes();
42741 for (var i = 0; i < selectedIndices.length; i++) {
42742 dragData.records.push(this.store.getAt(selectedIndices[i]));
42744 if (selNodes.length == 1) {
42745 dragData.ddel = target.cloneNode(true); // the div element
42747 var div = document.createElement('div'); // create the multi element drag "ghost"
42748 div.className = 'multi-proxy';
42749 for (var i = 0, len = selNodes.length; i < len; i++) {
42750 div.appendChild(selNodes[i].cloneNode(true));
42752 dragData.ddel = div;
42754 //console.log(dragData)
42755 //console.log(dragData.ddel.innerHTML)
42758 //console.log('nodragData')
42762 /** Specify to which ddGroup items in this DDView may be dragged. */
42763 setDraggable: function(ddGroup) {
42764 if (ddGroup instanceof Array) {
42765 Roo.each(ddGroup, this.setDraggable, this);
42768 if (this.dragZone) {
42769 this.dragZone.addToGroup(ddGroup);
42771 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
42772 containerScroll: true,
42776 // Draggability implies selection. DragZone's mousedown selects the element.
42777 if (!this.multiSelect) { this.singleSelect = true; }
42779 // Wire the DragZone's handlers up to methods in *this*
42780 this.dragZone.getDragData = this.getDragData.createDelegate(this);
42784 /** Specify from which ddGroup this DDView accepts drops. */
42785 setDroppable: function(ddGroup) {
42786 if (ddGroup instanceof Array) {
42787 Roo.each(ddGroup, this.setDroppable, this);
42790 if (this.dropZone) {
42791 this.dropZone.addToGroup(ddGroup);
42793 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
42794 containerScroll: true,
42798 // Wire the DropZone's handlers up to methods in *this*
42799 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
42800 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
42801 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
42802 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
42803 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
42807 /** Decide whether to drop above or below a View node. */
42808 getDropPoint : function(e, n, dd){
42809 if (n == this.el.dom) { return "above"; }
42810 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
42811 var c = t + (b - t) / 2;
42812 var y = Roo.lib.Event.getPageY(e);
42820 onNodeEnter : function(n, dd, e, data){
42824 onNodeOver : function(n, dd, e, data){
42825 var pt = this.getDropPoint(e, n, dd);
42826 // set the insert point style on the target node
42827 var dragElClass = this.dropNotAllowed;
42830 if (pt == "above"){
42831 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
42832 targetElClass = "x-view-drag-insert-above";
42834 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
42835 targetElClass = "x-view-drag-insert-below";
42837 if (this.lastInsertClass != targetElClass){
42838 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
42839 this.lastInsertClass = targetElClass;
42842 return dragElClass;
42845 onNodeOut : function(n, dd, e, data){
42846 this.removeDropIndicators(n);
42849 onNodeDrop : function(n, dd, e, data){
42850 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
42853 var pt = this.getDropPoint(e, n, dd);
42854 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
42855 if (pt == "below") { insertAt++; }
42856 for (var i = 0; i < data.records.length; i++) {
42857 var r = data.records[i];
42858 var dup = this.store.getById(r.id);
42859 if (dup && (dd != this.dragZone)) {
42860 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
42863 this.store.insert(insertAt++, r.copy());
42865 data.source.isDirtyFlag = true;
42867 this.store.insert(insertAt++, r);
42869 this.isDirtyFlag = true;
42872 this.dragZone.cachedTarget = null;
42876 removeDropIndicators : function(n){
42878 Roo.fly(n).removeClass([
42879 "x-view-drag-insert-above",
42880 "x-view-drag-insert-below"]);
42881 this.lastInsertClass = "_noclass";
42886 * Utility method. Add a delete option to the DDView's context menu.
42887 * @param {String} imageUrl The URL of the "delete" icon image.
42889 setDeletable: function(imageUrl) {
42890 if (!this.singleSelect && !this.multiSelect) {
42891 this.singleSelect = true;
42893 var c = this.getContextMenu();
42894 this.contextMenu.on("itemclick", function(item) {
42897 this.remove(this.getSelectedIndexes());
42901 this.contextMenu.add({
42908 /** Return the context menu for this DDView. */
42909 getContextMenu: function() {
42910 if (!this.contextMenu) {
42911 // Create the View's context menu
42912 this.contextMenu = new Roo.menu.Menu({
42913 id: this.id + "-contextmenu"
42915 this.el.on("contextmenu", this.showContextMenu, this);
42917 return this.contextMenu;
42920 disableContextMenu: function() {
42921 if (this.contextMenu) {
42922 this.el.un("contextmenu", this.showContextMenu, this);
42926 showContextMenu: function(e, item) {
42927 item = this.findItemFromChild(e.getTarget());
42930 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
42931 this.contextMenu.showAt(e.getXY());
42936 * Remove {@link Roo.data.Record}s at the specified indices.
42937 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
42939 remove: function(selectedIndices) {
42940 selectedIndices = [].concat(selectedIndices);
42941 for (var i = 0; i < selectedIndices.length; i++) {
42942 var rec = this.store.getAt(selectedIndices[i]);
42943 this.store.remove(rec);
42948 * Double click fires the event, but also, if this is draggable, and there is only one other
42949 * related DropZone, it transfers the selected node.
42951 onDblClick : function(e){
42952 var item = this.findItemFromChild(e.getTarget());
42954 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
42957 if (this.dragGroup) {
42958 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
42959 while (targets.indexOf(this.dropZone) > -1) {
42960 targets.remove(this.dropZone);
42962 if (targets.length == 1) {
42963 this.dragZone.cachedTarget = null;
42964 var el = Roo.get(targets[0].getEl());
42965 var box = el.getBox(true);
42966 targets[0].onNodeDrop(el.dom, {
42968 xy: [box.x, box.y + box.height - 1]
42969 }, null, this.getDragData(e));
42975 handleSelection: function(e) {
42976 this.dragZone.cachedTarget = null;
42977 var item = this.findItemFromChild(e.getTarget());
42979 this.clearSelections(true);
42982 if (item && (this.multiSelect || this.singleSelect)){
42983 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
42984 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
42985 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
42986 this.unselect(item);
42988 this.select(item, this.multiSelect && e.ctrlKey);
42989 this.lastSelection = item;
42994 onItemClick : function(item, index, e){
42995 if(this.fireEvent("beforeclick", this, index, item, e) === false){
43001 unselect : function(nodeInfo, suppressEvent){
43002 var node = this.getNode(nodeInfo);
43003 if(node && this.isSelected(node)){
43004 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
43005 Roo.fly(node).removeClass(this.selectedClass);
43006 this.selections.remove(node);
43007 if(!suppressEvent){
43008 this.fireEvent("selectionchange", this, this.selections);
43016 * Ext JS Library 1.1.1
43017 * Copyright(c) 2006-2007, Ext JS, LLC.
43019 * Originally Released Under LGPL - original licence link has changed is not relivant.
43022 * <script type="text/javascript">
43026 * @class Roo.LayoutManager
43027 * @extends Roo.util.Observable
43028 * Base class for layout managers.
43030 Roo.LayoutManager = function(container, config){
43031 Roo.LayoutManager.superclass.constructor.call(this);
43032 this.el = Roo.get(container);
43033 // ie scrollbar fix
43034 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
43035 document.body.scroll = "no";
43036 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
43037 this.el.position('relative');
43039 this.id = this.el.id;
43040 this.el.addClass("x-layout-container");
43041 /** false to disable window resize monitoring @type Boolean */
43042 this.monitorWindowResize = true;
43047 * Fires when a layout is performed.
43048 * @param {Roo.LayoutManager} this
43052 * @event regionresized
43053 * Fires when the user resizes a region.
43054 * @param {Roo.LayoutRegion} region The resized region
43055 * @param {Number} newSize The new size (width for east/west, height for north/south)
43057 "regionresized" : true,
43059 * @event regioncollapsed
43060 * Fires when a region is collapsed.
43061 * @param {Roo.LayoutRegion} region The collapsed region
43063 "regioncollapsed" : true,
43065 * @event regionexpanded
43066 * Fires when a region is expanded.
43067 * @param {Roo.LayoutRegion} region The expanded region
43069 "regionexpanded" : true
43071 this.updating = false;
43072 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
43075 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
43077 * Returns true if this layout is currently being updated
43078 * @return {Boolean}
43080 isUpdating : function(){
43081 return this.updating;
43085 * Suspend the LayoutManager from doing auto-layouts while
43086 * making multiple add or remove calls
43088 beginUpdate : function(){
43089 this.updating = true;
43093 * Restore auto-layouts and optionally disable the manager from performing a layout
43094 * @param {Boolean} noLayout true to disable a layout update
43096 endUpdate : function(noLayout){
43097 this.updating = false;
43103 layout: function(){
43107 onRegionResized : function(region, newSize){
43108 this.fireEvent("regionresized", region, newSize);
43112 onRegionCollapsed : function(region){
43113 this.fireEvent("regioncollapsed", region);
43116 onRegionExpanded : function(region){
43117 this.fireEvent("regionexpanded", region);
43121 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
43122 * performs box-model adjustments.
43123 * @return {Object} The size as an object {width: (the width), height: (the height)}
43125 getViewSize : function(){
43127 if(this.el.dom != document.body){
43128 size = this.el.getSize();
43130 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
43132 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
43133 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
43138 * Returns the Element this layout is bound to.
43139 * @return {Roo.Element}
43141 getEl : function(){
43146 * Returns the specified region.
43147 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
43148 * @return {Roo.LayoutRegion}
43150 getRegion : function(target){
43151 return this.regions[target.toLowerCase()];
43154 onWindowResize : function(){
43155 if(this.monitorWindowResize){
43161 * Ext JS Library 1.1.1
43162 * Copyright(c) 2006-2007, Ext JS, LLC.
43164 * Originally Released Under LGPL - original licence link has changed is not relivant.
43167 * <script type="text/javascript">
43170 * @class Roo.BorderLayout
43171 * @extends Roo.LayoutManager
43172 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
43173 * please see: <br><br>
43174 * <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>
43175 * <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>
43178 var layout = new Roo.BorderLayout(document.body, {
43212 preferredTabWidth: 150
43217 var CP = Roo.ContentPanel;
43219 layout.beginUpdate();
43220 layout.add("north", new CP("north", "North"));
43221 layout.add("south", new CP("south", {title: "South", closable: true}));
43222 layout.add("west", new CP("west", {title: "West"}));
43223 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
43224 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
43225 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
43226 layout.getRegion("center").showPanel("center1");
43227 layout.endUpdate();
43230 <b>The container the layout is rendered into can be either the body element or any other element.
43231 If it is not the body element, the container needs to either be an absolute positioned element,
43232 or you will need to add "position:relative" to the css of the container. You will also need to specify
43233 the container size if it is not the body element.</b>
43236 * Create a new BorderLayout
43237 * @param {String/HTMLElement/Element} container The container this layout is bound to
43238 * @param {Object} config Configuration options
43240 Roo.BorderLayout = function(container, config){
43241 config = config || {};
43242 Roo.BorderLayout.superclass.constructor.call(this, container, config);
43243 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
43244 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
43245 var target = this.factory.validRegions[i];
43246 if(config[target]){
43247 this.addRegion(target, config[target]);
43252 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
43254 * Creates and adds a new region if it doesn't already exist.
43255 * @param {String} target The target region key (north, south, east, west or center).
43256 * @param {Object} config The regions config object
43257 * @return {BorderLayoutRegion} The new region
43259 addRegion : function(target, config){
43260 if(!this.regions[target]){
43261 var r = this.factory.create(target, this, config);
43262 this.bindRegion(target, r);
43264 return this.regions[target];
43268 bindRegion : function(name, r){
43269 this.regions[name] = r;
43270 r.on("visibilitychange", this.layout, this);
43271 r.on("paneladded", this.layout, this);
43272 r.on("panelremoved", this.layout, this);
43273 r.on("invalidated", this.layout, this);
43274 r.on("resized", this.onRegionResized, this);
43275 r.on("collapsed", this.onRegionCollapsed, this);
43276 r.on("expanded", this.onRegionExpanded, this);
43280 * Performs a layout update.
43282 layout : function(){
43283 if(this.updating) return;
43284 var size = this.getViewSize();
43285 var w = size.width;
43286 var h = size.height;
43291 //var x = 0, y = 0;
43293 var rs = this.regions;
43294 var north = rs["north"];
43295 var south = rs["south"];
43296 var west = rs["west"];
43297 var east = rs["east"];
43298 var center = rs["center"];
43299 //if(this.hideOnLayout){ // not supported anymore
43300 //c.el.setStyle("display", "none");
43302 if(north && north.isVisible()){
43303 var b = north.getBox();
43304 var m = north.getMargins();
43305 b.width = w - (m.left+m.right);
43308 centerY = b.height + b.y + m.bottom;
43309 centerH -= centerY;
43310 north.updateBox(this.safeBox(b));
43312 if(south && south.isVisible()){
43313 var b = south.getBox();
43314 var m = south.getMargins();
43315 b.width = w - (m.left+m.right);
43317 var totalHeight = (b.height + m.top + m.bottom);
43318 b.y = h - totalHeight + m.top;
43319 centerH -= totalHeight;
43320 south.updateBox(this.safeBox(b));
43322 if(west && west.isVisible()){
43323 var b = west.getBox();
43324 var m = west.getMargins();
43325 b.height = centerH - (m.top+m.bottom);
43327 b.y = centerY + m.top;
43328 var totalWidth = (b.width + m.left + m.right);
43329 centerX += totalWidth;
43330 centerW -= totalWidth;
43331 west.updateBox(this.safeBox(b));
43333 if(east && east.isVisible()){
43334 var b = east.getBox();
43335 var m = east.getMargins();
43336 b.height = centerH - (m.top+m.bottom);
43337 var totalWidth = (b.width + m.left + m.right);
43338 b.x = w - totalWidth + m.left;
43339 b.y = centerY + m.top;
43340 centerW -= totalWidth;
43341 east.updateBox(this.safeBox(b));
43344 var m = center.getMargins();
43346 x: centerX + m.left,
43347 y: centerY + m.top,
43348 width: centerW - (m.left+m.right),
43349 height: centerH - (m.top+m.bottom)
43351 //if(this.hideOnLayout){
43352 //center.el.setStyle("display", "block");
43354 center.updateBox(this.safeBox(centerBox));
43357 this.fireEvent("layout", this);
43361 safeBox : function(box){
43362 box.width = Math.max(0, box.width);
43363 box.height = Math.max(0, box.height);
43368 * Adds a ContentPanel (or subclass) to this layout.
43369 * @param {String} target The target region key (north, south, east, west or center).
43370 * @param {Roo.ContentPanel} panel The panel to add
43371 * @return {Roo.ContentPanel} The added panel
43373 add : function(target, panel){
43375 target = target.toLowerCase();
43376 return this.regions[target].add(panel);
43380 * Remove a ContentPanel (or subclass) to this layout.
43381 * @param {String} target The target region key (north, south, east, west or center).
43382 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
43383 * @return {Roo.ContentPanel} The removed panel
43385 remove : function(target, panel){
43386 target = target.toLowerCase();
43387 return this.regions[target].remove(panel);
43391 * Searches all regions for a panel with the specified id
43392 * @param {String} panelId
43393 * @return {Roo.ContentPanel} The panel or null if it wasn't found
43395 findPanel : function(panelId){
43396 var rs = this.regions;
43397 for(var target in rs){
43398 if(typeof rs[target] != "function"){
43399 var p = rs[target].getPanel(panelId);
43409 * Searches all regions for a panel with the specified id and activates (shows) it.
43410 * @param {String/ContentPanel} panelId The panels id or the panel itself
43411 * @return {Roo.ContentPanel} The shown panel or null
43413 showPanel : function(panelId) {
43414 var rs = this.regions;
43415 for(var target in rs){
43416 var r = rs[target];
43417 if(typeof r != "function"){
43418 if(r.hasPanel(panelId)){
43419 return r.showPanel(panelId);
43427 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
43428 * @param {Roo.state.Provider} provider (optional) An alternate state provider
43430 restoreState : function(provider){
43432 provider = Roo.state.Manager;
43434 var sm = new Roo.LayoutStateManager();
43435 sm.init(this, provider);
43439 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
43440 * object should contain properties for each region to add ContentPanels to, and each property's value should be
43441 * a valid ContentPanel config object. Example:
43443 // Create the main layout
43444 var layout = new Roo.BorderLayout('main-ct', {
43455 // Create and add multiple ContentPanels at once via configs
43458 id: 'source-files',
43460 title:'Ext Source Files',
43473 * @param {Object} regions An object containing ContentPanel configs by region name
43475 batchAdd : function(regions){
43476 this.beginUpdate();
43477 for(var rname in regions){
43478 var lr = this.regions[rname];
43480 this.addTypedPanels(lr, regions[rname]);
43487 addTypedPanels : function(lr, ps){
43488 if(typeof ps == 'string'){
43489 lr.add(new Roo.ContentPanel(ps));
43491 else if(ps instanceof Array){
43492 for(var i =0, len = ps.length; i < len; i++){
43493 this.addTypedPanels(lr, ps[i]);
43496 else if(!ps.events){ // raw config?
43498 delete ps.el; // prevent conflict
43499 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
43501 else { // panel object assumed!
43506 * Adds a xtype elements to the layout.
43510 xtype : 'ContentPanel',
43517 xtype : 'NestedLayoutPanel',
43523 items : [ ... list of content panels or nested layout panels.. ]
43527 * @param {Object} cfg Xtype definition of item to add.
43529 addxtype : function(cfg)
43531 // basically accepts a pannel...
43532 // can accept a layout region..!?!?
43533 // console.log('BorderLayout add ' + cfg.xtype)
43535 if (!cfg.xtype.match(/Panel$/)) {
43539 var region = cfg.region;
43545 xitems = cfg.items;
43552 case 'ContentPanel': // ContentPanel (el, cfg)
43553 case 'ScrollPanel': // ContentPanel (el, cfg)
43554 if(cfg.autoCreate) {
43555 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43557 var el = this.el.createChild();
43558 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
43561 this.add(region, ret);
43565 case 'TreePanel': // our new panel!
43566 cfg.el = this.el.createChild();
43567 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43568 this.add(region, ret);
43571 case 'NestedLayoutPanel':
43572 // create a new Layout (which is a Border Layout...
43573 var el = this.el.createChild();
43574 var clayout = cfg.layout;
43576 clayout.items = clayout.items || [];
43577 // replace this exitems with the clayout ones..
43578 xitems = clayout.items;
43581 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
43582 cfg.background = false;
43584 var layout = new Roo.BorderLayout(el, clayout);
43586 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
43587 //console.log('adding nested layout panel ' + cfg.toSource());
43588 this.add(region, ret);
43594 // needs grid and region
43596 //var el = this.getRegion(region).el.createChild();
43597 var el = this.el.createChild();
43598 // create the grid first...
43600 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
43602 if (region == 'center' && this.active ) {
43603 cfg.background = false;
43605 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
43607 this.add(region, ret);
43608 if (cfg.background) {
43609 ret.on('activate', function(gp) {
43610 if (!gp.grid.rendered) {
43623 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
43625 // GridPanel (grid, cfg)
43628 this.beginUpdate();
43630 Roo.each(xitems, function(i) {
43640 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
43641 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
43642 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
43643 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
43646 var CP = Roo.ContentPanel;
43648 var layout = Roo.BorderLayout.create({
43652 panels: [new CP("north", "North")]
43661 panels: [new CP("west", {title: "West"})]
43670 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
43679 panels: [new CP("south", {title: "South", closable: true})]
43686 preferredTabWidth: 150,
43688 new CP("center1", {title: "Close Me", closable: true}),
43689 new CP("center2", {title: "Center Panel", closable: false})
43694 layout.getRegion("center").showPanel("center1");
43699 Roo.BorderLayout.create = function(config, targetEl){
43700 var layout = new Roo.BorderLayout(targetEl || document.body, config);
43701 layout.beginUpdate();
43702 var regions = Roo.BorderLayout.RegionFactory.validRegions;
43703 for(var j = 0, jlen = regions.length; j < jlen; j++){
43704 var lr = regions[j];
43705 if(layout.regions[lr] && config[lr].panels){
43706 var r = layout.regions[lr];
43707 var ps = config[lr].panels;
43708 layout.addTypedPanels(r, ps);
43711 layout.endUpdate();
43716 Roo.BorderLayout.RegionFactory = {
43718 validRegions : ["north","south","east","west","center"],
43721 create : function(target, mgr, config){
43722 target = target.toLowerCase();
43723 if(config.lightweight || config.basic){
43724 return new Roo.BasicLayoutRegion(mgr, config, target);
43728 return new Roo.NorthLayoutRegion(mgr, config);
43730 return new Roo.SouthLayoutRegion(mgr, config);
43732 return new Roo.EastLayoutRegion(mgr, config);
43734 return new Roo.WestLayoutRegion(mgr, config);
43736 return new Roo.CenterLayoutRegion(mgr, config);
43738 throw 'Layout region "'+target+'" not supported.';
43742 * Ext JS Library 1.1.1
43743 * Copyright(c) 2006-2007, Ext JS, LLC.
43745 * Originally Released Under LGPL - original licence link has changed is not relivant.
43748 * <script type="text/javascript">
43752 * @class Roo.BasicLayoutRegion
43753 * @extends Roo.util.Observable
43754 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
43755 * and does not have a titlebar, tabs or any other features. All it does is size and position
43756 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
43758 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
43760 this.position = pos;
43763 * @scope Roo.BasicLayoutRegion
43767 * @event beforeremove
43768 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
43769 * @param {Roo.LayoutRegion} this
43770 * @param {Roo.ContentPanel} panel The panel
43771 * @param {Object} e The cancel event object
43773 "beforeremove" : true,
43775 * @event invalidated
43776 * Fires when the layout for this region is changed.
43777 * @param {Roo.LayoutRegion} this
43779 "invalidated" : true,
43781 * @event visibilitychange
43782 * Fires when this region is shown or hidden
43783 * @param {Roo.LayoutRegion} this
43784 * @param {Boolean} visibility true or false
43786 "visibilitychange" : true,
43788 * @event paneladded
43789 * Fires when a panel is added.
43790 * @param {Roo.LayoutRegion} this
43791 * @param {Roo.ContentPanel} panel The panel
43793 "paneladded" : true,
43795 * @event panelremoved
43796 * Fires when a panel is removed.
43797 * @param {Roo.LayoutRegion} this
43798 * @param {Roo.ContentPanel} panel The panel
43800 "panelremoved" : true,
43803 * Fires when this region is collapsed.
43804 * @param {Roo.LayoutRegion} this
43806 "collapsed" : true,
43809 * Fires when this region is expanded.
43810 * @param {Roo.LayoutRegion} this
43815 * Fires when this region is slid into view.
43816 * @param {Roo.LayoutRegion} this
43818 "slideshow" : true,
43821 * Fires when this region slides out of view.
43822 * @param {Roo.LayoutRegion} this
43824 "slidehide" : true,
43826 * @event panelactivated
43827 * Fires when a panel is activated.
43828 * @param {Roo.LayoutRegion} this
43829 * @param {Roo.ContentPanel} panel The activated panel
43831 "panelactivated" : true,
43834 * Fires when the user resizes this region.
43835 * @param {Roo.LayoutRegion} this
43836 * @param {Number} newSize The new size (width for east/west, height for north/south)
43840 /** A collection of panels in this region. @type Roo.util.MixedCollection */
43841 this.panels = new Roo.util.MixedCollection();
43842 this.panels.getKey = this.getPanelId.createDelegate(this);
43844 this.activePanel = null;
43845 // ensure listeners are added...
43847 if (config.listeners || config.events) {
43848 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
43849 listeners : config.listeners || {},
43850 events : config.events || {}
43854 if(skipConfig !== true){
43855 this.applyConfig(config);
43859 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
43860 getPanelId : function(p){
43864 applyConfig : function(config){
43865 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43866 this.config = config;
43871 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
43872 * the width, for horizontal (north, south) the height.
43873 * @param {Number} newSize The new width or height
43875 resizeTo : function(newSize){
43876 var el = this.el ? this.el :
43877 (this.activePanel ? this.activePanel.getEl() : null);
43879 switch(this.position){
43882 el.setWidth(newSize);
43883 this.fireEvent("resized", this, newSize);
43887 el.setHeight(newSize);
43888 this.fireEvent("resized", this, newSize);
43894 getBox : function(){
43895 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
43898 getMargins : function(){
43899 return this.margins;
43902 updateBox : function(box){
43904 var el = this.activePanel.getEl();
43905 el.dom.style.left = box.x + "px";
43906 el.dom.style.top = box.y + "px";
43907 this.activePanel.setSize(box.width, box.height);
43911 * Returns the container element for this region.
43912 * @return {Roo.Element}
43914 getEl : function(){
43915 return this.activePanel;
43919 * Returns true if this region is currently visible.
43920 * @return {Boolean}
43922 isVisible : function(){
43923 return this.activePanel ? true : false;
43926 setActivePanel : function(panel){
43927 panel = this.getPanel(panel);
43928 if(this.activePanel && this.activePanel != panel){
43929 this.activePanel.setActiveState(false);
43930 this.activePanel.getEl().setLeftTop(-10000,-10000);
43932 this.activePanel = panel;
43933 panel.setActiveState(true);
43935 panel.setSize(this.box.width, this.box.height);
43937 this.fireEvent("panelactivated", this, panel);
43938 this.fireEvent("invalidated");
43942 * Show the specified panel.
43943 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
43944 * @return {Roo.ContentPanel} The shown panel or null
43946 showPanel : function(panel){
43947 if(panel = this.getPanel(panel)){
43948 this.setActivePanel(panel);
43954 * Get the active panel for this region.
43955 * @return {Roo.ContentPanel} The active panel or null
43957 getActivePanel : function(){
43958 return this.activePanel;
43962 * Add the passed ContentPanel(s)
43963 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43964 * @return {Roo.ContentPanel} The panel added (if only one was added)
43966 add : function(panel){
43967 if(arguments.length > 1){
43968 for(var i = 0, len = arguments.length; i < len; i++) {
43969 this.add(arguments[i]);
43973 if(this.hasPanel(panel)){
43974 this.showPanel(panel);
43977 var el = panel.getEl();
43978 if(el.dom.parentNode != this.mgr.el.dom){
43979 this.mgr.el.dom.appendChild(el.dom);
43981 if(panel.setRegion){
43982 panel.setRegion(this);
43984 this.panels.add(panel);
43985 el.setStyle("position", "absolute");
43986 if(!panel.background){
43987 this.setActivePanel(panel);
43988 if(this.config.initialSize && this.panels.getCount()==1){
43989 this.resizeTo(this.config.initialSize);
43992 this.fireEvent("paneladded", this, panel);
43997 * Returns true if the panel is in this region.
43998 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43999 * @return {Boolean}
44001 hasPanel : function(panel){
44002 if(typeof panel == "object"){ // must be panel obj
44003 panel = panel.getId();
44005 return this.getPanel(panel) ? true : false;
44009 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44010 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44011 * @param {Boolean} preservePanel Overrides the config preservePanel option
44012 * @return {Roo.ContentPanel} The panel that was removed
44014 remove : function(panel, preservePanel){
44015 panel = this.getPanel(panel);
44020 this.fireEvent("beforeremove", this, panel, e);
44021 if(e.cancel === true){
44024 var panelId = panel.getId();
44025 this.panels.removeKey(panelId);
44030 * Returns the panel specified or null if it's not in this region.
44031 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44032 * @return {Roo.ContentPanel}
44034 getPanel : function(id){
44035 if(typeof id == "object"){ // must be panel obj
44038 return this.panels.get(id);
44042 * Returns this regions position (north/south/east/west/center).
44045 getPosition: function(){
44046 return this.position;
44050 * Ext JS Library 1.1.1
44051 * Copyright(c) 2006-2007, Ext JS, LLC.
44053 * Originally Released Under LGPL - original licence link has changed is not relivant.
44056 * <script type="text/javascript">
44060 * @class Roo.LayoutRegion
44061 * @extends Roo.BasicLayoutRegion
44062 * This class represents a region in a layout manager.
44063 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
44064 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
44065 * @cfg {Boolean} floatable False to disable floating (defaults to true)
44066 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
44067 * @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})
44068 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
44069 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
44070 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
44071 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
44072 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
44073 * @cfg {String} title The title for the region (overrides panel titles)
44074 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
44075 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
44076 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
44077 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
44078 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
44079 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
44080 * the space available, similar to FireFox 1.5 tabs (defaults to false)
44081 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
44082 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
44083 * @cfg {Boolean} showPin True to show a pin button
44084 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
44085 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
44086 * @cfg {Boolean} disableTabTips True to disable tab tooltips
44087 * @cfg {Number} width For East/West panels
44088 * @cfg {Number} height For North/South panels
44089 * @cfg {Boolean} split To show the splitter
44091 Roo.LayoutRegion = function(mgr, config, pos){
44092 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
44093 var dh = Roo.DomHelper;
44094 /** This region's container element
44095 * @type Roo.Element */
44096 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
44097 /** This region's title element
44098 * @type Roo.Element */
44100 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
44101 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
44102 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
44104 this.titleEl.enableDisplayMode();
44105 /** This region's title text element
44106 * @type HTMLElement */
44107 this.titleTextEl = this.titleEl.dom.firstChild;
44108 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
44109 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
44110 this.closeBtn.enableDisplayMode();
44111 this.closeBtn.on("click", this.closeClicked, this);
44112 this.closeBtn.hide();
44114 this.createBody(config);
44115 this.visible = true;
44116 this.collapsed = false;
44118 if(config.hideWhenEmpty){
44120 this.on("paneladded", this.validateVisibility, this);
44121 this.on("panelremoved", this.validateVisibility, this);
44123 this.applyConfig(config);
44126 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
44128 createBody : function(){
44129 /** This region's body element
44130 * @type Roo.Element */
44131 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
44134 applyConfig : function(c){
44135 if(c.collapsible && this.position != "center" && !this.collapsedEl){
44136 var dh = Roo.DomHelper;
44137 if(c.titlebar !== false){
44138 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
44139 this.collapseBtn.on("click", this.collapse, this);
44140 this.collapseBtn.enableDisplayMode();
44142 if(c.showPin === true || this.showPin){
44143 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
44144 this.stickBtn.enableDisplayMode();
44145 this.stickBtn.on("click", this.expand, this);
44146 this.stickBtn.hide();
44149 /** This region's collapsed element
44150 * @type Roo.Element */
44151 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
44152 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
44154 if(c.floatable !== false){
44155 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
44156 this.collapsedEl.on("click", this.collapseClick, this);
44159 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
44160 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
44161 id: "message", unselectable: "on", style:{"float":"left"}});
44162 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
44164 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
44165 this.expandBtn.on("click", this.expand, this);
44167 if(this.collapseBtn){
44168 this.collapseBtn.setVisible(c.collapsible == true);
44170 this.cmargins = c.cmargins || this.cmargins ||
44171 (this.position == "west" || this.position == "east" ?
44172 {top: 0, left: 2, right:2, bottom: 0} :
44173 {top: 2, left: 0, right:0, bottom: 2});
44174 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44175 this.bottomTabs = c.tabPosition != "top";
44176 this.autoScroll = c.autoScroll || false;
44177 if(this.autoScroll){
44178 this.bodyEl.setStyle("overflow", "auto");
44180 this.bodyEl.setStyle("overflow", "hidden");
44182 //if(c.titlebar !== false){
44183 if((!c.titlebar && !c.title) || c.titlebar === false){
44184 this.titleEl.hide();
44186 this.titleEl.show();
44188 this.titleTextEl.innerHTML = c.title;
44192 this.duration = c.duration || .30;
44193 this.slideDuration = c.slideDuration || .45;
44196 this.collapse(true);
44203 * Returns true if this region is currently visible.
44204 * @return {Boolean}
44206 isVisible : function(){
44207 return this.visible;
44211 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
44212 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
44214 setCollapsedTitle : function(title){
44215 title = title || " ";
44216 if(this.collapsedTitleTextEl){
44217 this.collapsedTitleTextEl.innerHTML = title;
44221 getBox : function(){
44223 if(!this.collapsed){
44224 b = this.el.getBox(false, true);
44226 b = this.collapsedEl.getBox(false, true);
44231 getMargins : function(){
44232 return this.collapsed ? this.cmargins : this.margins;
44235 highlight : function(){
44236 this.el.addClass("x-layout-panel-dragover");
44239 unhighlight : function(){
44240 this.el.removeClass("x-layout-panel-dragover");
44243 updateBox : function(box){
44245 if(!this.collapsed){
44246 this.el.dom.style.left = box.x + "px";
44247 this.el.dom.style.top = box.y + "px";
44248 this.updateBody(box.width, box.height);
44250 this.collapsedEl.dom.style.left = box.x + "px";
44251 this.collapsedEl.dom.style.top = box.y + "px";
44252 this.collapsedEl.setSize(box.width, box.height);
44255 this.tabs.autoSizeTabs();
44259 updateBody : function(w, h){
44261 this.el.setWidth(w);
44262 w -= this.el.getBorderWidth("rl");
44263 if(this.config.adjustments){
44264 w += this.config.adjustments[0];
44268 this.el.setHeight(h);
44269 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
44270 h -= this.el.getBorderWidth("tb");
44271 if(this.config.adjustments){
44272 h += this.config.adjustments[1];
44274 this.bodyEl.setHeight(h);
44276 h = this.tabs.syncHeight(h);
44279 if(this.panelSize){
44280 w = w !== null ? w : this.panelSize.width;
44281 h = h !== null ? h : this.panelSize.height;
44283 if(this.activePanel){
44284 var el = this.activePanel.getEl();
44285 w = w !== null ? w : el.getWidth();
44286 h = h !== null ? h : el.getHeight();
44287 this.panelSize = {width: w, height: h};
44288 this.activePanel.setSize(w, h);
44290 if(Roo.isIE && this.tabs){
44291 this.tabs.el.repaint();
44296 * Returns the container element for this region.
44297 * @return {Roo.Element}
44299 getEl : function(){
44304 * Hides this region.
44307 if(!this.collapsed){
44308 this.el.dom.style.left = "-2000px";
44311 this.collapsedEl.dom.style.left = "-2000px";
44312 this.collapsedEl.hide();
44314 this.visible = false;
44315 this.fireEvent("visibilitychange", this, false);
44319 * Shows this region if it was previously hidden.
44322 if(!this.collapsed){
44325 this.collapsedEl.show();
44327 this.visible = true;
44328 this.fireEvent("visibilitychange", this, true);
44331 closeClicked : function(){
44332 if(this.activePanel){
44333 this.remove(this.activePanel);
44337 collapseClick : function(e){
44339 e.stopPropagation();
44342 e.stopPropagation();
44348 * Collapses this region.
44349 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
44351 collapse : function(skipAnim){
44352 if(this.collapsed) return;
44353 this.collapsed = true;
44355 this.split.el.hide();
44357 if(this.config.animate && skipAnim !== true){
44358 this.fireEvent("invalidated", this);
44359 this.animateCollapse();
44361 this.el.setLocation(-20000,-20000);
44363 this.collapsedEl.show();
44364 this.fireEvent("collapsed", this);
44365 this.fireEvent("invalidated", this);
44369 animateCollapse : function(){
44374 * Expands this region if it was previously collapsed.
44375 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
44376 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
44378 expand : function(e, skipAnim){
44379 if(e) e.stopPropagation();
44380 if(!this.collapsed || this.el.hasActiveFx()) return;
44382 this.afterSlideIn();
44385 this.collapsed = false;
44386 if(this.config.animate && skipAnim !== true){
44387 this.animateExpand();
44391 this.split.el.show();
44393 this.collapsedEl.setLocation(-2000,-2000);
44394 this.collapsedEl.hide();
44395 this.fireEvent("invalidated", this);
44396 this.fireEvent("expanded", this);
44400 animateExpand : function(){
44404 initTabs : function(){
44405 this.bodyEl.setStyle("overflow", "hidden");
44406 var ts = new Roo.TabPanel(this.bodyEl.dom, {
44407 tabPosition: this.bottomTabs ? 'bottom' : 'top',
44408 disableTooltips: this.config.disableTabTips
44410 if(this.config.hideTabs){
44411 ts.stripWrap.setDisplayed(false);
44414 ts.resizeTabs = this.config.resizeTabs === true;
44415 ts.minTabWidth = this.config.minTabWidth || 40;
44416 ts.maxTabWidth = this.config.maxTabWidth || 250;
44417 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
44418 ts.monitorResize = false;
44419 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44420 ts.bodyEl.addClass('x-layout-tabs-body');
44421 this.panels.each(this.initPanelAsTab, this);
44424 initPanelAsTab : function(panel){
44425 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
44426 this.config.closeOnTab && panel.isClosable());
44427 if(panel.tabTip !== undefined){
44428 ti.setTooltip(panel.tabTip);
44430 ti.on("activate", function(){
44431 this.setActivePanel(panel);
44433 if(this.config.closeOnTab){
44434 ti.on("beforeclose", function(t, e){
44436 this.remove(panel);
44442 updatePanelTitle : function(panel, title){
44443 if(this.activePanel == panel){
44444 this.updateTitle(title);
44447 var ti = this.tabs.getTab(panel.getEl().id);
44449 if(panel.tabTip !== undefined){
44450 ti.setTooltip(panel.tabTip);
44455 updateTitle : function(title){
44456 if(this.titleTextEl && !this.config.title){
44457 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
44461 setActivePanel : function(panel){
44462 panel = this.getPanel(panel);
44463 if(this.activePanel && this.activePanel != panel){
44464 this.activePanel.setActiveState(false);
44466 this.activePanel = panel;
44467 panel.setActiveState(true);
44468 if(this.panelSize){
44469 panel.setSize(this.panelSize.width, this.panelSize.height);
44472 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
44474 this.updateTitle(panel.getTitle());
44476 this.fireEvent("invalidated", this);
44478 this.fireEvent("panelactivated", this, panel);
44482 * Shows the specified panel.
44483 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
44484 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
44486 showPanel : function(panel){
44487 if(panel = this.getPanel(panel)){
44489 var tab = this.tabs.getTab(panel.getEl().id);
44490 if(tab.isHidden()){
44491 this.tabs.unhideTab(tab.id);
44495 this.setActivePanel(panel);
44502 * Get the active panel for this region.
44503 * @return {Roo.ContentPanel} The active panel or null
44505 getActivePanel : function(){
44506 return this.activePanel;
44509 validateVisibility : function(){
44510 if(this.panels.getCount() < 1){
44511 this.updateTitle(" ");
44512 this.closeBtn.hide();
44515 if(!this.isVisible()){
44522 * Adds the passed ContentPanel(s) to this region.
44523 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44524 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
44526 add : function(panel){
44527 if(arguments.length > 1){
44528 for(var i = 0, len = arguments.length; i < len; i++) {
44529 this.add(arguments[i]);
44533 if(this.hasPanel(panel)){
44534 this.showPanel(panel);
44537 panel.setRegion(this);
44538 this.panels.add(panel);
44539 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
44540 this.bodyEl.dom.appendChild(panel.getEl().dom);
44541 if(panel.background !== true){
44542 this.setActivePanel(panel);
44544 this.fireEvent("paneladded", this, panel);
44550 this.initPanelAsTab(panel);
44552 if(panel.background !== true){
44553 this.tabs.activate(panel.getEl().id);
44555 this.fireEvent("paneladded", this, panel);
44560 * Hides the tab for the specified panel.
44561 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44563 hidePanel : function(panel){
44564 if(this.tabs && (panel = this.getPanel(panel))){
44565 this.tabs.hideTab(panel.getEl().id);
44570 * Unhides the tab for a previously hidden panel.
44571 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44573 unhidePanel : function(panel){
44574 if(this.tabs && (panel = this.getPanel(panel))){
44575 this.tabs.unhideTab(panel.getEl().id);
44579 clearPanels : function(){
44580 while(this.panels.getCount() > 0){
44581 this.remove(this.panels.first());
44586 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44587 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44588 * @param {Boolean} preservePanel Overrides the config preservePanel option
44589 * @return {Roo.ContentPanel} The panel that was removed
44591 remove : function(panel, preservePanel){
44592 panel = this.getPanel(panel);
44597 this.fireEvent("beforeremove", this, panel, e);
44598 if(e.cancel === true){
44601 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
44602 var panelId = panel.getId();
44603 this.panels.removeKey(panelId);
44605 document.body.appendChild(panel.getEl().dom);
44608 this.tabs.removeTab(panel.getEl().id);
44609 }else if (!preservePanel){
44610 this.bodyEl.dom.removeChild(panel.getEl().dom);
44612 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
44613 var p = this.panels.first();
44614 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
44615 tempEl.appendChild(p.getEl().dom);
44616 this.bodyEl.update("");
44617 this.bodyEl.dom.appendChild(p.getEl().dom);
44619 this.updateTitle(p.getTitle());
44621 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44622 this.setActivePanel(p);
44624 panel.setRegion(null);
44625 if(this.activePanel == panel){
44626 this.activePanel = null;
44628 if(this.config.autoDestroy !== false && preservePanel !== true){
44629 try{panel.destroy();}catch(e){}
44631 this.fireEvent("panelremoved", this, panel);
44636 * Returns the TabPanel component used by this region
44637 * @return {Roo.TabPanel}
44639 getTabs : function(){
44643 createTool : function(parentEl, className){
44644 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
44645 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
44646 btn.addClassOnOver("x-layout-tools-button-over");
44651 * Ext JS Library 1.1.1
44652 * Copyright(c) 2006-2007, Ext JS, LLC.
44654 * Originally Released Under LGPL - original licence link has changed is not relivant.
44657 * <script type="text/javascript">
44663 * @class Roo.SplitLayoutRegion
44664 * @extends Roo.LayoutRegion
44665 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
44667 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
44668 this.cursor = cursor;
44669 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
44672 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
44673 splitTip : "Drag to resize.",
44674 collapsibleSplitTip : "Drag to resize. Double click to hide.",
44675 useSplitTips : false,
44677 applyConfig : function(config){
44678 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
44681 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
44682 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
44683 /** The SplitBar for this region
44684 * @type Roo.SplitBar */
44685 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
44686 this.split.on("moved", this.onSplitMove, this);
44687 this.split.useShim = config.useShim === true;
44688 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
44689 if(this.useSplitTips){
44690 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
44692 if(config.collapsible){
44693 this.split.el.on("dblclick", this.collapse, this);
44696 if(typeof config.minSize != "undefined"){
44697 this.split.minSize = config.minSize;
44699 if(typeof config.maxSize != "undefined"){
44700 this.split.maxSize = config.maxSize;
44702 if(config.hideWhenEmpty || config.hidden || config.collapsed){
44703 this.hideSplitter();
44708 getHMaxSize : function(){
44709 var cmax = this.config.maxSize || 10000;
44710 var center = this.mgr.getRegion("center");
44711 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
44714 getVMaxSize : function(){
44715 var cmax = this.config.maxSize || 10000;
44716 var center = this.mgr.getRegion("center");
44717 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
44720 onSplitMove : function(split, newSize){
44721 this.fireEvent("resized", this, newSize);
44725 * Returns the {@link Roo.SplitBar} for this region.
44726 * @return {Roo.SplitBar}
44728 getSplitBar : function(){
44733 this.hideSplitter();
44734 Roo.SplitLayoutRegion.superclass.hide.call(this);
44737 hideSplitter : function(){
44739 this.split.el.setLocation(-2000,-2000);
44740 this.split.el.hide();
44746 this.split.el.show();
44748 Roo.SplitLayoutRegion.superclass.show.call(this);
44751 beforeSlide: function(){
44752 if(Roo.isGecko){// firefox overflow auto bug workaround
44753 this.bodyEl.clip();
44754 if(this.tabs) this.tabs.bodyEl.clip();
44755 if(this.activePanel){
44756 this.activePanel.getEl().clip();
44758 if(this.activePanel.beforeSlide){
44759 this.activePanel.beforeSlide();
44765 afterSlide : function(){
44766 if(Roo.isGecko){// firefox overflow auto bug workaround
44767 this.bodyEl.unclip();
44768 if(this.tabs) this.tabs.bodyEl.unclip();
44769 if(this.activePanel){
44770 this.activePanel.getEl().unclip();
44771 if(this.activePanel.afterSlide){
44772 this.activePanel.afterSlide();
44778 initAutoHide : function(){
44779 if(this.autoHide !== false){
44780 if(!this.autoHideHd){
44781 var st = new Roo.util.DelayedTask(this.slideIn, this);
44782 this.autoHideHd = {
44783 "mouseout": function(e){
44784 if(!e.within(this.el, true)){
44788 "mouseover" : function(e){
44794 this.el.on(this.autoHideHd);
44798 clearAutoHide : function(){
44799 if(this.autoHide !== false){
44800 this.el.un("mouseout", this.autoHideHd.mouseout);
44801 this.el.un("mouseover", this.autoHideHd.mouseover);
44805 clearMonitor : function(){
44806 Roo.get(document).un("click", this.slideInIf, this);
44809 // these names are backwards but not changed for compat
44810 slideOut : function(){
44811 if(this.isSlid || this.el.hasActiveFx()){
44814 this.isSlid = true;
44815 if(this.collapseBtn){
44816 this.collapseBtn.hide();
44818 this.closeBtnState = this.closeBtn.getStyle('display');
44819 this.closeBtn.hide();
44821 this.stickBtn.show();
44824 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
44825 this.beforeSlide();
44826 this.el.setStyle("z-index", 10001);
44827 this.el.slideIn(this.getSlideAnchor(), {
44828 callback: function(){
44830 this.initAutoHide();
44831 Roo.get(document).on("click", this.slideInIf, this);
44832 this.fireEvent("slideshow", this);
44839 afterSlideIn : function(){
44840 this.clearAutoHide();
44841 this.isSlid = false;
44842 this.clearMonitor();
44843 this.el.setStyle("z-index", "");
44844 if(this.collapseBtn){
44845 this.collapseBtn.show();
44847 this.closeBtn.setStyle('display', this.closeBtnState);
44849 this.stickBtn.hide();
44851 this.fireEvent("slidehide", this);
44854 slideIn : function(cb){
44855 if(!this.isSlid || this.el.hasActiveFx()){
44859 this.isSlid = false;
44860 this.beforeSlide();
44861 this.el.slideOut(this.getSlideAnchor(), {
44862 callback: function(){
44863 this.el.setLeftTop(-10000, -10000);
44865 this.afterSlideIn();
44873 slideInIf : function(e){
44874 if(!e.within(this.el)){
44879 animateCollapse : function(){
44880 this.beforeSlide();
44881 this.el.setStyle("z-index", 20000);
44882 var anchor = this.getSlideAnchor();
44883 this.el.slideOut(anchor, {
44884 callback : function(){
44885 this.el.setStyle("z-index", "");
44886 this.collapsedEl.slideIn(anchor, {duration:.3});
44888 this.el.setLocation(-10000,-10000);
44890 this.fireEvent("collapsed", this);
44897 animateExpand : function(){
44898 this.beforeSlide();
44899 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
44900 this.el.setStyle("z-index", 20000);
44901 this.collapsedEl.hide({
44904 this.el.slideIn(this.getSlideAnchor(), {
44905 callback : function(){
44906 this.el.setStyle("z-index", "");
44909 this.split.el.show();
44911 this.fireEvent("invalidated", this);
44912 this.fireEvent("expanded", this);
44940 getAnchor : function(){
44941 return this.anchors[this.position];
44944 getCollapseAnchor : function(){
44945 return this.canchors[this.position];
44948 getSlideAnchor : function(){
44949 return this.sanchors[this.position];
44952 getAlignAdj : function(){
44953 var cm = this.cmargins;
44954 switch(this.position){
44970 getExpandAdj : function(){
44971 var c = this.collapsedEl, cm = this.cmargins;
44972 switch(this.position){
44974 return [-(cm.right+c.getWidth()+cm.left), 0];
44977 return [cm.right+c.getWidth()+cm.left, 0];
44980 return [0, -(cm.top+cm.bottom+c.getHeight())];
44983 return [0, cm.top+cm.bottom+c.getHeight()];
44989 * Ext JS Library 1.1.1
44990 * Copyright(c) 2006-2007, Ext JS, LLC.
44992 * Originally Released Under LGPL - original licence link has changed is not relivant.
44995 * <script type="text/javascript">
44998 * These classes are private internal classes
45000 Roo.CenterLayoutRegion = function(mgr, config){
45001 Roo.LayoutRegion.call(this, mgr, config, "center");
45002 this.visible = true;
45003 this.minWidth = config.minWidth || 20;
45004 this.minHeight = config.minHeight || 20;
45007 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
45009 // center panel can't be hidden
45013 // center panel can't be hidden
45016 getMinWidth: function(){
45017 return this.minWidth;
45020 getMinHeight: function(){
45021 return this.minHeight;
45026 Roo.NorthLayoutRegion = function(mgr, config){
45027 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
45029 this.split.placement = Roo.SplitBar.TOP;
45030 this.split.orientation = Roo.SplitBar.VERTICAL;
45031 this.split.el.addClass("x-layout-split-v");
45033 var size = config.initialSize || config.height;
45034 if(typeof size != "undefined"){
45035 this.el.setHeight(size);
45038 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
45039 orientation: Roo.SplitBar.VERTICAL,
45040 getBox : function(){
45041 if(this.collapsed){
45042 return this.collapsedEl.getBox();
45044 var box = this.el.getBox();
45046 box.height += this.split.el.getHeight();
45051 updateBox : function(box){
45052 if(this.split && !this.collapsed){
45053 box.height -= this.split.el.getHeight();
45054 this.split.el.setLeft(box.x);
45055 this.split.el.setTop(box.y+box.height);
45056 this.split.el.setWidth(box.width);
45058 if(this.collapsed){
45059 this.updateBody(box.width, null);
45061 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45065 Roo.SouthLayoutRegion = function(mgr, config){
45066 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
45068 this.split.placement = Roo.SplitBar.BOTTOM;
45069 this.split.orientation = Roo.SplitBar.VERTICAL;
45070 this.split.el.addClass("x-layout-split-v");
45072 var size = config.initialSize || config.height;
45073 if(typeof size != "undefined"){
45074 this.el.setHeight(size);
45077 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
45078 orientation: Roo.SplitBar.VERTICAL,
45079 getBox : function(){
45080 if(this.collapsed){
45081 return this.collapsedEl.getBox();
45083 var box = this.el.getBox();
45085 var sh = this.split.el.getHeight();
45092 updateBox : function(box){
45093 if(this.split && !this.collapsed){
45094 var sh = this.split.el.getHeight();
45097 this.split.el.setLeft(box.x);
45098 this.split.el.setTop(box.y-sh);
45099 this.split.el.setWidth(box.width);
45101 if(this.collapsed){
45102 this.updateBody(box.width, null);
45104 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45108 Roo.EastLayoutRegion = function(mgr, config){
45109 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
45111 this.split.placement = Roo.SplitBar.RIGHT;
45112 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45113 this.split.el.addClass("x-layout-split-h");
45115 var size = config.initialSize || config.width;
45116 if(typeof size != "undefined"){
45117 this.el.setWidth(size);
45120 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
45121 orientation: Roo.SplitBar.HORIZONTAL,
45122 getBox : function(){
45123 if(this.collapsed){
45124 return this.collapsedEl.getBox();
45126 var box = this.el.getBox();
45128 var sw = this.split.el.getWidth();
45135 updateBox : function(box){
45136 if(this.split && !this.collapsed){
45137 var sw = this.split.el.getWidth();
45139 this.split.el.setLeft(box.x);
45140 this.split.el.setTop(box.y);
45141 this.split.el.setHeight(box.height);
45144 if(this.collapsed){
45145 this.updateBody(null, box.height);
45147 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45151 Roo.WestLayoutRegion = function(mgr, config){
45152 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
45154 this.split.placement = Roo.SplitBar.LEFT;
45155 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45156 this.split.el.addClass("x-layout-split-h");
45158 var size = config.initialSize || config.width;
45159 if(typeof size != "undefined"){
45160 this.el.setWidth(size);
45163 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
45164 orientation: Roo.SplitBar.HORIZONTAL,
45165 getBox : function(){
45166 if(this.collapsed){
45167 return this.collapsedEl.getBox();
45169 var box = this.el.getBox();
45171 box.width += this.split.el.getWidth();
45176 updateBox : function(box){
45177 if(this.split && !this.collapsed){
45178 var sw = this.split.el.getWidth();
45180 this.split.el.setLeft(box.x+box.width);
45181 this.split.el.setTop(box.y);
45182 this.split.el.setHeight(box.height);
45184 if(this.collapsed){
45185 this.updateBody(null, box.height);
45187 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45192 * Ext JS Library 1.1.1
45193 * Copyright(c) 2006-2007, Ext JS, LLC.
45195 * Originally Released Under LGPL - original licence link has changed is not relivant.
45198 * <script type="text/javascript">
45203 * Private internal class for reading and applying state
45205 Roo.LayoutStateManager = function(layout){
45206 // default empty state
45215 Roo.LayoutStateManager.prototype = {
45216 init : function(layout, provider){
45217 this.provider = provider;
45218 var state = provider.get(layout.id+"-layout-state");
45220 var wasUpdating = layout.isUpdating();
45222 layout.beginUpdate();
45224 for(var key in state){
45225 if(typeof state[key] != "function"){
45226 var rstate = state[key];
45227 var r = layout.getRegion(key);
45230 r.resizeTo(rstate.size);
45232 if(rstate.collapsed == true){
45235 r.expand(null, true);
45241 layout.endUpdate();
45243 this.state = state;
45245 this.layout = layout;
45246 layout.on("regionresized", this.onRegionResized, this);
45247 layout.on("regioncollapsed", this.onRegionCollapsed, this);
45248 layout.on("regionexpanded", this.onRegionExpanded, this);
45251 storeState : function(){
45252 this.provider.set(this.layout.id+"-layout-state", this.state);
45255 onRegionResized : function(region, newSize){
45256 this.state[region.getPosition()].size = newSize;
45260 onRegionCollapsed : function(region){
45261 this.state[region.getPosition()].collapsed = true;
45265 onRegionExpanded : function(region){
45266 this.state[region.getPosition()].collapsed = false;
45271 * Ext JS Library 1.1.1
45272 * Copyright(c) 2006-2007, Ext JS, LLC.
45274 * Originally Released Under LGPL - original licence link has changed is not relivant.
45277 * <script type="text/javascript">
45280 * @class Roo.ContentPanel
45281 * @extends Roo.util.Observable
45282 * A basic ContentPanel element.
45283 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
45284 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
45285 * @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
45286 * @cfg {Boolean} closable True if the panel can be closed/removed
45287 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
45288 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
45289 * @cfg {Toolbar} toolbar A toolbar for this panel
45290 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
45291 * @cfg {String} title The title for this panel
45292 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
45293 * @cfg {String} url Calls {@link #setUrl} with this value
45294 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
45295 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
45296 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
45298 * Create a new ContentPanel.
45299 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
45300 * @param {String/Object} config A string to set only the title or a config object
45301 * @param {String} content (optional) Set the HTML content for this panel
45302 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
45304 Roo.ContentPanel = function(el, config, content){
45308 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
45312 if (config && config.parentLayout) {
45313 el = config.parentLayout.el.createChild();
45316 if(el.autoCreate){ // xtype is available if this is called from factory
45320 this.el = Roo.get(el);
45321 if(!this.el && config && config.autoCreate){
45322 if(typeof config.autoCreate == "object"){
45323 if(!config.autoCreate.id){
45324 config.autoCreate.id = config.id||el;
45326 this.el = Roo.DomHelper.append(document.body,
45327 config.autoCreate, true);
45329 this.el = Roo.DomHelper.append(document.body,
45330 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
45333 this.closable = false;
45334 this.loaded = false;
45335 this.active = false;
45336 if(typeof config == "string"){
45337 this.title = config;
45339 Roo.apply(this, config);
45342 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
45343 this.wrapEl = this.el.wrap();
45344 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
45351 this.resizeEl = Roo.get(this.resizeEl, true);
45353 this.resizeEl = this.el;
45358 * Fires when this panel is activated.
45359 * @param {Roo.ContentPanel} this
45363 * @event deactivate
45364 * Fires when this panel is activated.
45365 * @param {Roo.ContentPanel} this
45367 "deactivate" : true,
45371 * Fires when this panel is resized if fitToFrame is true.
45372 * @param {Roo.ContentPanel} this
45373 * @param {Number} width The width after any component adjustments
45374 * @param {Number} height The height after any component adjustments
45378 if(this.autoScroll){
45379 this.resizeEl.setStyle("overflow", "auto");
45381 // fix randome scrolling
45382 this.el.on('scroll', function() {
45383 this.scrollTo('top',0);
45386 content = content || this.content;
45388 this.setContent(content);
45390 if(config && config.url){
45391 this.setUrl(this.url, this.params, this.loadOnce);
45396 Roo.ContentPanel.superclass.constructor.call(this);
45399 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
45401 setRegion : function(region){
45402 this.region = region;
45404 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
45406 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
45411 * Returns the toolbar for this Panel if one was configured.
45412 * @return {Roo.Toolbar}
45414 getToolbar : function(){
45415 return this.toolbar;
45418 setActiveState : function(active){
45419 this.active = active;
45421 this.fireEvent("deactivate", this);
45423 this.fireEvent("activate", this);
45427 * Updates this panel's element
45428 * @param {String} content The new content
45429 * @param {Boolean} loadScripts (optional) true to look for and process scripts
45431 setContent : function(content, loadScripts){
45432 this.el.update(content, loadScripts);
45435 ignoreResize : function(w, h){
45436 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
45439 this.lastSize = {width: w, height: h};
45444 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
45445 * @return {Roo.UpdateManager} The UpdateManager
45447 getUpdateManager : function(){
45448 return this.el.getUpdateManager();
45451 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
45452 * @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:
45455 url: "your-url.php",
45456 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
45457 callback: yourFunction,
45458 scope: yourObject, //(optional scope)
45461 text: "Loading...",
45466 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
45467 * 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.
45468 * @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}
45469 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
45470 * @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.
45471 * @return {Roo.ContentPanel} this
45474 var um = this.el.getUpdateManager();
45475 um.update.apply(um, arguments);
45481 * 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.
45482 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
45483 * @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)
45484 * @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)
45485 * @return {Roo.UpdateManager} The UpdateManager
45487 setUrl : function(url, params, loadOnce){
45488 if(this.refreshDelegate){
45489 this.removeListener("activate", this.refreshDelegate);
45491 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
45492 this.on("activate", this.refreshDelegate);
45493 return this.el.getUpdateManager();
45496 _handleRefresh : function(url, params, loadOnce){
45497 if(!loadOnce || !this.loaded){
45498 var updater = this.el.getUpdateManager();
45499 updater.update(url, params, this._setLoaded.createDelegate(this));
45503 _setLoaded : function(){
45504 this.loaded = true;
45508 * Returns this panel's id
45511 getId : function(){
45516 * Returns this panel's element - used by regiosn to add.
45517 * @return {Roo.Element}
45519 getEl : function(){
45520 return this.wrapEl || this.el;
45523 adjustForComponents : function(width, height){
45524 if(this.resizeEl != this.el){
45525 width -= this.el.getFrameWidth('lr');
45526 height -= this.el.getFrameWidth('tb');
45529 var te = this.toolbar.getEl();
45530 height -= te.getHeight();
45531 te.setWidth(width);
45533 if(this.adjustments){
45534 width += this.adjustments[0];
45535 height += this.adjustments[1];
45537 return {"width": width, "height": height};
45540 setSize : function(width, height){
45541 if(this.fitToFrame && !this.ignoreResize(width, height)){
45542 if(this.fitContainer && this.resizeEl != this.el){
45543 this.el.setSize(width, height);
45545 var size = this.adjustForComponents(width, height);
45546 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
45547 this.fireEvent('resize', this, size.width, size.height);
45552 * Returns this panel's title
45555 getTitle : function(){
45560 * Set this panel's title
45561 * @param {String} title
45563 setTitle : function(title){
45564 this.title = title;
45566 this.region.updatePanelTitle(this, title);
45571 * Returns true is this panel was configured to be closable
45572 * @return {Boolean}
45574 isClosable : function(){
45575 return this.closable;
45578 beforeSlide : function(){
45580 this.resizeEl.clip();
45583 afterSlide : function(){
45585 this.resizeEl.unclip();
45589 * Force a content refresh from the URL specified in the {@link #setUrl} method.
45590 * Will fail silently if the {@link #setUrl} method has not been called.
45591 * This does not activate the panel, just updates its content.
45593 refresh : function(){
45594 if(this.refreshDelegate){
45595 this.loaded = false;
45596 this.refreshDelegate();
45601 * Destroys this panel
45603 destroy : function(){
45604 this.el.removeAllListeners();
45605 var tempEl = document.createElement("span");
45606 tempEl.appendChild(this.el.dom);
45607 tempEl.innerHTML = "";
45613 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
45623 * @param {Object} cfg Xtype definition of item to add.
45626 addxtype : function(cfg) {
45628 if (cfg.xtype.match(/^Form$/)) {
45629 var el = this.el.createChild();
45631 this.form = new Roo.form.Form(cfg);
45634 if ( this.form.allItems.length) this.form.render(el.dom);
45637 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
45639 cfg.el = this.el.appendChild(document.createElement("div"));
45641 var ret = new Roo[cfg.xtype](cfg);
45642 ret.render(false, ''); // render blank..
45652 * @class Roo.GridPanel
45653 * @extends Roo.ContentPanel
45655 * Create a new GridPanel.
45656 * @param {Roo.grid.Grid} grid The grid for this panel
45657 * @param {String/Object} config A string to set only the panel's title, or a config object
45659 Roo.GridPanel = function(grid, config){
45662 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
45663 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
45665 this.wrapper.dom.appendChild(grid.getGridEl().dom);
45667 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
45670 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
45672 // xtype created footer. - not sure if will work as we normally have to render first..
45673 if (this.footer && !this.footer.el && this.footer.xtype) {
45675 this.footer.container = this.grid.getView().getFooterPanel(true);
45676 this.footer.dataSource = this.grid.dataSource;
45677 this.footer = Roo.factory(this.footer, Roo);
45681 grid.monitorWindowResize = false; // turn off autosizing
45682 grid.autoHeight = false;
45683 grid.autoWidth = false;
45685 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
45688 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
45689 getId : function(){
45690 return this.grid.id;
45694 * Returns the grid for this panel
45695 * @return {Roo.grid.Grid}
45697 getGrid : function(){
45701 setSize : function(width, height){
45702 if(!this.ignoreResize(width, height)){
45703 var grid = this.grid;
45704 var size = this.adjustForComponents(width, height);
45705 grid.getGridEl().setSize(size.width, size.height);
45710 beforeSlide : function(){
45711 this.grid.getView().scroller.clip();
45714 afterSlide : function(){
45715 this.grid.getView().scroller.unclip();
45718 destroy : function(){
45719 this.grid.destroy();
45721 Roo.GridPanel.superclass.destroy.call(this);
45727 * @class Roo.NestedLayoutPanel
45728 * @extends Roo.ContentPanel
45730 * Create a new NestedLayoutPanel.
45733 * @param {Roo.BorderLayout} layout The layout for this panel
45734 * @param {String/Object} config A string to set only the title or a config object
45736 Roo.NestedLayoutPanel = function(layout, config)
45738 // construct with only one argument..
45739 /* FIXME - implement nicer consturctors
45740 if (layout.layout) {
45742 layout = config.layout;
45743 delete config.layout;
45745 if (layout.xtype && !layout.getEl) {
45746 // then layout needs constructing..
45747 layout = Roo.factory(layout, Roo);
45752 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
45754 layout.monitorWindowResize = false; // turn off autosizing
45755 this.layout = layout;
45756 this.layout.getEl().addClass("x-layout-nested-layout");
45763 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
45765 setSize : function(width, height){
45766 if(!this.ignoreResize(width, height)){
45767 var size = this.adjustForComponents(width, height);
45768 var el = this.layout.getEl();
45769 el.setSize(size.width, size.height);
45770 var touch = el.dom.offsetWidth;
45771 this.layout.layout();
45772 // ie requires a double layout on the first pass
45773 if(Roo.isIE && !this.initialized){
45774 this.initialized = true;
45775 this.layout.layout();
45780 // activate all subpanels if not currently active..
45782 setActiveState : function(active){
45783 this.active = active;
45785 this.fireEvent("deactivate", this);
45789 this.fireEvent("activate", this);
45790 // not sure if this should happen before or after..
45791 if (!this.layout) {
45792 return; // should not happen..
45795 for (var r in this.layout.regions) {
45796 reg = this.layout.getRegion(r);
45797 if (reg.getActivePanel()) {
45798 //reg.showPanel(reg.getActivePanel()); // force it to activate..
45799 reg.setActivePanel(reg.getActivePanel());
45802 if (!reg.panels.length) {
45805 reg.showPanel(reg.getPanel(0));
45814 * Returns the nested BorderLayout for this panel
45815 * @return {Roo.BorderLayout}
45817 getLayout : function(){
45818 return this.layout;
45822 * Adds a xtype elements to the layout of the nested panel
45826 xtype : 'ContentPanel',
45833 xtype : 'NestedLayoutPanel',
45839 items : [ ... list of content panels or nested layout panels.. ]
45843 * @param {Object} cfg Xtype definition of item to add.
45845 addxtype : function(cfg) {
45846 return this.layout.addxtype(cfg);
45851 Roo.ScrollPanel = function(el, config, content){
45852 config = config || {};
45853 config.fitToFrame = true;
45854 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
45856 this.el.dom.style.overflow = "hidden";
45857 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
45858 this.el.removeClass("x-layout-inactive-content");
45859 this.el.on("mousewheel", this.onWheel, this);
45861 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
45862 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
45863 up.unselectable(); down.unselectable();
45864 up.on("click", this.scrollUp, this);
45865 down.on("click", this.scrollDown, this);
45866 up.addClassOnOver("x-scroller-btn-over");
45867 down.addClassOnOver("x-scroller-btn-over");
45868 up.addClassOnClick("x-scroller-btn-click");
45869 down.addClassOnClick("x-scroller-btn-click");
45870 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
45872 this.resizeEl = this.el;
45873 this.el = wrap; this.up = up; this.down = down;
45876 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
45878 wheelIncrement : 5,
45879 scrollUp : function(){
45880 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
45883 scrollDown : function(){
45884 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
45887 afterScroll : function(){
45888 var el = this.resizeEl;
45889 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
45890 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45891 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45894 setSize : function(){
45895 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
45896 this.afterScroll();
45899 onWheel : function(e){
45900 var d = e.getWheelDelta();
45901 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
45902 this.afterScroll();
45906 setContent : function(content, loadScripts){
45907 this.resizeEl.update(content, loadScripts);
45921 * @class Roo.TreePanel
45922 * @extends Roo.ContentPanel
45924 * Create a new TreePanel. - defaults to fit/scoll contents.
45925 * @param {String/Object} config A string to set only the panel's title, or a config object
45926 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
45928 Roo.TreePanel = function(config){
45929 var el = config.el;
45930 var tree = config.tree;
45931 delete config.tree;
45932 delete config.el; // hopefull!
45934 // wrapper for IE7 strict & safari scroll issue
45936 var treeEl = el.createChild();
45937 config.resizeEl = treeEl;
45941 Roo.TreePanel.superclass.constructor.call(this, el, config);
45944 this.tree = new Roo.tree.TreePanel(treeEl , tree);
45945 //console.log(tree);
45946 this.on('activate', function()
45948 if (this.tree.rendered) {
45951 //console.log('render tree');
45952 this.tree.render();
45955 this.on('resize', function (cp, w, h) {
45956 this.tree.innerCt.setWidth(w);
45957 this.tree.innerCt.setHeight(h);
45958 this.tree.innerCt.setStyle('overflow-y', 'auto');
45965 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
45982 * Ext JS Library 1.1.1
45983 * Copyright(c) 2006-2007, Ext JS, LLC.
45985 * Originally Released Under LGPL - original licence link has changed is not relivant.
45988 * <script type="text/javascript">
45993 * @class Roo.ReaderLayout
45994 * @extends Roo.BorderLayout
45995 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
45996 * center region containing two nested regions (a top one for a list view and one for item preview below),
45997 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
45998 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
45999 * expedites the setup of the overall layout and regions for this common application style.
46002 var reader = new Roo.ReaderLayout();
46003 var CP = Roo.ContentPanel; // shortcut for adding
46005 reader.beginUpdate();
46006 reader.add("north", new CP("north", "North"));
46007 reader.add("west", new CP("west", {title: "West"}));
46008 reader.add("east", new CP("east", {title: "East"}));
46010 reader.regions.listView.add(new CP("listView", "List"));
46011 reader.regions.preview.add(new CP("preview", "Preview"));
46012 reader.endUpdate();
46015 * Create a new ReaderLayout
46016 * @param {Object} config Configuration options
46017 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
46018 * document.body if omitted)
46020 Roo.ReaderLayout = function(config, renderTo){
46021 var c = config || {size:{}};
46022 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
46023 north: c.north !== false ? Roo.apply({
46027 }, c.north) : false,
46028 west: c.west !== false ? Roo.apply({
46036 margins:{left:5,right:0,bottom:5,top:5},
46037 cmargins:{left:5,right:5,bottom:5,top:5}
46038 }, c.west) : false,
46039 east: c.east !== false ? Roo.apply({
46047 margins:{left:0,right:5,bottom:5,top:5},
46048 cmargins:{left:5,right:5,bottom:5,top:5}
46049 }, c.east) : false,
46050 center: Roo.apply({
46051 tabPosition: 'top',
46055 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
46059 this.el.addClass('x-reader');
46061 this.beginUpdate();
46063 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
46064 south: c.preview !== false ? Roo.apply({
46071 cmargins:{top:5,left:0, right:0, bottom:0}
46072 }, c.preview) : false,
46073 center: Roo.apply({
46079 this.add('center', new Roo.NestedLayoutPanel(inner,
46080 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
46084 this.regions.preview = inner.getRegion('south');
46085 this.regions.listView = inner.getRegion('center');
46088 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
46090 * Ext JS Library 1.1.1
46091 * Copyright(c) 2006-2007, Ext JS, LLC.
46093 * Originally Released Under LGPL - original licence link has changed is not relivant.
46096 * <script type="text/javascript">
46100 * @class Roo.grid.Grid
46101 * @extends Roo.util.Observable
46102 * This class represents the primary interface of a component based grid control.
46103 * <br><br>Usage:<pre><code>
46104 var grid = new Roo.grid.Grid("my-container-id", {
46107 selModel: mySelectionModel,
46108 autoSizeColumns: true,
46109 monitorWindowResize: false,
46110 trackMouseOver: true
46115 * <b>Common Problems:</b><br/>
46116 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
46117 * element will correct this<br/>
46118 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
46119 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
46120 * are unpredictable.<br/>
46121 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
46122 * grid to calculate dimensions/offsets.<br/>
46124 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
46125 * The container MUST have some type of size defined for the grid to fill. The container will be
46126 * automatically set to position relative if it isn't already.
46127 * @param {Object} config A config object that sets properties on this grid.
46129 Roo.grid.Grid = function(container, config){
46130 // initialize the container
46131 this.container = Roo.get(container);
46132 this.container.update("");
46133 this.container.setStyle("overflow", "hidden");
46134 this.container.addClass('x-grid-container');
46136 this.id = this.container.id;
46138 Roo.apply(this, config);
46139 // check and correct shorthanded configs
46141 this.dataSource = this.ds;
46145 this.colModel = this.cm;
46149 this.selModel = this.sm;
46153 if (this.selModel) {
46154 this.selModel = Roo.factory(this.selModel, Roo.grid);
46155 this.sm = this.selModel;
46156 this.sm.xmodule = this.xmodule || false;
46158 if (typeof(this.colModel.config) == 'undefined') {
46159 this.colModel = new Roo.grid.ColumnModel(this.colModel);
46160 this.cm = this.colModel;
46161 this.cm.xmodule = this.xmodule || false;
46163 if (this.dataSource) {
46164 this.dataSource= Roo.factory(this.dataSource, Roo.data);
46165 this.ds = this.dataSource;
46166 this.ds.xmodule = this.xmodule || false;
46173 this.container.setWidth(this.width);
46177 this.container.setHeight(this.height);
46184 * The raw click event for the entire grid.
46185 * @param {Roo.EventObject} e
46190 * The raw dblclick event for the entire grid.
46191 * @param {Roo.EventObject} e
46195 * @event contextmenu
46196 * The raw contextmenu event for the entire grid.
46197 * @param {Roo.EventObject} e
46199 "contextmenu" : true,
46202 * The raw mousedown event for the entire grid.
46203 * @param {Roo.EventObject} e
46205 "mousedown" : true,
46208 * The raw mouseup event for the entire grid.
46209 * @param {Roo.EventObject} e
46214 * The raw mouseover event for the entire grid.
46215 * @param {Roo.EventObject} e
46217 "mouseover" : true,
46220 * The raw mouseout event for the entire grid.
46221 * @param {Roo.EventObject} e
46226 * The raw keypress event for the entire grid.
46227 * @param {Roo.EventObject} e
46232 * The raw keydown event for the entire grid.
46233 * @param {Roo.EventObject} e
46241 * Fires when a cell is clicked
46242 * @param {Grid} this
46243 * @param {Number} rowIndex
46244 * @param {Number} columnIndex
46245 * @param {Roo.EventObject} e
46247 "cellclick" : true,
46249 * @event celldblclick
46250 * Fires when a cell is double clicked
46251 * @param {Grid} this
46252 * @param {Number} rowIndex
46253 * @param {Number} columnIndex
46254 * @param {Roo.EventObject} e
46256 "celldblclick" : true,
46259 * Fires when a row is clicked
46260 * @param {Grid} this
46261 * @param {Number} rowIndex
46262 * @param {Roo.EventObject} e
46266 * @event rowdblclick
46267 * Fires when a row is double clicked
46268 * @param {Grid} this
46269 * @param {Number} rowIndex
46270 * @param {Roo.EventObject} e
46272 "rowdblclick" : true,
46274 * @event headerclick
46275 * Fires when a header is clicked
46276 * @param {Grid} this
46277 * @param {Number} columnIndex
46278 * @param {Roo.EventObject} e
46280 "headerclick" : true,
46282 * @event headerdblclick
46283 * Fires when a header cell is double clicked
46284 * @param {Grid} this
46285 * @param {Number} columnIndex
46286 * @param {Roo.EventObject} e
46288 "headerdblclick" : true,
46290 * @event rowcontextmenu
46291 * Fires when a row is right clicked
46292 * @param {Grid} this
46293 * @param {Number} rowIndex
46294 * @param {Roo.EventObject} e
46296 "rowcontextmenu" : true,
46298 * @event cellcontextmenu
46299 * Fires when a cell is right clicked
46300 * @param {Grid} this
46301 * @param {Number} rowIndex
46302 * @param {Number} cellIndex
46303 * @param {Roo.EventObject} e
46305 "cellcontextmenu" : true,
46307 * @event headercontextmenu
46308 * Fires when a header is right clicked
46309 * @param {Grid} this
46310 * @param {Number} columnIndex
46311 * @param {Roo.EventObject} e
46313 "headercontextmenu" : true,
46315 * @event bodyscroll
46316 * Fires when the body element is scrolled
46317 * @param {Number} scrollLeft
46318 * @param {Number} scrollTop
46320 "bodyscroll" : true,
46322 * @event columnresize
46323 * Fires when the user resizes a column
46324 * @param {Number} columnIndex
46325 * @param {Number} newSize
46327 "columnresize" : true,
46329 * @event columnmove
46330 * Fires when the user moves a column
46331 * @param {Number} oldIndex
46332 * @param {Number} newIndex
46334 "columnmove" : true,
46337 * Fires when row(s) start being dragged
46338 * @param {Grid} this
46339 * @param {Roo.GridDD} dd The drag drop object
46340 * @param {event} e The raw browser event
46342 "startdrag" : true,
46345 * Fires when a drag operation is complete
46346 * @param {Grid} this
46347 * @param {Roo.GridDD} dd The drag drop object
46348 * @param {event} e The raw browser event
46353 * Fires when dragged row(s) are dropped on a valid DD target
46354 * @param {Grid} this
46355 * @param {Roo.GridDD} dd The drag drop object
46356 * @param {String} targetId The target drag drop object
46357 * @param {event} e The raw browser event
46362 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
46363 * @param {Grid} this
46364 * @param {Roo.GridDD} dd The drag drop object
46365 * @param {String} targetId The target drag drop object
46366 * @param {event} e The raw browser event
46371 * Fires when the dragged row(s) first cross another DD target while being dragged
46372 * @param {Grid} this
46373 * @param {Roo.GridDD} dd The drag drop object
46374 * @param {String} targetId The target drag drop object
46375 * @param {event} e The raw browser event
46377 "dragenter" : true,
46380 * Fires when the dragged row(s) leave another DD target while being dragged
46381 * @param {Grid} this
46382 * @param {Roo.GridDD} dd The drag drop object
46383 * @param {String} targetId The target drag drop object
46384 * @param {event} e The raw browser event
46389 * Fires when the grid is rendered
46390 * @param {Grid} grid
46395 Roo.grid.Grid.superclass.constructor.call(this);
46397 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
46400 * @cfg {String} ddGroup - drag drop group.
46404 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
46406 minColumnWidth : 25,
46409 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
46410 * <b>on initial render.</b> It is more efficient to explicitly size the columns
46411 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
46413 autoSizeColumns : false,
46416 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
46418 autoSizeHeaders : true,
46421 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
46423 monitorWindowResize : true,
46426 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
46427 * rows measured to get a columns size. Default is 0 (all rows).
46429 maxRowsToMeasure : 0,
46432 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
46434 trackMouseOver : true,
46437 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
46441 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
46443 enableDragDrop : false,
46446 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
46448 enableColumnMove : true,
46451 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
46453 enableColumnHide : true,
46456 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
46458 enableRowHeightSync : false,
46461 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
46466 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
46468 autoHeight : false,
46471 * @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.
46473 autoExpandColumn : false,
46476 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
46479 autoExpandMin : 50,
46482 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
46484 autoExpandMax : 1000,
46487 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
46492 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
46496 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
46503 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
46504 * of a fixed width. Default is false.
46507 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
46510 * Called once after all setup has been completed and the grid is ready to be rendered.
46511 * @return {Roo.grid.Grid} this
46513 render : function(){
46514 var c = this.container;
46515 // try to detect autoHeight/width mode
46516 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
46517 this.autoHeight = true;
46519 var view = this.getView();
46522 c.on("click", this.onClick, this);
46523 c.on("dblclick", this.onDblClick, this);
46524 c.on("contextmenu", this.onContextMenu, this);
46525 c.on("keydown", this.onKeyDown, this);
46527 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
46529 this.getSelectionModel().init(this);
46534 this.loadMask = new Roo.LoadMask(this.container,
46535 Roo.apply({store:this.dataSource}, this.loadMask));
46539 if (this.toolbar && this.toolbar.xtype) {
46540 this.toolbar.container = this.getView().getHeaderPanel(true);
46541 this.toolbar = new Ext.Toolbar(this.toolbar);
46543 if (this.footer && this.footer.xtype) {
46544 this.footer.dataSource = this.getDataSource();
46545 this.footer.container = this.getView().getFooterPanel(true);
46546 this.footer = Roo.factory(this.footer, Roo);
46548 if (this.dropTarget && this.dropTarget.xtype) {
46549 delete this.dropTarget.xtype;
46550 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
46554 this.rendered = true;
46555 this.fireEvent('render', this);
46560 * Reconfigures the grid to use a different Store and Column Model.
46561 * The View will be bound to the new objects and refreshed.
46562 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
46563 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
46565 reconfigure : function(dataSource, colModel){
46567 this.loadMask.destroy();
46568 this.loadMask = new Roo.LoadMask(this.container,
46569 Roo.apply({store:dataSource}, this.loadMask));
46571 this.view.bind(dataSource, colModel);
46572 this.dataSource = dataSource;
46573 this.colModel = colModel;
46574 this.view.refresh(true);
46578 onKeyDown : function(e){
46579 this.fireEvent("keydown", e);
46583 * Destroy this grid.
46584 * @param {Boolean} removeEl True to remove the element
46586 destroy : function(removeEl, keepListeners){
46588 this.loadMask.destroy();
46590 var c = this.container;
46591 c.removeAllListeners();
46592 this.view.destroy();
46593 this.colModel.purgeListeners();
46594 if(!keepListeners){
46595 this.purgeListeners();
46598 if(removeEl === true){
46604 processEvent : function(name, e){
46605 this.fireEvent(name, e);
46606 var t = e.getTarget();
46608 var header = v.findHeaderIndex(t);
46609 if(header !== false){
46610 this.fireEvent("header" + name, this, header, e);
46612 var row = v.findRowIndex(t);
46613 var cell = v.findCellIndex(t);
46615 this.fireEvent("row" + name, this, row, e);
46616 if(cell !== false){
46617 this.fireEvent("cell" + name, this, row, cell, e);
46624 onClick : function(e){
46625 this.processEvent("click", e);
46629 onContextMenu : function(e, t){
46630 this.processEvent("contextmenu", e);
46634 onDblClick : function(e){
46635 this.processEvent("dblclick", e);
46639 walkCells : function(row, col, step, fn, scope){
46640 var cm = this.colModel, clen = cm.getColumnCount();
46641 var ds = this.dataSource, rlen = ds.getCount(), first = true;
46653 if(fn.call(scope || this, row, col, cm) === true){
46671 if(fn.call(scope || this, row, col, cm) === true){
46683 getSelections : function(){
46684 return this.selModel.getSelections();
46688 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
46689 * but if manual update is required this method will initiate it.
46691 autoSize : function(){
46693 this.view.layout();
46694 if(this.view.adjustForScroll){
46695 this.view.adjustForScroll();
46701 * Returns the grid's underlying element.
46702 * @return {Element} The element
46704 getGridEl : function(){
46705 return this.container;
46708 // private for compatibility, overridden by editor grid
46709 stopEditing : function(){},
46712 * Returns the grid's SelectionModel.
46713 * @return {SelectionModel}
46715 getSelectionModel : function(){
46716 if(!this.selModel){
46717 this.selModel = new Roo.grid.RowSelectionModel();
46719 return this.selModel;
46723 * Returns the grid's DataSource.
46724 * @return {DataSource}
46726 getDataSource : function(){
46727 return this.dataSource;
46731 * Returns the grid's ColumnModel.
46732 * @return {ColumnModel}
46734 getColumnModel : function(){
46735 return this.colModel;
46739 * Returns the grid's GridView object.
46740 * @return {GridView}
46742 getView : function(){
46744 this.view = new Roo.grid.GridView(this.viewConfig);
46749 * Called to get grid's drag proxy text, by default returns this.ddText.
46752 getDragDropText : function(){
46753 var count = this.selModel.getCount();
46754 return String.format(this.ddText, count, count == 1 ? '' : 's');
46758 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
46759 * %0 is replaced with the number of selected rows.
46762 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
46764 * Ext JS Library 1.1.1
46765 * Copyright(c) 2006-2007, Ext JS, LLC.
46767 * Originally Released Under LGPL - original licence link has changed is not relivant.
46770 * <script type="text/javascript">
46773 Roo.grid.AbstractGridView = function(){
46777 "beforerowremoved" : true,
46778 "beforerowsinserted" : true,
46779 "beforerefresh" : true,
46780 "rowremoved" : true,
46781 "rowsinserted" : true,
46782 "rowupdated" : true,
46785 Roo.grid.AbstractGridView.superclass.constructor.call(this);
46788 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
46789 rowClass : "x-grid-row",
46790 cellClass : "x-grid-cell",
46791 tdClass : "x-grid-td",
46792 hdClass : "x-grid-hd",
46793 splitClass : "x-grid-hd-split",
46795 init: function(grid){
46797 var cid = this.grid.getGridEl().id;
46798 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
46799 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
46800 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
46801 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
46804 getColumnRenderers : function(){
46805 var renderers = [];
46806 var cm = this.grid.colModel;
46807 var colCount = cm.getColumnCount();
46808 for(var i = 0; i < colCount; i++){
46809 renderers[i] = cm.getRenderer(i);
46814 getColumnIds : function(){
46816 var cm = this.grid.colModel;
46817 var colCount = cm.getColumnCount();
46818 for(var i = 0; i < colCount; i++){
46819 ids[i] = cm.getColumnId(i);
46824 getDataIndexes : function(){
46825 if(!this.indexMap){
46826 this.indexMap = this.buildIndexMap();
46828 return this.indexMap.colToData;
46831 getColumnIndexByDataIndex : function(dataIndex){
46832 if(!this.indexMap){
46833 this.indexMap = this.buildIndexMap();
46835 return this.indexMap.dataToCol[dataIndex];
46839 * Set a css style for a column dynamically.
46840 * @param {Number} colIndex The index of the column
46841 * @param {String} name The css property name
46842 * @param {String} value The css value
46844 setCSSStyle : function(colIndex, name, value){
46845 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
46846 Roo.util.CSS.updateRule(selector, name, value);
46849 generateRules : function(cm){
46850 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
46851 Roo.util.CSS.removeStyleSheet(rulesId);
46852 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46853 var cid = cm.getColumnId(i);
46854 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
46855 this.tdSelector, cid, " {\n}\n",
46856 this.hdSelector, cid, " {\n}\n",
46857 this.splitSelector, cid, " {\n}\n");
46859 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
46863 * Ext JS Library 1.1.1
46864 * Copyright(c) 2006-2007, Ext JS, LLC.
46866 * Originally Released Under LGPL - original licence link has changed is not relivant.
46869 * <script type="text/javascript">
46873 // This is a support class used internally by the Grid components
46874 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
46876 this.view = grid.getView();
46877 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46878 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
46880 this.setHandleElId(Roo.id(hd));
46881 this.setOuterHandleElId(Roo.id(hd2));
46883 this.scroll = false;
46885 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
46887 getDragData : function(e){
46888 var t = Roo.lib.Event.getTarget(e);
46889 var h = this.view.findHeaderCell(t);
46891 return {ddel: h.firstChild, header:h};
46896 onInitDrag : function(e){
46897 this.view.headersDisabled = true;
46898 var clone = this.dragData.ddel.cloneNode(true);
46899 clone.id = Roo.id();
46900 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
46901 this.proxy.update(clone);
46905 afterValidDrop : function(){
46907 setTimeout(function(){
46908 v.headersDisabled = false;
46912 afterInvalidDrop : function(){
46914 setTimeout(function(){
46915 v.headersDisabled = false;
46921 * Ext JS Library 1.1.1
46922 * Copyright(c) 2006-2007, Ext JS, LLC.
46924 * Originally Released Under LGPL - original licence link has changed is not relivant.
46927 * <script type="text/javascript">
46930 // This is a support class used internally by the Grid components
46931 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
46933 this.view = grid.getView();
46934 // split the proxies so they don't interfere with mouse events
46935 this.proxyTop = Roo.DomHelper.append(document.body, {
46936 cls:"col-move-top", html:" "
46938 this.proxyBottom = Roo.DomHelper.append(document.body, {
46939 cls:"col-move-bottom", html:" "
46941 this.proxyTop.hide = this.proxyBottom.hide = function(){
46942 this.setLeftTop(-100,-100);
46943 this.setStyle("visibility", "hidden");
46945 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46946 // temporarily disabled
46947 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
46948 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
46950 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
46951 proxyOffsets : [-4, -9],
46952 fly: Roo.Element.fly,
46954 getTargetFromEvent : function(e){
46955 var t = Roo.lib.Event.getTarget(e);
46956 var cindex = this.view.findCellIndex(t);
46957 if(cindex !== false){
46958 return this.view.getHeaderCell(cindex);
46962 nextVisible : function(h){
46963 var v = this.view, cm = this.grid.colModel;
46966 if(!cm.isHidden(v.getCellIndex(h))){
46974 prevVisible : function(h){
46975 var v = this.view, cm = this.grid.colModel;
46978 if(!cm.isHidden(v.getCellIndex(h))){
46986 positionIndicator : function(h, n, e){
46987 var x = Roo.lib.Event.getPageX(e);
46988 var r = Roo.lib.Dom.getRegion(n.firstChild);
46989 var px, pt, py = r.top + this.proxyOffsets[1];
46990 if((r.right - x) <= (r.right-r.left)/2){
46991 px = r.right+this.view.borderWidth;
46997 var oldIndex = this.view.getCellIndex(h);
46998 var newIndex = this.view.getCellIndex(n);
47000 if(this.grid.colModel.isFixed(newIndex)){
47004 var locked = this.grid.colModel.isLocked(newIndex);
47009 if(oldIndex < newIndex){
47012 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
47015 px += this.proxyOffsets[0];
47016 this.proxyTop.setLeftTop(px, py);
47017 this.proxyTop.show();
47018 if(!this.bottomOffset){
47019 this.bottomOffset = this.view.mainHd.getHeight();
47021 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
47022 this.proxyBottom.show();
47026 onNodeEnter : function(n, dd, e, data){
47027 if(data.header != n){
47028 this.positionIndicator(data.header, n, e);
47032 onNodeOver : function(n, dd, e, data){
47033 var result = false;
47034 if(data.header != n){
47035 result = this.positionIndicator(data.header, n, e);
47038 this.proxyTop.hide();
47039 this.proxyBottom.hide();
47041 return result ? this.dropAllowed : this.dropNotAllowed;
47044 onNodeOut : function(n, dd, e, data){
47045 this.proxyTop.hide();
47046 this.proxyBottom.hide();
47049 onNodeDrop : function(n, dd, e, data){
47050 var h = data.header;
47052 var cm = this.grid.colModel;
47053 var x = Roo.lib.Event.getPageX(e);
47054 var r = Roo.lib.Dom.getRegion(n.firstChild);
47055 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
47056 var oldIndex = this.view.getCellIndex(h);
47057 var newIndex = this.view.getCellIndex(n);
47058 var locked = cm.isLocked(newIndex);
47062 if(oldIndex < newIndex){
47065 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
47068 cm.setLocked(oldIndex, locked, true);
47069 cm.moveColumn(oldIndex, newIndex);
47070 this.grid.fireEvent("columnmove", oldIndex, newIndex);
47078 * Ext JS Library 1.1.1
47079 * Copyright(c) 2006-2007, Ext JS, LLC.
47081 * Originally Released Under LGPL - original licence link has changed is not relivant.
47084 * <script type="text/javascript">
47088 * @class Roo.grid.GridView
47089 * @extends Roo.util.Observable
47092 * @param {Object} config
47094 Roo.grid.GridView = function(config){
47095 Roo.grid.GridView.superclass.constructor.call(this);
47098 Roo.apply(this, config);
47101 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
47104 * Override this function to apply custom css classes to rows during rendering
47105 * @param {Record} record The record
47106 * @param {Number} index
47107 * @method getRowClass
47109 rowClass : "x-grid-row",
47111 cellClass : "x-grid-col",
47113 tdClass : "x-grid-td",
47115 hdClass : "x-grid-hd",
47117 splitClass : "x-grid-split",
47119 sortClasses : ["sort-asc", "sort-desc"],
47121 enableMoveAnim : false,
47125 dh : Roo.DomHelper,
47127 fly : Roo.Element.fly,
47129 css : Roo.util.CSS,
47135 scrollIncrement : 22,
47137 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
47139 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
47141 bind : function(ds, cm){
47143 this.ds.un("load", this.onLoad, this);
47144 this.ds.un("datachanged", this.onDataChange, this);
47145 this.ds.un("add", this.onAdd, this);
47146 this.ds.un("remove", this.onRemove, this);
47147 this.ds.un("update", this.onUpdate, this);
47148 this.ds.un("clear", this.onClear, this);
47151 ds.on("load", this.onLoad, this);
47152 ds.on("datachanged", this.onDataChange, this);
47153 ds.on("add", this.onAdd, this);
47154 ds.on("remove", this.onRemove, this);
47155 ds.on("update", this.onUpdate, this);
47156 ds.on("clear", this.onClear, this);
47161 this.cm.un("widthchange", this.onColWidthChange, this);
47162 this.cm.un("headerchange", this.onHeaderChange, this);
47163 this.cm.un("hiddenchange", this.onHiddenChange, this);
47164 this.cm.un("columnmoved", this.onColumnMove, this);
47165 this.cm.un("columnlockchange", this.onColumnLock, this);
47168 this.generateRules(cm);
47169 cm.on("widthchange", this.onColWidthChange, this);
47170 cm.on("headerchange", this.onHeaderChange, this);
47171 cm.on("hiddenchange", this.onHiddenChange, this);
47172 cm.on("columnmoved", this.onColumnMove, this);
47173 cm.on("columnlockchange", this.onColumnLock, this);
47178 init: function(grid){
47179 Roo.grid.GridView.superclass.init.call(this, grid);
47181 this.bind(grid.dataSource, grid.colModel);
47183 grid.on("headerclick", this.handleHeaderClick, this);
47185 if(grid.trackMouseOver){
47186 grid.on("mouseover", this.onRowOver, this);
47187 grid.on("mouseout", this.onRowOut, this);
47189 grid.cancelTextSelection = function(){};
47190 this.gridId = grid.id;
47192 var tpls = this.templates || {};
47195 tpls.master = new Roo.Template(
47196 '<div class="x-grid" hidefocus="true">',
47197 '<div class="x-grid-topbar"></div>',
47198 '<div class="x-grid-scroller"><div></div></div>',
47199 '<div class="x-grid-locked">',
47200 '<div class="x-grid-header">{lockedHeader}</div>',
47201 '<div class="x-grid-body">{lockedBody}</div>',
47203 '<div class="x-grid-viewport">',
47204 '<div class="x-grid-header">{header}</div>',
47205 '<div class="x-grid-body">{body}</div>',
47207 '<div class="x-grid-bottombar"></div>',
47208 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
47209 '<div class="x-grid-resize-proxy"> </div>',
47212 tpls.master.disableformats = true;
47216 tpls.header = new Roo.Template(
47217 '<table border="0" cellspacing="0" cellpadding="0">',
47218 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
47221 tpls.header.disableformats = true;
47223 tpls.header.compile();
47226 tpls.hcell = new Roo.Template(
47227 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
47228 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
47231 tpls.hcell.disableFormats = true;
47233 tpls.hcell.compile();
47236 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
47237 tpls.hsplit.disableFormats = true;
47239 tpls.hsplit.compile();
47242 tpls.body = new Roo.Template(
47243 '<table border="0" cellspacing="0" cellpadding="0">',
47244 "<tbody>{rows}</tbody>",
47247 tpls.body.disableFormats = true;
47249 tpls.body.compile();
47252 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
47253 tpls.row.disableFormats = true;
47255 tpls.row.compile();
47258 tpls.cell = new Roo.Template(
47259 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
47260 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
47263 tpls.cell.disableFormats = true;
47265 tpls.cell.compile();
47267 this.templates = tpls;
47270 // remap these for backwards compat
47271 onColWidthChange : function(){
47272 this.updateColumns.apply(this, arguments);
47274 onHeaderChange : function(){
47275 this.updateHeaders.apply(this, arguments);
47277 onHiddenChange : function(){
47278 this.handleHiddenChange.apply(this, arguments);
47280 onColumnMove : function(){
47281 this.handleColumnMove.apply(this, arguments);
47283 onColumnLock : function(){
47284 this.handleLockChange.apply(this, arguments);
47287 onDataChange : function(){
47289 this.updateHeaderSortState();
47292 onClear : function(){
47296 onUpdate : function(ds, record){
47297 this.refreshRow(record);
47300 refreshRow : function(record){
47301 var ds = this.ds, index;
47302 if(typeof record == 'number'){
47304 record = ds.getAt(index);
47306 index = ds.indexOf(record);
47308 this.insertRows(ds, index, index, true);
47309 this.onRemove(ds, record, index+1, true);
47310 this.syncRowHeights(index, index);
47312 this.fireEvent("rowupdated", this, index, record);
47315 onAdd : function(ds, records, index){
47316 this.insertRows(ds, index, index + (records.length-1));
47319 onRemove : function(ds, record, index, isUpdate){
47320 if(isUpdate !== true){
47321 this.fireEvent("beforerowremoved", this, index, record);
47323 var bt = this.getBodyTable(), lt = this.getLockedTable();
47324 if(bt.rows[index]){
47325 bt.firstChild.removeChild(bt.rows[index]);
47327 if(lt.rows[index]){
47328 lt.firstChild.removeChild(lt.rows[index]);
47330 if(isUpdate !== true){
47331 this.stripeRows(index);
47332 this.syncRowHeights(index, index);
47334 this.fireEvent("rowremoved", this, index, record);
47338 onLoad : function(){
47339 this.scrollToTop();
47343 * Scrolls the grid to the top
47345 scrollToTop : function(){
47347 this.scroller.dom.scrollTop = 0;
47353 * Gets a panel in the header of the grid that can be used for toolbars etc.
47354 * After modifying the contents of this panel a call to grid.autoSize() may be
47355 * required to register any changes in size.
47356 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
47357 * @return Roo.Element
47359 getHeaderPanel : function(doShow){
47361 this.headerPanel.show();
47363 return this.headerPanel;
47367 * Gets a panel in the footer of the grid that can be used for toolbars etc.
47368 * After modifying the contents of this panel a call to grid.autoSize() may be
47369 * required to register any changes in size.
47370 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
47371 * @return Roo.Element
47373 getFooterPanel : function(doShow){
47375 this.footerPanel.show();
47377 return this.footerPanel;
47380 initElements : function(){
47381 var E = Roo.Element;
47382 var el = this.grid.getGridEl().dom.firstChild;
47383 var cs = el.childNodes;
47385 this.el = new E(el);
47386 this.headerPanel = new E(el.firstChild);
47387 this.headerPanel.enableDisplayMode("block");
47389 this.scroller = new E(cs[1]);
47390 this.scrollSizer = new E(this.scroller.dom.firstChild);
47392 this.lockedWrap = new E(cs[2]);
47393 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
47394 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
47396 this.mainWrap = new E(cs[3]);
47397 this.mainHd = new E(this.mainWrap.dom.firstChild);
47398 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
47400 this.footerPanel = new E(cs[4]);
47401 this.footerPanel.enableDisplayMode("block");
47403 this.focusEl = new E(cs[5]);
47404 this.focusEl.swallowEvent("click", true);
47405 this.resizeProxy = new E(cs[6]);
47407 this.headerSelector = String.format(
47408 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
47409 this.lockedHd.id, this.mainHd.id
47412 this.splitterSelector = String.format(
47413 '#{0} div.x-grid-split, #{1} div.x-grid-split',
47414 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
47417 idToCssName : function(s)
47419 return s.replace(/[^a-z0-9]+/ig, '-');
47422 getHeaderCell : function(index){
47423 return Roo.DomQuery.select(this.headerSelector)[index];
47426 getHeaderCellMeasure : function(index){
47427 return this.getHeaderCell(index).firstChild;
47430 getHeaderCellText : function(index){
47431 return this.getHeaderCell(index).firstChild.firstChild;
47434 getLockedTable : function(){
47435 return this.lockedBody.dom.firstChild;
47438 getBodyTable : function(){
47439 return this.mainBody.dom.firstChild;
47442 getLockedRow : function(index){
47443 return this.getLockedTable().rows[index];
47446 getRow : function(index){
47447 return this.getBodyTable().rows[index];
47450 getRowComposite : function(index){
47452 this.rowEl = new Roo.CompositeElementLite();
47454 var els = [], lrow, mrow;
47455 if(lrow = this.getLockedRow(index)){
47458 if(mrow = this.getRow(index)){
47461 this.rowEl.elements = els;
47465 getCell : function(rowIndex, colIndex){
47466 var locked = this.cm.getLockedCount();
47468 if(colIndex < locked){
47469 source = this.lockedBody.dom.firstChild;
47471 source = this.mainBody.dom.firstChild;
47472 colIndex -= locked;
47474 return source.rows[rowIndex].childNodes[colIndex];
47477 getCellText : function(rowIndex, colIndex){
47478 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
47481 getCellBox : function(cell){
47482 var b = this.fly(cell).getBox();
47483 if(Roo.isOpera){ // opera fails to report the Y
47484 b.y = cell.offsetTop + this.mainBody.getY();
47489 getCellIndex : function(cell){
47490 var id = String(cell.className).match(this.cellRE);
47492 return parseInt(id[1], 10);
47497 findHeaderIndex : function(n){
47498 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47499 return r ? this.getCellIndex(r) : false;
47502 findHeaderCell : function(n){
47503 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47504 return r ? r : false;
47507 findRowIndex : function(n){
47511 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
47512 return r ? r.rowIndex : false;
47515 findCellIndex : function(node){
47516 var stop = this.el.dom;
47517 while(node && node != stop){
47518 if(this.findRE.test(node.className)){
47519 return this.getCellIndex(node);
47521 node = node.parentNode;
47526 getColumnId : function(index){
47527 return this.cm.getColumnId(index);
47530 getSplitters : function(){
47531 if(this.splitterSelector){
47532 return Roo.DomQuery.select(this.splitterSelector);
47538 getSplitter : function(index){
47539 return this.getSplitters()[index];
47542 onRowOver : function(e, t){
47544 if((row = this.findRowIndex(t)) !== false){
47545 this.getRowComposite(row).addClass("x-grid-row-over");
47549 onRowOut : function(e, t){
47551 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
47552 this.getRowComposite(row).removeClass("x-grid-row-over");
47556 renderHeaders : function(){
47558 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
47559 var cb = [], lb = [], sb = [], lsb = [], p = {};
47560 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47561 p.cellId = "x-grid-hd-0-" + i;
47562 p.splitId = "x-grid-csplit-0-" + i;
47563 p.id = cm.getColumnId(i);
47564 p.title = cm.getColumnTooltip(i) || "";
47565 p.value = cm.getColumnHeader(i) || "";
47566 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
47567 if(!cm.isLocked(i)){
47568 cb[cb.length] = ct.apply(p);
47569 sb[sb.length] = st.apply(p);
47571 lb[lb.length] = ct.apply(p);
47572 lsb[lsb.length] = st.apply(p);
47575 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
47576 ht.apply({cells: cb.join(""), splits:sb.join("")})];
47579 updateHeaders : function(){
47580 var html = this.renderHeaders();
47581 this.lockedHd.update(html[0]);
47582 this.mainHd.update(html[1]);
47586 * Focuses the specified row.
47587 * @param {Number} row The row index
47589 focusRow : function(row){
47590 var x = this.scroller.dom.scrollLeft;
47591 this.focusCell(row, 0, false);
47592 this.scroller.dom.scrollLeft = x;
47596 * Focuses the specified cell.
47597 * @param {Number} row The row index
47598 * @param {Number} col The column index
47599 * @param {Boolean} hscroll false to disable horizontal scrolling
47601 focusCell : function(row, col, hscroll){
47602 var el = this.ensureVisible(row, col, hscroll);
47603 this.focusEl.alignTo(el, "tl-tl");
47605 this.focusEl.focus();
47607 this.focusEl.focus.defer(1, this.focusEl);
47612 * Scrolls the specified cell into view
47613 * @param {Number} row The row index
47614 * @param {Number} col The column index
47615 * @param {Boolean} hscroll false to disable horizontal scrolling
47617 ensureVisible : function(row, col, hscroll){
47618 if(typeof row != "number"){
47619 row = row.rowIndex;
47621 if(row < 0 && row >= this.ds.getCount()){
47624 col = (col !== undefined ? col : 0);
47625 var cm = this.grid.colModel;
47626 while(cm.isHidden(col)){
47630 var el = this.getCell(row, col);
47634 var c = this.scroller.dom;
47636 var ctop = parseInt(el.offsetTop, 10);
47637 var cleft = parseInt(el.offsetLeft, 10);
47638 var cbot = ctop + el.offsetHeight;
47639 var cright = cleft + el.offsetWidth;
47641 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
47642 var stop = parseInt(c.scrollTop, 10);
47643 var sleft = parseInt(c.scrollLeft, 10);
47644 var sbot = stop + ch;
47645 var sright = sleft + c.clientWidth;
47648 c.scrollTop = ctop;
47649 }else if(cbot > sbot){
47650 c.scrollTop = cbot-ch;
47653 if(hscroll !== false){
47655 c.scrollLeft = cleft;
47656 }else if(cright > sright){
47657 c.scrollLeft = cright-c.clientWidth;
47663 updateColumns : function(){
47664 this.grid.stopEditing();
47665 var cm = this.grid.colModel, colIds = this.getColumnIds();
47666 //var totalWidth = cm.getTotalWidth();
47668 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47669 //if(cm.isHidden(i)) continue;
47670 var w = cm.getColumnWidth(i);
47671 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
47672 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
47674 this.updateSplitters();
47677 generateRules : function(cm){
47678 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
47679 Roo.util.CSS.removeStyleSheet(rulesId);
47680 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47681 var cid = cm.getColumnId(i);
47683 if(cm.config[i].align){
47684 align = 'text-align:'+cm.config[i].align+';';
47687 if(cm.isHidden(i)){
47688 hidden = 'display:none;';
47690 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
47692 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
47693 this.hdSelector, cid, " {\n", align, width, "}\n",
47694 this.tdSelector, cid, " {\n",hidden,"\n}\n",
47695 this.splitSelector, cid, " {\n", hidden , "\n}\n");
47697 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
47700 updateSplitters : function(){
47701 var cm = this.cm, s = this.getSplitters();
47702 if(s){ // splitters not created yet
47703 var pos = 0, locked = true;
47704 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47705 if(cm.isHidden(i)) continue;
47706 var w = cm.getColumnWidth(i);
47707 if(!cm.isLocked(i) && locked){
47712 s[i].style.left = (pos-this.splitOffset) + "px";
47717 handleHiddenChange : function(colModel, colIndex, hidden){
47719 this.hideColumn(colIndex);
47721 this.unhideColumn(colIndex);
47725 hideColumn : function(colIndex){
47726 var cid = this.getColumnId(colIndex);
47727 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
47728 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
47730 this.updateHeaders();
47732 this.updateSplitters();
47736 unhideColumn : function(colIndex){
47737 var cid = this.getColumnId(colIndex);
47738 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
47739 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
47742 this.updateHeaders();
47744 this.updateSplitters();
47748 insertRows : function(dm, firstRow, lastRow, isUpdate){
47749 if(firstRow == 0 && lastRow == dm.getCount()-1){
47753 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
47755 var s = this.getScrollState();
47756 var markup = this.renderRows(firstRow, lastRow);
47757 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
47758 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
47759 this.restoreScroll(s);
47761 this.fireEvent("rowsinserted", this, firstRow, lastRow);
47762 this.syncRowHeights(firstRow, lastRow);
47763 this.stripeRows(firstRow);
47769 bufferRows : function(markup, target, index){
47770 var before = null, trows = target.rows, tbody = target.tBodies[0];
47771 if(index < trows.length){
47772 before = trows[index];
47774 var b = document.createElement("div");
47775 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
47776 var rows = b.firstChild.rows;
47777 for(var i = 0, len = rows.length; i < len; i++){
47779 tbody.insertBefore(rows[0], before);
47781 tbody.appendChild(rows[0]);
47788 deleteRows : function(dm, firstRow, lastRow){
47789 if(dm.getRowCount()<1){
47790 this.fireEvent("beforerefresh", this);
47791 this.mainBody.update("");
47792 this.lockedBody.update("");
47793 this.fireEvent("refresh", this);
47795 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
47796 var bt = this.getBodyTable();
47797 var tbody = bt.firstChild;
47798 var rows = bt.rows;
47799 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
47800 tbody.removeChild(rows[firstRow]);
47802 this.stripeRows(firstRow);
47803 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
47807 updateRows : function(dataSource, firstRow, lastRow){
47808 var s = this.getScrollState();
47810 this.restoreScroll(s);
47813 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
47817 this.updateHeaderSortState();
47820 getScrollState : function(){
47821 var sb = this.scroller.dom;
47822 return {left: sb.scrollLeft, top: sb.scrollTop};
47825 stripeRows : function(startRow){
47826 if(!this.grid.stripeRows || this.ds.getCount() < 1){
47829 startRow = startRow || 0;
47830 var rows = this.getBodyTable().rows;
47831 var lrows = this.getLockedTable().rows;
47832 var cls = ' x-grid-row-alt ';
47833 for(var i = startRow, len = rows.length; i < len; i++){
47834 var row = rows[i], lrow = lrows[i];
47835 var isAlt = ((i+1) % 2 == 0);
47836 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
47837 if(isAlt == hasAlt){
47841 row.className += " x-grid-row-alt";
47843 row.className = row.className.replace("x-grid-row-alt", "");
47846 lrow.className = row.className;
47851 restoreScroll : function(state){
47852 var sb = this.scroller.dom;
47853 sb.scrollLeft = state.left;
47854 sb.scrollTop = state.top;
47858 syncScroll : function(){
47859 var sb = this.scroller.dom;
47860 var sh = this.mainHd.dom;
47861 var bs = this.mainBody.dom;
47862 var lv = this.lockedBody.dom;
47863 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
47864 lv.scrollTop = bs.scrollTop = sb.scrollTop;
47867 handleScroll : function(e){
47869 var sb = this.scroller.dom;
47870 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
47874 handleWheel : function(e){
47875 var d = e.getWheelDelta();
47876 this.scroller.dom.scrollTop -= d*22;
47877 // set this here to prevent jumpy scrolling on large tables
47878 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
47882 renderRows : function(startRow, endRow){
47883 // pull in all the crap needed to render rows
47884 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
47885 var colCount = cm.getColumnCount();
47887 if(ds.getCount() < 1){
47891 // build a map for all the columns
47893 for(var i = 0; i < colCount; i++){
47894 var name = cm.getDataIndex(i);
47896 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
47897 renderer : cm.getRenderer(i),
47898 id : cm.getColumnId(i),
47899 locked : cm.isLocked(i)
47903 startRow = startRow || 0;
47904 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
47906 // records to render
47907 var rs = ds.getRange(startRow, endRow);
47909 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
47912 // As much as I hate to duplicate code, this was branched because FireFox really hates
47913 // [].join("") on strings. The performance difference was substantial enough to
47914 // branch this function
47915 doRender : Roo.isGecko ?
47916 function(cs, rs, ds, startRow, colCount, stripe){
47917 var ts = this.templates, ct = ts.cell, rt = ts.row;
47919 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
47920 for(var j = 0, len = rs.length; j < len; j++){
47921 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
47922 for(var i = 0; i < colCount; i++){
47924 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
47926 p.css = p.attr = "";
47927 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
47928 if(p.value == undefined || p.value === "") p.value = " ";
47929 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
47930 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47932 var markup = ct.apply(p);
47940 if(stripe && ((rowIndex+1) % 2 == 0)){
47941 alt[0] = "x-grid-row-alt";
47944 alt[1] = " x-grid-dirty-row";
47947 if(this.getRowClass){
47948 alt[2] = this.getRowClass(r, rowIndex);
47950 rp.alt = alt.join(" ");
47951 lbuf+= rt.apply(rp);
47953 buf+= rt.apply(rp);
47955 return [lbuf, buf];
47957 function(cs, rs, ds, startRow, colCount, stripe){
47958 var ts = this.templates, ct = ts.cell, rt = ts.row;
47960 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
47961 for(var j = 0, len = rs.length; j < len; j++){
47962 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
47963 for(var i = 0; i < colCount; i++){
47965 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
47967 p.css = p.attr = "";
47968 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
47969 if(p.value == undefined || p.value === "") p.value = " ";
47970 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
47971 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47973 var markup = ct.apply(p);
47975 cb[cb.length] = markup;
47977 lcb[lcb.length] = markup;
47981 if(stripe && ((rowIndex+1) % 2 == 0)){
47982 alt[0] = "x-grid-row-alt";
47985 alt[1] = " x-grid-dirty-row";
47988 if(this.getRowClass){
47989 alt[2] = this.getRowClass(r, rowIndex);
47991 rp.alt = alt.join(" ");
47992 rp.cells = lcb.join("");
47993 lbuf[lbuf.length] = rt.apply(rp);
47994 rp.cells = cb.join("");
47995 buf[buf.length] = rt.apply(rp);
47997 return [lbuf.join(""), buf.join("")];
48000 renderBody : function(){
48001 var markup = this.renderRows();
48002 var bt = this.templates.body;
48003 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
48007 * Refreshes the grid
48008 * @param {Boolean} headersToo
48010 refresh : function(headersToo){
48011 this.fireEvent("beforerefresh", this);
48012 this.grid.stopEditing();
48013 var result = this.renderBody();
48014 this.lockedBody.update(result[0]);
48015 this.mainBody.update(result[1]);
48016 if(headersToo === true){
48017 this.updateHeaders();
48018 this.updateColumns();
48019 this.updateSplitters();
48020 this.updateHeaderSortState();
48022 this.syncRowHeights();
48024 this.fireEvent("refresh", this);
48027 handleColumnMove : function(cm, oldIndex, newIndex){
48028 this.indexMap = null;
48029 var s = this.getScrollState();
48030 this.refresh(true);
48031 this.restoreScroll(s);
48032 this.afterMove(newIndex);
48035 afterMove : function(colIndex){
48036 if(this.enableMoveAnim && Roo.enableFx){
48037 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
48041 updateCell : function(dm, rowIndex, dataIndex){
48042 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
48043 if(typeof colIndex == "undefined"){ // not present in grid
48046 var cm = this.grid.colModel;
48047 var cell = this.getCell(rowIndex, colIndex);
48048 var cellText = this.getCellText(rowIndex, colIndex);
48051 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
48052 id : cm.getColumnId(colIndex),
48053 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
48055 var renderer = cm.getRenderer(colIndex);
48056 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
48057 if(typeof val == "undefined" || val === "") val = " ";
48058 cellText.innerHTML = val;
48059 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
48060 this.syncRowHeights(rowIndex, rowIndex);
48063 calcColumnWidth : function(colIndex, maxRowsToMeasure){
48065 if(this.grid.autoSizeHeaders){
48066 var h = this.getHeaderCellMeasure(colIndex);
48067 maxWidth = Math.max(maxWidth, h.scrollWidth);
48070 if(this.cm.isLocked(colIndex)){
48071 tb = this.getLockedTable();
48074 tb = this.getBodyTable();
48075 index = colIndex - this.cm.getLockedCount();
48078 var rows = tb.rows;
48079 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
48080 for(var i = 0; i < stopIndex; i++){
48081 var cell = rows[i].childNodes[index].firstChild;
48082 maxWidth = Math.max(maxWidth, cell.scrollWidth);
48085 return maxWidth + /*margin for error in IE*/ 5;
48088 * Autofit a column to its content.
48089 * @param {Number} colIndex
48090 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
48092 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
48093 if(this.cm.isHidden(colIndex)){
48094 return; // can't calc a hidden column
48097 var cid = this.cm.getColumnId(colIndex);
48098 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
48099 if(this.grid.autoSizeHeaders){
48100 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
48103 var newWidth = this.calcColumnWidth(colIndex);
48104 this.cm.setColumnWidth(colIndex,
48105 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
48106 if(!suppressEvent){
48107 this.grid.fireEvent("columnresize", colIndex, newWidth);
48112 * Autofits all columns to their content and then expands to fit any extra space in the grid
48114 autoSizeColumns : function(){
48115 var cm = this.grid.colModel;
48116 var colCount = cm.getColumnCount();
48117 for(var i = 0; i < colCount; i++){
48118 this.autoSizeColumn(i, true, true);
48120 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
48123 this.updateColumns();
48129 * Autofits all columns to the grid's width proportionate with their current size
48130 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
48132 fitColumns : function(reserveScrollSpace){
48133 var cm = this.grid.colModel;
48134 var colCount = cm.getColumnCount();
48138 for (i = 0; i < colCount; i++){
48139 if(!cm.isHidden(i) && !cm.isFixed(i)){
48140 w = cm.getColumnWidth(i);
48146 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
48147 if(reserveScrollSpace){
48150 var frac = (avail - cm.getTotalWidth())/width;
48151 while (cols.length){
48154 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
48156 this.updateColumns();
48160 onRowSelect : function(rowIndex){
48161 var row = this.getRowComposite(rowIndex);
48162 row.addClass("x-grid-row-selected");
48165 onRowDeselect : function(rowIndex){
48166 var row = this.getRowComposite(rowIndex);
48167 row.removeClass("x-grid-row-selected");
48170 onCellSelect : function(row, col){
48171 var cell = this.getCell(row, col);
48173 Roo.fly(cell).addClass("x-grid-cell-selected");
48177 onCellDeselect : function(row, col){
48178 var cell = this.getCell(row, col);
48180 Roo.fly(cell).removeClass("x-grid-cell-selected");
48184 updateHeaderSortState : function(){
48185 var state = this.ds.getSortState();
48189 this.sortState = state;
48190 var sortColumn = this.cm.findColumnIndex(state.field);
48191 if(sortColumn != -1){
48192 var sortDir = state.direction;
48193 var sc = this.sortClasses;
48194 var hds = this.el.select(this.headerSelector).removeClass(sc);
48195 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
48199 handleHeaderClick : function(g, index){
48200 if(this.headersDisabled){
48203 var dm = g.dataSource, cm = g.colModel;
48204 if(!cm.isSortable(index)){
48208 dm.sort(cm.getDataIndex(index));
48212 destroy : function(){
48214 this.colMenu.removeAll();
48215 Roo.menu.MenuMgr.unregister(this.colMenu);
48216 this.colMenu.getEl().remove();
48217 delete this.colMenu;
48220 this.hmenu.removeAll();
48221 Roo.menu.MenuMgr.unregister(this.hmenu);
48222 this.hmenu.getEl().remove();
48225 if(this.grid.enableColumnMove){
48226 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48228 for(var dd in dds){
48229 if(!dds[dd].config.isTarget && dds[dd].dragElId){
48230 var elid = dds[dd].dragElId;
48232 Roo.get(elid).remove();
48233 } else if(dds[dd].config.isTarget){
48234 dds[dd].proxyTop.remove();
48235 dds[dd].proxyBottom.remove();
48238 if(Roo.dd.DDM.locationCache[dd]){
48239 delete Roo.dd.DDM.locationCache[dd];
48242 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48245 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
48246 this.bind(null, null);
48247 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
48250 handleLockChange : function(){
48251 this.refresh(true);
48254 onDenyColumnLock : function(){
48258 onDenyColumnHide : function(){
48262 handleHdMenuClick : function(item){
48263 var index = this.hdCtxIndex;
48264 var cm = this.cm, ds = this.ds;
48267 ds.sort(cm.getDataIndex(index), "ASC");
48270 ds.sort(cm.getDataIndex(index), "DESC");
48273 var lc = cm.getLockedCount();
48274 if(cm.getColumnCount(true) <= lc+1){
48275 this.onDenyColumnLock();
48279 cm.setLocked(index, true, true);
48280 cm.moveColumn(index, lc);
48281 this.grid.fireEvent("columnmove", index, lc);
48283 cm.setLocked(index, true);
48287 var lc = cm.getLockedCount();
48288 if((lc-1) != index){
48289 cm.setLocked(index, false, true);
48290 cm.moveColumn(index, lc-1);
48291 this.grid.fireEvent("columnmove", index, lc-1);
48293 cm.setLocked(index, false);
48297 index = cm.getIndexById(item.id.substr(4));
48299 if(item.checked && cm.getColumnCount(true) <= 1){
48300 this.onDenyColumnHide();
48303 cm.setHidden(index, item.checked);
48309 beforeColMenuShow : function(){
48310 var cm = this.cm, colCount = cm.getColumnCount();
48311 this.colMenu.removeAll();
48312 for(var i = 0; i < colCount; i++){
48313 this.colMenu.add(new Roo.menu.CheckItem({
48314 id: "col-"+cm.getColumnId(i),
48315 text: cm.getColumnHeader(i),
48316 checked: !cm.isHidden(i),
48322 handleHdCtx : function(g, index, e){
48324 var hd = this.getHeaderCell(index);
48325 this.hdCtxIndex = index;
48326 var ms = this.hmenu.items, cm = this.cm;
48327 ms.get("asc").setDisabled(!cm.isSortable(index));
48328 ms.get("desc").setDisabled(!cm.isSortable(index));
48329 if(this.grid.enableColLock !== false){
48330 ms.get("lock").setDisabled(cm.isLocked(index));
48331 ms.get("unlock").setDisabled(!cm.isLocked(index));
48333 this.hmenu.show(hd, "tl-bl");
48336 handleHdOver : function(e){
48337 var hd = this.findHeaderCell(e.getTarget());
48338 if(hd && !this.headersDisabled){
48339 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
48340 this.fly(hd).addClass("x-grid-hd-over");
48345 handleHdOut : function(e){
48346 var hd = this.findHeaderCell(e.getTarget());
48348 this.fly(hd).removeClass("x-grid-hd-over");
48352 handleSplitDblClick : function(e, t){
48353 var i = this.getCellIndex(t);
48354 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
48355 this.autoSizeColumn(i, true);
48360 render : function(){
48363 var colCount = cm.getColumnCount();
48365 if(this.grid.monitorWindowResize === true){
48366 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48368 var header = this.renderHeaders();
48369 var body = this.templates.body.apply({rows:""});
48370 var html = this.templates.master.apply({
48373 lockedHeader: header[0],
48377 //this.updateColumns();
48379 this.grid.getGridEl().dom.innerHTML = html;
48381 this.initElements();
48383 // a kludge to fix the random scolling effect in webkit
48384 this.el.on("scroll", function() {
48385 this.el.dom.scrollTop=0; // hopefully not recursive..
48388 this.scroller.on("scroll", this.handleScroll, this);
48389 this.lockedBody.on("mousewheel", this.handleWheel, this);
48390 this.mainBody.on("mousewheel", this.handleWheel, this);
48392 this.mainHd.on("mouseover", this.handleHdOver, this);
48393 this.mainHd.on("mouseout", this.handleHdOut, this);
48394 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
48395 {delegate: "."+this.splitClass});
48397 this.lockedHd.on("mouseover", this.handleHdOver, this);
48398 this.lockedHd.on("mouseout", this.handleHdOut, this);
48399 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
48400 {delegate: "."+this.splitClass});
48402 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
48403 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48406 this.updateSplitters();
48408 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
48409 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48410 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48413 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
48414 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
48416 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
48417 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
48419 if(this.grid.enableColLock !== false){
48420 this.hmenu.add('-',
48421 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
48422 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
48425 if(this.grid.enableColumnHide !== false){
48427 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
48428 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
48429 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
48431 this.hmenu.add('-',
48432 {id:"columns", text: this.columnsText, menu: this.colMenu}
48435 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
48437 this.grid.on("headercontextmenu", this.handleHdCtx, this);
48440 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
48441 this.dd = new Roo.grid.GridDragZone(this.grid, {
48442 ddGroup : this.grid.ddGroup || 'GridDD'
48447 for(var i = 0; i < colCount; i++){
48448 if(cm.isHidden(i)){
48449 this.hideColumn(i);
48451 if(cm.config[i].align){
48452 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
48453 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
48457 this.updateHeaderSortState();
48459 this.beforeInitialResize();
48462 // two part rendering gives faster view to the user
48463 this.renderPhase2.defer(1, this);
48466 renderPhase2 : function(){
48467 // render the rows now
48469 if(this.grid.autoSizeColumns){
48470 this.autoSizeColumns();
48474 beforeInitialResize : function(){
48478 onColumnSplitterMoved : function(i, w){
48479 this.userResized = true;
48480 var cm = this.grid.colModel;
48481 cm.setColumnWidth(i, w, true);
48482 var cid = cm.getColumnId(i);
48483 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48484 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48485 this.updateSplitters();
48487 this.grid.fireEvent("columnresize", i, w);
48490 syncRowHeights : function(startIndex, endIndex){
48491 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
48492 startIndex = startIndex || 0;
48493 var mrows = this.getBodyTable().rows;
48494 var lrows = this.getLockedTable().rows;
48495 var len = mrows.length-1;
48496 endIndex = Math.min(endIndex || len, len);
48497 for(var i = startIndex; i <= endIndex; i++){
48498 var m = mrows[i], l = lrows[i];
48499 var h = Math.max(m.offsetHeight, l.offsetHeight);
48500 m.style.height = l.style.height = h + "px";
48505 layout : function(initialRender, is2ndPass){
48507 var auto = g.autoHeight;
48508 var scrollOffset = 16;
48509 var c = g.getGridEl(), cm = this.cm,
48510 expandCol = g.autoExpandColumn,
48512 //c.beginMeasure();
48514 if(!c.dom.offsetWidth){ // display:none?
48516 this.lockedWrap.show();
48517 this.mainWrap.show();
48522 var hasLock = this.cm.isLocked(0);
48524 var tbh = this.headerPanel.getHeight();
48525 var bbh = this.footerPanel.getHeight();
48528 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
48529 var newHeight = ch + c.getBorderWidth("tb");
48531 newHeight = Math.min(g.maxHeight, newHeight);
48533 c.setHeight(newHeight);
48537 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
48540 var s = this.scroller;
48542 var csize = c.getSize(true);
48544 this.el.setSize(csize.width, csize.height);
48546 this.headerPanel.setWidth(csize.width);
48547 this.footerPanel.setWidth(csize.width);
48549 var hdHeight = this.mainHd.getHeight();
48550 var vw = csize.width;
48551 var vh = csize.height - (tbh + bbh);
48555 var bt = this.getBodyTable();
48556 var ltWidth = hasLock ?
48557 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
48559 var scrollHeight = bt.offsetHeight;
48560 var scrollWidth = ltWidth + bt.offsetWidth;
48561 var vscroll = false, hscroll = false;
48563 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
48565 var lw = this.lockedWrap, mw = this.mainWrap;
48566 var lb = this.lockedBody, mb = this.mainBody;
48568 setTimeout(function(){
48569 var t = s.dom.offsetTop;
48570 var w = s.dom.clientWidth,
48571 h = s.dom.clientHeight;
48574 lw.setSize(ltWidth, h);
48576 mw.setLeftTop(ltWidth, t);
48577 mw.setSize(w-ltWidth, h);
48579 lb.setHeight(h-hdHeight);
48580 mb.setHeight(h-hdHeight);
48582 if(is2ndPass !== true && !gv.userResized && expandCol){
48583 // high speed resize without full column calculation
48585 var ci = cm.getIndexById(expandCol);
48587 ci = cm.findColumnIndex(expandCol);
48589 ci = Math.max(0, ci); // make sure it's got at least the first col.
48590 var expandId = cm.getColumnId(ci);
48591 var tw = cm.getTotalWidth(false);
48592 var currentWidth = cm.getColumnWidth(ci);
48593 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
48594 if(currentWidth != cw){
48595 cm.setColumnWidth(ci, cw, true);
48596 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48597 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48598 gv.updateSplitters();
48599 gv.layout(false, true);
48611 onWindowResize : function(){
48612 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
48618 appendFooter : function(parentEl){
48622 sortAscText : "Sort Ascending",
48623 sortDescText : "Sort Descending",
48624 lockText : "Lock Column",
48625 unlockText : "Unlock Column",
48626 columnsText : "Columns"
48630 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
48631 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
48632 this.proxy.el.addClass('x-grid3-col-dd');
48635 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
48636 handleMouseDown : function(e){
48640 callHandleMouseDown : function(e){
48641 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
48646 * Ext JS Library 1.1.1
48647 * Copyright(c) 2006-2007, Ext JS, LLC.
48649 * Originally Released Under LGPL - original licence link has changed is not relivant.
48652 * <script type="text/javascript">
48656 // This is a support class used internally by the Grid components
48657 Roo.grid.SplitDragZone = function(grid, hd, hd2){
48659 this.view = grid.getView();
48660 this.proxy = this.view.resizeProxy;
48661 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
48662 "gridSplitters" + this.grid.getGridEl().id, {
48663 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
48665 this.setHandleElId(Roo.id(hd));
48666 this.setOuterHandleElId(Roo.id(hd2));
48667 this.scroll = false;
48669 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
48670 fly: Roo.Element.fly,
48672 b4StartDrag : function(x, y){
48673 this.view.headersDisabled = true;
48674 this.proxy.setHeight(this.view.mainWrap.getHeight());
48675 var w = this.cm.getColumnWidth(this.cellIndex);
48676 var minw = Math.max(w-this.grid.minColumnWidth, 0);
48677 this.resetConstraints();
48678 this.setXConstraint(minw, 1000);
48679 this.setYConstraint(0, 0);
48680 this.minX = x - minw;
48681 this.maxX = x + 1000;
48683 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
48687 handleMouseDown : function(e){
48688 ev = Roo.EventObject.setEvent(e);
48689 var t = this.fly(ev.getTarget());
48690 if(t.hasClass("x-grid-split")){
48691 this.cellIndex = this.view.getCellIndex(t.dom);
48692 this.split = t.dom;
48693 this.cm = this.grid.colModel;
48694 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
48695 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
48700 endDrag : function(e){
48701 this.view.headersDisabled = false;
48702 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
48703 var diff = endX - this.startPos;
48704 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
48707 autoOffset : function(){
48708 this.setDelta(0,0);
48712 * Ext JS Library 1.1.1
48713 * Copyright(c) 2006-2007, Ext JS, LLC.
48715 * Originally Released Under LGPL - original licence link has changed is not relivant.
48718 * <script type="text/javascript">
48722 // This is a support class used internally by the Grid components
48723 Roo.grid.GridDragZone = function(grid, config){
48724 this.view = grid.getView();
48725 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
48726 if(this.view.lockedBody){
48727 this.setHandleElId(Roo.id(this.view.mainBody.dom));
48728 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
48730 this.scroll = false;
48732 this.ddel = document.createElement('div');
48733 this.ddel.className = 'x-grid-dd-wrap';
48736 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
48737 ddGroup : "GridDD",
48739 getDragData : function(e){
48740 var t = Roo.lib.Event.getTarget(e);
48741 var rowIndex = this.view.findRowIndex(t);
48742 if(rowIndex !== false){
48743 var sm = this.grid.selModel;
48744 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
48745 // sm.mouseDown(e, t);
48747 if (e.hasModifier()){
48748 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
48750 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
48755 onInitDrag : function(e){
48756 var data = this.dragData;
48757 this.ddel.innerHTML = this.grid.getDragDropText();
48758 this.proxy.update(this.ddel);
48759 // fire start drag?
48762 afterRepair : function(){
48763 this.dragging = false;
48766 getRepairXY : function(e, data){
48770 onEndDrag : function(data, e){
48774 onValidDrop : function(dd, e, id){
48779 beforeInvalidDrop : function(e, id){
48784 * Ext JS Library 1.1.1
48785 * Copyright(c) 2006-2007, Ext JS, LLC.
48787 * Originally Released Under LGPL - original licence link has changed is not relivant.
48790 * <script type="text/javascript">
48795 * @class Roo.grid.ColumnModel
48796 * @extends Roo.util.Observable
48797 * This is the default implementation of a ColumnModel used by the Grid. It defines
48798 * the columns in the grid.
48801 var colModel = new Roo.grid.ColumnModel([
48802 {header: "Ticker", width: 60, sortable: true, locked: true},
48803 {header: "Company Name", width: 150, sortable: true},
48804 {header: "Market Cap.", width: 100, sortable: true},
48805 {header: "$ Sales", width: 100, sortable: true, renderer: money},
48806 {header: "Employees", width: 100, sortable: true, resizable: false}
48811 * The config options listed for this class are options which may appear in each
48812 * individual column definition.
48813 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
48815 * @param {Object} config An Array of column config objects. See this class's
48816 * config objects for details.
48818 Roo.grid.ColumnModel = function(config){
48820 * The config passed into the constructor
48822 this.config = config;
48825 // if no id, create one
48826 // if the column does not have a dataIndex mapping,
48827 // map it to the order it is in the config
48828 for(var i = 0, len = config.length; i < len; i++){
48830 if(typeof c.dataIndex == "undefined"){
48833 if(typeof c.renderer == "string"){
48834 c.renderer = Roo.util.Format[c.renderer];
48836 if(typeof c.id == "undefined"){
48839 if(c.editor && c.editor.xtype){
48840 c.editor = Roo.factory(c.editor, Roo.grid);
48842 if(c.editor && c.editor.isFormField){
48843 c.editor = new Roo.grid.GridEditor(c.editor);
48845 this.lookup[c.id] = c;
48849 * The width of columns which have no width specified (defaults to 100)
48852 this.defaultWidth = 100;
48855 * Default sortable of columns which have no sortable specified (defaults to false)
48858 this.defaultSortable = false;
48862 * @event widthchange
48863 * Fires when the width of a column changes.
48864 * @param {ColumnModel} this
48865 * @param {Number} columnIndex The column index
48866 * @param {Number} newWidth The new width
48868 "widthchange": true,
48870 * @event headerchange
48871 * Fires when the text of a header changes.
48872 * @param {ColumnModel} this
48873 * @param {Number} columnIndex The column index
48874 * @param {Number} newText The new header text
48876 "headerchange": true,
48878 * @event hiddenchange
48879 * Fires when a column is hidden or "unhidden".
48880 * @param {ColumnModel} this
48881 * @param {Number} columnIndex The column index
48882 * @param {Boolean} hidden true if hidden, false otherwise
48884 "hiddenchange": true,
48886 * @event columnmoved
48887 * Fires when a column is moved.
48888 * @param {ColumnModel} this
48889 * @param {Number} oldIndex
48890 * @param {Number} newIndex
48892 "columnmoved" : true,
48894 * @event columlockchange
48895 * Fires when a column's locked state is changed
48896 * @param {ColumnModel} this
48897 * @param {Number} colIndex
48898 * @param {Boolean} locked true if locked
48900 "columnlockchange" : true
48902 Roo.grid.ColumnModel.superclass.constructor.call(this);
48904 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
48906 * @cfg {String} header The header text to display in the Grid view.
48909 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
48910 * {@link Roo.data.Record} definition from which to draw the column's value. If not
48911 * specified, the column's index is used as an index into the Record's data Array.
48914 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
48915 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
48918 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
48919 * Defaults to the value of the {@link #defaultSortable} property.
48920 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
48923 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
48926 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
48929 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
48932 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
48935 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
48936 * given the cell's data value. See {@link #setRenderer}. If not specified, the
48937 * default renderer uses the raw data value.
48940 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
48943 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
48947 * Returns the id of the column at the specified index.
48948 * @param {Number} index The column index
48949 * @return {String} the id
48951 getColumnId : function(index){
48952 return this.config[index].id;
48956 * Returns the column for a specified id.
48957 * @param {String} id The column id
48958 * @return {Object} the column
48960 getColumnById : function(id){
48961 return this.lookup[id];
48966 * Returns the column for a specified dataIndex.
48967 * @param {String} dataIndex The column dataIndex
48968 * @return {Object|Boolean} the column or false if not found
48970 getColumnByDataIndex: function(dataIndex){
48971 var index = this.findColumnIndex(dataIndex);
48972 return index > -1 ? this.config[index] : false;
48976 * Returns the index for a specified column id.
48977 * @param {String} id The column id
48978 * @return {Number} the index, or -1 if not found
48980 getIndexById : function(id){
48981 for(var i = 0, len = this.config.length; i < len; i++){
48982 if(this.config[i].id == id){
48990 * Returns the index for a specified column dataIndex.
48991 * @param {String} dataIndex The column dataIndex
48992 * @return {Number} the index, or -1 if not found
48995 findColumnIndex : function(dataIndex){
48996 for(var i = 0, len = this.config.length; i < len; i++){
48997 if(this.config[i].dataIndex == dataIndex){
49005 moveColumn : function(oldIndex, newIndex){
49006 var c = this.config[oldIndex];
49007 this.config.splice(oldIndex, 1);
49008 this.config.splice(newIndex, 0, c);
49009 this.dataMap = null;
49010 this.fireEvent("columnmoved", this, oldIndex, newIndex);
49013 isLocked : function(colIndex){
49014 return this.config[colIndex].locked === true;
49017 setLocked : function(colIndex, value, suppressEvent){
49018 if(this.isLocked(colIndex) == value){
49021 this.config[colIndex].locked = value;
49022 if(!suppressEvent){
49023 this.fireEvent("columnlockchange", this, colIndex, value);
49027 getTotalLockedWidth : function(){
49028 var totalWidth = 0;
49029 for(var i = 0; i < this.config.length; i++){
49030 if(this.isLocked(i) && !this.isHidden(i)){
49031 this.totalWidth += this.getColumnWidth(i);
49037 getLockedCount : function(){
49038 for(var i = 0, len = this.config.length; i < len; i++){
49039 if(!this.isLocked(i)){
49046 * Returns the number of columns.
49049 getColumnCount : function(visibleOnly){
49050 if(visibleOnly === true){
49052 for(var i = 0, len = this.config.length; i < len; i++){
49053 if(!this.isHidden(i)){
49059 return this.config.length;
49063 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
49064 * @param {Function} fn
49065 * @param {Object} scope (optional)
49066 * @return {Array} result
49068 getColumnsBy : function(fn, scope){
49070 for(var i = 0, len = this.config.length; i < len; i++){
49071 var c = this.config[i];
49072 if(fn.call(scope||this, c, i) === true){
49080 * Returns true if the specified column is sortable.
49081 * @param {Number} col The column index
49082 * @return {Boolean}
49084 isSortable : function(col){
49085 if(typeof this.config[col].sortable == "undefined"){
49086 return this.defaultSortable;
49088 return this.config[col].sortable;
49092 * Returns the rendering (formatting) function defined for the column.
49093 * @param {Number} col The column index.
49094 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
49096 getRenderer : function(col){
49097 if(!this.config[col].renderer){
49098 return Roo.grid.ColumnModel.defaultRenderer;
49100 return this.config[col].renderer;
49104 * Sets the rendering (formatting) function for a column.
49105 * @param {Number} col The column index
49106 * @param {Function} fn The function to use to process the cell's raw data
49107 * to return HTML markup for the grid view. The render function is called with
49108 * the following parameters:<ul>
49109 * <li>Data value.</li>
49110 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
49111 * <li>css A CSS style string to apply to the table cell.</li>
49112 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
49113 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
49114 * <li>Row index</li>
49115 * <li>Column index</li>
49116 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
49118 setRenderer : function(col, fn){
49119 this.config[col].renderer = fn;
49123 * Returns the width for the specified column.
49124 * @param {Number} col The column index
49127 getColumnWidth : function(col){
49128 return this.config[col].width || this.defaultWidth;
49132 * Sets the width for a column.
49133 * @param {Number} col The column index
49134 * @param {Number} width The new width
49136 setColumnWidth : function(col, width, suppressEvent){
49137 this.config[col].width = width;
49138 this.totalWidth = null;
49139 if(!suppressEvent){
49140 this.fireEvent("widthchange", this, col, width);
49145 * Returns the total width of all columns.
49146 * @param {Boolean} includeHidden True to include hidden column widths
49149 getTotalWidth : function(includeHidden){
49150 if(!this.totalWidth){
49151 this.totalWidth = 0;
49152 for(var i = 0, len = this.config.length; i < len; i++){
49153 if(includeHidden || !this.isHidden(i)){
49154 this.totalWidth += this.getColumnWidth(i);
49158 return this.totalWidth;
49162 * Returns the header for the specified column.
49163 * @param {Number} col The column index
49166 getColumnHeader : function(col){
49167 return this.config[col].header;
49171 * Sets the header for a column.
49172 * @param {Number} col The column index
49173 * @param {String} header The new header
49175 setColumnHeader : function(col, header){
49176 this.config[col].header = header;
49177 this.fireEvent("headerchange", this, col, header);
49181 * Returns the tooltip for the specified column.
49182 * @param {Number} col The column index
49185 getColumnTooltip : function(col){
49186 return this.config[col].tooltip;
49189 * Sets the tooltip for a column.
49190 * @param {Number} col The column index
49191 * @param {String} tooltip The new tooltip
49193 setColumnTooltip : function(col, tooltip){
49194 this.config[col].tooltip = tooltip;
49198 * Returns the dataIndex for the specified column.
49199 * @param {Number} col The column index
49202 getDataIndex : function(col){
49203 return this.config[col].dataIndex;
49207 * Sets the dataIndex for a column.
49208 * @param {Number} col The column index
49209 * @param {Number} dataIndex The new dataIndex
49211 setDataIndex : function(col, dataIndex){
49212 this.config[col].dataIndex = dataIndex;
49218 * Returns true if the cell is editable.
49219 * @param {Number} colIndex The column index
49220 * @param {Number} rowIndex The row index
49221 * @return {Boolean}
49223 isCellEditable : function(colIndex, rowIndex){
49224 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
49228 * Returns the editor defined for the cell/column.
49229 * return false or null to disable editing.
49230 * @param {Number} colIndex The column index
49231 * @param {Number} rowIndex The row index
49234 getCellEditor : function(colIndex, rowIndex){
49235 return this.config[colIndex].editor;
49239 * Sets if a column is editable.
49240 * @param {Number} col The column index
49241 * @param {Boolean} editable True if the column is editable
49243 setEditable : function(col, editable){
49244 this.config[col].editable = editable;
49249 * Returns true if the column is hidden.
49250 * @param {Number} colIndex The column index
49251 * @return {Boolean}
49253 isHidden : function(colIndex){
49254 return this.config[colIndex].hidden;
49259 * Returns true if the column width cannot be changed
49261 isFixed : function(colIndex){
49262 return this.config[colIndex].fixed;
49266 * Returns true if the column can be resized
49267 * @return {Boolean}
49269 isResizable : function(colIndex){
49270 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
49273 * Sets if a column is hidden.
49274 * @param {Number} colIndex The column index
49275 * @param {Boolean} hidden True if the column is hidden
49277 setHidden : function(colIndex, hidden){
49278 this.config[colIndex].hidden = hidden;
49279 this.totalWidth = null;
49280 this.fireEvent("hiddenchange", this, colIndex, hidden);
49284 * Sets the editor for a column.
49285 * @param {Number} col The column index
49286 * @param {Object} editor The editor object
49288 setEditor : function(col, editor){
49289 this.config[col].editor = editor;
49293 Roo.grid.ColumnModel.defaultRenderer = function(value){
49294 if(typeof value == "string" && value.length < 1){
49300 // Alias for backwards compatibility
49301 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
49304 * Ext JS Library 1.1.1
49305 * Copyright(c) 2006-2007, Ext JS, LLC.
49307 * Originally Released Under LGPL - original licence link has changed is not relivant.
49310 * <script type="text/javascript">
49314 * @class Roo.grid.AbstractSelectionModel
49315 * @extends Roo.util.Observable
49316 * Abstract base class for grid SelectionModels. It provides the interface that should be
49317 * implemented by descendant classes. This class should not be directly instantiated.
49320 Roo.grid.AbstractSelectionModel = function(){
49321 this.locked = false;
49322 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
49325 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
49326 /** @ignore Called by the grid automatically. Do not call directly. */
49327 init : function(grid){
49333 * Locks the selections.
49336 this.locked = true;
49340 * Unlocks the selections.
49342 unlock : function(){
49343 this.locked = false;
49347 * Returns true if the selections are locked.
49348 * @return {Boolean}
49350 isLocked : function(){
49351 return this.locked;
49355 * Ext JS Library 1.1.1
49356 * Copyright(c) 2006-2007, Ext JS, LLC.
49358 * Originally Released Under LGPL - original licence link has changed is not relivant.
49361 * <script type="text/javascript">
49364 * @extends Roo.grid.AbstractSelectionModel
49365 * @class Roo.grid.RowSelectionModel
49366 * The default SelectionModel used by {@link Roo.grid.Grid}.
49367 * It supports multiple selections and keyboard selection/navigation.
49369 * @param {Object} config
49371 Roo.grid.RowSelectionModel = function(config){
49372 Roo.apply(this, config);
49373 this.selections = new Roo.util.MixedCollection(false, function(o){
49378 this.lastActive = false;
49382 * @event selectionchange
49383 * Fires when the selection changes
49384 * @param {SelectionModel} this
49386 "selectionchange" : true,
49388 * @event afterselectionchange
49389 * Fires after the selection changes (eg. by key press or clicking)
49390 * @param {SelectionModel} this
49392 "afterselectionchange" : true,
49394 * @event beforerowselect
49395 * Fires when a row is selected being selected, return false to cancel.
49396 * @param {SelectionModel} this
49397 * @param {Number} rowIndex The selected index
49398 * @param {Boolean} keepExisting False if other selections will be cleared
49400 "beforerowselect" : true,
49403 * Fires when a row is selected.
49404 * @param {SelectionModel} this
49405 * @param {Number} rowIndex The selected index
49406 * @param {Roo.data.Record} r The record
49408 "rowselect" : true,
49410 * @event rowdeselect
49411 * Fires when a row is deselected.
49412 * @param {SelectionModel} this
49413 * @param {Number} rowIndex The selected index
49415 "rowdeselect" : true
49417 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
49418 this.locked = false;
49421 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
49423 * @cfg {Boolean} singleSelect
49424 * True to allow selection of only one row at a time (defaults to false)
49426 singleSelect : false,
49429 initEvents : function(){
49431 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
49432 this.grid.on("mousedown", this.handleMouseDown, this);
49433 }else{ // allow click to work like normal
49434 this.grid.on("rowclick", this.handleDragableRowClick, this);
49437 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
49438 "up" : function(e){
49440 this.selectPrevious(e.shiftKey);
49441 }else if(this.last !== false && this.lastActive !== false){
49442 var last = this.last;
49443 this.selectRange(this.last, this.lastActive-1);
49444 this.grid.getView().focusRow(this.lastActive);
49445 if(last !== false){
49449 this.selectFirstRow();
49451 this.fireEvent("afterselectionchange", this);
49453 "down" : function(e){
49455 this.selectNext(e.shiftKey);
49456 }else if(this.last !== false && this.lastActive !== false){
49457 var last = this.last;
49458 this.selectRange(this.last, this.lastActive+1);
49459 this.grid.getView().focusRow(this.lastActive);
49460 if(last !== false){
49464 this.selectFirstRow();
49466 this.fireEvent("afterselectionchange", this);
49471 var view = this.grid.view;
49472 view.on("refresh", this.onRefresh, this);
49473 view.on("rowupdated", this.onRowUpdated, this);
49474 view.on("rowremoved", this.onRemove, this);
49478 onRefresh : function(){
49479 var ds = this.grid.dataSource, i, v = this.grid.view;
49480 var s = this.selections;
49481 s.each(function(r){
49482 if((i = ds.indexOfId(r.id)) != -1){
49491 onRemove : function(v, index, r){
49492 this.selections.remove(r);
49496 onRowUpdated : function(v, index, r){
49497 if(this.isSelected(r)){
49498 v.onRowSelect(index);
49504 * @param {Array} records The records to select
49505 * @param {Boolean} keepExisting (optional) True to keep existing selections
49507 selectRecords : function(records, keepExisting){
49509 this.clearSelections();
49511 var ds = this.grid.dataSource;
49512 for(var i = 0, len = records.length; i < len; i++){
49513 this.selectRow(ds.indexOf(records[i]), true);
49518 * Gets the number of selected rows.
49521 getCount : function(){
49522 return this.selections.length;
49526 * Selects the first row in the grid.
49528 selectFirstRow : function(){
49533 * Select the last row.
49534 * @param {Boolean} keepExisting (optional) True to keep existing selections
49536 selectLastRow : function(keepExisting){
49537 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
49541 * Selects the row immediately following the last selected row.
49542 * @param {Boolean} keepExisting (optional) True to keep existing selections
49544 selectNext : function(keepExisting){
49545 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
49546 this.selectRow(this.last+1, keepExisting);
49547 this.grid.getView().focusRow(this.last);
49552 * Selects the row that precedes the last selected row.
49553 * @param {Boolean} keepExisting (optional) True to keep existing selections
49555 selectPrevious : function(keepExisting){
49557 this.selectRow(this.last-1, keepExisting);
49558 this.grid.getView().focusRow(this.last);
49563 * Returns the selected records
49564 * @return {Array} Array of selected records
49566 getSelections : function(){
49567 return [].concat(this.selections.items);
49571 * Returns the first selected record.
49574 getSelected : function(){
49575 return this.selections.itemAt(0);
49580 * Clears all selections.
49582 clearSelections : function(fast){
49583 if(this.locked) return;
49585 var ds = this.grid.dataSource;
49586 var s = this.selections;
49587 s.each(function(r){
49588 this.deselectRow(ds.indexOfId(r.id));
49592 this.selections.clear();
49599 * Selects all rows.
49601 selectAll : function(){
49602 if(this.locked) return;
49603 this.selections.clear();
49604 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
49605 this.selectRow(i, true);
49610 * Returns True if there is a selection.
49611 * @return {Boolean}
49613 hasSelection : function(){
49614 return this.selections.length > 0;
49618 * Returns True if the specified row is selected.
49619 * @param {Number/Record} record The record or index of the record to check
49620 * @return {Boolean}
49622 isSelected : function(index){
49623 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
49624 return (r && this.selections.key(r.id) ? true : false);
49628 * Returns True if the specified record id is selected.
49629 * @param {String} id The id of record to check
49630 * @return {Boolean}
49632 isIdSelected : function(id){
49633 return (this.selections.key(id) ? true : false);
49637 handleMouseDown : function(e, t){
49638 var view = this.grid.getView(), rowIndex;
49639 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
49642 if(e.shiftKey && this.last !== false){
49643 var last = this.last;
49644 this.selectRange(last, rowIndex, e.ctrlKey);
49645 this.last = last; // reset the last
49646 view.focusRow(rowIndex);
49648 var isSelected = this.isSelected(rowIndex);
49649 if(e.button !== 0 && isSelected){
49650 view.focusRow(rowIndex);
49651 }else if(e.ctrlKey && isSelected){
49652 this.deselectRow(rowIndex);
49653 }else if(!isSelected){
49654 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
49655 view.focusRow(rowIndex);
49658 this.fireEvent("afterselectionchange", this);
49661 handleDragableRowClick : function(grid, rowIndex, e)
49663 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
49664 this.selectRow(rowIndex, false);
49665 grid.view.focusRow(rowIndex);
49666 this.fireEvent("afterselectionchange", this);
49671 * Selects multiple rows.
49672 * @param {Array} rows Array of the indexes of the row to select
49673 * @param {Boolean} keepExisting (optional) True to keep existing selections
49675 selectRows : function(rows, keepExisting){
49677 this.clearSelections();
49679 for(var i = 0, len = rows.length; i < len; i++){
49680 this.selectRow(rows[i], true);
49685 * Selects a range of rows. All rows in between startRow and endRow are also selected.
49686 * @param {Number} startRow The index of the first row in the range
49687 * @param {Number} endRow The index of the last row in the range
49688 * @param {Boolean} keepExisting (optional) True to retain existing selections
49690 selectRange : function(startRow, endRow, keepExisting){
49691 if(this.locked) return;
49693 this.clearSelections();
49695 if(startRow <= endRow){
49696 for(var i = startRow; i <= endRow; i++){
49697 this.selectRow(i, true);
49700 for(var i = startRow; i >= endRow; i--){
49701 this.selectRow(i, true);
49707 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
49708 * @param {Number} startRow The index of the first row in the range
49709 * @param {Number} endRow The index of the last row in the range
49711 deselectRange : function(startRow, endRow, preventViewNotify){
49712 if(this.locked) return;
49713 for(var i = startRow; i <= endRow; i++){
49714 this.deselectRow(i, preventViewNotify);
49720 * @param {Number} row The index of the row to select
49721 * @param {Boolean} keepExisting (optional) True to keep existing selections
49723 selectRow : function(index, keepExisting, preventViewNotify){
49724 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
49725 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
49726 if(!keepExisting || this.singleSelect){
49727 this.clearSelections();
49729 var r = this.grid.dataSource.getAt(index);
49730 this.selections.add(r);
49731 this.last = this.lastActive = index;
49732 if(!preventViewNotify){
49733 this.grid.getView().onRowSelect(index);
49735 this.fireEvent("rowselect", this, index, r);
49736 this.fireEvent("selectionchange", this);
49742 * @param {Number} row The index of the row to deselect
49744 deselectRow : function(index, preventViewNotify){
49745 if(this.locked) return;
49746 if(this.last == index){
49749 if(this.lastActive == index){
49750 this.lastActive = false;
49752 var r = this.grid.dataSource.getAt(index);
49753 this.selections.remove(r);
49754 if(!preventViewNotify){
49755 this.grid.getView().onRowDeselect(index);
49757 this.fireEvent("rowdeselect", this, index);
49758 this.fireEvent("selectionchange", this);
49762 restoreLast : function(){
49764 this.last = this._last;
49769 acceptsNav : function(row, col, cm){
49770 return !cm.isHidden(col) && cm.isCellEditable(col, row);
49774 onEditorKey : function(field, e){
49775 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
49780 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
49782 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
49784 }else if(k == e.ENTER && !e.ctrlKey){
49788 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
49790 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
49792 }else if(k == e.ESC){
49796 g.startEditing(newCell[0], newCell[1]);
49801 * Ext JS Library 1.1.1
49802 * Copyright(c) 2006-2007, Ext JS, LLC.
49804 * Originally Released Under LGPL - original licence link has changed is not relivant.
49807 * <script type="text/javascript">
49810 * @class Roo.grid.CellSelectionModel
49811 * @extends Roo.grid.AbstractSelectionModel
49812 * This class provides the basic implementation for cell selection in a grid.
49814 * @param {Object} config The object containing the configuration of this model.
49816 Roo.grid.CellSelectionModel = function(config){
49817 Roo.apply(this, config);
49819 this.selection = null;
49823 * @event beforerowselect
49824 * Fires before a cell is selected.
49825 * @param {SelectionModel} this
49826 * @param {Number} rowIndex The selected row index
49827 * @param {Number} colIndex The selected cell index
49829 "beforecellselect" : true,
49831 * @event cellselect
49832 * Fires when a cell is selected.
49833 * @param {SelectionModel} this
49834 * @param {Number} rowIndex The selected row index
49835 * @param {Number} colIndex The selected cell index
49837 "cellselect" : true,
49839 * @event selectionchange
49840 * Fires when the active selection changes.
49841 * @param {SelectionModel} this
49842 * @param {Object} selection null for no selection or an object (o) with two properties
49844 <li>o.record: the record object for the row the selection is in</li>
49845 <li>o.cell: An array of [rowIndex, columnIndex]</li>
49848 "selectionchange" : true
49850 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
49853 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
49856 initEvents : function(){
49857 this.grid.on("mousedown", this.handleMouseDown, this);
49858 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
49859 var view = this.grid.view;
49860 view.on("refresh", this.onViewChange, this);
49861 view.on("rowupdated", this.onRowUpdated, this);
49862 view.on("beforerowremoved", this.clearSelections, this);
49863 view.on("beforerowsinserted", this.clearSelections, this);
49864 if(this.grid.isEditor){
49865 this.grid.on("beforeedit", this.beforeEdit, this);
49870 beforeEdit : function(e){
49871 this.select(e.row, e.column, false, true, e.record);
49875 onRowUpdated : function(v, index, r){
49876 if(this.selection && this.selection.record == r){
49877 v.onCellSelect(index, this.selection.cell[1]);
49882 onViewChange : function(){
49883 this.clearSelections(true);
49887 * Returns the currently selected cell,.
49888 * @return {Array} The selected cell (row, column) or null if none selected.
49890 getSelectedCell : function(){
49891 return this.selection ? this.selection.cell : null;
49895 * Clears all selections.
49896 * @param {Boolean} true to prevent the gridview from being notified about the change.
49898 clearSelections : function(preventNotify){
49899 var s = this.selection;
49901 if(preventNotify !== true){
49902 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
49904 this.selection = null;
49905 this.fireEvent("selectionchange", this, null);
49910 * Returns true if there is a selection.
49911 * @return {Boolean}
49913 hasSelection : function(){
49914 return this.selection ? true : false;
49918 handleMouseDown : function(e, t){
49919 var v = this.grid.getView();
49920 if(this.isLocked()){
49923 var row = v.findRowIndex(t);
49924 var cell = v.findCellIndex(t);
49925 if(row !== false && cell !== false){
49926 this.select(row, cell);
49932 * @param {Number} rowIndex
49933 * @param {Number} collIndex
49935 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
49936 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
49937 this.clearSelections();
49938 r = r || this.grid.dataSource.getAt(rowIndex);
49941 cell : [rowIndex, colIndex]
49943 if(!preventViewNotify){
49944 var v = this.grid.getView();
49945 v.onCellSelect(rowIndex, colIndex);
49946 if(preventFocus !== true){
49947 v.focusCell(rowIndex, colIndex);
49950 this.fireEvent("cellselect", this, rowIndex, colIndex);
49951 this.fireEvent("selectionchange", this, this.selection);
49956 isSelectable : function(rowIndex, colIndex, cm){
49957 return !cm.isHidden(colIndex);
49961 handleKeyDown : function(e){
49962 Roo.log('Cell Sel Model handleKeyDown');
49963 if(!e.isNavKeyPress()){
49966 var g = this.grid, s = this.selection;
49969 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
49971 this.select(cell[0], cell[1]);
49976 var walk = function(row, col, step){
49977 return g.walkCells(row, col, step, sm.isSelectable, sm);
49979 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
49984 // handled by onEditorKey
49985 if (g.isEditor && g.editing) {
49989 newCell = walk(r, c-1, -1);
49991 newCell = walk(r, c+1, 1);
49995 newCell = walk(r+1, c, 1);
49998 newCell = walk(r-1, c, -1);
50001 newCell = walk(r, c+1, 1);
50004 newCell = walk(r, c-1, -1);
50007 if(g.isEditor && !g.editing){
50008 g.startEditing(r, c);
50015 this.select(newCell[0], newCell[1]);
50020 acceptsNav : function(row, col, cm){
50021 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50024 onEditorKey : function(field, e){
50026 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50027 ///Roo.log('onEditorKey' + k);
50031 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50033 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50036 }else if(k == e.ENTER && !e.ctrlKey){
50039 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50040 }else if(k == e.ESC){
50046 //Roo.log('next cell after edit');
50047 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
50052 * Ext JS Library 1.1.1
50053 * Copyright(c) 2006-2007, Ext JS, LLC.
50055 * Originally Released Under LGPL - original licence link has changed is not relivant.
50058 * <script type="text/javascript">
50062 * @class Roo.grid.EditorGrid
50063 * @extends Roo.grid.Grid
50064 * Class for creating and editable grid.
50065 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50066 * The container MUST have some type of size defined for the grid to fill. The container will be
50067 * automatically set to position relative if it isn't already.
50068 * @param {Object} dataSource The data model to bind to
50069 * @param {Object} colModel The column model with info about this grid's columns
50071 Roo.grid.EditorGrid = function(container, config){
50072 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
50073 this.getGridEl().addClass("xedit-grid");
50075 if(!this.selModel){
50076 this.selModel = new Roo.grid.CellSelectionModel();
50079 this.activeEditor = null;
50083 * @event beforeedit
50084 * Fires before cell editing is triggered. The edit event object has the following properties <br />
50085 * <ul style="padding:5px;padding-left:16px;">
50086 * <li>grid - This grid</li>
50087 * <li>record - The record being edited</li>
50088 * <li>field - The field name being edited</li>
50089 * <li>value - The value for the field being edited.</li>
50090 * <li>row - The grid row index</li>
50091 * <li>column - The grid column index</li>
50092 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50094 * @param {Object} e An edit event (see above for description)
50096 "beforeedit" : true,
50099 * Fires after a cell is edited. <br />
50100 * <ul style="padding:5px;padding-left:16px;">
50101 * <li>grid - This grid</li>
50102 * <li>record - The record being edited</li>
50103 * <li>field - The field name being edited</li>
50104 * <li>value - The value being set</li>
50105 * <li>originalValue - The original value for the field, before the edit.</li>
50106 * <li>row - The grid row index</li>
50107 * <li>column - The grid column index</li>
50109 * @param {Object} e An edit event (see above for description)
50111 "afteredit" : true,
50113 * @event validateedit
50114 * Fires after a cell is edited, but before the value is set in the record.
50115 * You can use this to modify the value being set in the field, Return false
50116 * to cancel the change. The edit event object has the following properties <br />
50117 * <ul style="padding:5px;padding-left:16px;">
50118 * <li>editor - This editor</li>
50119 * <li>grid - This grid</li>
50120 * <li>record - The record being edited</li>
50121 * <li>field - The field name being edited</li>
50122 * <li>value - The value being set</li>
50123 * <li>originalValue - The original value for the field, before the edit.</li>
50124 * <li>row - The grid row index</li>
50125 * <li>column - The grid column index</li>
50126 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50128 * @param {Object} e An edit event (see above for description)
50130 "validateedit" : true
50132 this.on("bodyscroll", this.stopEditing, this);
50133 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
50136 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
50138 * @cfg {Number} clicksToEdit
50139 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
50146 trackMouseOver: false, // causes very odd FF errors
50148 onCellDblClick : function(g, row, col){
50149 this.startEditing(row, col);
50152 onEditComplete : function(ed, value, startValue){
50153 this.editing = false;
50154 this.activeEditor = null;
50155 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
50157 var field = this.colModel.getDataIndex(ed.col);
50162 originalValue: startValue,
50169 if(String(value) !== String(startValue)){
50171 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
50172 r.set(field, e.value);
50173 // if we are dealing with a combo box..
50174 // then we also set the 'name' colum to be the displayField
50175 if (ed.field.displayField && ed.field.name) {
50176 r.set(ed.field.name, ed.field.el.dom.value);
50179 delete e.cancel; //?? why!!!
50180 this.fireEvent("afteredit", e);
50183 this.fireEvent("afteredit", e); // always fire it!
50185 this.view.focusCell(ed.row, ed.col);
50189 * Starts editing the specified for the specified row/column
50190 * @param {Number} rowIndex
50191 * @param {Number} colIndex
50193 startEditing : function(row, col){
50194 this.stopEditing();
50195 if(this.colModel.isCellEditable(col, row)){
50196 this.view.ensureVisible(row, col, true);
50197 var r = this.dataSource.getAt(row);
50198 var field = this.colModel.getDataIndex(col);
50203 value: r.data[field],
50208 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
50209 this.editing = true;
50210 var ed = this.colModel.getCellEditor(col, row);
50216 ed.render(ed.parentEl || document.body);
50219 (function(){ // complex but required for focus issues in safari, ie and opera
50223 ed.on("complete", this.onEditComplete, this, {single: true});
50224 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
50225 this.activeEditor = ed;
50226 var v = r.data[field];
50227 ed.startEdit(this.view.getCell(row, col), v);
50228 // combo's with 'displayField and name set
50229 if (ed.field.displayField && ed.field.name) {
50230 ed.field.el.dom.value = r.data[ed.field.name];
50234 }).defer(50, this);
50240 * Stops any active editing
50242 stopEditing : function(){
50243 if(this.activeEditor){
50244 this.activeEditor.completeEdit();
50246 this.activeEditor = null;
50250 * Ext JS Library 1.1.1
50251 * Copyright(c) 2006-2007, Ext JS, LLC.
50253 * Originally Released Under LGPL - original licence link has changed is not relivant.
50256 * <script type="text/javascript">
50259 // private - not really -- you end up using it !
50260 // This is a support class used internally by the Grid components
50263 * @class Roo.grid.GridEditor
50264 * @extends Roo.Editor
50265 * Class for creating and editable grid elements.
50266 * @param {Object} config any settings (must include field)
50268 Roo.grid.GridEditor = function(field, config){
50269 if (!config && field.field) {
50271 field = Roo.factory(config.field, Roo.form);
50273 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
50274 field.monitorTab = false;
50277 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
50280 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
50283 alignment: "tl-tl",
50286 cls: "x-small-editor x-grid-editor",
50291 * Ext JS Library 1.1.1
50292 * Copyright(c) 2006-2007, Ext JS, LLC.
50294 * Originally Released Under LGPL - original licence link has changed is not relivant.
50297 * <script type="text/javascript">
50302 Roo.grid.PropertyRecord = Roo.data.Record.create([
50303 {name:'name',type:'string'}, 'value'
50307 Roo.grid.PropertyStore = function(grid, source){
50309 this.store = new Roo.data.Store({
50310 recordType : Roo.grid.PropertyRecord
50312 this.store.on('update', this.onUpdate, this);
50314 this.setSource(source);
50316 Roo.grid.PropertyStore.superclass.constructor.call(this);
50321 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
50322 setSource : function(o){
50324 this.store.removeAll();
50327 if(this.isEditableValue(o[k])){
50328 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
50331 this.store.loadRecords({records: data}, {}, true);
50334 onUpdate : function(ds, record, type){
50335 if(type == Roo.data.Record.EDIT){
50336 var v = record.data['value'];
50337 var oldValue = record.modified['value'];
50338 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
50339 this.source[record.id] = v;
50341 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
50348 getProperty : function(row){
50349 return this.store.getAt(row);
50352 isEditableValue: function(val){
50353 if(val && val instanceof Date){
50355 }else if(typeof val == 'object' || typeof val == 'function'){
50361 setValue : function(prop, value){
50362 this.source[prop] = value;
50363 this.store.getById(prop).set('value', value);
50366 getSource : function(){
50367 return this.source;
50371 Roo.grid.PropertyColumnModel = function(grid, store){
50374 g.PropertyColumnModel.superclass.constructor.call(this, [
50375 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
50376 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
50378 this.store = store;
50379 this.bselect = Roo.DomHelper.append(document.body, {
50380 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
50381 {tag: 'option', value: 'true', html: 'true'},
50382 {tag: 'option', value: 'false', html: 'false'}
50385 Roo.id(this.bselect);
50388 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
50389 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
50390 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
50391 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
50392 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
50394 this.renderCellDelegate = this.renderCell.createDelegate(this);
50395 this.renderPropDelegate = this.renderProp.createDelegate(this);
50398 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
50402 valueText : 'Value',
50404 dateFormat : 'm/j/Y',
50407 renderDate : function(dateVal){
50408 return dateVal.dateFormat(this.dateFormat);
50411 renderBool : function(bVal){
50412 return bVal ? 'true' : 'false';
50415 isCellEditable : function(colIndex, rowIndex){
50416 return colIndex == 1;
50419 getRenderer : function(col){
50421 this.renderCellDelegate : this.renderPropDelegate;
50424 renderProp : function(v){
50425 return this.getPropertyName(v);
50428 renderCell : function(val){
50430 if(val instanceof Date){
50431 rv = this.renderDate(val);
50432 }else if(typeof val == 'boolean'){
50433 rv = this.renderBool(val);
50435 return Roo.util.Format.htmlEncode(rv);
50438 getPropertyName : function(name){
50439 var pn = this.grid.propertyNames;
50440 return pn && pn[name] ? pn[name] : name;
50443 getCellEditor : function(colIndex, rowIndex){
50444 var p = this.store.getProperty(rowIndex);
50445 var n = p.data['name'], val = p.data['value'];
50447 if(typeof(this.grid.customEditors[n]) == 'string'){
50448 return this.editors[this.grid.customEditors[n]];
50450 if(typeof(this.grid.customEditors[n]) != 'undefined'){
50451 return this.grid.customEditors[n];
50453 if(val instanceof Date){
50454 return this.editors['date'];
50455 }else if(typeof val == 'number'){
50456 return this.editors['number'];
50457 }else if(typeof val == 'boolean'){
50458 return this.editors['boolean'];
50460 return this.editors['string'];
50466 * @class Roo.grid.PropertyGrid
50467 * @extends Roo.grid.EditorGrid
50468 * This class represents the interface of a component based property grid control.
50469 * <br><br>Usage:<pre><code>
50470 var grid = new Roo.grid.PropertyGrid("my-container-id", {
50478 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50479 * The container MUST have some type of size defined for the grid to fill. The container will be
50480 * automatically set to position relative if it isn't already.
50481 * @param {Object} config A config object that sets properties on this grid.
50483 Roo.grid.PropertyGrid = function(container, config){
50484 config = config || {};
50485 var store = new Roo.grid.PropertyStore(this);
50486 this.store = store;
50487 var cm = new Roo.grid.PropertyColumnModel(this, store);
50488 store.store.sort('name', 'ASC');
50489 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
50492 enableColLock:false,
50493 enableColumnMove:false,
50495 trackMouseOver: false,
50498 this.getGridEl().addClass('x-props-grid');
50499 this.lastEditRow = null;
50500 this.on('columnresize', this.onColumnResize, this);
50503 * @event beforepropertychange
50504 * Fires before a property changes (return false to stop?)
50505 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50506 * @param {String} id Record Id
50507 * @param {String} newval New Value
50508 * @param {String} oldval Old Value
50510 "beforepropertychange": true,
50512 * @event propertychange
50513 * Fires after a property changes
50514 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50515 * @param {String} id Record Id
50516 * @param {String} newval New Value
50517 * @param {String} oldval Old Value
50519 "propertychange": true
50521 this.customEditors = this.customEditors || {};
50523 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
50526 * @cfg {Object} customEditors map of colnames=> custom editors.
50527 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
50528 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
50529 * false disables editing of the field.
50533 * @cfg {Object} propertyNames map of property Names to their displayed value
50536 render : function(){
50537 Roo.grid.PropertyGrid.superclass.render.call(this);
50538 this.autoSize.defer(100, this);
50541 autoSize : function(){
50542 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
50544 this.view.fitColumns();
50548 onColumnResize : function(){
50549 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
50553 * Sets the data for the Grid
50554 * accepts a Key => Value object of all the elements avaiable.
50555 * @param {Object} data to appear in grid.
50557 setSource : function(source){
50558 this.store.setSource(source);
50562 * Gets all the data from the grid.
50563 * @return {Object} data data stored in grid
50565 getSource : function(){
50566 return this.store.getSource();
50570 * Ext JS Library 1.1.1
50571 * Copyright(c) 2006-2007, Ext JS, LLC.
50573 * Originally Released Under LGPL - original licence link has changed is not relivant.
50576 * <script type="text/javascript">
50580 * @class Roo.LoadMask
50581 * A simple utility class for generically masking elements while loading data. If the element being masked has
50582 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
50583 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
50584 * element's UpdateManager load indicator and will be destroyed after the initial load.
50586 * Create a new LoadMask
50587 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
50588 * @param {Object} config The config object
50590 Roo.LoadMask = function(el, config){
50591 this.el = Roo.get(el);
50592 Roo.apply(this, config);
50594 this.store.on('beforeload', this.onBeforeLoad, this);
50595 this.store.on('load', this.onLoad, this);
50596 this.store.on('loadexception', this.onLoad, this);
50597 this.removeMask = false;
50599 var um = this.el.getUpdateManager();
50600 um.showLoadIndicator = false; // disable the default indicator
50601 um.on('beforeupdate', this.onBeforeLoad, this);
50602 um.on('update', this.onLoad, this);
50603 um.on('failure', this.onLoad, this);
50604 this.removeMask = true;
50608 Roo.LoadMask.prototype = {
50610 * @cfg {Boolean} removeMask
50611 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
50612 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
50615 * @cfg {String} msg
50616 * The text to display in a centered loading message box (defaults to 'Loading...')
50618 msg : 'Loading...',
50620 * @cfg {String} msgCls
50621 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
50623 msgCls : 'x-mask-loading',
50626 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
50632 * Disables the mask to prevent it from being displayed
50634 disable : function(){
50635 this.disabled = true;
50639 * Enables the mask so that it can be displayed
50641 enable : function(){
50642 this.disabled = false;
50646 onLoad : function(){
50647 this.el.unmask(this.removeMask);
50651 onBeforeLoad : function(){
50652 if(!this.disabled){
50653 this.el.mask(this.msg, this.msgCls);
50658 destroy : function(){
50660 this.store.un('beforeload', this.onBeforeLoad, this);
50661 this.store.un('load', this.onLoad, this);
50662 this.store.un('loadexception', this.onLoad, this);
50664 var um = this.el.getUpdateManager();
50665 um.un('beforeupdate', this.onBeforeLoad, this);
50666 um.un('update', this.onLoad, this);
50667 um.un('failure', this.onLoad, this);
50672 * Ext JS Library 1.1.1
50673 * Copyright(c) 2006-2007, Ext JS, LLC.
50675 * Originally Released Under LGPL - original licence link has changed is not relivant.
50678 * <script type="text/javascript">
50680 Roo.XTemplate = function(){
50681 Roo.XTemplate.superclass.constructor.apply(this, arguments);
50684 s = ['<tpl>', s, '</tpl>'].join('');
50686 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
50688 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
50689 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
50690 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
50694 while(m = s.match(re)){
50695 var m2 = m[0].match(nameRe);
50696 var m3 = m[0].match(ifRe);
50697 var m4 = m[0].match(execRe);
50698 var exp = null, fn = null, exec = null;
50699 var name = m2 && m2[1] ? m2[1] : '';
50701 exp = m3 && m3[1] ? m3[1] : null;
50703 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
50707 exp = m4 && m4[1] ? m4[1] : null;
50709 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
50714 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
50715 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
50716 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
50726 s = s.replace(m[0], '{xtpl'+ id + '}');
50729 for(var i = tpls.length-1; i >= 0; --i){
50730 this.compileTpl(tpls[i]);
50732 this.master = tpls[tpls.length-1];
50735 Roo.extend(Roo.XTemplate, Roo.Template, {
50737 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
50739 applySubTemplate : function(id, values, parent){
50740 var t = this.tpls[id];
50741 if(t.test && !t.test.call(this, values, parent)){
50744 if(t.exec && t.exec.call(this, values, parent)){
50747 var vs = t.target ? t.target.call(this, values, parent) : values;
50748 parent = t.target ? values : parent;
50749 if(t.target && vs instanceof Array){
50751 for(var i = 0, len = vs.length; i < len; i++){
50752 buf[buf.length] = t.compiled.call(this, vs[i], parent);
50754 return buf.join('');
50756 return t.compiled.call(this, vs, parent);
50759 compileTpl : function(tpl){
50760 var fm = Roo.util.Format;
50761 var useF = this.disableFormats !== true;
50762 var sep = Roo.isGecko ? "+" : ",";
50763 var fn = function(m, name, format, args){
50764 if(name.substr(0, 4) == 'xtpl'){
50765 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
50768 if(name.indexOf('.') != -1){
50771 v = "values['" + name + "']";
50773 if(format && useF){
50774 args = args ? ',' + args : "";
50775 if(format.substr(0, 5) != "this."){
50776 format = "fm." + format + '(';
50778 format = 'this.call("'+ format.substr(5) + '", ';
50782 args= ''; format = "("+v+" === undefined ? '' : ";
50784 return "'"+ sep + format + v + args + ")"+sep+"'";
50787 // branched to use + in gecko and [].join() in others
50789 body = "tpl.compiled = function(values, parent){ return '" +
50790 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
50793 body = ["tpl.compiled = function(values, parent){ return ['"];
50794 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
50795 body.push("'].join('');};");
50796 body = body.join('');
50798 /** eval:var:zzzzzzz */
50803 applyTemplate : function(values){
50804 return this.master.compiled.call(this, values, {});
50808 apply : function(){
50809 return this.applyTemplate.apply(this, arguments);
50812 compile : function(){return this;}
50815 Roo.XTemplate.from = function(el){
50816 el = Roo.getDom(el);
50817 return new Roo.XTemplate(el.value || el.innerHTML);
50819 * Original code for Roojs - LGPL
50820 * <script type="text/javascript">
50824 * @class Roo.XComponent
50825 * A delayed Element creator...
50827 * Mypart.xyx = new Roo.XComponent({
50829 parent : 'Mypart.xyz', // empty == document.element.!!
50833 disabled : function() {}
50835 tree : function() { // return an tree of xtype declared components
50839 xtype : 'NestedLayoutPanel',
50844 * @extends Roo.util.Observable
50846 * @param cfg {Object} configuration of component
50849 Roo.XComponent = function(cfg) {
50850 Roo.apply(this, cfg);
50854 * Fires when this the componnt is built
50855 * @param {Roo.XComponent} c the component
50859 * @event buildcomplete
50860 * Fires on the top level element when all elements have been built
50861 * @param {Roo.XComponent} c the top level component.
50863 'buildcomplete' : true
50867 Roo.XComponent.register(this);
50868 this.modules = false;
50869 this.el = false; // where the layout goes..
50873 Roo.extend(Roo.XComponent, Roo.util.Observable, {
50876 * The created element (with Roo.factory())
50877 * @type {Roo.Layout}
50883 * for BC - use el in new code
50884 * @type {Roo.Layout}
50890 * for BC - use el in new code
50891 * @type {Roo.Layout}
50896 * @cfg {Function|boolean} disabled
50897 * If this module is disabled by some rule, return true from the funtion
50902 * @cfg {String} parent
50903 * Name of parent element which it get xtype added to..
50908 * @cfg {String} order
50909 * Used to set the order in which elements are created (usefull for multiple tabs)
50914 * @cfg {String} name
50915 * String to display while loading.
50919 * @cfg {Array} items
50920 * A single item array - the first element is the root of the tree..
50921 * It's done this way to stay compatible with the Xtype system...
50929 Roo.apply(Roo.XComponent, {
50932 * @property buildCompleted
50933 * True when the builder has completed building the interface.
50936 buildCompleted : false,
50939 * @property topModule
50940 * the upper most module - uses document.element as it's constructor.
50947 * @property modules
50948 * array of modules to be created by registration system.
50949 * @type Roo.XComponent
50956 * Register components to be built later.
50958 * This solves the following issues
50959 * - Building is not done on page load, but after an authentication process has occured.
50960 * - Interface elements are registered on page load
50961 * - Parent Interface elements may not be loaded before child, so this handles that..
50968 module : 'Pman.Tab.projectMgr',
50970 parent : 'Pman.layout',
50971 disabled : false, // or use a function..
50974 * * @param {Object} details about module
50976 register : function(obj) {
50977 this.modules.push(obj);
50981 * convert a string to an object..
50985 toObject : function(str)
50987 if (!str || typeof(str) == 'object') {
50990 var ar = str.split('.');
50994 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
50996 throw "Module not found : " + str;
50998 Roo.each(ar, function(e) {
50999 if (typeof(o[e]) == 'undefined') {
51000 throw "Module not found : " + str;
51010 * move modules into their correct place in the tree..
51013 preBuild : function ()
51016 Roo.each(this.modules , function (obj)
51018 obj.parent = this.toObject(obj.parent);
51021 this.topModule = obj;
51025 if (!obj.parent.modules) {
51026 obj.parent.modules = new Roo.util.MixedCollection(false,
51027 function(o) { return o.order + '' }
51031 obj.parent.modules.add(obj);
51036 * make a list of modules to build.
51037 * @return {Array} list of modules.
51040 buildOrder : function()
51043 var cmp = function(a,b) {
51044 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
51047 if (!this.topModule || !this.topModule.modules) {
51048 throw "No top level modules to build";
51051 // make a flat list in order of modules to build.
51052 var mods = [ this.topModule ];
51055 // add modules to their parents..
51056 var addMod = function(m) {
51057 // Roo.debug && Roo.log(m.modKey);
51061 m.modules.keySort('ASC', cmp );
51062 m.modules.each(addMod);
51064 // not sure if this is used any more..
51066 m.finalize.name = m.name + " (clean up) ";
51067 mods.push(m.finalize);
51071 this.topModule.modules.keySort('ASC', cmp );
51072 this.topModule.modules.each(addMod);
51077 * Build the registered modules.
51078 * @param {Object} parent element.
51079 * @param {Function} optional method to call after module has been added.
51087 var mods = this.buildOrder();
51089 //this.allmods = mods;
51090 //Roo.debug && Roo.log(mods);
51092 if (!mods.length) { // should not happen
51093 throw "NO modules!!!";
51098 // flash it up as modal - so we store the mask!?
51099 Roo.MessageBox.show({ title: 'loading' });
51100 Roo.MessageBox.show({
51101 title: "Please wait...",
51102 msg: "Building Interface...",
51109 var total = mods.length;
51112 var progressRun = function() {
51113 if (!mods.length) {
51114 Roo.debug && Roo.log('hide?');
51115 Roo.MessageBox.hide();
51116 _this.topModule.fireEvent('buildcomplete', _this.topModule);
51120 var m = mods.shift();
51121 Roo.debug && Roo.log(m);
51122 if (typeof(m) == 'function') { // not sure if this is supported any more..
51124 return progressRun.defer(10, _this);
51127 Roo.MessageBox.updateProgress(
51128 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
51130 (m.name ? (' - ' + m.name) : '')
51135 var disabled = (typeof(m.disabled) == 'function') ?
51136 m.disabled.call(m.module.disabled) : m.disabled;
51140 return progressRun(); // we do not update the display!
51144 // it's a top level one..
51145 var layoutbase = new Ext.BorderLayout(document.body, {
51151 tabPosition: 'top',
51152 //resizeTabs: true,
51153 alwaysShowTabs: true,
51157 var tree = m.tree();
51158 tree.region = 'center';
51159 m.el = layoutbase.addxtype(tree);
51161 m.layout = m.panel.layout;
51162 return progressRun.defer(10, _this);
51165 var tree = m.tree();
51166 tree.region = tree.region || m.region;
51167 m.el = m.parent.el.addxtype(tree);
51168 m.fireEvent('built', m);
51170 m.layout = m.panel.layout;
51171 progressRun.defer(10, _this);
51174 progressRun.defer(1, _this);
51184 //<script type="text/javascript">
51189 * @extends Roo.LayoutDialog
51190 * A generic Login Dialog..... - only one needed in theory!?!?
51192 * Fires XComponent builder on success...
51195 * username,password, lang = for login actions.
51196 * check = 1 for periodic checking that sesion is valid.
51197 * passwordRequest = email request password
51198 * logout = 1 = to logout
51200 * Affects: (this id="????" elements)
51201 * loading (removed) (used to indicate application is loading)
51202 * loading-mask (hides) (used to hide application when it's building loading)
51208 * Myapp.login = Roo.Login({
51224 Roo.Login = function(cfg)
51230 Roo.apply(this,cfg);
51232 Roo.onReady(function() {
51238 Roo.Login.superclass.constructor.call(this, this);
51239 //this.addxtype(this.items[0]);
51245 Roo.extend(Roo.Login, Roo.LayoutDialog, {
51248 * @cfg {String} method
51249 * Method used to query for login details.
51254 * @cfg {String} url
51255 * URL to query login data. - eg. baseURL + '/Login.php'
51261 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
51266 * @property checkFails
51267 * Number of times we have attempted to get authentication check, and failed.
51272 * @property intervalID
51273 * The window interval that does the constant login checking.
51279 onLoad : function() // called on page load...
51283 if (Roo.get('loading')) { // clear any loading indicator..
51284 Roo.get('loading').remove();
51287 //this.switchLang('en'); // set the language to english..
51290 success: function(response, opts) { // check successfull...
51292 var res = this.processResponse(response);
51293 this.checkFails =0;
51294 if (!res.success) { // error!
51295 this.checkFails = 5;
51296 //console.log('call failure');
51297 return this.failure(response,opts);
51300 if (!res.data.id) { // id=0 == login failure.
51301 return this.show();
51305 //console.log(success);
51306 this.fillAuth(res.data);
51307 this.checkFails =0;
51308 Roo.XComponent.build();
51310 failure : this.show
51316 check: function(cfg) // called every so often to refresh cookie etc..
51318 if (cfg.again) { // could be undefined..
51321 this.checkFails = 0;
51324 if (this.sending) {
51325 if ( this.checkFails > 4) {
51326 Roo.MessageBox.alert("Error",
51327 "Error getting authentication status. - try reloading, or wait a while", function() {
51328 _this.sending = false;
51333 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
51336 this.sending = true;
51343 method: this.method,
51344 success: cfg.success || this.success,
51345 failure : cfg.failure || this.failure,
51355 window.onbeforeunload = function() { }; // false does not work for IE..
51365 failure : function() {
51366 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
51367 document.location = document.location.toString() + '?ts=' + Math.random();
51371 success : function() {
51372 _this.user = false;
51373 this.checkFails =0;
51375 document.location = document.location.toString() + '?ts=' + Math.random();
51382 processResponse : function (response)
51386 res = Roo.decode(response.responseText);
51388 if (typeof(res) != 'object') {
51389 res = { success : false, errorMsg : res, errors : true };
51391 if (typeof(res.success) == 'undefined') {
51392 res.success = false;
51396 res = { success : false, errorMsg : response.responseText, errors : true };
51401 success : function(response, opts) // check successfull...
51403 this.sending = false;
51404 var res = this.processResponse(response);
51405 if (!res.success) {
51406 return this.failure(response, opts);
51408 if (!res.data || !res.data.id) {
51409 return this.failure(response,opts);
51411 //console.log(res);
51412 this.fillAuth(res.data);
51414 this.checkFails =0;
51419 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
51421 this.authUser = -1;
51422 this.sending = false;
51423 var res = this.processResponse(response);
51424 //console.log(res);
51425 if ( this.checkFails > 2) {
51427 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
51428 "Error getting authentication status. - try reloading");
51431 opts.callCfg.again = true;
51432 this.check.defer(1000, this, [ opts.callCfg ]);
51438 fillAuth: function(au) {
51439 this.startAuthCheck();
51440 this.authUserId = au.id;
51441 this.authUser = au;
51442 this.lastChecked = new Date();
51443 this.fireEvent('refreshed', au);
51444 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
51445 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
51446 au.lang = au.lang || 'en';
51447 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
51448 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
51449 this.switchLang(au.lang );
51452 // open system... - -on setyp..
51453 if (this.authUserId < 0) {
51454 Roo.MessageBox.alert("Warning",
51455 "This is an open system - please set up a admin user with a password.");
51458 //Pman.onload(); // which should do nothing if it's a re-auth result...
51463 startAuthCheck : function() // starter for timeout checking..
51465 if (this.intervalID) { // timer already in place...
51469 this.intervalID = window.setInterval(function() {
51470 _this.check(false);
51471 }, 120000); // every 120 secs = 2mins..
51477 switchLang : function (lang)
51479 _T = typeof(_T) == 'undefined' ? false : _T;
51480 if (!_T || !lang.length) {
51484 if (!_T && lang != 'en') {
51485 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51489 if (typeof(_T.en) == 'undefined') {
51491 Roo.apply(_T.en, _T);
51494 if (typeof(_T[lang]) == 'undefined') {
51495 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51500 Roo.apply(_T, _T[lang]);
51501 // just need to set the text values for everything...
51503 /* this will not work ...
51507 function formLabel(name, val) {
51508 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
51511 formLabel('password', "Password"+':');
51512 formLabel('username', "Email Address"+':');
51513 formLabel('lang', "Language"+':');
51514 this.dialog.setTitle("Login");
51515 this.dialog.buttons[0].setText("Forgot Password");
51516 this.dialog.buttons[1].setText("Login");
51535 collapsible: false,
51537 center: { // needed??
51540 // tabPosition: 'top',
51543 alwaysShowTabs: false
51547 show : function(dlg)
51549 //console.log(this);
51550 this.form = this.layout.getRegion('center').activePanel.form;
51551 this.form.dialog = dlg;
51552 this.buttons[0].form = this.form;
51553 this.buttons[0].dialog = dlg;
51554 this.buttons[1].form = this.form;
51555 this.buttons[1].dialog = dlg;
51557 //this.resizeToLogo.defer(1000,this);
51558 // this is all related to resizing for logos..
51559 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
51561 // this.resizeToLogo.defer(1000,this);
51564 //var w = Ext.lib.Dom.getViewWidth() - 100;
51565 //var h = Ext.lib.Dom.getViewHeight() - 100;
51566 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
51568 if (this.disabled) {
51573 if (this.user.id < 0) { // used for inital setup situations.
51577 if (this.intervalID) {
51578 // remove the timer
51579 window.clearInterval(this.intervalID);
51580 this.intervalID = false;
51584 if (Roo.get('loading')) {
51585 Roo.get('loading').remove();
51587 if (Roo.get('loading-mask')) {
51588 Roo.get('loading-mask').hide();
51591 //incomming._node = tnode;
51593 //this.dialog.modal = !modal;
51594 //this.dialog.show();
51598 this.form.setValues({
51599 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
51600 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
51603 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
51604 if (this.form.findField('username').getValue().length > 0 ){
51605 this.form.findField('password').focus();
51607 this.form.findField('username').focus();
51615 xtype : 'ContentPanel',
51627 style : 'margin: 10px;',
51630 actionfailed : function(f, act) {
51631 // form can return { errors: .... }
51633 //act.result.errors // invalid form element list...
51634 //act.result.errorMsg// invalid form element list...
51636 this.dialog.el.unmask();
51637 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
51638 "Login failed - communication error - try again.");
51641 actioncomplete: function(re, act) {
51643 Roo.state.Manager.set(
51644 this.dialog.realm + '.username',
51645 this.findField('username').getValue()
51647 Roo.state.Manager.set(
51648 this.dialog.realm + '.lang',
51649 this.findField('lang').getValue()
51652 this.dialog.fillAuth(act.result.data);
51654 this.dialog.hide();
51656 if (Roo.get('loading-mask')) {
51657 Roo.get('loading-mask').show();
51659 Roo.XComponent.build();
51667 xtype : 'TextField',
51669 fieldLabel: "Email Address",
51672 autoCreate : {tag: "input", type: "text", size: "20"}
51675 xtype : 'TextField',
51677 fieldLabel: "Password",
51678 inputType: 'password',
51681 autoCreate : {tag: "input", type: "text", size: "20"},
51683 specialkey : function(e,ev) {
51684 if (ev.keyCode == 13) {
51685 this.form.dialog.el.mask("Logging in");
51686 this.form.doAction('submit', {
51687 url: this.form.dialog.url,
51688 method: this.form.dialog.method
51695 xtype : 'ComboBox',
51697 fieldLabel: "Language",
51700 xtype : 'SimpleStore',
51701 fields: ['lang', 'ldisp'],
51703 [ 'en', 'English' ],
51704 [ 'zh_HK' , '\u7E41\u4E2D' ],
51705 [ 'zh_CN', '\u7C21\u4E2D' ]
51709 valueField : 'lang',
51710 hiddenName: 'lang',
51712 displayField:'ldisp',
51716 triggerAction: 'all',
51717 emptyText:'Select a Language...',
51718 selectOnFocus:true,
51720 select : function(cb, rec, ix) {
51721 this.form.switchLang(rec.data.lang);
51737 text : "Forgot Password",
51739 click : function() {
51740 //console.log(this);
51741 var n = this.form.findField('username').getValue();
51743 Roo.MessageBox.alert("Error", "Fill in your email address");
51747 url: this.dialog.url,
51751 method: this.dialog.method,
51752 success: function(response, opts) { // check successfull...
51754 var res = this.dialog.processResponse(response);
51755 if (!res.success) { // error!
51756 Roo.MessageBox.alert("Error" ,
51757 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
51760 Roo.MessageBox.alert("Notice" ,
51761 "Please check you email for the Password Reset message");
51763 failure : function() {
51764 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
51777 click : function () {
51779 this.dialog.el.mask("Logging in");
51780 this.form.doAction('submit', {
51781 url: this.dialog.url,
51782 method: this.dialog.method