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 Roo.apply(this, config);
18269 if(this.containerScroll){
18270 Roo.dd.ScrollManager.register(this.el);
18274 * @scope Roo.dd.DropTarget
18279 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18280 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18281 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18283 * IMPORTANT : it should set this.overClass and this.dropAllowed
18285 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18286 * @param {Event} e The event
18287 * @param {Object} data An object containing arbitrary data supplied by the drag source
18293 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18294 * This method will be called on every mouse movement while the drag source is over the drop target.
18295 * This default implementation simply returns the dropAllowed config value.
18297 * IMPORTANT : it should set this.dropAllowed
18299 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18300 * @param {Event} e The event
18301 * @param {Object} data An object containing arbitrary data supplied by the drag source
18307 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18308 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18309 * overClass (if any) from the drop element.
18310 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18311 * @param {Event} e The event
18312 * @param {Object} data An object containing arbitrary data supplied by the drag source
18318 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18319 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18320 * implementation that does something to process the drop event and returns true so that the drag source's
18321 * repair action does not run.
18323 * IMPORTANT : it should set this.success
18325 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18326 * @param {Event} e The event
18327 * @param {Object} data An object containing arbitrary data supplied by the drag source
18333 Roo.dd.DropTarget.superclass.constructor.call( this,
18335 this.ddGroup || this.group,
18338 listeners : config.listeners || {}
18346 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18348 * @cfg {String} overClass
18349 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18352 * @cfg {String} ddGroup
18353 * The drag drop group to handle drop events for
18357 * @cfg {String} dropAllowed
18358 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18360 dropAllowed : "x-dd-drop-ok",
18362 * @cfg {String} dropNotAllowed
18363 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18365 dropNotAllowed : "x-dd-drop-nodrop",
18367 * @cfg {boolean} success
18368 * set this after drop listener..
18372 * @cfg {boolean} valid
18373 * if the drop point is valid for over/enter..
18380 isNotifyTarget : true,
18385 notifyEnter : function(dd, e, data){
18387 this.fireEvent('enter', this, dd, e, data);
18388 if(this.overClass){
18389 this.el.addClass(this.overClass);
18391 return this.valid ? this.dropAllowed : this.dropNotAllowed;
18397 notifyOver : function(dd, e, data){
18399 this.fireEvent('over', this, dd, e, data);
18400 return this.valid ? this.dropAllowed : this.dropNotAllowed;
18406 notifyOut : function(dd, e, data){
18407 this.fireEvent('out', this, dd, e, data);
18408 if(this.overClass){
18409 this.el.removeClass(this.overClass);
18416 notifyDrop : function(dd, e, data){
18417 this.success = false;
18418 this.fireEvent('drop', this, dd, e, data);
18419 return this.success;
18423 * Ext JS Library 1.1.1
18424 * Copyright(c) 2006-2007, Ext JS, LLC.
18426 * Originally Released Under LGPL - original licence link has changed is not relivant.
18429 * <script type="text/javascript">
18434 * @class Roo.dd.DragZone
18435 * @extends Roo.dd.DragSource
18436 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18437 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18439 * @param {String/HTMLElement/Element} el The container element
18440 * @param {Object} config
18442 Roo.dd.DragZone = function(el, config){
18443 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18444 if(this.containerScroll){
18445 Roo.dd.ScrollManager.register(this.el);
18449 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18451 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18452 * for auto scrolling during drag operations.
18455 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18456 * method after a failed drop (defaults to "c3daf9" - light blue)
18460 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18461 * for a valid target to drag based on the mouse down. Override this method
18462 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18463 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18464 * @param {EventObject} e The mouse down event
18465 * @return {Object} The dragData
18467 getDragData : function(e){
18468 return Roo.dd.Registry.getHandleFromEvent(e);
18472 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18473 * this.dragData.ddel
18474 * @param {Number} x The x position of the click on the dragged object
18475 * @param {Number} y The y position of the click on the dragged object
18476 * @return {Boolean} true to continue the drag, false to cancel
18478 onInitDrag : function(x, y){
18479 this.proxy.update(this.dragData.ddel.cloneNode(true));
18480 this.onStartDrag(x, y);
18485 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18487 afterRepair : function(){
18489 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18491 this.dragging = false;
18495 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18496 * the XY of this.dragData.ddel
18497 * @param {EventObject} e The mouse up event
18498 * @return {Array} The xy location (e.g. [100, 200])
18500 getRepairXY : function(e){
18501 return Roo.Element.fly(this.dragData.ddel).getXY();
18505 * Ext JS Library 1.1.1
18506 * Copyright(c) 2006-2007, Ext JS, LLC.
18508 * Originally Released Under LGPL - original licence link has changed is not relivant.
18511 * <script type="text/javascript">
18514 * @class Roo.dd.DropZone
18515 * @extends Roo.dd.DropTarget
18516 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18517 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18519 * @param {String/HTMLElement/Element} el The container element
18520 * @param {Object} config
18522 Roo.dd.DropZone = function(el, config){
18523 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18526 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18528 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18529 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18530 * provide your own custom lookup.
18531 * @param {Event} e The event
18532 * @return {Object} data The custom data
18534 getTargetFromEvent : function(e){
18535 return Roo.dd.Registry.getTargetFromEvent(e);
18539 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18540 * that it has registered. This method has no default implementation and should be overridden to provide
18541 * node-specific processing if necessary.
18542 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18543 * {@link #getTargetFromEvent} for this node)
18544 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18545 * @param {Event} e The event
18546 * @param {Object} data An object containing arbitrary data supplied by the drag source
18548 onNodeEnter : function(n, dd, e, data){
18553 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18554 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18555 * overridden to provide the proper feedback.
18556 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18557 * {@link #getTargetFromEvent} for this node)
18558 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18559 * @param {Event} e The event
18560 * @param {Object} data An object containing arbitrary data supplied by the drag source
18561 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18562 * underlying {@link Roo.dd.StatusProxy} can be updated
18564 onNodeOver : function(n, dd, e, data){
18565 return this.dropAllowed;
18569 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18570 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18571 * node-specific processing if necessary.
18572 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18573 * {@link #getTargetFromEvent} for this node)
18574 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18575 * @param {Event} e The event
18576 * @param {Object} data An object containing arbitrary data supplied by the drag source
18578 onNodeOut : function(n, dd, e, data){
18583 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18584 * the drop node. The default implementation returns false, so it should be overridden to provide the
18585 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18586 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18587 * {@link #getTargetFromEvent} for this node)
18588 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18589 * @param {Event} e The event
18590 * @param {Object} data An object containing arbitrary data supplied by the drag source
18591 * @return {Boolean} True if the drop was valid, else false
18593 onNodeDrop : function(n, dd, e, data){
18598 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18599 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18600 * it should be overridden to provide the proper feedback if necessary.
18601 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18602 * @param {Event} e The event
18603 * @param {Object} data An object containing arbitrary data supplied by the drag source
18604 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18605 * underlying {@link Roo.dd.StatusProxy} can be updated
18607 onContainerOver : function(dd, e, data){
18608 return this.dropNotAllowed;
18612 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18613 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18614 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18615 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18616 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18617 * @param {Event} e The event
18618 * @param {Object} data An object containing arbitrary data supplied by the drag source
18619 * @return {Boolean} True if the drop was valid, else false
18621 onContainerDrop : function(dd, e, data){
18626 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18627 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18628 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18629 * you should override this method and provide a custom implementation.
18630 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18631 * @param {Event} e The event
18632 * @param {Object} data An object containing arbitrary data supplied by the drag source
18633 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18634 * underlying {@link Roo.dd.StatusProxy} can be updated
18636 notifyEnter : function(dd, e, data){
18637 return this.dropNotAllowed;
18641 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18642 * This method will be called on every mouse movement while the drag source is over the drop zone.
18643 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18644 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18645 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18646 * registered node, it will call {@link #onContainerOver}.
18647 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18648 * @param {Event} e The event
18649 * @param {Object} data An object containing arbitrary data supplied by the drag source
18650 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18651 * underlying {@link Roo.dd.StatusProxy} can be updated
18653 notifyOver : function(dd, e, data){
18654 var n = this.getTargetFromEvent(e);
18655 if(!n){ // not over valid drop target
18656 if(this.lastOverNode){
18657 this.onNodeOut(this.lastOverNode, dd, e, data);
18658 this.lastOverNode = null;
18660 return this.onContainerOver(dd, e, data);
18662 if(this.lastOverNode != n){
18663 if(this.lastOverNode){
18664 this.onNodeOut(this.lastOverNode, dd, e, data);
18666 this.onNodeEnter(n, dd, e, data);
18667 this.lastOverNode = n;
18669 return this.onNodeOver(n, dd, e, data);
18673 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18674 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18675 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18676 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18677 * @param {Event} e The event
18678 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18680 notifyOut : function(dd, e, data){
18681 if(this.lastOverNode){
18682 this.onNodeOut(this.lastOverNode, dd, e, data);
18683 this.lastOverNode = null;
18688 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18689 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18690 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18691 * otherwise it will call {@link #onContainerDrop}.
18692 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18693 * @param {Event} e The event
18694 * @param {Object} data An object containing arbitrary data supplied by the drag source
18695 * @return {Boolean} True if the drop was valid, else false
18697 notifyDrop : function(dd, e, data){
18698 if(this.lastOverNode){
18699 this.onNodeOut(this.lastOverNode, dd, e, data);
18700 this.lastOverNode = null;
18702 var n = this.getTargetFromEvent(e);
18704 this.onNodeDrop(n, dd, e, data) :
18705 this.onContainerDrop(dd, e, data);
18709 triggerCacheRefresh : function(){
18710 Roo.dd.DDM.refreshCache(this.groups);
18714 * Ext JS Library 1.1.1
18715 * Copyright(c) 2006-2007, Ext JS, LLC.
18717 * Originally Released Under LGPL - original licence link has changed is not relivant.
18720 * <script type="text/javascript">
18725 * @class Roo.data.SortTypes
18727 * Defines the default sorting (casting?) comparison functions used when sorting data.
18729 Roo.data.SortTypes = {
18731 * Default sort that does nothing
18732 * @param {Mixed} s The value being converted
18733 * @return {Mixed} The comparison value
18735 none : function(s){
18740 * The regular expression used to strip tags
18744 stripTagsRE : /<\/?[^>]+>/gi,
18747 * Strips all HTML tags to sort on text only
18748 * @param {Mixed} s The value being converted
18749 * @return {String} The comparison value
18751 asText : function(s){
18752 return String(s).replace(this.stripTagsRE, "");
18756 * Strips all HTML tags to sort on text only - Case insensitive
18757 * @param {Mixed} s The value being converted
18758 * @return {String} The comparison value
18760 asUCText : function(s){
18761 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18765 * Case insensitive string
18766 * @param {Mixed} s The value being converted
18767 * @return {String} The comparison value
18769 asUCString : function(s) {
18770 return String(s).toUpperCase();
18775 * @param {Mixed} s The value being converted
18776 * @return {Number} The comparison value
18778 asDate : function(s) {
18782 if(s instanceof Date){
18783 return s.getTime();
18785 return Date.parse(String(s));
18790 * @param {Mixed} s The value being converted
18791 * @return {Float} The comparison value
18793 asFloat : function(s) {
18794 var val = parseFloat(String(s).replace(/,/g, ""));
18795 if(isNaN(val)) val = 0;
18801 * @param {Mixed} s The value being converted
18802 * @return {Number} The comparison value
18804 asInt : function(s) {
18805 var val = parseInt(String(s).replace(/,/g, ""));
18806 if(isNaN(val)) val = 0;
18811 * Ext JS Library 1.1.1
18812 * Copyright(c) 2006-2007, Ext JS, LLC.
18814 * Originally Released Under LGPL - original licence link has changed is not relivant.
18817 * <script type="text/javascript">
18821 * @class Roo.data.Record
18822 * Instances of this class encapsulate both record <em>definition</em> information, and record
18823 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18824 * to access Records cached in an {@link Roo.data.Store} object.<br>
18826 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18827 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18830 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18832 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18833 * {@link #create}. The parameters are the same.
18834 * @param {Array} data An associative Array of data values keyed by the field name.
18835 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18836 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18837 * not specified an integer id is generated.
18839 Roo.data.Record = function(data, id){
18840 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18845 * Generate a constructor for a specific record layout.
18846 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18847 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18848 * Each field definition object may contain the following properties: <ul>
18849 * <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,
18850 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18851 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18852 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18853 * is being used, then this is a string containing the javascript expression to reference the data relative to
18854 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18855 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18856 * this may be omitted.</p></li>
18857 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18858 * <ul><li>auto (Default, implies no conversion)</li>
18863 * <li>date</li></ul></p></li>
18864 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18865 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18866 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18867 * by the Reader into an object that will be stored in the Record. It is passed the
18868 * following parameters:<ul>
18869 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18871 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18873 * <br>usage:<br><pre><code>
18874 var TopicRecord = Roo.data.Record.create(
18875 {name: 'title', mapping: 'topic_title'},
18876 {name: 'author', mapping: 'username'},
18877 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18878 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18879 {name: 'lastPoster', mapping: 'user2'},
18880 {name: 'excerpt', mapping: 'post_text'}
18883 var myNewRecord = new TopicRecord({
18884 title: 'Do my job please',
18887 lastPost: new Date(),
18888 lastPoster: 'Animal',
18889 excerpt: 'No way dude!'
18891 myStore.add(myNewRecord);
18896 Roo.data.Record.create = function(o){
18897 var f = function(){
18898 f.superclass.constructor.apply(this, arguments);
18900 Roo.extend(f, Roo.data.Record);
18901 var p = f.prototype;
18902 p.fields = new Roo.util.MixedCollection(false, function(field){
18905 for(var i = 0, len = o.length; i < len; i++){
18906 p.fields.add(new Roo.data.Field(o[i]));
18908 f.getField = function(name){
18909 return p.fields.get(name);
18914 Roo.data.Record.AUTO_ID = 1000;
18915 Roo.data.Record.EDIT = 'edit';
18916 Roo.data.Record.REJECT = 'reject';
18917 Roo.data.Record.COMMIT = 'commit';
18919 Roo.data.Record.prototype = {
18921 * Readonly flag - true if this record has been modified.
18930 join : function(store){
18931 this.store = store;
18935 * Set the named field to the specified value.
18936 * @param {String} name The name of the field to set.
18937 * @param {Object} value The value to set the field to.
18939 set : function(name, value){
18940 if(this.data[name] == value){
18944 if(!this.modified){
18945 this.modified = {};
18947 if(typeof this.modified[name] == 'undefined'){
18948 this.modified[name] = this.data[name];
18950 this.data[name] = value;
18952 this.store.afterEdit(this);
18957 * Get the value of the named field.
18958 * @param {String} name The name of the field to get the value of.
18959 * @return {Object} The value of the field.
18961 get : function(name){
18962 return this.data[name];
18966 beginEdit : function(){
18967 this.editing = true;
18968 this.modified = {};
18972 cancelEdit : function(){
18973 this.editing = false;
18974 delete this.modified;
18978 endEdit : function(){
18979 this.editing = false;
18980 if(this.dirty && this.store){
18981 this.store.afterEdit(this);
18986 * Usually called by the {@link Roo.data.Store} which owns the Record.
18987 * Rejects all changes made to the Record since either creation, or the last commit operation.
18988 * Modified fields are reverted to their original values.
18990 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18991 * of reject operations.
18993 reject : function(){
18994 var m = this.modified;
18996 if(typeof m[n] != "function"){
18997 this.data[n] = m[n];
19000 this.dirty = false;
19001 delete this.modified;
19002 this.editing = false;
19004 this.store.afterReject(this);
19009 * Usually called by the {@link Roo.data.Store} which owns the Record.
19010 * Commits all changes made to the Record since either creation, or the last commit operation.
19012 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19013 * of commit operations.
19015 commit : function(){
19016 this.dirty = false;
19017 delete this.modified;
19018 this.editing = false;
19020 this.store.afterCommit(this);
19025 hasError : function(){
19026 return this.error != null;
19030 clearError : function(){
19035 * Creates a copy of this record.
19036 * @param {String} id (optional) A new record id if you don't want to use this record's id
19039 copy : function(newId) {
19040 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19044 * Ext JS Library 1.1.1
19045 * Copyright(c) 2006-2007, Ext JS, LLC.
19047 * Originally Released Under LGPL - original licence link has changed is not relivant.
19050 * <script type="text/javascript">
19056 * @class Roo.data.Store
19057 * @extends Roo.util.Observable
19058 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19059 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19061 * 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
19062 * has no knowledge of the format of the data returned by the Proxy.<br>
19064 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19065 * instances from the data object. These records are cached and made available through accessor functions.
19067 * Creates a new Store.
19068 * @param {Object} config A config object containing the objects needed for the Store to access data,
19069 * and read the data into Records.
19071 Roo.data.Store = function(config){
19072 this.data = new Roo.util.MixedCollection(false);
19073 this.data.getKey = function(o){
19076 this.baseParams = {};
19078 this.paramNames = {
19085 if(config && config.data){
19086 this.inlineData = config.data;
19087 delete config.data;
19090 Roo.apply(this, config);
19092 if(this.reader){ // reader passed
19093 this.reader = Roo.factory(this.reader, Roo.data);
19094 this.reader.xmodule = this.xmodule || false;
19095 if(!this.recordType){
19096 this.recordType = this.reader.recordType;
19098 if(this.reader.onMetaChange){
19099 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19103 if(this.recordType){
19104 this.fields = this.recordType.prototype.fields;
19106 this.modified = [];
19110 * @event datachanged
19111 * Fires when the data cache has changed, and a widget which is using this Store
19112 * as a Record cache should refresh its view.
19113 * @param {Store} this
19115 datachanged : true,
19117 * @event metachange
19118 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19119 * @param {Store} this
19120 * @param {Object} meta The JSON metadata
19125 * Fires when Records have been added to the Store
19126 * @param {Store} this
19127 * @param {Roo.data.Record[]} records The array of Records added
19128 * @param {Number} index The index at which the record(s) were added
19133 * Fires when a Record has been removed from the Store
19134 * @param {Store} this
19135 * @param {Roo.data.Record} record The Record that was removed
19136 * @param {Number} index The index at which the record was removed
19141 * Fires when a Record has been updated
19142 * @param {Store} this
19143 * @param {Roo.data.Record} record The Record that was updated
19144 * @param {String} operation The update operation being performed. Value may be one of:
19146 Roo.data.Record.EDIT
19147 Roo.data.Record.REJECT
19148 Roo.data.Record.COMMIT
19154 * Fires when the data cache has been cleared.
19155 * @param {Store} this
19159 * @event beforeload
19160 * Fires before a request is made for a new data object. If the beforeload handler returns false
19161 * the load action will be canceled.
19162 * @param {Store} this
19163 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19168 * Fires after a new set of Records has been loaded.
19169 * @param {Store} this
19170 * @param {Roo.data.Record[]} records The Records that were loaded
19171 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19175 * @event loadexception
19176 * Fires if an exception occurs in the Proxy during loading.
19177 * Called with the signature of the Proxy's "loadexception" event.
19178 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19181 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19182 * @param {Object} load options
19183 * @param {Object} jsonData from your request (normally this contains the Exception)
19185 loadexception : true
19189 this.proxy = Roo.factory(this.proxy, Roo.data);
19190 this.proxy.xmodule = this.xmodule || false;
19191 this.relayEvents(this.proxy, ["loadexception"]);
19193 this.sortToggle = {};
19195 Roo.data.Store.superclass.constructor.call(this);
19197 if(this.inlineData){
19198 this.loadData(this.inlineData);
19199 delete this.inlineData;
19202 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19204 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19205 * without a remote query - used by combo/forms at present.
19209 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19212 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19215 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19216 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19219 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19220 * on any HTTP request
19223 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19226 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19227 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19229 remoteSort : false,
19232 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19233 * loaded or when a record is removed. (defaults to false).
19235 pruneModifiedRecords : false,
19238 lastOptions : null,
19241 * Add Records to the Store and fires the add event.
19242 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19244 add : function(records){
19245 records = [].concat(records);
19246 for(var i = 0, len = records.length; i < len; i++){
19247 records[i].join(this);
19249 var index = this.data.length;
19250 this.data.addAll(records);
19251 this.fireEvent("add", this, records, index);
19255 * Remove a Record from the Store and fires the remove event.
19256 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19258 remove : function(record){
19259 var index = this.data.indexOf(record);
19260 this.data.removeAt(index);
19261 if(this.pruneModifiedRecords){
19262 this.modified.remove(record);
19264 this.fireEvent("remove", this, record, index);
19268 * Remove all Records from the Store and fires the clear event.
19270 removeAll : function(){
19272 if(this.pruneModifiedRecords){
19273 this.modified = [];
19275 this.fireEvent("clear", this);
19279 * Inserts Records to the Store at the given index and fires the add event.
19280 * @param {Number} index The start index at which to insert the passed Records.
19281 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19283 insert : function(index, records){
19284 records = [].concat(records);
19285 for(var i = 0, len = records.length; i < len; i++){
19286 this.data.insert(index, records[i]);
19287 records[i].join(this);
19289 this.fireEvent("add", this, records, index);
19293 * Get the index within the cache of the passed Record.
19294 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19295 * @return {Number} The index of the passed Record. Returns -1 if not found.
19297 indexOf : function(record){
19298 return this.data.indexOf(record);
19302 * Get the index within the cache of the Record with the passed id.
19303 * @param {String} id The id of the Record to find.
19304 * @return {Number} The index of the Record. Returns -1 if not found.
19306 indexOfId : function(id){
19307 return this.data.indexOfKey(id);
19311 * Get the Record with the specified id.
19312 * @param {String} id The id of the Record to find.
19313 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19315 getById : function(id){
19316 return this.data.key(id);
19320 * Get the Record at the specified index.
19321 * @param {Number} index The index of the Record to find.
19322 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19324 getAt : function(index){
19325 return this.data.itemAt(index);
19329 * Returns a range of Records between specified indices.
19330 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19331 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19332 * @return {Roo.data.Record[]} An array of Records
19334 getRange : function(start, end){
19335 return this.data.getRange(start, end);
19339 storeOptions : function(o){
19340 o = Roo.apply({}, o);
19343 this.lastOptions = o;
19347 * Loads the Record cache from the configured Proxy using the configured Reader.
19349 * If using remote paging, then the first load call must specify the <em>start</em>
19350 * and <em>limit</em> properties in the options.params property to establish the initial
19351 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19353 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19354 * and this call will return before the new data has been loaded. Perform any post-processing
19355 * in a callback function, or in a "load" event handler.</strong>
19357 * @param {Object} options An object containing properties which control loading options:<ul>
19358 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19359 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19360 * passed the following arguments:<ul>
19361 * <li>r : Roo.data.Record[]</li>
19362 * <li>options: Options object from the load call</li>
19363 * <li>success: Boolean success indicator</li></ul></li>
19364 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19365 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19368 load : function(options){
19369 options = options || {};
19370 if(this.fireEvent("beforeload", this, options) !== false){
19371 this.storeOptions(options);
19372 var p = Roo.apply(options.params || {}, this.baseParams);
19373 // if meta was not loaded from remote source.. try requesting it.
19374 if (!this.reader.metaFromRemote) {
19375 p._requestMeta = 1;
19377 if(this.sortInfo && this.remoteSort){
19378 var pn = this.paramNames;
19379 p[pn["sort"]] = this.sortInfo.field;
19380 p[pn["dir"]] = this.sortInfo.direction;
19382 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19387 * Reloads the Record cache from the configured Proxy using the configured Reader and
19388 * the options from the last load operation performed.
19389 * @param {Object} options (optional) An object containing properties which may override the options
19390 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19391 * the most recently used options are reused).
19393 reload : function(options){
19394 this.load(Roo.applyIf(options||{}, this.lastOptions));
19398 // Called as a callback by the Reader during a load operation.
19399 loadRecords : function(o, options, success){
19400 if(!o || success === false){
19401 if(success !== false){
19402 this.fireEvent("load", this, [], options);
19404 if(options.callback){
19405 options.callback.call(options.scope || this, [], options, false);
19409 // if data returned failure - throw an exception.
19410 if (o.success === false) {
19411 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19414 var r = o.records, t = o.totalRecords || r.length;
19415 if(!options || options.add !== true){
19416 if(this.pruneModifiedRecords){
19417 this.modified = [];
19419 for(var i = 0, len = r.length; i < len; i++){
19423 this.data = this.snapshot;
19424 delete this.snapshot;
19427 this.data.addAll(r);
19428 this.totalLength = t;
19430 this.fireEvent("datachanged", this);
19432 this.totalLength = Math.max(t, this.data.length+r.length);
19435 this.fireEvent("load", this, r, options);
19436 if(options.callback){
19437 options.callback.call(options.scope || this, r, options, true);
19442 * Loads data from a passed data block. A Reader which understands the format of the data
19443 * must have been configured in the constructor.
19444 * @param {Object} data The data block from which to read the Records. The format of the data expected
19445 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19446 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19448 loadData : function(o, append){
19449 var r = this.reader.readRecords(o);
19450 this.loadRecords(r, {add: append}, true);
19454 * Gets the number of cached records.
19456 * <em>If using paging, this may not be the total size of the dataset. If the data object
19457 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19458 * the data set size</em>
19460 getCount : function(){
19461 return this.data.length || 0;
19465 * Gets the total number of records in the dataset as returned by the server.
19467 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19468 * the dataset size</em>
19470 getTotalCount : function(){
19471 return this.totalLength || 0;
19475 * Returns the sort state of the Store as an object with two properties:
19477 field {String} The name of the field by which the Records are sorted
19478 direction {String} The sort order, "ASC" or "DESC"
19481 getSortState : function(){
19482 return this.sortInfo;
19486 applySort : function(){
19487 if(this.sortInfo && !this.remoteSort){
19488 var s = this.sortInfo, f = s.field;
19489 var st = this.fields.get(f).sortType;
19490 var fn = function(r1, r2){
19491 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19492 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19494 this.data.sort(s.direction, fn);
19495 if(this.snapshot && this.snapshot != this.data){
19496 this.snapshot.sort(s.direction, fn);
19502 * Sets the default sort column and order to be used by the next load operation.
19503 * @param {String} fieldName The name of the field to sort by.
19504 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19506 setDefaultSort : function(field, dir){
19507 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19511 * Sort the Records.
19512 * If remote sorting is used, the sort is performed on the server, and the cache is
19513 * reloaded. If local sorting is used, the cache is sorted internally.
19514 * @param {String} fieldName The name of the field to sort by.
19515 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19517 sort : function(fieldName, dir){
19518 var f = this.fields.get(fieldName);
19520 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19521 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19526 this.sortToggle[f.name] = dir;
19527 this.sortInfo = {field: f.name, direction: dir};
19528 if(!this.remoteSort){
19530 this.fireEvent("datachanged", this);
19532 this.load(this.lastOptions);
19537 * Calls the specified function for each of the Records in the cache.
19538 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19539 * Returning <em>false</em> aborts and exits the iteration.
19540 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19542 each : function(fn, scope){
19543 this.data.each(fn, scope);
19547 * Gets all records modified since the last commit. Modified records are persisted across load operations
19548 * (e.g., during paging).
19549 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19551 getModifiedRecords : function(){
19552 return this.modified;
19556 createFilterFn : function(property, value, anyMatch){
19557 if(!value.exec){ // not a regex
19558 value = String(value);
19559 if(value.length == 0){
19562 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19564 return function(r){
19565 return value.test(r.data[property]);
19570 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19571 * @param {String} property A field on your records
19572 * @param {Number} start The record index to start at (defaults to 0)
19573 * @param {Number} end The last record index to include (defaults to length - 1)
19574 * @return {Number} The sum
19576 sum : function(property, start, end){
19577 var rs = this.data.items, v = 0;
19578 start = start || 0;
19579 end = (end || end === 0) ? end : rs.length-1;
19581 for(var i = start; i <= end; i++){
19582 v += (rs[i].data[property] || 0);
19588 * Filter the records by a specified property.
19589 * @param {String} field A field on your records
19590 * @param {String/RegExp} value Either a string that the field
19591 * should start with or a RegExp to test against the field
19592 * @param {Boolean} anyMatch True to match any part not just the beginning
19594 filter : function(property, value, anyMatch){
19595 var fn = this.createFilterFn(property, value, anyMatch);
19596 return fn ? this.filterBy(fn) : this.clearFilter();
19600 * Filter by a function. The specified function will be called with each
19601 * record in this data source. If the function returns true the record is included,
19602 * otherwise it is filtered.
19603 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19604 * @param {Object} scope (optional) The scope of the function (defaults to this)
19606 filterBy : function(fn, scope){
19607 this.snapshot = this.snapshot || this.data;
19608 this.data = this.queryBy(fn, scope||this);
19609 this.fireEvent("datachanged", this);
19613 * Query the records by a specified property.
19614 * @param {String} field A field on your records
19615 * @param {String/RegExp} value Either a string that the field
19616 * should start with or a RegExp to test against the field
19617 * @param {Boolean} anyMatch True to match any part not just the beginning
19618 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19620 query : function(property, value, anyMatch){
19621 var fn = this.createFilterFn(property, value, anyMatch);
19622 return fn ? this.queryBy(fn) : this.data.clone();
19626 * Query by a function. The specified function will be called with each
19627 * record in this data source. If the function returns true the record is included
19629 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19630 * @param {Object} scope (optional) The scope of the function (defaults to this)
19631 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19633 queryBy : function(fn, scope){
19634 var data = this.snapshot || this.data;
19635 return data.filterBy(fn, scope||this);
19639 * Collects unique values for a particular dataIndex from this store.
19640 * @param {String} dataIndex The property to collect
19641 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19642 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19643 * @return {Array} An array of the unique values
19645 collect : function(dataIndex, allowNull, bypassFilter){
19646 var d = (bypassFilter === true && this.snapshot) ?
19647 this.snapshot.items : this.data.items;
19648 var v, sv, r = [], l = {};
19649 for(var i = 0, len = d.length; i < len; i++){
19650 v = d[i].data[dataIndex];
19652 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19661 * Revert to a view of the Record cache with no filtering applied.
19662 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19664 clearFilter : function(suppressEvent){
19665 if(this.snapshot && this.snapshot != this.data){
19666 this.data = this.snapshot;
19667 delete this.snapshot;
19668 if(suppressEvent !== true){
19669 this.fireEvent("datachanged", this);
19675 afterEdit : function(record){
19676 if(this.modified.indexOf(record) == -1){
19677 this.modified.push(record);
19679 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19683 afterReject : function(record){
19684 this.modified.remove(record);
19685 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19689 afterCommit : function(record){
19690 this.modified.remove(record);
19691 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19695 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19696 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19698 commitChanges : function(){
19699 var m = this.modified.slice(0);
19700 this.modified = [];
19701 for(var i = 0, len = m.length; i < len; i++){
19707 * Cancel outstanding changes on all changed records.
19709 rejectChanges : function(){
19710 var m = this.modified.slice(0);
19711 this.modified = [];
19712 for(var i = 0, len = m.length; i < len; i++){
19717 onMetaChange : function(meta, rtype, o){
19718 this.recordType = rtype;
19719 this.fields = rtype.prototype.fields;
19720 delete this.snapshot;
19721 this.sortInfo = meta.sortInfo || this.sortInfo;
19722 this.modified = [];
19723 this.fireEvent('metachange', this, this.reader.meta);
19727 * Ext JS Library 1.1.1
19728 * Copyright(c) 2006-2007, Ext JS, LLC.
19730 * Originally Released Under LGPL - original licence link has changed is not relivant.
19733 * <script type="text/javascript">
19737 * @class Roo.data.SimpleStore
19738 * @extends Roo.data.Store
19739 * Small helper class to make creating Stores from Array data easier.
19740 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19741 * @cfg {Array} fields An array of field definition objects, or field name strings.
19742 * @cfg {Array} data The multi-dimensional array of data
19744 * @param {Object} config
19746 Roo.data.SimpleStore = function(config){
19747 Roo.data.SimpleStore.superclass.constructor.call(this, {
19749 reader: new Roo.data.ArrayReader({
19752 Roo.data.Record.create(config.fields)
19754 proxy : new Roo.data.MemoryProxy(config.data)
19758 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19760 * Ext JS Library 1.1.1
19761 * Copyright(c) 2006-2007, Ext JS, LLC.
19763 * Originally Released Under LGPL - original licence link has changed is not relivant.
19766 * <script type="text/javascript">
19771 * @extends Roo.data.Store
19772 * @class Roo.data.JsonStore
19773 * Small helper class to make creating Stores for JSON data easier. <br/>
19775 var store = new Roo.data.JsonStore({
19776 url: 'get-images.php',
19778 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19781 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19782 * JsonReader and HttpProxy (unless inline data is provided).</b>
19783 * @cfg {Array} fields An array of field definition objects, or field name strings.
19785 * @param {Object} config
19787 Roo.data.JsonStore = function(c){
19788 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19789 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19790 reader: new Roo.data.JsonReader(c, c.fields)
19793 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19795 * Ext JS Library 1.1.1
19796 * Copyright(c) 2006-2007, Ext JS, LLC.
19798 * Originally Released Under LGPL - original licence link has changed is not relivant.
19801 * <script type="text/javascript">
19805 Roo.data.Field = function(config){
19806 if(typeof config == "string"){
19807 config = {name: config};
19809 Roo.apply(this, config);
19812 this.type = "auto";
19815 var st = Roo.data.SortTypes;
19816 // named sortTypes are supported, here we look them up
19817 if(typeof this.sortType == "string"){
19818 this.sortType = st[this.sortType];
19821 // set default sortType for strings and dates
19822 if(!this.sortType){
19825 this.sortType = st.asUCString;
19828 this.sortType = st.asDate;
19831 this.sortType = st.none;
19836 var stripRe = /[\$,%]/g;
19838 // prebuilt conversion function for this field, instead of
19839 // switching every time we're reading a value
19841 var cv, dateFormat = this.dateFormat;
19846 cv = function(v){ return v; };
19849 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19853 return v !== undefined && v !== null && v !== '' ?
19854 parseInt(String(v).replace(stripRe, ""), 10) : '';
19859 return v !== undefined && v !== null && v !== '' ?
19860 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19865 cv = function(v){ return v === true || v === "true" || v == 1; };
19872 if(v instanceof Date){
19876 if(dateFormat == "timestamp"){
19877 return new Date(v*1000);
19879 return Date.parseDate(v, dateFormat);
19881 var parsed = Date.parse(v);
19882 return parsed ? new Date(parsed) : null;
19891 Roo.data.Field.prototype = {
19899 * Ext JS Library 1.1.1
19900 * Copyright(c) 2006-2007, Ext JS, LLC.
19902 * Originally Released Under LGPL - original licence link has changed is not relivant.
19905 * <script type="text/javascript">
19908 // Base class for reading structured data from a data source. This class is intended to be
19909 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19912 * @class Roo.data.DataReader
19913 * Base class for reading structured data from a data source. This class is intended to be
19914 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
19917 Roo.data.DataReader = function(meta, recordType){
19921 this.recordType = recordType instanceof Array ?
19922 Roo.data.Record.create(recordType) : recordType;
19925 Roo.data.DataReader.prototype = {
19927 * Create an empty record
19928 * @param {Object} data (optional) - overlay some values
19929 * @return {Roo.data.Record} record created.
19931 newRow : function(d) {
19933 this.recordType.prototype.fields.each(function(c) {
19935 case 'int' : da[c.name] = 0; break;
19936 case 'date' : da[c.name] = new Date(); break;
19937 case 'float' : da[c.name] = 0.0; break;
19938 case 'boolean' : da[c.name] = false; break;
19939 default : da[c.name] = ""; break;
19943 return new this.recordType(Roo.apply(da, d));
19948 * Ext JS Library 1.1.1
19949 * Copyright(c) 2006-2007, Ext JS, LLC.
19951 * Originally Released Under LGPL - original licence link has changed is not relivant.
19954 * <script type="text/javascript">
19958 * @class Roo.data.DataProxy
19959 * @extends Roo.data.Observable
19960 * This class is an abstract base class for implementations which provide retrieval of
19961 * unformatted data objects.<br>
19963 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
19964 * (of the appropriate type which knows how to parse the data object) to provide a block of
19965 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
19967 * Custom implementations must implement the load method as described in
19968 * {@link Roo.data.HttpProxy#load}.
19970 Roo.data.DataProxy = function(){
19973 * @event beforeload
19974 * Fires before a network request is made to retrieve a data object.
19975 * @param {Object} This DataProxy object.
19976 * @param {Object} params The params parameter to the load function.
19981 * Fires before the load method's callback is called.
19982 * @param {Object} This DataProxy object.
19983 * @param {Object} o The data object.
19984 * @param {Object} arg The callback argument object passed to the load function.
19988 * @event loadexception
19989 * Fires if an Exception occurs during data retrieval.
19990 * @param {Object} This DataProxy object.
19991 * @param {Object} o The data object.
19992 * @param {Object} arg The callback argument object passed to the load function.
19993 * @param {Object} e The Exception.
19995 loadexception : true
19997 Roo.data.DataProxy.superclass.constructor.call(this);
20000 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20003 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20007 * Ext JS Library 1.1.1
20008 * Copyright(c) 2006-2007, Ext JS, LLC.
20010 * Originally Released Under LGPL - original licence link has changed is not relivant.
20013 * <script type="text/javascript">
20016 * @class Roo.data.MemoryProxy
20017 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20018 * to the Reader when its load method is called.
20020 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20022 Roo.data.MemoryProxy = function(data){
20026 Roo.data.MemoryProxy.superclass.constructor.call(this);
20030 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20032 * Load data from the requested source (in this case an in-memory
20033 * data object passed to the constructor), read the data object into
20034 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20035 * process that block using the passed callback.
20036 * @param {Object} params This parameter is not used by the MemoryProxy class.
20037 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20038 * object into a block of Roo.data.Records.
20039 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20040 * The function must be passed <ul>
20041 * <li>The Record block object</li>
20042 * <li>The "arg" argument from the load function</li>
20043 * <li>A boolean success indicator</li>
20045 * @param {Object} scope The scope in which to call the callback
20046 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20048 load : function(params, reader, callback, scope, arg){
20049 params = params || {};
20052 result = reader.readRecords(this.data);
20054 this.fireEvent("loadexception", this, arg, null, e);
20055 callback.call(scope, null, arg, false);
20058 callback.call(scope, result, arg, true);
20062 update : function(params, records){
20067 * Ext JS Library 1.1.1
20068 * Copyright(c) 2006-2007, Ext JS, LLC.
20070 * Originally Released Under LGPL - original licence link has changed is not relivant.
20073 * <script type="text/javascript">
20076 * @class Roo.data.HttpProxy
20077 * @extends Roo.data.DataProxy
20078 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20079 * configured to reference a certain URL.<br><br>
20081 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20082 * from which the running page was served.<br><br>
20084 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20086 * Be aware that to enable the browser to parse an XML document, the server must set
20087 * the Content-Type header in the HTTP response to "text/xml".
20089 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20090 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20091 * will be used to make the request.
20093 Roo.data.HttpProxy = function(conn){
20094 Roo.data.HttpProxy.superclass.constructor.call(this);
20095 // is conn a conn config or a real conn?
20097 this.useAjax = !conn || !conn.events;
20101 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20102 // thse are take from connection...
20105 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20108 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20109 * extra parameters to each request made by this object. (defaults to undefined)
20112 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20113 * to each request made by this object. (defaults to undefined)
20116 * @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)
20119 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20122 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20128 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20132 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20133 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20134 * a finer-grained basis than the DataProxy events.
20136 getConnection : function(){
20137 return this.useAjax ? Roo.Ajax : this.conn;
20141 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20142 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20143 * process that block using the passed callback.
20144 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20145 * for the request to the remote server.
20146 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20147 * object into a block of Roo.data.Records.
20148 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20149 * The function must be passed <ul>
20150 * <li>The Record block object</li>
20151 * <li>The "arg" argument from the load function</li>
20152 * <li>A boolean success indicator</li>
20154 * @param {Object} scope The scope in which to call the callback
20155 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20157 load : function(params, reader, callback, scope, arg){
20158 if(this.fireEvent("beforeload", this, params) !== false){
20160 params : params || {},
20162 callback : callback,
20167 callback : this.loadResponse,
20171 Roo.applyIf(o, this.conn);
20172 if(this.activeRequest){
20173 Roo.Ajax.abort(this.activeRequest);
20175 this.activeRequest = Roo.Ajax.request(o);
20177 this.conn.request(o);
20180 callback.call(scope||this, null, arg, false);
20185 loadResponse : function(o, success, response){
20186 delete this.activeRequest;
20188 this.fireEvent("loadexception", this, o, response);
20189 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20194 result = o.reader.read(response);
20196 this.fireEvent("loadexception", this, o, response, e);
20197 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20201 this.fireEvent("load", this, o, o.request.arg);
20202 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20206 update : function(dataSet){
20211 updateResponse : function(dataSet){
20216 * Ext JS Library 1.1.1
20217 * Copyright(c) 2006-2007, Ext JS, LLC.
20219 * Originally Released Under LGPL - original licence link has changed is not relivant.
20222 * <script type="text/javascript">
20226 * @class Roo.data.ScriptTagProxy
20227 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20228 * other than the originating domain of the running page.<br><br>
20230 * <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
20231 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20233 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20234 * source code that is used as the source inside a <script> tag.<br><br>
20236 * In order for the browser to process the returned data, the server must wrap the data object
20237 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20238 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20239 * depending on whether the callback name was passed:
20242 boolean scriptTag = false;
20243 String cb = request.getParameter("callback");
20246 response.setContentType("text/javascript");
20248 response.setContentType("application/x-json");
20250 Writer out = response.getWriter();
20252 out.write(cb + "(");
20254 out.print(dataBlock.toJsonString());
20261 * @param {Object} config A configuration object.
20263 Roo.data.ScriptTagProxy = function(config){
20264 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20265 Roo.apply(this, config);
20266 this.head = document.getElementsByTagName("head")[0];
20269 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20271 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20273 * @cfg {String} url The URL from which to request the data object.
20276 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20280 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20281 * the server the name of the callback function set up by the load call to process the returned data object.
20282 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20283 * javascript output which calls this named function passing the data object as its only parameter.
20285 callbackParam : "callback",
20287 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20288 * name to the request.
20293 * Load data from the configured URL, read the data object into
20294 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20295 * process that block using the passed callback.
20296 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20297 * for the request to the remote server.
20298 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20299 * object into a block of Roo.data.Records.
20300 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20301 * The function must be passed <ul>
20302 * <li>The Record block object</li>
20303 * <li>The "arg" argument from the load function</li>
20304 * <li>A boolean success indicator</li>
20306 * @param {Object} scope The scope in which to call the callback
20307 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20309 load : function(params, reader, callback, scope, arg){
20310 if(this.fireEvent("beforeload", this, params) !== false){
20312 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20314 var url = this.url;
20315 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20317 url += "&_dc=" + (new Date().getTime());
20319 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20322 cb : "stcCallback"+transId,
20323 scriptId : "stcScript"+transId,
20327 callback : callback,
20333 window[trans.cb] = function(o){
20334 conn.handleResponse(o, trans);
20337 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20339 if(this.autoAbort !== false){
20343 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20345 var script = document.createElement("script");
20346 script.setAttribute("src", url);
20347 script.setAttribute("type", "text/javascript");
20348 script.setAttribute("id", trans.scriptId);
20349 this.head.appendChild(script);
20351 this.trans = trans;
20353 callback.call(scope||this, null, arg, false);
20358 isLoading : function(){
20359 return this.trans ? true : false;
20363 * Abort the current server request.
20365 abort : function(){
20366 if(this.isLoading()){
20367 this.destroyTrans(this.trans);
20372 destroyTrans : function(trans, isLoaded){
20373 this.head.removeChild(document.getElementById(trans.scriptId));
20374 clearTimeout(trans.timeoutId);
20376 window[trans.cb] = undefined;
20378 delete window[trans.cb];
20381 // if hasn't been loaded, wait for load to remove it to prevent script error
20382 window[trans.cb] = function(){
20383 window[trans.cb] = undefined;
20385 delete window[trans.cb];
20392 handleResponse : function(o, trans){
20393 this.trans = false;
20394 this.destroyTrans(trans, true);
20397 result = trans.reader.readRecords(o);
20399 this.fireEvent("loadexception", this, o, trans.arg, e);
20400 trans.callback.call(trans.scope||window, null, trans.arg, false);
20403 this.fireEvent("load", this, o, trans.arg);
20404 trans.callback.call(trans.scope||window, result, trans.arg, true);
20408 handleFailure : function(trans){
20409 this.trans = false;
20410 this.destroyTrans(trans, false);
20411 this.fireEvent("loadexception", this, null, trans.arg);
20412 trans.callback.call(trans.scope||window, null, trans.arg, false);
20416 * Ext JS Library 1.1.1
20417 * Copyright(c) 2006-2007, Ext JS, LLC.
20419 * Originally Released Under LGPL - original licence link has changed is not relivant.
20422 * <script type="text/javascript">
20426 * @class Roo.data.JsonReader
20427 * @extends Roo.data.DataReader
20428 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20429 * based on mappings in a provided Roo.data.Record constructor.
20431 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20432 * in the reply previously.
20437 var RecordDef = Roo.data.Record.create([
20438 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20439 {name: 'occupation'} // This field will use "occupation" as the mapping.
20441 var myReader = new Roo.data.JsonReader({
20442 totalProperty: "results", // The property which contains the total dataset size (optional)
20443 root: "rows", // The property which contains an Array of row objects
20444 id: "id" // The property within each row object that provides an ID for the record (optional)
20448 * This would consume a JSON file like this:
20450 { 'results': 2, 'rows': [
20451 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20452 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20455 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20456 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20457 * paged from the remote server.
20458 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20459 * @cfg {String} root name of the property which contains the Array of row objects.
20460 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20462 * Create a new JsonReader
20463 * @param {Object} meta Metadata configuration options
20464 * @param {Object} recordType Either an Array of field definition objects,
20465 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20467 Roo.data.JsonReader = function(meta, recordType){
20470 // set some defaults:
20471 Roo.applyIf(meta, {
20472 totalProperty: 'total',
20473 successProperty : 'success',
20478 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20480 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20483 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20484 * Used by Store query builder to append _requestMeta to params.
20487 metaFromRemote : false,
20489 * This method is only used by a DataProxy which has retrieved data from a remote server.
20490 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20491 * @return {Object} data A data block which is used by an Roo.data.Store object as
20492 * a cache of Roo.data.Records.
20494 read : function(response){
20495 var json = response.responseText;
20497 var o = /* eval:var:o */ eval("("+json+")");
20499 throw {message: "JsonReader.read: Json object not found"};
20505 this.metaFromRemote = true;
20506 this.meta = o.metaData;
20507 this.recordType = Roo.data.Record.create(o.metaData.fields);
20508 this.onMetaChange(this.meta, this.recordType, o);
20510 return this.readRecords(o);
20513 // private function a store will implement
20514 onMetaChange : function(meta, recordType, o){
20521 simpleAccess: function(obj, subsc) {
20528 getJsonAccessor: function(){
20530 return function(expr) {
20532 return(re.test(expr))
20533 ? new Function("obj", "return obj." + expr)
20538 return Roo.emptyFn;
20543 * Create a data block containing Roo.data.Records from an XML document.
20544 * @param {Object} o An object which contains an Array of row objects in the property specified
20545 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20546 * which contains the total size of the dataset.
20547 * @return {Object} data A data block which is used by an Roo.data.Store object as
20548 * a cache of Roo.data.Records.
20550 readRecords : function(o){
20552 * After any data loads, the raw JSON data is available for further custom processing.
20556 var s = this.meta, Record = this.recordType,
20557 f = Record.prototype.fields, fi = f.items, fl = f.length;
20559 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20561 if(s.totalProperty) {
20562 this.getTotal = this.getJsonAccessor(s.totalProperty);
20564 if(s.successProperty) {
20565 this.getSuccess = this.getJsonAccessor(s.successProperty);
20567 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20569 var g = this.getJsonAccessor(s.id);
20570 this.getId = function(rec) {
20572 return (r === undefined || r === "") ? null : r;
20575 this.getId = function(){return null;};
20578 for(var jj = 0; jj < fl; jj++){
20580 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20581 this.ef[jj] = this.getJsonAccessor(map);
20585 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20586 if(s.totalProperty){
20587 var vt = parseInt(this.getTotal(o), 10);
20592 if(s.successProperty){
20593 var vs = this.getSuccess(o);
20594 if(vs === false || vs === 'false'){
20599 for(var i = 0; i < c; i++){
20602 var id = this.getId(n);
20603 for(var j = 0; j < fl; j++){
20605 var v = this.ef[j](n);
20607 Roo.log('missing convert for ' + f.name);
20611 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20613 var record = new Record(values, id);
20615 records[i] = record;
20620 totalRecords : totalRecords
20625 * Ext JS Library 1.1.1
20626 * Copyright(c) 2006-2007, Ext JS, LLC.
20628 * Originally Released Under LGPL - original licence link has changed is not relivant.
20631 * <script type="text/javascript">
20635 * @class Roo.data.XmlReader
20636 * @extends Roo.data.DataReader
20637 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20638 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20640 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20641 * header in the HTTP response must be set to "text/xml".</em>
20645 var RecordDef = Roo.data.Record.create([
20646 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20647 {name: 'occupation'} // This field will use "occupation" as the mapping.
20649 var myReader = new Roo.data.XmlReader({
20650 totalRecords: "results", // The element which contains the total dataset size (optional)
20651 record: "row", // The repeated element which contains row information
20652 id: "id" // The element within the row that provides an ID for the record (optional)
20656 * This would consume an XML file like this:
20660 <results>2</results>
20663 <name>Bill</name>
20664 <occupation>Gardener</occupation>
20668 <name>Ben</name>
20669 <occupation>Horticulturalist</occupation>
20673 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20674 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20675 * paged from the remote server.
20676 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20677 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20678 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20679 * a record identifier value.
20681 * Create a new XmlReader
20682 * @param {Object} meta Metadata configuration options
20683 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20684 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20685 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20687 Roo.data.XmlReader = function(meta, recordType){
20689 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20691 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20693 * This method is only used by a DataProxy which has retrieved data from a remote server.
20694 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20695 * to contain a method called 'responseXML' that returns an XML document object.
20696 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20697 * a cache of Roo.data.Records.
20699 read : function(response){
20700 var doc = response.responseXML;
20702 throw {message: "XmlReader.read: XML Document not available"};
20704 return this.readRecords(doc);
20708 * Create a data block containing Roo.data.Records from an XML document.
20709 * @param {Object} doc A parsed XML document.
20710 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20711 * a cache of Roo.data.Records.
20713 readRecords : function(doc){
20715 * After any data loads/reads, the raw XML Document is available for further custom processing.
20716 * @type XMLDocument
20718 this.xmlData = doc;
20719 var root = doc.documentElement || doc;
20720 var q = Roo.DomQuery;
20721 var recordType = this.recordType, fields = recordType.prototype.fields;
20722 var sid = this.meta.id;
20723 var totalRecords = 0, success = true;
20724 if(this.meta.totalRecords){
20725 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20728 if(this.meta.success){
20729 var sv = q.selectValue(this.meta.success, root, true);
20730 success = sv !== false && sv !== 'false';
20733 var ns = q.select(this.meta.record, root);
20734 for(var i = 0, len = ns.length; i < len; i++) {
20737 var id = sid ? q.selectValue(sid, n) : undefined;
20738 for(var j = 0, jlen = fields.length; j < jlen; j++){
20739 var f = fields.items[j];
20740 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20742 values[f.name] = v;
20744 var record = new recordType(values, id);
20746 records[records.length] = record;
20752 totalRecords : totalRecords || records.length
20757 * Ext JS Library 1.1.1
20758 * Copyright(c) 2006-2007, Ext JS, LLC.
20760 * Originally Released Under LGPL - original licence link has changed is not relivant.
20763 * <script type="text/javascript">
20767 * @class Roo.data.ArrayReader
20768 * @extends Roo.data.DataReader
20769 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20770 * Each element of that Array represents a row of data fields. The
20771 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20772 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20776 var RecordDef = Roo.data.Record.create([
20777 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20778 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20780 var myReader = new Roo.data.ArrayReader({
20781 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20785 * This would consume an Array like this:
20787 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20789 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20791 * Create a new JsonReader
20792 * @param {Object} meta Metadata configuration options.
20793 * @param {Object} recordType Either an Array of field definition objects
20794 * as specified to {@link Roo.data.Record#create},
20795 * or an {@link Roo.data.Record} object
20796 * created using {@link Roo.data.Record#create}.
20798 Roo.data.ArrayReader = function(meta, recordType){
20799 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20802 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20804 * Create a data block containing Roo.data.Records from an XML document.
20805 * @param {Object} o An Array of row objects which represents the dataset.
20806 * @return {Object} data A data block which is used by an Roo.data.Store object as
20807 * a cache of Roo.data.Records.
20809 readRecords : function(o){
20810 var sid = this.meta ? this.meta.id : null;
20811 var recordType = this.recordType, fields = recordType.prototype.fields;
20814 for(var i = 0; i < root.length; i++){
20817 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20818 for(var j = 0, jlen = fields.length; j < jlen; j++){
20819 var f = fields.items[j];
20820 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20821 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20823 values[f.name] = v;
20825 var record = new recordType(values, id);
20827 records[records.length] = record;
20831 totalRecords : records.length
20836 * Ext JS Library 1.1.1
20837 * Copyright(c) 2006-2007, Ext JS, LLC.
20839 * Originally Released Under LGPL - original licence link has changed is not relivant.
20842 * <script type="text/javascript">
20847 * @class Roo.data.Tree
20848 * @extends Roo.util.Observable
20849 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20850 * in the tree have most standard DOM functionality.
20852 * @param {Node} root (optional) The root node
20854 Roo.data.Tree = function(root){
20855 this.nodeHash = {};
20857 * The root node for this tree
20862 this.setRootNode(root);
20867 * Fires when a new child node is appended to a node in this tree.
20868 * @param {Tree} tree The owner tree
20869 * @param {Node} parent The parent node
20870 * @param {Node} node The newly appended node
20871 * @param {Number} index The index of the newly appended node
20876 * Fires when a child node is removed from a node in this tree.
20877 * @param {Tree} tree The owner tree
20878 * @param {Node} parent The parent node
20879 * @param {Node} node The child node removed
20884 * Fires when a node is moved to a new location in the tree
20885 * @param {Tree} tree The owner tree
20886 * @param {Node} node The node moved
20887 * @param {Node} oldParent The old parent of this node
20888 * @param {Node} newParent The new parent of this node
20889 * @param {Number} index The index it was moved to
20894 * Fires when a new child node is inserted in a node in this tree.
20895 * @param {Tree} tree The owner tree
20896 * @param {Node} parent The parent node
20897 * @param {Node} node The child node inserted
20898 * @param {Node} refNode The child node the node was inserted before
20902 * @event beforeappend
20903 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20904 * @param {Tree} tree The owner tree
20905 * @param {Node} parent The parent node
20906 * @param {Node} node The child node to be appended
20908 "beforeappend" : true,
20910 * @event beforeremove
20911 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20912 * @param {Tree} tree The owner tree
20913 * @param {Node} parent The parent node
20914 * @param {Node} node The child node to be removed
20916 "beforeremove" : true,
20918 * @event beforemove
20919 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
20920 * @param {Tree} tree The owner tree
20921 * @param {Node} node The node being moved
20922 * @param {Node} oldParent The parent of the node
20923 * @param {Node} newParent The new parent the node is moving to
20924 * @param {Number} index The index it is being moved to
20926 "beforemove" : true,
20928 * @event beforeinsert
20929 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
20930 * @param {Tree} tree The owner tree
20931 * @param {Node} parent The parent node
20932 * @param {Node} node The child node to be inserted
20933 * @param {Node} refNode The child node the node is being inserted before
20935 "beforeinsert" : true
20938 Roo.data.Tree.superclass.constructor.call(this);
20941 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
20942 pathSeparator: "/",
20944 proxyNodeEvent : function(){
20945 return this.fireEvent.apply(this, arguments);
20949 * Returns the root node for this tree.
20952 getRootNode : function(){
20957 * Sets the root node for this tree.
20958 * @param {Node} node
20961 setRootNode : function(node){
20963 node.ownerTree = this;
20964 node.isRoot = true;
20965 this.registerNode(node);
20970 * Gets a node in this tree by its id.
20971 * @param {String} id
20974 getNodeById : function(id){
20975 return this.nodeHash[id];
20978 registerNode : function(node){
20979 this.nodeHash[node.id] = node;
20982 unregisterNode : function(node){
20983 delete this.nodeHash[node.id];
20986 toString : function(){
20987 return "[Tree"+(this.id?" "+this.id:"")+"]";
20992 * @class Roo.data.Node
20993 * @extends Roo.util.Observable
20994 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
20995 * @cfg {String} id The id for this node. If one is not specified, one is generated.
20997 * @param {Object} attributes The attributes/config for the node
20999 Roo.data.Node = function(attributes){
21001 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21004 this.attributes = attributes || {};
21005 this.leaf = this.attributes.leaf;
21007 * The node id. @type String
21009 this.id = this.attributes.id;
21011 this.id = Roo.id(null, "ynode-");
21012 this.attributes.id = this.id;
21015 * All child nodes of this node. @type Array
21017 this.childNodes = [];
21018 if(!this.childNodes.indexOf){ // indexOf is a must
21019 this.childNodes.indexOf = function(o){
21020 for(var i = 0, len = this.length; i < len; i++){
21029 * The parent node for this node. @type Node
21031 this.parentNode = null;
21033 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21035 this.firstChild = null;
21037 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21039 this.lastChild = null;
21041 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21043 this.previousSibling = null;
21045 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21047 this.nextSibling = null;
21052 * Fires when a new child node is appended
21053 * @param {Tree} tree The owner tree
21054 * @param {Node} this This node
21055 * @param {Node} node The newly appended node
21056 * @param {Number} index The index of the newly appended node
21061 * Fires when a child node is removed
21062 * @param {Tree} tree The owner tree
21063 * @param {Node} this This node
21064 * @param {Node} node The removed node
21069 * Fires when this node is moved to a new location in the tree
21070 * @param {Tree} tree The owner tree
21071 * @param {Node} this This node
21072 * @param {Node} oldParent The old parent of this node
21073 * @param {Node} newParent The new parent of this node
21074 * @param {Number} index The index it was moved to
21079 * Fires when a new child node is inserted.
21080 * @param {Tree} tree The owner tree
21081 * @param {Node} this This node
21082 * @param {Node} node The child node inserted
21083 * @param {Node} refNode The child node the node was inserted before
21087 * @event beforeappend
21088 * Fires before a new child is appended, return false to cancel the append.
21089 * @param {Tree} tree The owner tree
21090 * @param {Node} this This node
21091 * @param {Node} node The child node to be appended
21093 "beforeappend" : true,
21095 * @event beforeremove
21096 * Fires before a child is removed, return false to cancel the remove.
21097 * @param {Tree} tree The owner tree
21098 * @param {Node} this This node
21099 * @param {Node} node The child node to be removed
21101 "beforeremove" : true,
21103 * @event beforemove
21104 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21105 * @param {Tree} tree The owner tree
21106 * @param {Node} this This node
21107 * @param {Node} oldParent The parent of this node
21108 * @param {Node} newParent The new parent this node is moving to
21109 * @param {Number} index The index it is being moved to
21111 "beforemove" : true,
21113 * @event beforeinsert
21114 * Fires before a new child is inserted, return false to cancel the insert.
21115 * @param {Tree} tree The owner tree
21116 * @param {Node} this This node
21117 * @param {Node} node The child node to be inserted
21118 * @param {Node} refNode The child node the node is being inserted before
21120 "beforeinsert" : true
21122 this.listeners = this.attributes.listeners;
21123 Roo.data.Node.superclass.constructor.call(this);
21126 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21127 fireEvent : function(evtName){
21128 // first do standard event for this node
21129 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21132 // then bubble it up to the tree if the event wasn't cancelled
21133 var ot = this.getOwnerTree();
21135 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21143 * Returns true if this node is a leaf
21144 * @return {Boolean}
21146 isLeaf : function(){
21147 return this.leaf === true;
21151 setFirstChild : function(node){
21152 this.firstChild = node;
21156 setLastChild : function(node){
21157 this.lastChild = node;
21162 * Returns true if this node is the last child of its parent
21163 * @return {Boolean}
21165 isLast : function(){
21166 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21170 * Returns true if this node is the first child of its parent
21171 * @return {Boolean}
21173 isFirst : function(){
21174 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21177 hasChildNodes : function(){
21178 return !this.isLeaf() && this.childNodes.length > 0;
21182 * Insert node(s) as the last child node of this node.
21183 * @param {Node/Array} node The node or Array of nodes to append
21184 * @return {Node} The appended node if single append, or null if an array was passed
21186 appendChild : function(node){
21188 if(node instanceof Array){
21190 }else if(arguments.length > 1){
21193 // if passed an array or multiple args do them one by one
21195 for(var i = 0, len = multi.length; i < len; i++) {
21196 this.appendChild(multi[i]);
21199 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21202 var index = this.childNodes.length;
21203 var oldParent = node.parentNode;
21204 // it's a move, make sure we move it cleanly
21206 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21209 oldParent.removeChild(node);
21211 index = this.childNodes.length;
21213 this.setFirstChild(node);
21215 this.childNodes.push(node);
21216 node.parentNode = this;
21217 var ps = this.childNodes[index-1];
21219 node.previousSibling = ps;
21220 ps.nextSibling = node;
21222 node.previousSibling = null;
21224 node.nextSibling = null;
21225 this.setLastChild(node);
21226 node.setOwnerTree(this.getOwnerTree());
21227 this.fireEvent("append", this.ownerTree, this, node, index);
21229 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21236 * Removes a child node from this node.
21237 * @param {Node} node The node to remove
21238 * @return {Node} The removed node
21240 removeChild : function(node){
21241 var index = this.childNodes.indexOf(node);
21245 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21249 // remove it from childNodes collection
21250 this.childNodes.splice(index, 1);
21253 if(node.previousSibling){
21254 node.previousSibling.nextSibling = node.nextSibling;
21256 if(node.nextSibling){
21257 node.nextSibling.previousSibling = node.previousSibling;
21260 // update child refs
21261 if(this.firstChild == node){
21262 this.setFirstChild(node.nextSibling);
21264 if(this.lastChild == node){
21265 this.setLastChild(node.previousSibling);
21268 node.setOwnerTree(null);
21269 // clear any references from the node
21270 node.parentNode = null;
21271 node.previousSibling = null;
21272 node.nextSibling = null;
21273 this.fireEvent("remove", this.ownerTree, this, node);
21278 * Inserts the first node before the second node in this nodes childNodes collection.
21279 * @param {Node} node The node to insert
21280 * @param {Node} refNode The node to insert before (if null the node is appended)
21281 * @return {Node} The inserted node
21283 insertBefore : function(node, refNode){
21284 if(!refNode){ // like standard Dom, refNode can be null for append
21285 return this.appendChild(node);
21288 if(node == refNode){
21292 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21295 var index = this.childNodes.indexOf(refNode);
21296 var oldParent = node.parentNode;
21297 var refIndex = index;
21299 // when moving internally, indexes will change after remove
21300 if(oldParent == this && this.childNodes.indexOf(node) < index){
21304 // it's a move, make sure we move it cleanly
21306 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21309 oldParent.removeChild(node);
21312 this.setFirstChild(node);
21314 this.childNodes.splice(refIndex, 0, node);
21315 node.parentNode = this;
21316 var ps = this.childNodes[refIndex-1];
21318 node.previousSibling = ps;
21319 ps.nextSibling = node;
21321 node.previousSibling = null;
21323 node.nextSibling = refNode;
21324 refNode.previousSibling = node;
21325 node.setOwnerTree(this.getOwnerTree());
21326 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21328 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21334 * Returns the child node at the specified index.
21335 * @param {Number} index
21338 item : function(index){
21339 return this.childNodes[index];
21343 * Replaces one child node in this node with another.
21344 * @param {Node} newChild The replacement node
21345 * @param {Node} oldChild The node to replace
21346 * @return {Node} The replaced node
21348 replaceChild : function(newChild, oldChild){
21349 this.insertBefore(newChild, oldChild);
21350 this.removeChild(oldChild);
21355 * Returns the index of a child node
21356 * @param {Node} node
21357 * @return {Number} The index of the node or -1 if it was not found
21359 indexOf : function(child){
21360 return this.childNodes.indexOf(child);
21364 * Returns the tree this node is in.
21367 getOwnerTree : function(){
21368 // if it doesn't have one, look for one
21369 if(!this.ownerTree){
21373 this.ownerTree = p.ownerTree;
21379 return this.ownerTree;
21383 * Returns depth of this node (the root node has a depth of 0)
21386 getDepth : function(){
21389 while(p.parentNode){
21397 setOwnerTree : function(tree){
21398 // if it's move, we need to update everyone
21399 if(tree != this.ownerTree){
21400 if(this.ownerTree){
21401 this.ownerTree.unregisterNode(this);
21403 this.ownerTree = tree;
21404 var cs = this.childNodes;
21405 for(var i = 0, len = cs.length; i < len; i++) {
21406 cs[i].setOwnerTree(tree);
21409 tree.registerNode(this);
21415 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21416 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21417 * @return {String} The path
21419 getPath : function(attr){
21420 attr = attr || "id";
21421 var p = this.parentNode;
21422 var b = [this.attributes[attr]];
21424 b.unshift(p.attributes[attr]);
21427 var sep = this.getOwnerTree().pathSeparator;
21428 return sep + b.join(sep);
21432 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21433 * function call will be the scope provided or the current node. The arguments to the function
21434 * will be the args provided or the current node. If the function returns false at any point,
21435 * the bubble is stopped.
21436 * @param {Function} fn The function to call
21437 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21438 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21440 bubble : function(fn, scope, args){
21443 if(fn.call(scope || p, args || p) === false){
21451 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21452 * function call will be the scope provided or the current node. The arguments to the function
21453 * will be the args provided or the current node. If the function returns false at any point,
21454 * the cascade is stopped on that branch.
21455 * @param {Function} fn The function to call
21456 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21457 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21459 cascade : function(fn, scope, args){
21460 if(fn.call(scope || this, args || this) !== false){
21461 var cs = this.childNodes;
21462 for(var i = 0, len = cs.length; i < len; i++) {
21463 cs[i].cascade(fn, scope, args);
21469 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21470 * function call will be the scope provided or the current node. The arguments to the function
21471 * will be the args provided or the current node. If the function returns false at any point,
21472 * the iteration stops.
21473 * @param {Function} fn The function to call
21474 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21475 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21477 eachChild : function(fn, scope, args){
21478 var cs = this.childNodes;
21479 for(var i = 0, len = cs.length; i < len; i++) {
21480 if(fn.call(scope || this, args || cs[i]) === false){
21487 * Finds the first child that has the attribute with the specified value.
21488 * @param {String} attribute The attribute name
21489 * @param {Mixed} value The value to search for
21490 * @return {Node} The found child or null if none was found
21492 findChild : function(attribute, value){
21493 var cs = this.childNodes;
21494 for(var i = 0, len = cs.length; i < len; i++) {
21495 if(cs[i].attributes[attribute] == value){
21503 * Finds the first child by a custom function. The child matches if the function passed
21505 * @param {Function} fn
21506 * @param {Object} scope (optional)
21507 * @return {Node} The found child or null if none was found
21509 findChildBy : function(fn, scope){
21510 var cs = this.childNodes;
21511 for(var i = 0, len = cs.length; i < len; i++) {
21512 if(fn.call(scope||cs[i], cs[i]) === true){
21520 * Sorts this nodes children using the supplied sort function
21521 * @param {Function} fn
21522 * @param {Object} scope (optional)
21524 sort : function(fn, scope){
21525 var cs = this.childNodes;
21526 var len = cs.length;
21528 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21530 for(var i = 0; i < len; i++){
21532 n.previousSibling = cs[i-1];
21533 n.nextSibling = cs[i+1];
21535 this.setFirstChild(n);
21538 this.setLastChild(n);
21545 * Returns true if this node is an ancestor (at any point) of the passed node.
21546 * @param {Node} node
21547 * @return {Boolean}
21549 contains : function(node){
21550 return node.isAncestor(this);
21554 * Returns true if the passed node is an ancestor (at any point) of this node.
21555 * @param {Node} node
21556 * @return {Boolean}
21558 isAncestor : function(node){
21559 var p = this.parentNode;
21569 toString : function(){
21570 return "[Node"+(this.id?" "+this.id:"")+"]";
21574 * Ext JS Library 1.1.1
21575 * Copyright(c) 2006-2007, Ext JS, LLC.
21577 * Originally Released Under LGPL - original licence link has changed is not relivant.
21580 * <script type="text/javascript">
21585 * @class Roo.ComponentMgr
21586 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21589 Roo.ComponentMgr = function(){
21590 var all = new Roo.util.MixedCollection();
21594 * Registers a component.
21595 * @param {Roo.Component} c The component
21597 register : function(c){
21602 * Unregisters a component.
21603 * @param {Roo.Component} c The component
21605 unregister : function(c){
21610 * Returns a component by id
21611 * @param {String} id The component id
21613 get : function(id){
21614 return all.get(id);
21618 * Registers a function that will be called when a specified component is added to ComponentMgr
21619 * @param {String} id The component id
21620 * @param {Funtction} fn The callback function
21621 * @param {Object} scope The scope of the callback
21623 onAvailable : function(id, fn, scope){
21624 all.on("add", function(index, o){
21626 fn.call(scope || o, o);
21627 all.un("add", fn, scope);
21634 * Ext JS Library 1.1.1
21635 * Copyright(c) 2006-2007, Ext JS, LLC.
21637 * Originally Released Under LGPL - original licence link has changed is not relivant.
21640 * <script type="text/javascript">
21644 * @class Roo.Component
21645 * @extends Roo.util.Observable
21646 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21647 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21648 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21649 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21650 * All visual components (widgets) that require rendering into a layout should subclass Component.
21652 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21653 * 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
21654 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21656 Roo.Component = function(config){
21657 config = config || {};
21658 if(config.tagName || config.dom || typeof config == "string"){ // element object
21659 config = {el: config, id: config.id || config};
21661 this.initialConfig = config;
21663 Roo.apply(this, config);
21667 * Fires after the component is disabled.
21668 * @param {Roo.Component} this
21673 * Fires after the component is enabled.
21674 * @param {Roo.Component} this
21678 * @event beforeshow
21679 * Fires before the component is shown. Return false to stop the show.
21680 * @param {Roo.Component} this
21685 * Fires after the component is shown.
21686 * @param {Roo.Component} this
21690 * @event beforehide
21691 * Fires before the component is hidden. Return false to stop the hide.
21692 * @param {Roo.Component} this
21697 * Fires after the component is hidden.
21698 * @param {Roo.Component} this
21702 * @event beforerender
21703 * Fires before the component is rendered. Return false to stop the render.
21704 * @param {Roo.Component} this
21706 beforerender : true,
21709 * Fires after the component is rendered.
21710 * @param {Roo.Component} this
21714 * @event beforedestroy
21715 * Fires before the component is destroyed. Return false to stop the destroy.
21716 * @param {Roo.Component} this
21718 beforedestroy : true,
21721 * Fires after the component is destroyed.
21722 * @param {Roo.Component} this
21727 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21729 Roo.ComponentMgr.register(this);
21730 Roo.Component.superclass.constructor.call(this);
21731 this.initComponent();
21732 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21733 this.render(this.renderTo);
21734 delete this.renderTo;
21739 Roo.Component.AUTO_ID = 1000;
21741 Roo.extend(Roo.Component, Roo.util.Observable, {
21743 * @property {Boolean} hidden
21744 * true if this component is hidden. Read-only.
21748 * true if this component is disabled. Read-only.
21752 * true if this component has been rendered. Read-only.
21756 /** @cfg {String} disableClass
21757 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21759 disabledClass : "x-item-disabled",
21760 /** @cfg {Boolean} allowDomMove
21761 * Whether the component can move the Dom node when rendering (defaults to true).
21763 allowDomMove : true,
21764 /** @cfg {String} hideMode
21765 * How this component should hidden. Supported values are
21766 * "visibility" (css visibility), "offsets" (negative offset position) and
21767 * "display" (css display) - defaults to "display".
21769 hideMode: 'display',
21772 ctype : "Roo.Component",
21774 /** @cfg {String} actionMode
21775 * which property holds the element that used for hide() / show() / disable() / enable()
21781 getActionEl : function(){
21782 return this[this.actionMode];
21785 initComponent : Roo.emptyFn,
21787 * If this is a lazy rendering component, render it to its container element.
21788 * @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.
21790 render : function(container, position){
21791 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21792 if(!container && this.el){
21793 this.el = Roo.get(this.el);
21794 container = this.el.dom.parentNode;
21795 this.allowDomMove = false;
21797 this.container = Roo.get(container);
21798 this.rendered = true;
21799 if(position !== undefined){
21800 if(typeof position == 'number'){
21801 position = this.container.dom.childNodes[position];
21803 position = Roo.getDom(position);
21806 this.onRender(this.container, position || null);
21808 this.el.addClass(this.cls);
21812 this.el.applyStyles(this.style);
21815 this.fireEvent("render", this);
21816 this.afterRender(this.container);
21828 // default function is not really useful
21829 onRender : function(ct, position){
21831 this.el = Roo.get(this.el);
21832 if(this.allowDomMove !== false){
21833 ct.dom.insertBefore(this.el.dom, position);
21839 getAutoCreate : function(){
21840 var cfg = typeof this.autoCreate == "object" ?
21841 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21842 if(this.id && !cfg.id){
21849 afterRender : Roo.emptyFn,
21852 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21853 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21855 destroy : function(){
21856 if(this.fireEvent("beforedestroy", this) !== false){
21857 this.purgeListeners();
21858 this.beforeDestroy();
21860 this.el.removeAllListeners();
21862 if(this.actionMode == "container"){
21863 this.container.remove();
21867 Roo.ComponentMgr.unregister(this);
21868 this.fireEvent("destroy", this);
21873 beforeDestroy : function(){
21878 onDestroy : function(){
21883 * Returns the underlying {@link Roo.Element}.
21884 * @return {Roo.Element} The element
21886 getEl : function(){
21891 * Returns the id of this component.
21894 getId : function(){
21899 * Try to focus this component.
21900 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21901 * @return {Roo.Component} this
21903 focus : function(selectText){
21906 if(selectText === true){
21907 this.el.dom.select();
21922 * Disable this component.
21923 * @return {Roo.Component} this
21925 disable : function(){
21929 this.disabled = true;
21930 this.fireEvent("disable", this);
21935 onDisable : function(){
21936 this.getActionEl().addClass(this.disabledClass);
21937 this.el.dom.disabled = true;
21941 * Enable this component.
21942 * @return {Roo.Component} this
21944 enable : function(){
21948 this.disabled = false;
21949 this.fireEvent("enable", this);
21954 onEnable : function(){
21955 this.getActionEl().removeClass(this.disabledClass);
21956 this.el.dom.disabled = false;
21960 * Convenience function for setting disabled/enabled by boolean.
21961 * @param {Boolean} disabled
21963 setDisabled : function(disabled){
21964 this[disabled ? "disable" : "enable"]();
21968 * Show this component.
21969 * @return {Roo.Component} this
21972 if(this.fireEvent("beforeshow", this) !== false){
21973 this.hidden = false;
21977 this.fireEvent("show", this);
21983 onShow : function(){
21984 var ae = this.getActionEl();
21985 if(this.hideMode == 'visibility'){
21986 ae.dom.style.visibility = "visible";
21987 }else if(this.hideMode == 'offsets'){
21988 ae.removeClass('x-hidden');
21990 ae.dom.style.display = "";
21995 * Hide this component.
21996 * @return {Roo.Component} this
21999 if(this.fireEvent("beforehide", this) !== false){
22000 this.hidden = true;
22004 this.fireEvent("hide", this);
22010 onHide : function(){
22011 var ae = this.getActionEl();
22012 if(this.hideMode == 'visibility'){
22013 ae.dom.style.visibility = "hidden";
22014 }else if(this.hideMode == 'offsets'){
22015 ae.addClass('x-hidden');
22017 ae.dom.style.display = "none";
22022 * Convenience function to hide or show this component by boolean.
22023 * @param {Boolean} visible True to show, false to hide
22024 * @return {Roo.Component} this
22026 setVisible: function(visible){
22036 * Returns true if this component is visible.
22038 isVisible : function(){
22039 return this.getActionEl().isVisible();
22042 cloneConfig : function(overrides){
22043 overrides = overrides || {};
22044 var id = overrides.id || Roo.id();
22045 var cfg = Roo.applyIf(overrides, this.initialConfig);
22046 cfg.id = id; // prevent dup id
22047 return new this.constructor(cfg);
22051 * Ext JS Library 1.1.1
22052 * Copyright(c) 2006-2007, Ext JS, LLC.
22054 * Originally Released Under LGPL - original licence link has changed is not relivant.
22057 * <script type="text/javascript">
22062 * @extends Roo.Element
22063 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22064 * automatic maintaining of shadow/shim positions.
22065 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22066 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22067 * you can pass a string with a CSS class name. False turns off the shadow.
22068 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22069 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22070 * @cfg {String} cls CSS class to add to the element
22071 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22072 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22074 * @param {Object} config An object with config options.
22075 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22078 Roo.Layer = function(config, existingEl){
22079 config = config || {};
22080 var dh = Roo.DomHelper;
22081 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22083 this.dom = Roo.getDom(existingEl);
22086 var o = config.dh || {tag: "div", cls: "x-layer"};
22087 this.dom = dh.append(pel, o);
22090 this.addClass(config.cls);
22092 this.constrain = config.constrain !== false;
22093 this.visibilityMode = Roo.Element.VISIBILITY;
22095 this.id = this.dom.id = config.id;
22097 this.id = Roo.id(this.dom);
22099 this.zindex = config.zindex || this.getZIndex();
22100 this.position("absolute", this.zindex);
22102 this.shadowOffset = config.shadowOffset || 4;
22103 this.shadow = new Roo.Shadow({
22104 offset : this.shadowOffset,
22105 mode : config.shadow
22108 this.shadowOffset = 0;
22110 this.useShim = config.shim !== false && Roo.useShims;
22111 this.useDisplay = config.useDisplay;
22115 var supr = Roo.Element.prototype;
22117 // shims are shared among layer to keep from having 100 iframes
22120 Roo.extend(Roo.Layer, Roo.Element, {
22122 getZIndex : function(){
22123 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22126 getShim : function(){
22133 var shim = shims.shift();
22135 shim = this.createShim();
22136 shim.enableDisplayMode('block');
22137 shim.dom.style.display = 'none';
22138 shim.dom.style.visibility = 'visible';
22140 var pn = this.dom.parentNode;
22141 if(shim.dom.parentNode != pn){
22142 pn.insertBefore(shim.dom, this.dom);
22144 shim.setStyle('z-index', this.getZIndex()-2);
22149 hideShim : function(){
22151 this.shim.setDisplayed(false);
22152 shims.push(this.shim);
22157 disableShadow : function(){
22159 this.shadowDisabled = true;
22160 this.shadow.hide();
22161 this.lastShadowOffset = this.shadowOffset;
22162 this.shadowOffset = 0;
22166 enableShadow : function(show){
22168 this.shadowDisabled = false;
22169 this.shadowOffset = this.lastShadowOffset;
22170 delete this.lastShadowOffset;
22178 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22179 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22180 sync : function(doShow){
22181 var sw = this.shadow;
22182 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22183 var sh = this.getShim();
22185 var w = this.getWidth(),
22186 h = this.getHeight();
22188 var l = this.getLeft(true),
22189 t = this.getTop(true);
22191 if(sw && !this.shadowDisabled){
22192 if(doShow && !sw.isVisible()){
22195 sw.realign(l, t, w, h);
22201 // fit the shim behind the shadow, so it is shimmed too
22202 var a = sw.adjusts, s = sh.dom.style;
22203 s.left = (Math.min(l, l+a.l))+"px";
22204 s.top = (Math.min(t, t+a.t))+"px";
22205 s.width = (w+a.w)+"px";
22206 s.height = (h+a.h)+"px";
22213 sh.setLeftTop(l, t);
22220 destroy : function(){
22223 this.shadow.hide();
22225 this.removeAllListeners();
22226 var pn = this.dom.parentNode;
22228 pn.removeChild(this.dom);
22230 Roo.Element.uncache(this.id);
22233 remove : function(){
22238 beginUpdate : function(){
22239 this.updating = true;
22243 endUpdate : function(){
22244 this.updating = false;
22249 hideUnders : function(negOffset){
22251 this.shadow.hide();
22257 constrainXY : function(){
22258 if(this.constrain){
22259 var vw = Roo.lib.Dom.getViewWidth(),
22260 vh = Roo.lib.Dom.getViewHeight();
22261 var s = Roo.get(document).getScroll();
22263 var xy = this.getXY();
22264 var x = xy[0], y = xy[1];
22265 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22266 // only move it if it needs it
22268 // first validate right/bottom
22269 if((x + w) > vw+s.left){
22270 x = vw - w - this.shadowOffset;
22273 if((y + h) > vh+s.top){
22274 y = vh - h - this.shadowOffset;
22277 // then make sure top/left isn't negative
22288 var ay = this.avoidY;
22289 if(y <= ay && (y+h) >= ay){
22295 supr.setXY.call(this, xy);
22301 isVisible : function(){
22302 return this.visible;
22306 showAction : function(){
22307 this.visible = true; // track visibility to prevent getStyle calls
22308 if(this.useDisplay === true){
22309 this.setDisplayed("");
22310 }else if(this.lastXY){
22311 supr.setXY.call(this, this.lastXY);
22312 }else if(this.lastLT){
22313 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22318 hideAction : function(){
22319 this.visible = false;
22320 if(this.useDisplay === true){
22321 this.setDisplayed(false);
22323 this.setLeftTop(-10000,-10000);
22327 // overridden Element method
22328 setVisible : function(v, a, d, c, e){
22333 var cb = function(){
22338 }.createDelegate(this);
22339 supr.setVisible.call(this, true, true, d, cb, e);
22342 this.hideUnders(true);
22351 }.createDelegate(this);
22353 supr.setVisible.call(this, v, a, d, cb, e);
22362 storeXY : function(xy){
22363 delete this.lastLT;
22367 storeLeftTop : function(left, top){
22368 delete this.lastXY;
22369 this.lastLT = [left, top];
22373 beforeFx : function(){
22374 this.beforeAction();
22375 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22379 afterFx : function(){
22380 Roo.Layer.superclass.afterFx.apply(this, arguments);
22381 this.sync(this.isVisible());
22385 beforeAction : function(){
22386 if(!this.updating && this.shadow){
22387 this.shadow.hide();
22391 // overridden Element method
22392 setLeft : function(left){
22393 this.storeLeftTop(left, this.getTop(true));
22394 supr.setLeft.apply(this, arguments);
22398 setTop : function(top){
22399 this.storeLeftTop(this.getLeft(true), top);
22400 supr.setTop.apply(this, arguments);
22404 setLeftTop : function(left, top){
22405 this.storeLeftTop(left, top);
22406 supr.setLeftTop.apply(this, arguments);
22410 setXY : function(xy, a, d, c, e){
22412 this.beforeAction();
22414 var cb = this.createCB(c);
22415 supr.setXY.call(this, xy, a, d, cb, e);
22422 createCB : function(c){
22433 // overridden Element method
22434 setX : function(x, a, d, c, e){
22435 this.setXY([x, this.getY()], a, d, c, e);
22438 // overridden Element method
22439 setY : function(y, a, d, c, e){
22440 this.setXY([this.getX(), y], a, d, c, e);
22443 // overridden Element method
22444 setSize : function(w, h, a, d, c, e){
22445 this.beforeAction();
22446 var cb = this.createCB(c);
22447 supr.setSize.call(this, w, h, a, d, cb, e);
22453 // overridden Element method
22454 setWidth : function(w, a, d, c, e){
22455 this.beforeAction();
22456 var cb = this.createCB(c);
22457 supr.setWidth.call(this, w, a, d, cb, e);
22463 // overridden Element method
22464 setHeight : function(h, a, d, c, e){
22465 this.beforeAction();
22466 var cb = this.createCB(c);
22467 supr.setHeight.call(this, h, a, d, cb, e);
22473 // overridden Element method
22474 setBounds : function(x, y, w, h, a, d, c, e){
22475 this.beforeAction();
22476 var cb = this.createCB(c);
22478 this.storeXY([x, y]);
22479 supr.setXY.call(this, [x, y]);
22480 supr.setSize.call(this, w, h, a, d, cb, e);
22483 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22489 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22490 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22491 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22492 * @param {Number} zindex The new z-index to set
22493 * @return {this} The Layer
22495 setZIndex : function(zindex){
22496 this.zindex = zindex;
22497 this.setStyle("z-index", zindex + 2);
22499 this.shadow.setZIndex(zindex + 1);
22502 this.shim.setStyle("z-index", zindex);
22508 * Ext JS Library 1.1.1
22509 * Copyright(c) 2006-2007, Ext JS, LLC.
22511 * Originally Released Under LGPL - original licence link has changed is not relivant.
22514 * <script type="text/javascript">
22519 * @class Roo.Shadow
22520 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22521 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22522 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22524 * Create a new Shadow
22525 * @param {Object} config The config object
22527 Roo.Shadow = function(config){
22528 Roo.apply(this, config);
22529 if(typeof this.mode != "string"){
22530 this.mode = this.defaultMode;
22532 var o = this.offset, a = {h: 0};
22533 var rad = Math.floor(this.offset/2);
22534 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22540 a.l -= this.offset + rad;
22541 a.t -= this.offset + rad;
22552 a.l -= (this.offset - rad);
22553 a.t -= this.offset + rad;
22555 a.w -= (this.offset - rad)*2;
22566 a.l -= (this.offset - rad);
22567 a.t -= (this.offset - rad);
22569 a.w -= (this.offset + rad + 1);
22570 a.h -= (this.offset + rad);
22579 Roo.Shadow.prototype = {
22581 * @cfg {String} mode
22582 * The shadow display mode. Supports the following options:<br />
22583 * sides: Shadow displays on both sides and bottom only<br />
22584 * frame: Shadow displays equally on all four sides<br />
22585 * drop: Traditional bottom-right drop shadow (default)
22588 * @cfg {String} offset
22589 * The number of pixels to offset the shadow from the element (defaults to 4)
22594 defaultMode: "drop",
22597 * Displays the shadow under the target element
22598 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22600 show : function(target){
22601 target = Roo.get(target);
22603 this.el = Roo.Shadow.Pool.pull();
22604 if(this.el.dom.nextSibling != target.dom){
22605 this.el.insertBefore(target);
22608 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22610 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22613 target.getLeft(true),
22614 target.getTop(true),
22618 this.el.dom.style.display = "block";
22622 * Returns true if the shadow is visible, else false
22624 isVisible : function(){
22625 return this.el ? true : false;
22629 * Direct alignment when values are already available. Show must be called at least once before
22630 * calling this method to ensure it is initialized.
22631 * @param {Number} left The target element left position
22632 * @param {Number} top The target element top position
22633 * @param {Number} width The target element width
22634 * @param {Number} height The target element height
22636 realign : function(l, t, w, h){
22640 var a = this.adjusts, d = this.el.dom, s = d.style;
22642 s.left = (l+a.l)+"px";
22643 s.top = (t+a.t)+"px";
22644 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22646 if(s.width != sws || s.height != shs){
22650 var cn = d.childNodes;
22651 var sww = Math.max(0, (sw-12))+"px";
22652 cn[0].childNodes[1].style.width = sww;
22653 cn[1].childNodes[1].style.width = sww;
22654 cn[2].childNodes[1].style.width = sww;
22655 cn[1].style.height = Math.max(0, (sh-12))+"px";
22661 * Hides this shadow
22665 this.el.dom.style.display = "none";
22666 Roo.Shadow.Pool.push(this.el);
22672 * Adjust the z-index of this shadow
22673 * @param {Number} zindex The new z-index
22675 setZIndex : function(z){
22678 this.el.setStyle("z-index", z);
22683 // Private utility class that manages the internal Shadow cache
22684 Roo.Shadow.Pool = function(){
22686 var markup = Roo.isIE ?
22687 '<div class="x-ie-shadow"></div>' :
22688 '<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>';
22691 var sh = p.shift();
22693 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22694 sh.autoBoxAdjust = false;
22699 push : function(sh){
22705 * Ext JS Library 1.1.1
22706 * Copyright(c) 2006-2007, Ext JS, LLC.
22708 * Originally Released Under LGPL - original licence link has changed is not relivant.
22711 * <script type="text/javascript">
22715 * @class Roo.BoxComponent
22716 * @extends Roo.Component
22717 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22718 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22719 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22720 * layout containers.
22722 * @param {Roo.Element/String/Object} config The configuration options.
22724 Roo.BoxComponent = function(config){
22725 Roo.Component.call(this, config);
22729 * Fires after the component is resized.
22730 * @param {Roo.Component} this
22731 * @param {Number} adjWidth The box-adjusted width that was set
22732 * @param {Number} adjHeight The box-adjusted height that was set
22733 * @param {Number} rawWidth The width that was originally specified
22734 * @param {Number} rawHeight The height that was originally specified
22739 * Fires after the component is moved.
22740 * @param {Roo.Component} this
22741 * @param {Number} x The new x position
22742 * @param {Number} y The new y position
22748 Roo.extend(Roo.BoxComponent, Roo.Component, {
22749 // private, set in afterRender to signify that the component has been rendered
22751 // private, used to defer height settings to subclasses
22752 deferHeight: false,
22753 /** @cfg {Number} width
22754 * width (optional) size of component
22756 /** @cfg {Number} height
22757 * height (optional) size of component
22761 * Sets the width and height of the component. This method fires the resize event. This method can accept
22762 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22763 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22764 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22765 * @return {Roo.BoxComponent} this
22767 setSize : function(w, h){
22768 // support for standard size objects
22769 if(typeof w == 'object'){
22774 if(!this.boxReady){
22780 // prevent recalcs when not needed
22781 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22784 this.lastSize = {width: w, height: h};
22786 var adj = this.adjustSize(w, h);
22787 var aw = adj.width, ah = adj.height;
22788 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22789 var rz = this.getResizeEl();
22790 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22791 rz.setSize(aw, ah);
22792 }else if(!this.deferHeight && ah !== undefined){
22794 }else if(aw !== undefined){
22797 this.onResize(aw, ah, w, h);
22798 this.fireEvent('resize', this, aw, ah, w, h);
22804 * Gets the current size of the component's underlying element.
22805 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22807 getSize : function(){
22808 return this.el.getSize();
22812 * Gets the current XY position of the component's underlying element.
22813 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22814 * @return {Array} The XY position of the element (e.g., [100, 200])
22816 getPosition : function(local){
22817 if(local === true){
22818 return [this.el.getLeft(true), this.el.getTop(true)];
22820 return this.xy || this.el.getXY();
22824 * Gets the current box measurements of the component's underlying element.
22825 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22826 * @returns {Object} box An object in the format {x, y, width, height}
22828 getBox : function(local){
22829 var s = this.el.getSize();
22831 s.x = this.el.getLeft(true);
22832 s.y = this.el.getTop(true);
22834 var xy = this.xy || this.el.getXY();
22842 * Sets the current box measurements of the component's underlying element.
22843 * @param {Object} box An object in the format {x, y, width, height}
22844 * @returns {Roo.BoxComponent} this
22846 updateBox : function(box){
22847 this.setSize(box.width, box.height);
22848 this.setPagePosition(box.x, box.y);
22853 getResizeEl : function(){
22854 return this.resizeEl || this.el;
22858 getPositionEl : function(){
22859 return this.positionEl || this.el;
22863 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22864 * This method fires the move event.
22865 * @param {Number} left The new left
22866 * @param {Number} top The new top
22867 * @returns {Roo.BoxComponent} this
22869 setPosition : function(x, y){
22872 if(!this.boxReady){
22875 var adj = this.adjustPosition(x, y);
22876 var ax = adj.x, ay = adj.y;
22878 var el = this.getPositionEl();
22879 if(ax !== undefined || ay !== undefined){
22880 if(ax !== undefined && ay !== undefined){
22881 el.setLeftTop(ax, ay);
22882 }else if(ax !== undefined){
22884 }else if(ay !== undefined){
22887 this.onPosition(ax, ay);
22888 this.fireEvent('move', this, ax, ay);
22894 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22895 * This method fires the move event.
22896 * @param {Number} x The new x position
22897 * @param {Number} y The new y position
22898 * @returns {Roo.BoxComponent} this
22900 setPagePosition : function(x, y){
22903 if(!this.boxReady){
22906 if(x === undefined || y === undefined){ // cannot translate undefined points
22909 var p = this.el.translatePoints(x, y);
22910 this.setPosition(p.left, p.top);
22915 onRender : function(ct, position){
22916 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
22918 this.resizeEl = Roo.get(this.resizeEl);
22920 if(this.positionEl){
22921 this.positionEl = Roo.get(this.positionEl);
22926 afterRender : function(){
22927 Roo.BoxComponent.superclass.afterRender.call(this);
22928 this.boxReady = true;
22929 this.setSize(this.width, this.height);
22930 if(this.x || this.y){
22931 this.setPosition(this.x, this.y);
22933 if(this.pageX || this.pageY){
22934 this.setPagePosition(this.pageX, this.pageY);
22939 * Force the component's size to recalculate based on the underlying element's current height and width.
22940 * @returns {Roo.BoxComponent} this
22942 syncSize : function(){
22943 delete this.lastSize;
22944 this.setSize(this.el.getWidth(), this.el.getHeight());
22949 * Called after the component is resized, this method is empty by default but can be implemented by any
22950 * subclass that needs to perform custom logic after a resize occurs.
22951 * @param {Number} adjWidth The box-adjusted width that was set
22952 * @param {Number} adjHeight The box-adjusted height that was set
22953 * @param {Number} rawWidth The width that was originally specified
22954 * @param {Number} rawHeight The height that was originally specified
22956 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
22961 * Called after the component is moved, this method is empty by default but can be implemented by any
22962 * subclass that needs to perform custom logic after a move occurs.
22963 * @param {Number} x The new x position
22964 * @param {Number} y The new y position
22966 onPosition : function(x, y){
22971 adjustSize : function(w, h){
22972 if(this.autoWidth){
22975 if(this.autoHeight){
22978 return {width : w, height: h};
22982 adjustPosition : function(x, y){
22983 return {x : x, y: y};
22987 * Ext JS Library 1.1.1
22988 * Copyright(c) 2006-2007, Ext JS, LLC.
22990 * Originally Released Under LGPL - original licence link has changed is not relivant.
22993 * <script type="text/javascript">
22998 * @class Roo.SplitBar
22999 * @extends Roo.util.Observable
23000 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23004 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23005 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23006 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23007 split.minSize = 100;
23008 split.maxSize = 600;
23009 split.animate = true;
23010 split.on('moved', splitterMoved);
23013 * Create a new SplitBar
23014 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23015 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23016 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23017 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23018 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23019 position of the SplitBar).
23021 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23024 this.el = Roo.get(dragElement, true);
23025 this.el.dom.unselectable = "on";
23027 this.resizingEl = Roo.get(resizingElement, true);
23031 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23032 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23035 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23038 * The minimum size of the resizing element. (Defaults to 0)
23044 * The maximum size of the resizing element. (Defaults to 2000)
23047 this.maxSize = 2000;
23050 * Whether to animate the transition to the new size
23053 this.animate = false;
23056 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23059 this.useShim = false;
23064 if(!existingProxy){
23066 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23068 this.proxy = Roo.get(existingProxy).dom;
23071 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23074 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23077 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23080 this.dragSpecs = {};
23083 * @private The adapter to use to positon and resize elements
23085 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23086 this.adapter.init(this);
23088 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23090 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23091 this.el.addClass("x-splitbar-h");
23094 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23095 this.el.addClass("x-splitbar-v");
23101 * Fires when the splitter is moved (alias for {@link #event-moved})
23102 * @param {Roo.SplitBar} this
23103 * @param {Number} newSize the new width or height
23108 * Fires when the splitter is moved
23109 * @param {Roo.SplitBar} this
23110 * @param {Number} newSize the new width or height
23114 * @event beforeresize
23115 * Fires before the splitter is dragged
23116 * @param {Roo.SplitBar} this
23118 "beforeresize" : true,
23120 "beforeapply" : true
23123 Roo.util.Observable.call(this);
23126 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23127 onStartProxyDrag : function(x, y){
23128 this.fireEvent("beforeresize", this);
23130 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23132 o.enableDisplayMode("block");
23133 // all splitbars share the same overlay
23134 Roo.SplitBar.prototype.overlay = o;
23136 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23137 this.overlay.show();
23138 Roo.get(this.proxy).setDisplayed("block");
23139 var size = this.adapter.getElementSize(this);
23140 this.activeMinSize = this.getMinimumSize();;
23141 this.activeMaxSize = this.getMaximumSize();;
23142 var c1 = size - this.activeMinSize;
23143 var c2 = Math.max(this.activeMaxSize - size, 0);
23144 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23145 this.dd.resetConstraints();
23146 this.dd.setXConstraint(
23147 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23148 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23150 this.dd.setYConstraint(0, 0);
23152 this.dd.resetConstraints();
23153 this.dd.setXConstraint(0, 0);
23154 this.dd.setYConstraint(
23155 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23156 this.placement == Roo.SplitBar.TOP ? c2 : c1
23159 this.dragSpecs.startSize = size;
23160 this.dragSpecs.startPoint = [x, y];
23161 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23165 * @private Called after the drag operation by the DDProxy
23167 onEndProxyDrag : function(e){
23168 Roo.get(this.proxy).setDisplayed(false);
23169 var endPoint = Roo.lib.Event.getXY(e);
23171 this.overlay.hide();
23174 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23175 newSize = this.dragSpecs.startSize +
23176 (this.placement == Roo.SplitBar.LEFT ?
23177 endPoint[0] - this.dragSpecs.startPoint[0] :
23178 this.dragSpecs.startPoint[0] - endPoint[0]
23181 newSize = this.dragSpecs.startSize +
23182 (this.placement == Roo.SplitBar.TOP ?
23183 endPoint[1] - this.dragSpecs.startPoint[1] :
23184 this.dragSpecs.startPoint[1] - endPoint[1]
23187 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23188 if(newSize != this.dragSpecs.startSize){
23189 if(this.fireEvent('beforeapply', this, newSize) !== false){
23190 this.adapter.setElementSize(this, newSize);
23191 this.fireEvent("moved", this, newSize);
23192 this.fireEvent("resize", this, newSize);
23198 * Get the adapter this SplitBar uses
23199 * @return The adapter object
23201 getAdapter : function(){
23202 return this.adapter;
23206 * Set the adapter this SplitBar uses
23207 * @param {Object} adapter A SplitBar adapter object
23209 setAdapter : function(adapter){
23210 this.adapter = adapter;
23211 this.adapter.init(this);
23215 * Gets the minimum size for the resizing element
23216 * @return {Number} The minimum size
23218 getMinimumSize : function(){
23219 return this.minSize;
23223 * Sets the minimum size for the resizing element
23224 * @param {Number} minSize The minimum size
23226 setMinimumSize : function(minSize){
23227 this.minSize = minSize;
23231 * Gets the maximum size for the resizing element
23232 * @return {Number} The maximum size
23234 getMaximumSize : function(){
23235 return this.maxSize;
23239 * Sets the maximum size for the resizing element
23240 * @param {Number} maxSize The maximum size
23242 setMaximumSize : function(maxSize){
23243 this.maxSize = maxSize;
23247 * Sets the initialize size for the resizing element
23248 * @param {Number} size The initial size
23250 setCurrentSize : function(size){
23251 var oldAnimate = this.animate;
23252 this.animate = false;
23253 this.adapter.setElementSize(this, size);
23254 this.animate = oldAnimate;
23258 * Destroy this splitbar.
23259 * @param {Boolean} removeEl True to remove the element
23261 destroy : function(removeEl){
23263 this.shim.remove();
23266 this.proxy.parentNode.removeChild(this.proxy);
23274 * @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.
23276 Roo.SplitBar.createProxy = function(dir){
23277 var proxy = new Roo.Element(document.createElement("div"));
23278 proxy.unselectable();
23279 var cls = 'x-splitbar-proxy';
23280 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23281 document.body.appendChild(proxy.dom);
23286 * @class Roo.SplitBar.BasicLayoutAdapter
23287 * Default Adapter. It assumes the splitter and resizing element are not positioned
23288 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23290 Roo.SplitBar.BasicLayoutAdapter = function(){
23293 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23294 // do nothing for now
23295 init : function(s){
23299 * Called before drag operations to get the current size of the resizing element.
23300 * @param {Roo.SplitBar} s The SplitBar using this adapter
23302 getElementSize : function(s){
23303 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23304 return s.resizingEl.getWidth();
23306 return s.resizingEl.getHeight();
23311 * Called after drag operations to set the size of the resizing element.
23312 * @param {Roo.SplitBar} s The SplitBar using this adapter
23313 * @param {Number} newSize The new size to set
23314 * @param {Function} onComplete A function to be invoked when resizing is complete
23316 setElementSize : function(s, newSize, onComplete){
23317 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23319 s.resizingEl.setWidth(newSize);
23321 onComplete(s, newSize);
23324 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23329 s.resizingEl.setHeight(newSize);
23331 onComplete(s, newSize);
23334 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23341 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23342 * @extends Roo.SplitBar.BasicLayoutAdapter
23343 * Adapter that moves the splitter element to align with the resized sizing element.
23344 * Used with an absolute positioned SplitBar.
23345 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23346 * document.body, make sure you assign an id to the body element.
23348 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23349 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23350 this.container = Roo.get(container);
23353 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23354 init : function(s){
23355 this.basic.init(s);
23358 getElementSize : function(s){
23359 return this.basic.getElementSize(s);
23362 setElementSize : function(s, newSize, onComplete){
23363 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23366 moveSplitter : function(s){
23367 var yes = Roo.SplitBar;
23368 switch(s.placement){
23370 s.el.setX(s.resizingEl.getRight());
23373 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23376 s.el.setY(s.resizingEl.getBottom());
23379 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23386 * Orientation constant - Create a vertical SplitBar
23390 Roo.SplitBar.VERTICAL = 1;
23393 * Orientation constant - Create a horizontal SplitBar
23397 Roo.SplitBar.HORIZONTAL = 2;
23400 * Placement constant - The resizing element is to the left of the splitter element
23404 Roo.SplitBar.LEFT = 1;
23407 * Placement constant - The resizing element is to the right of the splitter element
23411 Roo.SplitBar.RIGHT = 2;
23414 * Placement constant - The resizing element is positioned above the splitter element
23418 Roo.SplitBar.TOP = 3;
23421 * Placement constant - The resizing element is positioned under splitter element
23425 Roo.SplitBar.BOTTOM = 4;
23428 * Ext JS Library 1.1.1
23429 * Copyright(c) 2006-2007, Ext JS, LLC.
23431 * Originally Released Under LGPL - original licence link has changed is not relivant.
23434 * <script type="text/javascript">
23439 * @extends Roo.util.Observable
23440 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23441 * This class also supports single and multi selection modes. <br>
23442 * Create a data model bound view:
23444 var store = new Roo.data.Store(...);
23446 var view = new Roo.View({
23448 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23450 singleSelect: true,
23451 selectedClass: "ydataview-selected",
23455 // listen for node click?
23456 view.on("click", function(vw, index, node, e){
23457 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23461 dataModel.load("foobar.xml");
23463 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23465 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23466 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23468 * Note: old style constructor is still suported (container, template, config)
23471 * Create a new View
23472 * @param {Object} config The config object
23475 Roo.View = function(config, depreciated_tpl, depreciated_config){
23477 if (typeof(depreciated_tpl) == 'undefined') {
23478 // new way.. - universal constructor.
23479 Roo.apply(this, config);
23480 this.el = Roo.get(this.el);
23483 this.el = Roo.get(config);
23484 this.tpl = depreciated_tpl;
23485 Roo.apply(this, depreciated_config);
23489 if(typeof(this.tpl) == "string"){
23490 this.tpl = new Roo.Template(this.tpl);
23492 // support xtype ctors..
23493 this.tpl = new Roo.factory(this.tpl, Roo);
23497 this.tpl.compile();
23504 * @event beforeclick
23505 * Fires before a click is processed. Returns false to cancel the default action.
23506 * @param {Roo.View} this
23507 * @param {Number} index The index of the target node
23508 * @param {HTMLElement} node The target node
23509 * @param {Roo.EventObject} e The raw event object
23511 "beforeclick" : true,
23514 * Fires when a template node is clicked.
23515 * @param {Roo.View} this
23516 * @param {Number} index The index of the target node
23517 * @param {HTMLElement} node The target node
23518 * @param {Roo.EventObject} e The raw event object
23523 * Fires when a template node is double clicked.
23524 * @param {Roo.View} this
23525 * @param {Number} index The index of the target node
23526 * @param {HTMLElement} node The target node
23527 * @param {Roo.EventObject} e The raw event object
23531 * @event contextmenu
23532 * Fires when a template node is right clicked.
23533 * @param {Roo.View} this
23534 * @param {Number} index The index of the target node
23535 * @param {HTMLElement} node The target node
23536 * @param {Roo.EventObject} e The raw event object
23538 "contextmenu" : true,
23540 * @event selectionchange
23541 * Fires when the selected nodes change.
23542 * @param {Roo.View} this
23543 * @param {Array} selections Array of the selected nodes
23545 "selectionchange" : true,
23548 * @event beforeselect
23549 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23550 * @param {Roo.View} this
23551 * @param {HTMLElement} node The node to be selected
23552 * @param {Array} selections Array of currently selected nodes
23554 "beforeselect" : true
23558 "click": this.onClick,
23559 "dblclick": this.onDblClick,
23560 "contextmenu": this.onContextMenu,
23564 this.selections = [];
23566 this.cmp = new Roo.CompositeElementLite([]);
23568 this.store = Roo.factory(this.store, Roo.data);
23569 this.setStore(this.store, true);
23571 Roo.View.superclass.constructor.call(this);
23574 Roo.extend(Roo.View, Roo.util.Observable, {
23577 * @cfg {Roo.data.Store} store Data store to load data from.
23582 * @cfg {String|Roo.Element} el The container element.
23587 * @cfg {String|Roo.Template} tpl The template used by this View
23592 * @cfg {String} selectedClass The css class to add to selected nodes
23594 selectedClass : "x-view-selected",
23596 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23600 * @cfg {Boolean} multiSelect Allow multiple selection
23603 multiSelect : false,
23605 * @cfg {Boolean} singleSelect Allow single selection
23607 singleSelect: false,
23610 * Returns the element this view is bound to.
23611 * @return {Roo.Element}
23613 getEl : function(){
23618 * Refreshes the view.
23620 refresh : function(){
23622 this.clearSelections();
23623 this.el.update("");
23625 var records = this.store.getRange();
23626 if(records.length < 1){
23627 this.el.update(this.emptyText);
23630 for(var i = 0, len = records.length; i < len; i++){
23631 var data = this.prepareData(records[i].data, i, records[i]);
23632 html[html.length] = t.apply(data);
23634 this.el.update(html.join(""));
23635 this.nodes = this.el.dom.childNodes;
23636 this.updateIndexes(0);
23640 * Function to override to reformat the data that is sent to
23641 * the template for each node.
23642 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23643 * a JSON object for an UpdateManager bound view).
23645 prepareData : function(data){
23649 onUpdate : function(ds, record){
23650 this.clearSelections();
23651 var index = this.store.indexOf(record);
23652 var n = this.nodes[index];
23653 this.tpl.insertBefore(n, this.prepareData(record.data));
23654 n.parentNode.removeChild(n);
23655 this.updateIndexes(index, index);
23658 onAdd : function(ds, records, index){
23659 this.clearSelections();
23660 if(this.nodes.length == 0){
23664 var n = this.nodes[index];
23665 for(var i = 0, len = records.length; i < len; i++){
23666 var d = this.prepareData(records[i].data);
23668 this.tpl.insertBefore(n, d);
23670 this.tpl.append(this.el, d);
23673 this.updateIndexes(index);
23676 onRemove : function(ds, record, index){
23677 this.clearSelections();
23678 this.el.dom.removeChild(this.nodes[index]);
23679 this.updateIndexes(index);
23683 * Refresh an individual node.
23684 * @param {Number} index
23686 refreshNode : function(index){
23687 this.onUpdate(this.store, this.store.getAt(index));
23690 updateIndexes : function(startIndex, endIndex){
23691 var ns = this.nodes;
23692 startIndex = startIndex || 0;
23693 endIndex = endIndex || ns.length - 1;
23694 for(var i = startIndex; i <= endIndex; i++){
23695 ns[i].nodeIndex = i;
23700 * Changes the data store this view uses and refresh the view.
23701 * @param {Store} store
23703 setStore : function(store, initial){
23704 if(!initial && this.store){
23705 this.store.un("datachanged", this.refresh);
23706 this.store.un("add", this.onAdd);
23707 this.store.un("remove", this.onRemove);
23708 this.store.un("update", this.onUpdate);
23709 this.store.un("clear", this.refresh);
23713 store.on("datachanged", this.refresh, this);
23714 store.on("add", this.onAdd, this);
23715 store.on("remove", this.onRemove, this);
23716 store.on("update", this.onUpdate, this);
23717 store.on("clear", this.refresh, this);
23726 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23727 * @param {HTMLElement} node
23728 * @return {HTMLElement} The template node
23730 findItemFromChild : function(node){
23731 var el = this.el.dom;
23732 if(!node || node.parentNode == el){
23735 var p = node.parentNode;
23736 while(p && p != el){
23737 if(p.parentNode == el){
23746 onClick : function(e){
23747 var item = this.findItemFromChild(e.getTarget());
23749 var index = this.indexOf(item);
23750 if(this.onItemClick(item, index, e) !== false){
23751 this.fireEvent("click", this, index, item, e);
23754 this.clearSelections();
23759 onContextMenu : function(e){
23760 var item = this.findItemFromChild(e.getTarget());
23762 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23767 onDblClick : function(e){
23768 var item = this.findItemFromChild(e.getTarget());
23770 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23774 onItemClick : function(item, index, e){
23775 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23778 if(this.multiSelect || this.singleSelect){
23779 if(this.multiSelect && e.shiftKey && this.lastSelection){
23780 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23782 this.select(item, this.multiSelect && e.ctrlKey);
23783 this.lastSelection = item;
23785 e.preventDefault();
23791 * Get the number of selected nodes.
23794 getSelectionCount : function(){
23795 return this.selections.length;
23799 * Get the currently selected nodes.
23800 * @return {Array} An array of HTMLElements
23802 getSelectedNodes : function(){
23803 return this.selections;
23807 * Get the indexes of the selected nodes.
23810 getSelectedIndexes : function(){
23811 var indexes = [], s = this.selections;
23812 for(var i = 0, len = s.length; i < len; i++){
23813 indexes.push(s[i].nodeIndex);
23819 * Clear all selections
23820 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23822 clearSelections : function(suppressEvent){
23823 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23824 this.cmp.elements = this.selections;
23825 this.cmp.removeClass(this.selectedClass);
23826 this.selections = [];
23827 if(!suppressEvent){
23828 this.fireEvent("selectionchange", this, this.selections);
23834 * Returns true if the passed node is selected
23835 * @param {HTMLElement/Number} node The node or node index
23836 * @return {Boolean}
23838 isSelected : function(node){
23839 var s = this.selections;
23843 node = this.getNode(node);
23844 return s.indexOf(node) !== -1;
23849 * @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
23850 * @param {Boolean} keepExisting (optional) true to keep existing selections
23851 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23853 select : function(nodeInfo, keepExisting, suppressEvent){
23854 if(nodeInfo instanceof Array){
23856 this.clearSelections(true);
23858 for(var i = 0, len = nodeInfo.length; i < len; i++){
23859 this.select(nodeInfo[i], true, true);
23862 var node = this.getNode(nodeInfo);
23863 if(node && !this.isSelected(node)){
23865 this.clearSelections(true);
23867 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23868 Roo.fly(node).addClass(this.selectedClass);
23869 this.selections.push(node);
23870 if(!suppressEvent){
23871 this.fireEvent("selectionchange", this, this.selections);
23879 * Gets a template node.
23880 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23881 * @return {HTMLElement} The node or null if it wasn't found
23883 getNode : function(nodeInfo){
23884 if(typeof nodeInfo == "string"){
23885 return document.getElementById(nodeInfo);
23886 }else if(typeof nodeInfo == "number"){
23887 return this.nodes[nodeInfo];
23893 * Gets a range template nodes.
23894 * @param {Number} startIndex
23895 * @param {Number} endIndex
23896 * @return {Array} An array of nodes
23898 getNodes : function(start, end){
23899 var ns = this.nodes;
23900 start = start || 0;
23901 end = typeof end == "undefined" ? ns.length - 1 : end;
23904 for(var i = start; i <= end; i++){
23908 for(var i = start; i >= end; i--){
23916 * Finds the index of the passed node
23917 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23918 * @return {Number} The index of the node or -1
23920 indexOf : function(node){
23921 node = this.getNode(node);
23922 if(typeof node.nodeIndex == "number"){
23923 return node.nodeIndex;
23925 var ns = this.nodes;
23926 for(var i = 0, len = ns.length; i < len; i++){
23936 * Ext JS Library 1.1.1
23937 * Copyright(c) 2006-2007, Ext JS, LLC.
23939 * Originally Released Under LGPL - original licence link has changed is not relivant.
23942 * <script type="text/javascript">
23946 * @class Roo.JsonView
23947 * @extends Roo.View
23948 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
23950 var view = new Roo.JsonView({
23951 container: "my-element",
23952 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
23957 // listen for node click?
23958 view.on("click", function(vw, index, node, e){
23959 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23962 // direct load of JSON data
23963 view.load("foobar.php");
23965 // Example from my blog list
23966 var tpl = new Roo.Template(
23967 '<div class="entry">' +
23968 '<a class="entry-title" href="{link}">{title}</a>' +
23969 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
23970 "</div><hr />"
23973 var moreView = new Roo.JsonView({
23974 container : "entry-list",
23978 moreView.on("beforerender", this.sortEntries, this);
23980 url: "/blog/get-posts.php",
23981 params: "allposts=true",
23982 text: "Loading Blog Entries..."
23986 * Note: old code is supported with arguments : (container, template, config)
23990 * Create a new JsonView
23992 * @param {Object} config The config object
23995 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
23998 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24000 var um = this.el.getUpdateManager();
24001 um.setRenderer(this);
24002 um.on("update", this.onLoad, this);
24003 um.on("failure", this.onLoadException, this);
24006 * @event beforerender
24007 * Fires before rendering of the downloaded JSON data.
24008 * @param {Roo.JsonView} this
24009 * @param {Object} data The JSON data loaded
24013 * Fires when data is loaded.
24014 * @param {Roo.JsonView} this
24015 * @param {Object} data The JSON data loaded
24016 * @param {Object} response The raw Connect response object
24019 * @event loadexception
24020 * Fires when loading fails.
24021 * @param {Roo.JsonView} this
24022 * @param {Object} response The raw Connect response object
24025 'beforerender' : true,
24027 'loadexception' : true
24030 Roo.extend(Roo.JsonView, Roo.View, {
24032 * @type {String} The root property in the loaded JSON object that contains the data
24037 * Refreshes the view.
24039 refresh : function(){
24040 this.clearSelections();
24041 this.el.update("");
24043 var o = this.jsonData;
24044 if(o && o.length > 0){
24045 for(var i = 0, len = o.length; i < len; i++){
24046 var data = this.prepareData(o[i], i, o);
24047 html[html.length] = this.tpl.apply(data);
24050 html.push(this.emptyText);
24052 this.el.update(html.join(""));
24053 this.nodes = this.el.dom.childNodes;
24054 this.updateIndexes(0);
24058 * 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.
24059 * @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:
24062 url: "your-url.php",
24063 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24064 callback: yourFunction,
24065 scope: yourObject, //(optional scope)
24068 text: "Loading...",
24073 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24074 * 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.
24075 * @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}
24076 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24077 * @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.
24080 var um = this.el.getUpdateManager();
24081 um.update.apply(um, arguments);
24084 render : function(el, response){
24085 this.clearSelections();
24086 this.el.update("");
24089 o = Roo.util.JSON.decode(response.responseText);
24092 o = o[this.jsonRoot];
24097 * The current JSON data or null
24100 this.beforeRender();
24105 * Get the number of records in the current JSON dataset
24108 getCount : function(){
24109 return this.jsonData ? this.jsonData.length : 0;
24113 * Returns the JSON object for the specified node(s)
24114 * @param {HTMLElement/Array} node The node or an array of nodes
24115 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24116 * you get the JSON object for the node
24118 getNodeData : function(node){
24119 if(node instanceof Array){
24121 for(var i = 0, len = node.length; i < len; i++){
24122 data.push(this.getNodeData(node[i]));
24126 return this.jsonData[this.indexOf(node)] || null;
24129 beforeRender : function(){
24130 this.snapshot = this.jsonData;
24132 this.sort.apply(this, this.sortInfo);
24134 this.fireEvent("beforerender", this, this.jsonData);
24137 onLoad : function(el, o){
24138 this.fireEvent("load", this, this.jsonData, o);
24141 onLoadException : function(el, o){
24142 this.fireEvent("loadexception", this, o);
24146 * Filter the data by a specific property.
24147 * @param {String} property A property on your JSON objects
24148 * @param {String/RegExp} value Either string that the property values
24149 * should start with, or a RegExp to test against the property
24151 filter : function(property, value){
24154 var ss = this.snapshot;
24155 if(typeof value == "string"){
24156 var vlen = value.length;
24158 this.clearFilter();
24161 value = value.toLowerCase();
24162 for(var i = 0, len = ss.length; i < len; i++){
24164 if(o[property].substr(0, vlen).toLowerCase() == value){
24168 } else if(value.exec){ // regex?
24169 for(var i = 0, len = ss.length; i < len; i++){
24171 if(value.test(o[property])){
24178 this.jsonData = data;
24184 * Filter by a function. The passed function will be called with each
24185 * object in the current dataset. If the function returns true the value is kept,
24186 * otherwise it is filtered.
24187 * @param {Function} fn
24188 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24190 filterBy : function(fn, scope){
24193 var ss = this.snapshot;
24194 for(var i = 0, len = ss.length; i < len; i++){
24196 if(fn.call(scope || this, o)){
24200 this.jsonData = data;
24206 * Clears the current filter.
24208 clearFilter : function(){
24209 if(this.snapshot && this.jsonData != this.snapshot){
24210 this.jsonData = this.snapshot;
24217 * Sorts the data for this view and refreshes it.
24218 * @param {String} property A property on your JSON objects to sort on
24219 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24220 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24222 sort : function(property, dir, sortType){
24223 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24226 var dsc = dir && dir.toLowerCase() == "desc";
24227 var f = function(o1, o2){
24228 var v1 = sortType ? sortType(o1[p]) : o1[p];
24229 var v2 = sortType ? sortType(o2[p]) : o2[p];
24232 return dsc ? +1 : -1;
24233 } else if(v1 > v2){
24234 return dsc ? -1 : +1;
24239 this.jsonData.sort(f);
24241 if(this.jsonData != this.snapshot){
24242 this.snapshot.sort(f);
24248 * Ext JS Library 1.1.1
24249 * Copyright(c) 2006-2007, Ext JS, LLC.
24251 * Originally Released Under LGPL - original licence link has changed is not relivant.
24254 * <script type="text/javascript">
24259 * @class Roo.ColorPalette
24260 * @extends Roo.Component
24261 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24262 * Here's an example of typical usage:
24264 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24265 cp.render('my-div');
24267 cp.on('select', function(palette, selColor){
24268 // do something with selColor
24272 * Create a new ColorPalette
24273 * @param {Object} config The config object
24275 Roo.ColorPalette = function(config){
24276 Roo.ColorPalette.superclass.constructor.call(this, config);
24280 * Fires when a color is selected
24281 * @param {ColorPalette} this
24282 * @param {String} color The 6-digit color hex code (without the # symbol)
24288 this.on("select", this.handler, this.scope, true);
24291 Roo.extend(Roo.ColorPalette, Roo.Component, {
24293 * @cfg {String} itemCls
24294 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24296 itemCls : "x-color-palette",
24298 * @cfg {String} value
24299 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24300 * the hex codes are case-sensitive.
24303 clickEvent:'click',
24305 ctype: "Roo.ColorPalette",
24308 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24310 allowReselect : false,
24313 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24314 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24315 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24316 * of colors with the width setting until the box is symmetrical.</p>
24317 * <p>You can override individual colors if needed:</p>
24319 var cp = new Roo.ColorPalette();
24320 cp.colors[0] = "FF0000"; // change the first box to red
24323 Or you can provide a custom array of your own for complete control:
24325 var cp = new Roo.ColorPalette();
24326 cp.colors = ["000000", "993300", "333300"];
24331 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24332 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24333 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24334 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24335 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24339 onRender : function(container, position){
24340 var t = new Roo.MasterTemplate(
24341 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24343 var c = this.colors;
24344 for(var i = 0, len = c.length; i < len; i++){
24347 var el = document.createElement("div");
24348 el.className = this.itemCls;
24350 container.dom.insertBefore(el, position);
24351 this.el = Roo.get(el);
24352 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24353 if(this.clickEvent != 'click'){
24354 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24359 afterRender : function(){
24360 Roo.ColorPalette.superclass.afterRender.call(this);
24362 var s = this.value;
24369 handleClick : function(e, t){
24370 e.preventDefault();
24371 if(!this.disabled){
24372 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24373 this.select(c.toUpperCase());
24378 * Selects the specified color in the palette (fires the select event)
24379 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24381 select : function(color){
24382 color = color.replace("#", "");
24383 if(color != this.value || this.allowReselect){
24386 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24388 el.child("a.color-"+color).addClass("x-color-palette-sel");
24389 this.value = color;
24390 this.fireEvent("select", this, color);
24395 * Ext JS Library 1.1.1
24396 * Copyright(c) 2006-2007, Ext JS, LLC.
24398 * Originally Released Under LGPL - original licence link has changed is not relivant.
24401 * <script type="text/javascript">
24405 * @class Roo.DatePicker
24406 * @extends Roo.Component
24407 * Simple date picker class.
24409 * Create a new DatePicker
24410 * @param {Object} config The config object
24412 Roo.DatePicker = function(config){
24413 Roo.DatePicker.superclass.constructor.call(this, config);
24415 this.value = config && config.value ?
24416 config.value.clearTime() : new Date().clearTime();
24421 * Fires when a date is selected
24422 * @param {DatePicker} this
24423 * @param {Date} date The selected date
24429 this.on("select", this.handler, this.scope || this);
24431 // build the disabledDatesRE
24432 if(!this.disabledDatesRE && this.disabledDates){
24433 var dd = this.disabledDates;
24435 for(var i = 0; i < dd.length; i++){
24437 if(i != dd.length-1) re += "|";
24439 this.disabledDatesRE = new RegExp(re + ")");
24443 Roo.extend(Roo.DatePicker, Roo.Component, {
24445 * @cfg {String} todayText
24446 * The text to display on the button that selects the current date (defaults to "Today")
24448 todayText : "Today",
24450 * @cfg {String} okText
24451 * The text to display on the ok button
24453 okText : " OK ", //   to give the user extra clicking room
24455 * @cfg {String} cancelText
24456 * The text to display on the cancel button
24458 cancelText : "Cancel",
24460 * @cfg {String} todayTip
24461 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24463 todayTip : "{0} (Spacebar)",
24465 * @cfg {Date} minDate
24466 * Minimum allowable date (JavaScript date object, defaults to null)
24470 * @cfg {Date} maxDate
24471 * Maximum allowable date (JavaScript date object, defaults to null)
24475 * @cfg {String} minText
24476 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24478 minText : "This date is before the minimum date",
24480 * @cfg {String} maxText
24481 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24483 maxText : "This date is after the maximum date",
24485 * @cfg {String} format
24486 * The default date format string which can be overriden for localization support. The format must be
24487 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24491 * @cfg {Array} disabledDays
24492 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24494 disabledDays : null,
24496 * @cfg {String} disabledDaysText
24497 * The tooltip to display when the date falls on a disabled day (defaults to "")
24499 disabledDaysText : "",
24501 * @cfg {RegExp} disabledDatesRE
24502 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24504 disabledDatesRE : null,
24506 * @cfg {String} disabledDatesText
24507 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24509 disabledDatesText : "",
24511 * @cfg {Boolean} constrainToViewport
24512 * True to constrain the date picker to the viewport (defaults to true)
24514 constrainToViewport : true,
24516 * @cfg {Array} monthNames
24517 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24519 monthNames : Date.monthNames,
24521 * @cfg {Array} dayNames
24522 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24524 dayNames : Date.dayNames,
24526 * @cfg {String} nextText
24527 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24529 nextText: 'Next Month (Control+Right)',
24531 * @cfg {String} prevText
24532 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24534 prevText: 'Previous Month (Control+Left)',
24536 * @cfg {String} monthYearText
24537 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24539 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24541 * @cfg {Number} startDay
24542 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24546 * @cfg {Bool} showClear
24547 * Show a clear button (usefull for date form elements that can be blank.)
24553 * Sets the value of the date field
24554 * @param {Date} value The date to set
24556 setValue : function(value){
24557 var old = this.value;
24558 this.value = value.clearTime(true);
24560 this.update(this.value);
24565 * Gets the current selected value of the date field
24566 * @return {Date} The selected date
24568 getValue : function(){
24573 focus : function(){
24575 this.update(this.activeDate);
24580 onRender : function(container, position){
24582 '<table cellspacing="0">',
24583 '<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>',
24584 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24585 var dn = this.dayNames;
24586 for(var i = 0; i < 7; i++){
24587 var d = this.startDay+i;
24591 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24593 m[m.length] = "</tr></thead><tbody><tr>";
24594 for(var i = 0; i < 42; i++) {
24595 if(i % 7 == 0 && i != 0){
24596 m[m.length] = "</tr><tr>";
24598 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24600 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24601 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24603 var el = document.createElement("div");
24604 el.className = "x-date-picker";
24605 el.innerHTML = m.join("");
24607 container.dom.insertBefore(el, position);
24609 this.el = Roo.get(el);
24610 this.eventEl = Roo.get(el.firstChild);
24612 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24613 handler: this.showPrevMonth,
24615 preventDefault:true,
24619 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24620 handler: this.showNextMonth,
24622 preventDefault:true,
24626 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24628 this.monthPicker = this.el.down('div.x-date-mp');
24629 this.monthPicker.enableDisplayMode('block');
24631 var kn = new Roo.KeyNav(this.eventEl, {
24632 "left" : function(e){
24634 this.showPrevMonth() :
24635 this.update(this.activeDate.add("d", -1));
24638 "right" : function(e){
24640 this.showNextMonth() :
24641 this.update(this.activeDate.add("d", 1));
24644 "up" : function(e){
24646 this.showNextYear() :
24647 this.update(this.activeDate.add("d", -7));
24650 "down" : function(e){
24652 this.showPrevYear() :
24653 this.update(this.activeDate.add("d", 7));
24656 "pageUp" : function(e){
24657 this.showNextMonth();
24660 "pageDown" : function(e){
24661 this.showPrevMonth();
24664 "enter" : function(e){
24665 e.stopPropagation();
24672 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24674 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24676 this.el.unselectable();
24678 this.cells = this.el.select("table.x-date-inner tbody td");
24679 this.textNodes = this.el.query("table.x-date-inner tbody span");
24681 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24683 tooltip: this.monthYearText
24686 this.mbtn.on('click', this.showMonthPicker, this);
24687 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24690 var today = (new Date()).dateFormat(this.format);
24692 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24693 if (this.showClear) {
24694 baseTb.add( new Roo.Toolbar.Fill());
24697 text: String.format(this.todayText, today),
24698 tooltip: String.format(this.todayTip, today),
24699 handler: this.selectToday,
24703 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24706 if (this.showClear) {
24708 baseTb.add( new Roo.Toolbar.Fill());
24711 cls: 'x-btn-icon x-btn-clear',
24712 handler: function() {
24714 this.fireEvent("select", this, '');
24724 this.update(this.value);
24727 createMonthPicker : function(){
24728 if(!this.monthPicker.dom.firstChild){
24729 var buf = ['<table border="0" cellspacing="0">'];
24730 for(var i = 0; i < 6; i++){
24732 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24733 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24735 '<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>' :
24736 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24740 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24742 '</button><button type="button" class="x-date-mp-cancel">',
24744 '</button></td></tr>',
24747 this.monthPicker.update(buf.join(''));
24748 this.monthPicker.on('click', this.onMonthClick, this);
24749 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24751 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24752 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24754 this.mpMonths.each(function(m, a, i){
24757 m.dom.xmonth = 5 + Math.round(i * .5);
24759 m.dom.xmonth = Math.round((i-1) * .5);
24765 showMonthPicker : function(){
24766 this.createMonthPicker();
24767 var size = this.el.getSize();
24768 this.monthPicker.setSize(size);
24769 this.monthPicker.child('table').setSize(size);
24771 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24772 this.updateMPMonth(this.mpSelMonth);
24773 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24774 this.updateMPYear(this.mpSelYear);
24776 this.monthPicker.slideIn('t', {duration:.2});
24779 updateMPYear : function(y){
24781 var ys = this.mpYears.elements;
24782 for(var i = 1; i <= 10; i++){
24783 var td = ys[i-1], y2;
24785 y2 = y + Math.round(i * .5);
24786 td.firstChild.innerHTML = y2;
24789 y2 = y - (5-Math.round(i * .5));
24790 td.firstChild.innerHTML = y2;
24793 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24797 updateMPMonth : function(sm){
24798 this.mpMonths.each(function(m, a, i){
24799 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24803 selectMPMonth: function(m){
24807 onMonthClick : function(e, t){
24809 var el = new Roo.Element(t), pn;
24810 if(el.is('button.x-date-mp-cancel')){
24811 this.hideMonthPicker();
24813 else if(el.is('button.x-date-mp-ok')){
24814 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24815 this.hideMonthPicker();
24817 else if(pn = el.up('td.x-date-mp-month', 2)){
24818 this.mpMonths.removeClass('x-date-mp-sel');
24819 pn.addClass('x-date-mp-sel');
24820 this.mpSelMonth = pn.dom.xmonth;
24822 else if(pn = el.up('td.x-date-mp-year', 2)){
24823 this.mpYears.removeClass('x-date-mp-sel');
24824 pn.addClass('x-date-mp-sel');
24825 this.mpSelYear = pn.dom.xyear;
24827 else if(el.is('a.x-date-mp-prev')){
24828 this.updateMPYear(this.mpyear-10);
24830 else if(el.is('a.x-date-mp-next')){
24831 this.updateMPYear(this.mpyear+10);
24835 onMonthDblClick : function(e, t){
24837 var el = new Roo.Element(t), pn;
24838 if(pn = el.up('td.x-date-mp-month', 2)){
24839 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24840 this.hideMonthPicker();
24842 else if(pn = el.up('td.x-date-mp-year', 2)){
24843 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24844 this.hideMonthPicker();
24848 hideMonthPicker : function(disableAnim){
24849 if(this.monthPicker){
24850 if(disableAnim === true){
24851 this.monthPicker.hide();
24853 this.monthPicker.slideOut('t', {duration:.2});
24859 showPrevMonth : function(e){
24860 this.update(this.activeDate.add("mo", -1));
24864 showNextMonth : function(e){
24865 this.update(this.activeDate.add("mo", 1));
24869 showPrevYear : function(){
24870 this.update(this.activeDate.add("y", -1));
24874 showNextYear : function(){
24875 this.update(this.activeDate.add("y", 1));
24879 handleMouseWheel : function(e){
24880 var delta = e.getWheelDelta();
24882 this.showPrevMonth();
24884 } else if(delta < 0){
24885 this.showNextMonth();
24891 handleDateClick : function(e, t){
24893 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24894 this.setValue(new Date(t.dateValue));
24895 this.fireEvent("select", this, this.value);
24900 selectToday : function(){
24901 this.setValue(new Date().clearTime());
24902 this.fireEvent("select", this, this.value);
24906 update : function(date){
24907 var vd = this.activeDate;
24908 this.activeDate = date;
24910 var t = date.getTime();
24911 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
24912 this.cells.removeClass("x-date-selected");
24913 this.cells.each(function(c){
24914 if(c.dom.firstChild.dateValue == t){
24915 c.addClass("x-date-selected");
24916 setTimeout(function(){
24917 try{c.dom.firstChild.focus();}catch(e){}
24925 var days = date.getDaysInMonth();
24926 var firstOfMonth = date.getFirstDateOfMonth();
24927 var startingPos = firstOfMonth.getDay()-this.startDay;
24929 if(startingPos <= this.startDay){
24933 var pm = date.add("mo", -1);
24934 var prevStart = pm.getDaysInMonth()-startingPos;
24936 var cells = this.cells.elements;
24937 var textEls = this.textNodes;
24938 days += startingPos;
24940 // convert everything to numbers so it's fast
24941 var day = 86400000;
24942 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
24943 var today = new Date().clearTime().getTime();
24944 var sel = date.clearTime().getTime();
24945 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
24946 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
24947 var ddMatch = this.disabledDatesRE;
24948 var ddText = this.disabledDatesText;
24949 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
24950 var ddaysText = this.disabledDaysText;
24951 var format = this.format;
24953 var setCellClass = function(cal, cell){
24955 var t = d.getTime();
24956 cell.firstChild.dateValue = t;
24958 cell.className += " x-date-today";
24959 cell.title = cal.todayText;
24962 cell.className += " x-date-selected";
24963 setTimeout(function(){
24964 try{cell.firstChild.focus();}catch(e){}
24969 cell.className = " x-date-disabled";
24970 cell.title = cal.minText;
24974 cell.className = " x-date-disabled";
24975 cell.title = cal.maxText;
24979 if(ddays.indexOf(d.getDay()) != -1){
24980 cell.title = ddaysText;
24981 cell.className = " x-date-disabled";
24984 if(ddMatch && format){
24985 var fvalue = d.dateFormat(format);
24986 if(ddMatch.test(fvalue)){
24987 cell.title = ddText.replace("%0", fvalue);
24988 cell.className = " x-date-disabled";
24994 for(; i < startingPos; i++) {
24995 textEls[i].innerHTML = (++prevStart);
24996 d.setDate(d.getDate()+1);
24997 cells[i].className = "x-date-prevday";
24998 setCellClass(this, cells[i]);
25000 for(; i < days; i++){
25001 intDay = i - startingPos + 1;
25002 textEls[i].innerHTML = (intDay);
25003 d.setDate(d.getDate()+1);
25004 cells[i].className = "x-date-active";
25005 setCellClass(this, cells[i]);
25008 for(; i < 42; i++) {
25009 textEls[i].innerHTML = (++extraDays);
25010 d.setDate(d.getDate()+1);
25011 cells[i].className = "x-date-nextday";
25012 setCellClass(this, cells[i]);
25015 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25017 if(!this.internalRender){
25018 var main = this.el.dom.firstChild;
25019 var w = main.offsetWidth;
25020 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25021 Roo.fly(main).setWidth(w);
25022 this.internalRender = true;
25023 // opera does not respect the auto grow header center column
25024 // then, after it gets a width opera refuses to recalculate
25025 // without a second pass
25026 if(Roo.isOpera && !this.secondPass){
25027 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25028 this.secondPass = true;
25029 this.update.defer(10, this, [date]);
25035 * Ext JS Library 1.1.1
25036 * Copyright(c) 2006-2007, Ext JS, LLC.
25038 * Originally Released Under LGPL - original licence link has changed is not relivant.
25041 * <script type="text/javascript">
25044 * @class Roo.TabPanel
25045 * @extends Roo.util.Observable
25046 * A lightweight tab container.
25050 // basic tabs 1, built from existing content
25051 var tabs = new Roo.TabPanel("tabs1");
25052 tabs.addTab("script", "View Script");
25053 tabs.addTab("markup", "View Markup");
25054 tabs.activate("script");
25056 // more advanced tabs, built from javascript
25057 var jtabs = new Roo.TabPanel("jtabs");
25058 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25060 // set up the UpdateManager
25061 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25062 var updater = tab2.getUpdateManager();
25063 updater.setDefaultUrl("ajax1.htm");
25064 tab2.on('activate', updater.refresh, updater, true);
25066 // Use setUrl for Ajax loading
25067 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25068 tab3.setUrl("ajax2.htm", null, true);
25071 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25074 jtabs.activate("jtabs-1");
25077 * Create a new TabPanel.
25078 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25079 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25081 Roo.TabPanel = function(container, config){
25083 * The container element for this TabPanel.
25084 * @type Roo.Element
25086 this.el = Roo.get(container, true);
25088 if(typeof config == "boolean"){
25089 this.tabPosition = config ? "bottom" : "top";
25091 Roo.apply(this, config);
25094 if(this.tabPosition == "bottom"){
25095 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25096 this.el.addClass("x-tabs-bottom");
25098 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25099 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25100 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25102 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25104 if(this.tabPosition != "bottom"){
25105 /** The body element that contains {@link Roo.TabPanelItem} bodies.
25106 * @type Roo.Element
25108 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25109 this.el.addClass("x-tabs-top");
25113 this.bodyEl.setStyle("position", "relative");
25115 this.active = null;
25116 this.activateDelegate = this.activate.createDelegate(this);
25121 * Fires when the active tab changes
25122 * @param {Roo.TabPanel} this
25123 * @param {Roo.TabPanelItem} activePanel The new active tab
25127 * @event beforetabchange
25128 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25129 * @param {Roo.TabPanel} this
25130 * @param {Object} e Set cancel to true on this object to cancel the tab change
25131 * @param {Roo.TabPanelItem} tab The tab being changed to
25133 "beforetabchange" : true
25136 Roo.EventManager.onWindowResize(this.onResize, this);
25137 this.cpad = this.el.getPadding("lr");
25138 this.hiddenCount = 0;
25140 Roo.TabPanel.superclass.constructor.call(this);
25143 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25145 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25147 tabPosition : "top",
25149 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25151 currentTabWidth : 0,
25153 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25157 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25161 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25163 preferredTabWidth : 175,
25165 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25167 resizeTabs : false,
25169 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25171 monitorResize : true,
25174 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25175 * @param {String} id The id of the div to use <b>or create</b>
25176 * @param {String} text The text for the tab
25177 * @param {String} content (optional) Content to put in the TabPanelItem body
25178 * @param {Boolean} closable (optional) True to create a close icon on the tab
25179 * @return {Roo.TabPanelItem} The created TabPanelItem
25181 addTab : function(id, text, content, closable){
25182 var item = new Roo.TabPanelItem(this, id, text, closable);
25183 this.addTabItem(item);
25185 item.setContent(content);
25191 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25192 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25193 * @return {Roo.TabPanelItem}
25195 getTab : function(id){
25196 return this.items[id];
25200 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25201 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25203 hideTab : function(id){
25204 var t = this.items[id];
25207 this.hiddenCount++;
25208 this.autoSizeTabs();
25213 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25214 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25216 unhideTab : function(id){
25217 var t = this.items[id];
25219 t.setHidden(false);
25220 this.hiddenCount--;
25221 this.autoSizeTabs();
25226 * Adds an existing {@link Roo.TabPanelItem}.
25227 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25229 addTabItem : function(item){
25230 this.items[item.id] = item;
25231 this.items.push(item);
25232 if(this.resizeTabs){
25233 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25234 this.autoSizeTabs();
25241 * Removes a {@link Roo.TabPanelItem}.
25242 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25244 removeTab : function(id){
25245 var items = this.items;
25246 var tab = items[id];
25247 if(!tab) { return; }
25248 var index = items.indexOf(tab);
25249 if(this.active == tab && items.length > 1){
25250 var newTab = this.getNextAvailable(index);
25255 this.stripEl.dom.removeChild(tab.pnode.dom);
25256 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25257 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25259 items.splice(index, 1);
25260 delete this.items[tab.id];
25261 tab.fireEvent("close", tab);
25262 tab.purgeListeners();
25263 this.autoSizeTabs();
25266 getNextAvailable : function(start){
25267 var items = this.items;
25269 // look for a next tab that will slide over to
25270 // replace the one being removed
25271 while(index < items.length){
25272 var item = items[++index];
25273 if(item && !item.isHidden()){
25277 // if one isn't found select the previous tab (on the left)
25280 var item = items[--index];
25281 if(item && !item.isHidden()){
25289 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25290 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25292 disableTab : function(id){
25293 var tab = this.items[id];
25294 if(tab && this.active != tab){
25300 * Enables a {@link Roo.TabPanelItem} that is disabled.
25301 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25303 enableTab : function(id){
25304 var tab = this.items[id];
25309 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25310 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25311 * @return {Roo.TabPanelItem} The TabPanelItem.
25313 activate : function(id){
25314 var tab = this.items[id];
25318 if(tab == this.active || tab.disabled){
25322 this.fireEvent("beforetabchange", this, e, tab);
25323 if(e.cancel !== true && !tab.disabled){
25325 this.active.hide();
25327 this.active = this.items[id];
25328 this.active.show();
25329 this.fireEvent("tabchange", this, this.active);
25335 * Gets the active {@link Roo.TabPanelItem}.
25336 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25338 getActiveTab : function(){
25339 return this.active;
25343 * Updates the tab body element to fit the height of the container element
25344 * for overflow scrolling
25345 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25347 syncHeight : function(targetHeight){
25348 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25349 var bm = this.bodyEl.getMargins();
25350 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25351 this.bodyEl.setHeight(newHeight);
25355 onResize : function(){
25356 if(this.monitorResize){
25357 this.autoSizeTabs();
25362 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25364 beginUpdate : function(){
25365 this.updating = true;
25369 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25371 endUpdate : function(){
25372 this.updating = false;
25373 this.autoSizeTabs();
25377 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25379 autoSizeTabs : function(){
25380 var count = this.items.length;
25381 var vcount = count - this.hiddenCount;
25382 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25383 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25384 var availWidth = Math.floor(w / vcount);
25385 var b = this.stripBody;
25386 if(b.getWidth() > w){
25387 var tabs = this.items;
25388 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25389 if(availWidth < this.minTabWidth){
25390 /*if(!this.sleft){ // incomplete scrolling code
25391 this.createScrollButtons();
25394 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25397 if(this.currentTabWidth < this.preferredTabWidth){
25398 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25404 * Returns the number of tabs in this TabPanel.
25407 getCount : function(){
25408 return this.items.length;
25412 * Resizes all the tabs to the passed width
25413 * @param {Number} The new width
25415 setTabWidth : function(width){
25416 this.currentTabWidth = width;
25417 for(var i = 0, len = this.items.length; i < len; i++) {
25418 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25423 * Destroys this TabPanel
25424 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25426 destroy : function(removeEl){
25427 Roo.EventManager.removeResizeListener(this.onResize, this);
25428 for(var i = 0, len = this.items.length; i < len; i++){
25429 this.items[i].purgeListeners();
25431 if(removeEl === true){
25432 this.el.update("");
25439 * @class Roo.TabPanelItem
25440 * @extends Roo.util.Observable
25441 * Represents an individual item (tab plus body) in a TabPanel.
25442 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25443 * @param {String} id The id of this TabPanelItem
25444 * @param {String} text The text for the tab of this TabPanelItem
25445 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25447 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25449 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25450 * @type Roo.TabPanel
25452 this.tabPanel = tabPanel;
25454 * The id for this TabPanelItem
25459 this.disabled = false;
25463 this.loaded = false;
25464 this.closable = closable;
25467 * The body element for this TabPanelItem.
25468 * @type Roo.Element
25470 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25471 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25472 this.bodyEl.setStyle("display", "block");
25473 this.bodyEl.setStyle("zoom", "1");
25476 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25478 this.el = Roo.get(els.el, true);
25479 this.inner = Roo.get(els.inner, true);
25480 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25481 this.pnode = Roo.get(els.el.parentNode, true);
25482 this.el.on("mousedown", this.onTabMouseDown, this);
25483 this.el.on("click", this.onTabClick, this);
25486 var c = Roo.get(els.close, true);
25487 c.dom.title = this.closeText;
25488 c.addClassOnOver("close-over");
25489 c.on("click", this.closeClick, this);
25495 * Fires when this tab becomes the active tab.
25496 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25497 * @param {Roo.TabPanelItem} this
25501 * @event beforeclose
25502 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25503 * @param {Roo.TabPanelItem} this
25504 * @param {Object} e Set cancel to true on this object to cancel the close.
25506 "beforeclose": true,
25509 * Fires when this tab is closed.
25510 * @param {Roo.TabPanelItem} this
25514 * @event deactivate
25515 * Fires when this tab is no longer the active tab.
25516 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25517 * @param {Roo.TabPanelItem} this
25519 "deactivate" : true
25521 this.hidden = false;
25523 Roo.TabPanelItem.superclass.constructor.call(this);
25526 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25527 purgeListeners : function(){
25528 Roo.util.Observable.prototype.purgeListeners.call(this);
25529 this.el.removeAllListeners();
25532 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25535 this.pnode.addClass("on");
25538 this.tabPanel.stripWrap.repaint();
25540 this.fireEvent("activate", this.tabPanel, this);
25544 * Returns true if this tab is the active tab.
25545 * @return {Boolean}
25547 isActive : function(){
25548 return this.tabPanel.getActiveTab() == this;
25552 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25555 this.pnode.removeClass("on");
25557 this.fireEvent("deactivate", this.tabPanel, this);
25560 hideAction : function(){
25561 this.bodyEl.hide();
25562 this.bodyEl.setStyle("position", "absolute");
25563 this.bodyEl.setLeft("-20000px");
25564 this.bodyEl.setTop("-20000px");
25567 showAction : function(){
25568 this.bodyEl.setStyle("position", "relative");
25569 this.bodyEl.setTop("");
25570 this.bodyEl.setLeft("");
25571 this.bodyEl.show();
25575 * Set the tooltip for the tab.
25576 * @param {String} tooltip The tab's tooltip
25578 setTooltip : function(text){
25579 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25580 this.textEl.dom.qtip = text;
25581 this.textEl.dom.removeAttribute('title');
25583 this.textEl.dom.title = text;
25587 onTabClick : function(e){
25588 e.preventDefault();
25589 this.tabPanel.activate(this.id);
25592 onTabMouseDown : function(e){
25593 e.preventDefault();
25594 this.tabPanel.activate(this.id);
25597 getWidth : function(){
25598 return this.inner.getWidth();
25601 setWidth : function(width){
25602 var iwidth = width - this.pnode.getPadding("lr");
25603 this.inner.setWidth(iwidth);
25604 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25605 this.pnode.setWidth(width);
25609 * Show or hide the tab
25610 * @param {Boolean} hidden True to hide or false to show.
25612 setHidden : function(hidden){
25613 this.hidden = hidden;
25614 this.pnode.setStyle("display", hidden ? "none" : "");
25618 * Returns true if this tab is "hidden"
25619 * @return {Boolean}
25621 isHidden : function(){
25622 return this.hidden;
25626 * Returns the text for this tab
25629 getText : function(){
25633 autoSize : function(){
25634 //this.el.beginMeasure();
25635 this.textEl.setWidth(1);
25636 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25637 //this.el.endMeasure();
25641 * Sets the text for the tab (Note: this also sets the tooltip text)
25642 * @param {String} text The tab's text and tooltip
25644 setText : function(text){
25646 this.textEl.update(text);
25647 this.setTooltip(text);
25648 if(!this.tabPanel.resizeTabs){
25653 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25655 activate : function(){
25656 this.tabPanel.activate(this.id);
25660 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25662 disable : function(){
25663 if(this.tabPanel.active != this){
25664 this.disabled = true;
25665 this.pnode.addClass("disabled");
25670 * Enables this TabPanelItem if it was previously disabled.
25672 enable : function(){
25673 this.disabled = false;
25674 this.pnode.removeClass("disabled");
25678 * Sets the content for this TabPanelItem.
25679 * @param {String} content The content
25680 * @param {Boolean} loadScripts true to look for and load scripts
25682 setContent : function(content, loadScripts){
25683 this.bodyEl.update(content, loadScripts);
25687 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25688 * @return {Roo.UpdateManager} The UpdateManager
25690 getUpdateManager : function(){
25691 return this.bodyEl.getUpdateManager();
25695 * Set a URL to be used to load the content for this TabPanelItem.
25696 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25697 * @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)
25698 * @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)
25699 * @return {Roo.UpdateManager} The UpdateManager
25701 setUrl : function(url, params, loadOnce){
25702 if(this.refreshDelegate){
25703 this.un('activate', this.refreshDelegate);
25705 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25706 this.on("activate", this.refreshDelegate);
25707 return this.bodyEl.getUpdateManager();
25711 _handleRefresh : function(url, params, loadOnce){
25712 if(!loadOnce || !this.loaded){
25713 var updater = this.bodyEl.getUpdateManager();
25714 updater.update(url, params, this._setLoaded.createDelegate(this));
25719 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25720 * Will fail silently if the setUrl method has not been called.
25721 * This does not activate the panel, just updates its content.
25723 refresh : function(){
25724 if(this.refreshDelegate){
25725 this.loaded = false;
25726 this.refreshDelegate();
25731 _setLoaded : function(){
25732 this.loaded = true;
25736 closeClick : function(e){
25739 this.fireEvent("beforeclose", this, o);
25740 if(o.cancel !== true){
25741 this.tabPanel.removeTab(this.id);
25745 * The text displayed in the tooltip for the close icon.
25748 closeText : "Close this tab"
25752 Roo.TabPanel.prototype.createStrip = function(container){
25753 var strip = document.createElement("div");
25754 strip.className = "x-tabs-wrap";
25755 container.appendChild(strip);
25759 Roo.TabPanel.prototype.createStripList = function(strip){
25760 // div wrapper for retard IE
25761 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>';
25762 return strip.firstChild.firstChild.firstChild.firstChild;
25765 Roo.TabPanel.prototype.createBody = function(container){
25766 var body = document.createElement("div");
25767 Roo.id(body, "tab-body");
25768 Roo.fly(body).addClass("x-tabs-body");
25769 container.appendChild(body);
25773 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25774 var body = Roo.getDom(id);
25776 body = document.createElement("div");
25779 Roo.fly(body).addClass("x-tabs-item-body");
25780 bodyEl.insertBefore(body, bodyEl.firstChild);
25784 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25785 var td = document.createElement("td");
25786 stripEl.appendChild(td);
25788 td.className = "x-tabs-closable";
25789 if(!this.closeTpl){
25790 this.closeTpl = new Roo.Template(
25791 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25792 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25793 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25796 var el = this.closeTpl.overwrite(td, {"text": text});
25797 var close = el.getElementsByTagName("div")[0];
25798 var inner = el.getElementsByTagName("em")[0];
25799 return {"el": el, "close": close, "inner": inner};
25802 this.tabTpl = new Roo.Template(
25803 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25804 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25807 var el = this.tabTpl.overwrite(td, {"text": text});
25808 var inner = el.getElementsByTagName("em")[0];
25809 return {"el": el, "inner": inner};
25813 * Ext JS Library 1.1.1
25814 * Copyright(c) 2006-2007, Ext JS, LLC.
25816 * Originally Released Under LGPL - original licence link has changed is not relivant.
25819 * <script type="text/javascript">
25823 * @class Roo.Button
25824 * @extends Roo.util.Observable
25825 * Simple Button class
25826 * @cfg {String} text The button text
25827 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25828 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25829 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25830 * @cfg {Object} scope The scope of the handler
25831 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25832 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25833 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25834 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25835 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25836 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25837 applies if enableToggle = true)
25838 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25839 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25840 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25842 * Create a new button
25843 * @param {Object} config The config object
25845 Roo.Button = function(renderTo, config)
25849 renderTo = config.renderTo || false;
25852 Roo.apply(this, config);
25856 * Fires when this button is clicked
25857 * @param {Button} this
25858 * @param {EventObject} e The click event
25863 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25864 * @param {Button} this
25865 * @param {Boolean} pressed
25870 * Fires when the mouse hovers over the button
25871 * @param {Button} this
25872 * @param {Event} e The event object
25874 'mouseover' : true,
25877 * Fires when the mouse exits the button
25878 * @param {Button} this
25879 * @param {Event} e The event object
25884 * Fires when the button is rendered
25885 * @param {Button} this
25890 this.menu = Roo.menu.MenuMgr.get(this.menu);
25892 // register listeners first!! - so render can be captured..
25893 Roo.util.Observable.call(this);
25895 this.render(renderTo);
25901 Roo.extend(Roo.Button, Roo.util.Observable, {
25907 * Read-only. True if this button is hidden
25912 * Read-only. True if this button is disabled
25917 * Read-only. True if this button is pressed (only if enableToggle = true)
25923 * @cfg {Number} tabIndex
25924 * The DOM tabIndex for this button (defaults to undefined)
25926 tabIndex : undefined,
25929 * @cfg {Boolean} enableToggle
25930 * True to enable pressed/not pressed toggling (defaults to false)
25932 enableToggle: false,
25934 * @cfg {Mixed} menu
25935 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
25939 * @cfg {String} menuAlign
25940 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
25942 menuAlign : "tl-bl?",
25945 * @cfg {String} iconCls
25946 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
25948 iconCls : undefined,
25950 * @cfg {String} type
25951 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
25956 menuClassTarget: 'tr',
25959 * @cfg {String} clickEvent
25960 * The type of event to map to the button's event handler (defaults to 'click')
25962 clickEvent : 'click',
25965 * @cfg {Boolean} handleMouseEvents
25966 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
25968 handleMouseEvents : true,
25971 * @cfg {String} tooltipType
25972 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
25974 tooltipType : 'qtip',
25977 * @cfg {String} cls
25978 * A CSS class to apply to the button's main element.
25982 * @cfg {Roo.Template} template (Optional)
25983 * An {@link Roo.Template} with which to create the Button's main element. This Template must
25984 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
25985 * require code modifications if required elements (e.g. a button) aren't present.
25989 render : function(renderTo){
25991 if(this.hideParent){
25992 this.parentEl = Roo.get(renderTo);
25994 if(!this.dhconfig){
25995 if(!this.template){
25996 if(!Roo.Button.buttonTemplate){
25997 // hideous table template
25998 Roo.Button.buttonTemplate = new Roo.Template(
25999 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26000 '<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>',
26001 "</tr></tbody></table>");
26003 this.template = Roo.Button.buttonTemplate;
26005 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26006 var btnEl = btn.child("button:first");
26007 btnEl.on('focus', this.onFocus, this);
26008 btnEl.on('blur', this.onBlur, this);
26010 btn.addClass(this.cls);
26013 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26016 btnEl.addClass(this.iconCls);
26018 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26021 if(this.tabIndex !== undefined){
26022 btnEl.dom.tabIndex = this.tabIndex;
26025 if(typeof this.tooltip == 'object'){
26026 Roo.QuickTips.tips(Roo.apply({
26030 btnEl.dom[this.tooltipType] = this.tooltip;
26034 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26038 this.el.dom.id = this.el.id = this.id;
26041 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26042 this.menu.on("show", this.onMenuShow, this);
26043 this.menu.on("hide", this.onMenuHide, this);
26045 btn.addClass("x-btn");
26046 if(Roo.isIE && !Roo.isIE7){
26047 this.autoWidth.defer(1, this);
26051 if(this.handleMouseEvents){
26052 btn.on("mouseover", this.onMouseOver, this);
26053 btn.on("mouseout", this.onMouseOut, this);
26054 btn.on("mousedown", this.onMouseDown, this);
26056 btn.on(this.clickEvent, this.onClick, this);
26057 //btn.on("mouseup", this.onMouseUp, this);
26064 Roo.ButtonToggleMgr.register(this);
26066 this.el.addClass("x-btn-pressed");
26069 var repeater = new Roo.util.ClickRepeater(btn,
26070 typeof this.repeat == "object" ? this.repeat : {}
26072 repeater.on("click", this.onClick, this);
26075 this.fireEvent('render', this);
26079 * Returns the button's underlying element
26080 * @return {Roo.Element} The element
26082 getEl : function(){
26087 * Destroys this Button and removes any listeners.
26089 destroy : function(){
26090 Roo.ButtonToggleMgr.unregister(this);
26091 this.el.removeAllListeners();
26092 this.purgeListeners();
26097 autoWidth : function(){
26099 this.el.setWidth("auto");
26100 if(Roo.isIE7 && Roo.isStrict){
26101 var ib = this.el.child('button');
26102 if(ib && ib.getWidth() > 20){
26104 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26109 this.el.beginMeasure();
26111 if(this.el.getWidth() < this.minWidth){
26112 this.el.setWidth(this.minWidth);
26115 this.el.endMeasure();
26122 * Assigns this button's click handler
26123 * @param {Function} handler The function to call when the button is clicked
26124 * @param {Object} scope (optional) Scope for the function passed in
26126 setHandler : function(handler, scope){
26127 this.handler = handler;
26128 this.scope = scope;
26132 * Sets this button's text
26133 * @param {String} text The button text
26135 setText : function(text){
26138 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26144 * Gets the text for this button
26145 * @return {String} The button text
26147 getText : function(){
26155 this.hidden = false;
26157 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26165 this.hidden = true;
26167 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26172 * Convenience function for boolean show/hide
26173 * @param {Boolean} visible True to show, false to hide
26175 setVisible: function(visible){
26184 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26185 * @param {Boolean} state (optional) Force a particular state
26187 toggle : function(state){
26188 state = state === undefined ? !this.pressed : state;
26189 if(state != this.pressed){
26191 this.el.addClass("x-btn-pressed");
26192 this.pressed = true;
26193 this.fireEvent("toggle", this, true);
26195 this.el.removeClass("x-btn-pressed");
26196 this.pressed = false;
26197 this.fireEvent("toggle", this, false);
26199 if(this.toggleHandler){
26200 this.toggleHandler.call(this.scope || this, this, state);
26208 focus : function(){
26209 this.el.child('button:first').focus();
26213 * Disable this button
26215 disable : function(){
26217 this.el.addClass("x-btn-disabled");
26219 this.disabled = true;
26223 * Enable this button
26225 enable : function(){
26227 this.el.removeClass("x-btn-disabled");
26229 this.disabled = false;
26233 * Convenience function for boolean enable/disable
26234 * @param {Boolean} enabled True to enable, false to disable
26236 setDisabled : function(v){
26237 this[v !== true ? "enable" : "disable"]();
26241 onClick : function(e){
26243 e.preventDefault();
26248 if(!this.disabled){
26249 if(this.enableToggle){
26252 if(this.menu && !this.menu.isVisible()){
26253 this.menu.show(this.el, this.menuAlign);
26255 this.fireEvent("click", this, e);
26257 this.el.removeClass("x-btn-over");
26258 this.handler.call(this.scope || this, this, e);
26263 onMouseOver : function(e){
26264 if(!this.disabled){
26265 this.el.addClass("x-btn-over");
26266 this.fireEvent('mouseover', this, e);
26270 onMouseOut : function(e){
26271 if(!e.within(this.el, true)){
26272 this.el.removeClass("x-btn-over");
26273 this.fireEvent('mouseout', this, e);
26277 onFocus : function(e){
26278 if(!this.disabled){
26279 this.el.addClass("x-btn-focus");
26283 onBlur : function(e){
26284 this.el.removeClass("x-btn-focus");
26287 onMouseDown : function(e){
26288 if(!this.disabled && e.button == 0){
26289 this.el.addClass("x-btn-click");
26290 Roo.get(document).on('mouseup', this.onMouseUp, this);
26294 onMouseUp : function(e){
26296 this.el.removeClass("x-btn-click");
26297 Roo.get(document).un('mouseup', this.onMouseUp, this);
26301 onMenuShow : function(e){
26302 this.el.addClass("x-btn-menu-active");
26305 onMenuHide : function(e){
26306 this.el.removeClass("x-btn-menu-active");
26310 // Private utility class used by Button
26311 Roo.ButtonToggleMgr = function(){
26314 function toggleGroup(btn, state){
26316 var g = groups[btn.toggleGroup];
26317 for(var i = 0, l = g.length; i < l; i++){
26319 g[i].toggle(false);
26326 register : function(btn){
26327 if(!btn.toggleGroup){
26330 var g = groups[btn.toggleGroup];
26332 g = groups[btn.toggleGroup] = [];
26335 btn.on("toggle", toggleGroup);
26338 unregister : function(btn){
26339 if(!btn.toggleGroup){
26342 var g = groups[btn.toggleGroup];
26345 btn.un("toggle", toggleGroup);
26351 * Ext JS Library 1.1.1
26352 * Copyright(c) 2006-2007, Ext JS, LLC.
26354 * Originally Released Under LGPL - original licence link has changed is not relivant.
26357 * <script type="text/javascript">
26361 * @class Roo.SplitButton
26362 * @extends Roo.Button
26363 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26364 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26365 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26366 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26367 * @cfg {String} arrowTooltip The title attribute of the arrow
26369 * Create a new menu button
26370 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26371 * @param {Object} config The config object
26373 Roo.SplitButton = function(renderTo, config){
26374 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26376 * @event arrowclick
26377 * Fires when this button's arrow is clicked
26378 * @param {SplitButton} this
26379 * @param {EventObject} e The click event
26381 this.addEvents({"arrowclick":true});
26384 Roo.extend(Roo.SplitButton, Roo.Button, {
26385 render : function(renderTo){
26386 // this is one sweet looking template!
26387 var tpl = new Roo.Template(
26388 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26389 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26390 '<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>',
26391 "</tbody></table></td><td>",
26392 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26393 '<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>',
26394 "</tbody></table></td></tr></table>"
26396 var btn = tpl.append(renderTo, [this.text, this.type], true);
26397 var btnEl = btn.child("button");
26399 btn.addClass(this.cls);
26402 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26405 btnEl.addClass(this.iconCls);
26407 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26411 if(this.handleMouseEvents){
26412 btn.on("mouseover", this.onMouseOver, this);
26413 btn.on("mouseout", this.onMouseOut, this);
26414 btn.on("mousedown", this.onMouseDown, this);
26415 btn.on("mouseup", this.onMouseUp, this);
26417 btn.on(this.clickEvent, this.onClick, this);
26419 if(typeof this.tooltip == 'object'){
26420 Roo.QuickTips.tips(Roo.apply({
26424 btnEl.dom[this.tooltipType] = this.tooltip;
26427 if(this.arrowTooltip){
26428 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26437 this.el.addClass("x-btn-pressed");
26439 if(Roo.isIE && !Roo.isIE7){
26440 this.autoWidth.defer(1, this);
26445 this.menu.on("show", this.onMenuShow, this);
26446 this.menu.on("hide", this.onMenuHide, this);
26448 this.fireEvent('render', this);
26452 autoWidth : function(){
26454 var tbl = this.el.child("table:first");
26455 var tbl2 = this.el.child("table:last");
26456 this.el.setWidth("auto");
26457 tbl.setWidth("auto");
26458 if(Roo.isIE7 && Roo.isStrict){
26459 var ib = this.el.child('button:first');
26460 if(ib && ib.getWidth() > 20){
26462 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26467 this.el.beginMeasure();
26469 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26470 tbl.setWidth(this.minWidth-tbl2.getWidth());
26473 this.el.endMeasure();
26476 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26480 * Sets this button's click handler
26481 * @param {Function} handler The function to call when the button is clicked
26482 * @param {Object} scope (optional) Scope for the function passed above
26484 setHandler : function(handler, scope){
26485 this.handler = handler;
26486 this.scope = scope;
26490 * Sets this button's arrow click handler
26491 * @param {Function} handler The function to call when the arrow is clicked
26492 * @param {Object} scope (optional) Scope for the function passed above
26494 setArrowHandler : function(handler, scope){
26495 this.arrowHandler = handler;
26496 this.scope = scope;
26502 focus : function(){
26504 this.el.child("button:first").focus();
26509 onClick : function(e){
26510 e.preventDefault();
26511 if(!this.disabled){
26512 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26513 if(this.menu && !this.menu.isVisible()){
26514 this.menu.show(this.el, this.menuAlign);
26516 this.fireEvent("arrowclick", this, e);
26517 if(this.arrowHandler){
26518 this.arrowHandler.call(this.scope || this, this, e);
26521 this.fireEvent("click", this, e);
26523 this.handler.call(this.scope || this, this, e);
26529 onMouseDown : function(e){
26530 if(!this.disabled){
26531 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26535 onMouseUp : function(e){
26536 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26541 // backwards compat
26542 Roo.MenuButton = Roo.SplitButton;/*
26544 * Ext JS Library 1.1.1
26545 * Copyright(c) 2006-2007, Ext JS, LLC.
26547 * Originally Released Under LGPL - original licence link has changed is not relivant.
26550 * <script type="text/javascript">
26554 * @class Roo.Toolbar
26555 * Basic Toolbar class.
26557 * Creates a new Toolbar
26558 * @param {Object} config The config object
26560 Roo.Toolbar = function(container, buttons, config)
26562 /// old consturctor format still supported..
26563 if(container instanceof Array){ // omit the container for later rendering
26564 buttons = container;
26568 if (typeof(container) == 'object' && container.xtype) {
26569 config = container;
26570 container = config.container;
26571 buttons = config.buttons; // not really - use items!!
26574 if (config && config.items) {
26575 xitems = config.items;
26576 delete config.items;
26578 Roo.apply(this, config);
26579 this.buttons = buttons;
26582 this.render(container);
26584 Roo.each(xitems, function(b) {
26590 Roo.Toolbar.prototype = {
26592 * @cfg {Roo.data.Store} items
26593 * array of button configs or elements to add
26597 * @cfg {String/HTMLElement/Element} container
26598 * The id or element that will contain the toolbar
26601 render : function(ct){
26602 this.el = Roo.get(ct);
26604 this.el.addClass(this.cls);
26606 // using a table allows for vertical alignment
26607 // 100% width is needed by Safari...
26608 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26609 this.tr = this.el.child("tr", true);
26611 this.items = new Roo.util.MixedCollection(false, function(o){
26612 return o.id || ("item" + (++autoId));
26615 this.add.apply(this, this.buttons);
26616 delete this.buttons;
26621 * Adds element(s) to the toolbar -- this function takes a variable number of
26622 * arguments of mixed type and adds them to the toolbar.
26623 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26625 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26626 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26627 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26628 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26629 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26630 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26631 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26632 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26633 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26635 * @param {Mixed} arg2
26636 * @param {Mixed} etc.
26639 var a = arguments, l = a.length;
26640 for(var i = 0; i < l; i++){
26645 _add : function(el) {
26648 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26651 if (el.applyTo){ // some kind of form field
26652 return this.addField(el);
26654 if (el.render){ // some kind of Toolbar.Item
26655 return this.addItem(el);
26657 if (typeof el == "string"){ // string
26658 if(el == "separator" || el == "-"){
26659 return this.addSeparator();
26662 return this.addSpacer();
26665 return this.addFill();
26667 return this.addText(el);
26670 if(el.tagName){ // element
26671 return this.addElement(el);
26673 if(typeof el == "object"){ // must be button config?
26674 return this.addButton(el);
26676 // and now what?!?!
26682 * Add an Xtype element
26683 * @param {Object} xtype Xtype Object
26684 * @return {Object} created Object
26686 addxtype : function(e){
26687 return this.add(e);
26691 * Returns the Element for this toolbar.
26692 * @return {Roo.Element}
26694 getEl : function(){
26700 * @return {Roo.Toolbar.Item} The separator item
26702 addSeparator : function(){
26703 return this.addItem(new Roo.Toolbar.Separator());
26707 * Adds a spacer element
26708 * @return {Roo.Toolbar.Spacer} The spacer item
26710 addSpacer : function(){
26711 return this.addItem(new Roo.Toolbar.Spacer());
26715 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26716 * @return {Roo.Toolbar.Fill} The fill item
26718 addFill : function(){
26719 return this.addItem(new Roo.Toolbar.Fill());
26723 * Adds any standard HTML element to the toolbar
26724 * @param {String/HTMLElement/Element} el The element or id of the element to add
26725 * @return {Roo.Toolbar.Item} The element's item
26727 addElement : function(el){
26728 return this.addItem(new Roo.Toolbar.Item(el));
26731 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26732 * @type Roo.util.MixedCollection
26737 * Adds any Toolbar.Item or subclass
26738 * @param {Roo.Toolbar.Item} item
26739 * @return {Roo.Toolbar.Item} The item
26741 addItem : function(item){
26742 var td = this.nextBlock();
26744 this.items.add(item);
26749 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26750 * @param {Object/Array} config A button config or array of configs
26751 * @return {Roo.Toolbar.Button/Array}
26753 addButton : function(config){
26754 if(config instanceof Array){
26756 for(var i = 0, len = config.length; i < len; i++) {
26757 buttons.push(this.addButton(config[i]));
26762 if(!(config instanceof Roo.Toolbar.Button)){
26764 new Roo.Toolbar.SplitButton(config) :
26765 new Roo.Toolbar.Button(config);
26767 var td = this.nextBlock();
26774 * Adds text to the toolbar
26775 * @param {String} text The text to add
26776 * @return {Roo.Toolbar.Item} The element's item
26778 addText : function(text){
26779 return this.addItem(new Roo.Toolbar.TextItem(text));
26783 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26784 * @param {Number} index The index where the item is to be inserted
26785 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26786 * @return {Roo.Toolbar.Button/Item}
26788 insertButton : function(index, item){
26789 if(item instanceof Array){
26791 for(var i = 0, len = item.length; i < len; i++) {
26792 buttons.push(this.insertButton(index + i, item[i]));
26796 if (!(item instanceof Roo.Toolbar.Button)){
26797 item = new Roo.Toolbar.Button(item);
26799 var td = document.createElement("td");
26800 this.tr.insertBefore(td, this.tr.childNodes[index]);
26802 this.items.insert(index, item);
26807 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26808 * @param {Object} config
26809 * @return {Roo.Toolbar.Item} The element's item
26811 addDom : function(config, returnEl){
26812 var td = this.nextBlock();
26813 Roo.DomHelper.overwrite(td, config);
26814 var ti = new Roo.Toolbar.Item(td.firstChild);
26816 this.items.add(ti);
26821 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26822 * @type Roo.util.MixedCollection
26827 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26828 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26829 * @param {Roo.form.Field} field
26830 * @return {Roo.ToolbarItem}
26834 addField : function(field) {
26835 if (!this.fields) {
26837 this.fields = new Roo.util.MixedCollection(false, function(o){
26838 return o.id || ("item" + (++autoId));
26843 var td = this.nextBlock();
26845 var ti = new Roo.Toolbar.Item(td.firstChild);
26847 this.items.add(ti);
26848 this.fields.add(field);
26859 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26860 this.el.child('div').hide();
26868 this.el.child('div').show();
26872 nextBlock : function(){
26873 var td = document.createElement("td");
26874 this.tr.appendChild(td);
26879 destroy : function(){
26880 if(this.items){ // rendered?
26881 Roo.destroy.apply(Roo, this.items.items);
26883 if(this.fields){ // rendered?
26884 Roo.destroy.apply(Roo, this.fields.items);
26886 Roo.Element.uncache(this.el, this.tr);
26891 * @class Roo.Toolbar.Item
26892 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26894 * Creates a new Item
26895 * @param {HTMLElement} el
26897 Roo.Toolbar.Item = function(el){
26898 this.el = Roo.getDom(el);
26899 this.id = Roo.id(this.el);
26900 this.hidden = false;
26903 Roo.Toolbar.Item.prototype = {
26906 * Get this item's HTML Element
26907 * @return {HTMLElement}
26909 getEl : function(){
26914 render : function(td){
26916 td.appendChild(this.el);
26920 * Removes and destroys this item.
26922 destroy : function(){
26923 this.td.parentNode.removeChild(this.td);
26930 this.hidden = false;
26931 this.td.style.display = "";
26938 this.hidden = true;
26939 this.td.style.display = "none";
26943 * Convenience function for boolean show/hide.
26944 * @param {Boolean} visible true to show/false to hide
26946 setVisible: function(visible){
26955 * Try to focus this item.
26957 focus : function(){
26958 Roo.fly(this.el).focus();
26962 * Disables this item.
26964 disable : function(){
26965 Roo.fly(this.td).addClass("x-item-disabled");
26966 this.disabled = true;
26967 this.el.disabled = true;
26971 * Enables this item.
26973 enable : function(){
26974 Roo.fly(this.td).removeClass("x-item-disabled");
26975 this.disabled = false;
26976 this.el.disabled = false;
26982 * @class Roo.Toolbar.Separator
26983 * @extends Roo.Toolbar.Item
26984 * A simple toolbar separator class
26986 * Creates a new Separator
26988 Roo.Toolbar.Separator = function(){
26989 var s = document.createElement("span");
26990 s.className = "ytb-sep";
26991 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
26993 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
26994 enable:Roo.emptyFn,
26995 disable:Roo.emptyFn,
27000 * @class Roo.Toolbar.Spacer
27001 * @extends Roo.Toolbar.Item
27002 * A simple element that adds extra horizontal space to a toolbar.
27004 * Creates a new Spacer
27006 Roo.Toolbar.Spacer = function(){
27007 var s = document.createElement("div");
27008 s.className = "ytb-spacer";
27009 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27011 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27012 enable:Roo.emptyFn,
27013 disable:Roo.emptyFn,
27018 * @class Roo.Toolbar.Fill
27019 * @extends Roo.Toolbar.Spacer
27020 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27022 * Creates a new Spacer
27024 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27026 render : function(td){
27027 td.style.width = '100%';
27028 Roo.Toolbar.Fill.superclass.render.call(this, td);
27033 * @class Roo.Toolbar.TextItem
27034 * @extends Roo.Toolbar.Item
27035 * A simple class that renders text directly into a toolbar.
27037 * Creates a new TextItem
27038 * @param {String} text
27040 Roo.Toolbar.TextItem = function(text){
27041 if (typeof(text) == 'object') {
27044 var s = document.createElement("span");
27045 s.className = "ytb-text";
27046 s.innerHTML = text;
27047 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27049 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27050 enable:Roo.emptyFn,
27051 disable:Roo.emptyFn,
27056 * @class Roo.Toolbar.Button
27057 * @extends Roo.Button
27058 * A button that renders into a toolbar.
27060 * Creates a new Button
27061 * @param {Object} config A standard {@link Roo.Button} config object
27063 Roo.Toolbar.Button = function(config){
27064 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27066 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27067 render : function(td){
27069 Roo.Toolbar.Button.superclass.render.call(this, td);
27073 * Removes and destroys this button
27075 destroy : function(){
27076 Roo.Toolbar.Button.superclass.destroy.call(this);
27077 this.td.parentNode.removeChild(this.td);
27081 * Shows this button
27084 this.hidden = false;
27085 this.td.style.display = "";
27089 * Hides this button
27092 this.hidden = true;
27093 this.td.style.display = "none";
27097 * Disables this item
27099 disable : function(){
27100 Roo.fly(this.td).addClass("x-item-disabled");
27101 this.disabled = true;
27105 * Enables this item
27107 enable : function(){
27108 Roo.fly(this.td).removeClass("x-item-disabled");
27109 this.disabled = false;
27112 // backwards compat
27113 Roo.ToolbarButton = Roo.Toolbar.Button;
27116 * @class Roo.Toolbar.SplitButton
27117 * @extends Roo.SplitButton
27118 * A menu button that renders into a toolbar.
27120 * Creates a new SplitButton
27121 * @param {Object} config A standard {@link Roo.SplitButton} config object
27123 Roo.Toolbar.SplitButton = function(config){
27124 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27126 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27127 render : function(td){
27129 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27133 * Removes and destroys this button
27135 destroy : function(){
27136 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27137 this.td.parentNode.removeChild(this.td);
27141 * Shows this button
27144 this.hidden = false;
27145 this.td.style.display = "";
27149 * Hides this button
27152 this.hidden = true;
27153 this.td.style.display = "none";
27157 // backwards compat
27158 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27160 * Ext JS Library 1.1.1
27161 * Copyright(c) 2006-2007, Ext JS, LLC.
27163 * Originally Released Under LGPL - original licence link has changed is not relivant.
27166 * <script type="text/javascript">
27170 * @class Roo.PagingToolbar
27171 * @extends Roo.Toolbar
27172 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27174 * Create a new PagingToolbar
27175 * @param {Object} config The config object
27177 Roo.PagingToolbar = function(el, ds, config)
27179 // old args format still supported... - xtype is prefered..
27180 if (typeof(el) == 'object' && el.xtype) {
27181 // created from xtype...
27183 ds = el.dataSource;
27184 el = config.container;
27187 if (config.items) {
27188 items = config.items;
27192 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27195 this.renderButtons(this.el);
27198 // supprot items array.
27200 Roo.each(items, function(e) {
27201 this.add(Roo.factory(e));
27206 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27208 * @cfg {Roo.data.Store} dataSource
27209 * The underlying data store providing the paged data
27212 * @cfg {String/HTMLElement/Element} container
27213 * container The id or element that will contain the toolbar
27216 * @cfg {Boolean} displayInfo
27217 * True to display the displayMsg (defaults to false)
27220 * @cfg {Number} pageSize
27221 * The number of records to display per page (defaults to 20)
27225 * @cfg {String} displayMsg
27226 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27228 displayMsg : 'Displaying {0} - {1} of {2}',
27230 * @cfg {String} emptyMsg
27231 * The message to display when no records are found (defaults to "No data to display")
27233 emptyMsg : 'No data to display',
27235 * Customizable piece of the default paging text (defaults to "Page")
27238 beforePageText : "Page",
27240 * Customizable piece of the default paging text (defaults to "of %0")
27243 afterPageText : "of {0}",
27245 * Customizable piece of the default paging text (defaults to "First Page")
27248 firstText : "First Page",
27250 * Customizable piece of the default paging text (defaults to "Previous Page")
27253 prevText : "Previous Page",
27255 * Customizable piece of the default paging text (defaults to "Next Page")
27258 nextText : "Next Page",
27260 * Customizable piece of the default paging text (defaults to "Last Page")
27263 lastText : "Last Page",
27265 * Customizable piece of the default paging text (defaults to "Refresh")
27268 refreshText : "Refresh",
27271 renderButtons : function(el){
27272 Roo.PagingToolbar.superclass.render.call(this, el);
27273 this.first = this.addButton({
27274 tooltip: this.firstText,
27275 cls: "x-btn-icon x-grid-page-first",
27277 handler: this.onClick.createDelegate(this, ["first"])
27279 this.prev = this.addButton({
27280 tooltip: this.prevText,
27281 cls: "x-btn-icon x-grid-page-prev",
27283 handler: this.onClick.createDelegate(this, ["prev"])
27285 //this.addSeparator();
27286 this.add(this.beforePageText);
27287 this.field = Roo.get(this.addDom({
27292 cls: "x-grid-page-number"
27294 this.field.on("keydown", this.onPagingKeydown, this);
27295 this.field.on("focus", function(){this.dom.select();});
27296 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27297 this.field.setHeight(18);
27298 //this.addSeparator();
27299 this.next = this.addButton({
27300 tooltip: this.nextText,
27301 cls: "x-btn-icon x-grid-page-next",
27303 handler: this.onClick.createDelegate(this, ["next"])
27305 this.last = this.addButton({
27306 tooltip: this.lastText,
27307 cls: "x-btn-icon x-grid-page-last",
27309 handler: this.onClick.createDelegate(this, ["last"])
27311 //this.addSeparator();
27312 this.loading = this.addButton({
27313 tooltip: this.refreshText,
27314 cls: "x-btn-icon x-grid-loading",
27315 handler: this.onClick.createDelegate(this, ["refresh"])
27318 if(this.displayInfo){
27319 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27324 updateInfo : function(){
27325 if(this.displayEl){
27326 var count = this.ds.getCount();
27327 var msg = count == 0 ?
27331 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27333 this.displayEl.update(msg);
27338 onLoad : function(ds, r, o){
27339 this.cursor = o.params ? o.params.start : 0;
27340 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27342 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27343 this.field.dom.value = ap;
27344 this.first.setDisabled(ap == 1);
27345 this.prev.setDisabled(ap == 1);
27346 this.next.setDisabled(ap == ps);
27347 this.last.setDisabled(ap == ps);
27348 this.loading.enable();
27353 getPageData : function(){
27354 var total = this.ds.getTotalCount();
27357 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27358 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27363 onLoadError : function(){
27364 this.loading.enable();
27368 onPagingKeydown : function(e){
27369 var k = e.getKey();
27370 var d = this.getPageData();
27372 var v = this.field.dom.value, pageNum;
27373 if(!v || isNaN(pageNum = parseInt(v, 10))){
27374 this.field.dom.value = d.activePage;
27377 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27378 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27381 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))
27383 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27384 this.field.dom.value = pageNum;
27385 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27388 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27390 var v = this.field.dom.value, pageNum;
27391 var increment = (e.shiftKey) ? 10 : 1;
27392 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27394 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27395 this.field.dom.value = d.activePage;
27398 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27400 this.field.dom.value = parseInt(v, 10) + increment;
27401 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27402 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27409 beforeLoad : function(){
27411 this.loading.disable();
27416 onClick : function(which){
27420 ds.load({params:{start: 0, limit: this.pageSize}});
27423 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27426 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27429 var total = ds.getTotalCount();
27430 var extra = total % this.pageSize;
27431 var lastStart = extra ? (total - extra) : total-this.pageSize;
27432 ds.load({params:{start: lastStart, limit: this.pageSize}});
27435 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27441 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27442 * @param {Roo.data.Store} store The data store to unbind
27444 unbind : function(ds){
27445 ds.un("beforeload", this.beforeLoad, this);
27446 ds.un("load", this.onLoad, this);
27447 ds.un("loadexception", this.onLoadError, this);
27448 ds.un("remove", this.updateInfo, this);
27449 ds.un("add", this.updateInfo, this);
27450 this.ds = undefined;
27454 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27455 * @param {Roo.data.Store} store The data store to bind
27457 bind : function(ds){
27458 ds.on("beforeload", this.beforeLoad, this);
27459 ds.on("load", this.onLoad, this);
27460 ds.on("loadexception", this.onLoadError, this);
27461 ds.on("remove", this.updateInfo, this);
27462 ds.on("add", this.updateInfo, this);
27467 * Ext JS Library 1.1.1
27468 * Copyright(c) 2006-2007, Ext JS, LLC.
27470 * Originally Released Under LGPL - original licence link has changed is not relivant.
27473 * <script type="text/javascript">
27477 * @class Roo.Resizable
27478 * @extends Roo.util.Observable
27479 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27480 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27481 * 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
27482 * the element will be wrapped for you automatically.</p>
27483 * <p>Here is the list of valid resize handles:</p>
27486 ------ -------------------
27495 'hd' horizontal drag
27498 * <p>Here's an example showing the creation of a typical Resizable:</p>
27500 var resizer = new Roo.Resizable("element-id", {
27508 resizer.on("resize", myHandler);
27510 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27511 * resizer.east.setDisplayed(false);</p>
27512 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27513 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27514 * resize operation's new size (defaults to [0, 0])
27515 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27516 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27517 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27518 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27519 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27520 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27521 * @cfg {Number} width The width of the element in pixels (defaults to null)
27522 * @cfg {Number} height The height of the element in pixels (defaults to null)
27523 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27524 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27525 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27526 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27527 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27528 * in favor of the handles config option (defaults to false)
27529 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27530 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27531 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27532 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27533 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27534 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27535 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27536 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27537 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27538 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27539 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27541 * Create a new resizable component
27542 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27543 * @param {Object} config configuration options
27545 Roo.Resizable = function(el, config)
27547 this.el = Roo.get(el);
27549 if(config && config.wrap){
27550 config.resizeChild = this.el;
27551 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27552 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27553 this.el.setStyle("overflow", "hidden");
27554 this.el.setPositioning(config.resizeChild.getPositioning());
27555 config.resizeChild.clearPositioning();
27556 if(!config.width || !config.height){
27557 var csize = config.resizeChild.getSize();
27558 this.el.setSize(csize.width, csize.height);
27560 if(config.pinned && !config.adjustments){
27561 config.adjustments = "auto";
27565 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27566 this.proxy.unselectable();
27567 this.proxy.enableDisplayMode('block');
27569 Roo.apply(this, config);
27572 this.disableTrackOver = true;
27573 this.el.addClass("x-resizable-pinned");
27575 // if the element isn't positioned, make it relative
27576 var position = this.el.getStyle("position");
27577 if(position != "absolute" && position != "fixed"){
27578 this.el.setStyle("position", "relative");
27580 if(!this.handles){ // no handles passed, must be legacy style
27581 this.handles = 's,e,se';
27582 if(this.multiDirectional){
27583 this.handles += ',n,w';
27586 if(this.handles == "all"){
27587 this.handles = "n s e w ne nw se sw";
27589 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27590 var ps = Roo.Resizable.positions;
27591 for(var i = 0, len = hs.length; i < len; i++){
27592 if(hs[i] && ps[hs[i]]){
27593 var pos = ps[hs[i]];
27594 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27598 this.corner = this.southeast;
27600 // updateBox = the box can move..
27601 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27602 this.updateBox = true;
27605 this.activeHandle = null;
27607 if(this.resizeChild){
27608 if(typeof this.resizeChild == "boolean"){
27609 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27611 this.resizeChild = Roo.get(this.resizeChild, true);
27615 if(this.adjustments == "auto"){
27616 var rc = this.resizeChild;
27617 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27618 if(rc && (hw || hn)){
27619 rc.position("relative");
27620 rc.setLeft(hw ? hw.el.getWidth() : 0);
27621 rc.setTop(hn ? hn.el.getHeight() : 0);
27623 this.adjustments = [
27624 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27625 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27629 if(this.draggable){
27630 this.dd = this.dynamic ?
27631 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27632 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27638 * @event beforeresize
27639 * Fired before resize is allowed. Set enabled to false to cancel resize.
27640 * @param {Roo.Resizable} this
27641 * @param {Roo.EventObject} e The mousedown event
27643 "beforeresize" : true,
27646 * Fired after a resize.
27647 * @param {Roo.Resizable} this
27648 * @param {Number} width The new width
27649 * @param {Number} height The new height
27650 * @param {Roo.EventObject} e The mouseup event
27655 if(this.width !== null && this.height !== null){
27656 this.resizeTo(this.width, this.height);
27658 this.updateChildSize();
27661 this.el.dom.style.zoom = 1;
27663 Roo.Resizable.superclass.constructor.call(this);
27666 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27667 resizeChild : false,
27668 adjustments : [0, 0],
27678 multiDirectional : false,
27679 disableTrackOver : false,
27680 easing : 'easeOutStrong',
27681 widthIncrement : 0,
27682 heightIncrement : 0,
27686 preserveRatio : false,
27687 transparent: false,
27693 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27695 constrainTo: undefined,
27697 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27699 resizeRegion: undefined,
27703 * Perform a manual resize
27704 * @param {Number} width
27705 * @param {Number} height
27707 resizeTo : function(width, height){
27708 this.el.setSize(width, height);
27709 this.updateChildSize();
27710 this.fireEvent("resize", this, width, height, null);
27714 startSizing : function(e, handle){
27715 this.fireEvent("beforeresize", this, e);
27716 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27719 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27720 this.overlay.unselectable();
27721 this.overlay.enableDisplayMode("block");
27722 this.overlay.on("mousemove", this.onMouseMove, this);
27723 this.overlay.on("mouseup", this.onMouseUp, this);
27725 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27727 this.resizing = true;
27728 this.startBox = this.el.getBox();
27729 this.startPoint = e.getXY();
27730 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27731 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27733 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27734 this.overlay.show();
27736 if(this.constrainTo) {
27737 var ct = Roo.get(this.constrainTo);
27738 this.resizeRegion = ct.getRegion().adjust(
27739 ct.getFrameWidth('t'),
27740 ct.getFrameWidth('l'),
27741 -ct.getFrameWidth('b'),
27742 -ct.getFrameWidth('r')
27746 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27748 this.proxy.setBox(this.startBox);
27750 this.proxy.setStyle('visibility', 'visible');
27756 onMouseDown : function(handle, e){
27759 this.activeHandle = handle;
27760 this.startSizing(e, handle);
27765 onMouseUp : function(e){
27766 var size = this.resizeElement();
27767 this.resizing = false;
27769 this.overlay.hide();
27771 this.fireEvent("resize", this, size.width, size.height, e);
27775 updateChildSize : function(){
27776 if(this.resizeChild){
27778 var child = this.resizeChild;
27779 var adj = this.adjustments;
27780 if(el.dom.offsetWidth){
27781 var b = el.getSize(true);
27782 child.setSize(b.width+adj[0], b.height+adj[1]);
27784 // Second call here for IE
27785 // The first call enables instant resizing and
27786 // the second call corrects scroll bars if they
27789 setTimeout(function(){
27790 if(el.dom.offsetWidth){
27791 var b = el.getSize(true);
27792 child.setSize(b.width+adj[0], b.height+adj[1]);
27800 snap : function(value, inc, min){
27801 if(!inc || !value) return value;
27802 var newValue = value;
27803 var m = value % inc;
27806 newValue = value + (inc-m);
27808 newValue = value - m;
27811 return Math.max(min, newValue);
27815 resizeElement : function(){
27816 var box = this.proxy.getBox();
27817 if(this.updateBox){
27818 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27820 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27822 this.updateChildSize();
27830 constrain : function(v, diff, m, mx){
27833 }else if(v - diff > mx){
27840 onMouseMove : function(e){
27842 try{// try catch so if something goes wrong the user doesn't get hung
27844 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27848 //var curXY = this.startPoint;
27849 var curSize = this.curSize || this.startBox;
27850 var x = this.startBox.x, y = this.startBox.y;
27851 var ox = x, oy = y;
27852 var w = curSize.width, h = curSize.height;
27853 var ow = w, oh = h;
27854 var mw = this.minWidth, mh = this.minHeight;
27855 var mxw = this.maxWidth, mxh = this.maxHeight;
27856 var wi = this.widthIncrement;
27857 var hi = this.heightIncrement;
27859 var eventXY = e.getXY();
27860 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27861 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27863 var pos = this.activeHandle.position;
27868 w = Math.min(Math.max(mw, w), mxw);
27873 h = Math.min(Math.max(mh, h), mxh);
27878 w = Math.min(Math.max(mw, w), mxw);
27879 h = Math.min(Math.max(mh, h), mxh);
27882 diffY = this.constrain(h, diffY, mh, mxh);
27889 var adiffX = Math.abs(diffX);
27890 var sub = (adiffX % wi); // how much
27891 if (sub > (wi/2)) { // far enough to snap
27892 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
27894 // remove difference..
27895 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
27899 x = Math.max(this.minX, x);
27902 diffX = this.constrain(w, diffX, mw, mxw);
27908 w = Math.min(Math.max(mw, w), mxw);
27909 diffY = this.constrain(h, diffY, mh, mxh);
27914 diffX = this.constrain(w, diffX, mw, mxw);
27915 diffY = this.constrain(h, diffY, mh, mxh);
27922 diffX = this.constrain(w, diffX, mw, mxw);
27924 h = Math.min(Math.max(mh, h), mxh);
27930 var sw = this.snap(w, wi, mw);
27931 var sh = this.snap(h, hi, mh);
27932 if(sw != w || sh != h){
27955 if(this.preserveRatio){
27960 h = Math.min(Math.max(mh, h), mxh);
27965 w = Math.min(Math.max(mw, w), mxw);
27970 w = Math.min(Math.max(mw, w), mxw);
27976 w = Math.min(Math.max(mw, w), mxw);
27982 h = Math.min(Math.max(mh, h), mxh);
27990 h = Math.min(Math.max(mh, h), mxh);
28000 h = Math.min(Math.max(mh, h), mxh);
28008 if (pos == 'hdrag') {
28011 this.proxy.setBounds(x, y, w, h);
28013 this.resizeElement();
28020 handleOver : function(){
28022 this.el.addClass("x-resizable-over");
28027 handleOut : function(){
28028 if(!this.resizing){
28029 this.el.removeClass("x-resizable-over");
28034 * Returns the element this component is bound to.
28035 * @return {Roo.Element}
28037 getEl : function(){
28042 * Returns the resizeChild element (or null).
28043 * @return {Roo.Element}
28045 getResizeChild : function(){
28046 return this.resizeChild;
28050 * Destroys this resizable. If the element was wrapped and
28051 * removeEl is not true then the element remains.
28052 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28054 destroy : function(removeEl){
28055 this.proxy.remove();
28057 this.overlay.removeAllListeners();
28058 this.overlay.remove();
28060 var ps = Roo.Resizable.positions;
28062 if(typeof ps[k] != "function" && this[ps[k]]){
28063 var h = this[ps[k]];
28064 h.el.removeAllListeners();
28069 this.el.update("");
28076 // hash to map config positions to true positions
28077 Roo.Resizable.positions = {
28078 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28083 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28085 // only initialize the template if resizable is used
28086 var tpl = Roo.DomHelper.createTemplate(
28087 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28090 Roo.Resizable.Handle.prototype.tpl = tpl;
28092 this.position = pos;
28094 // show north drag fro topdra
28095 var handlepos = pos == 'hdrag' ? 'north' : pos;
28097 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28098 if (pos == 'hdrag') {
28099 this.el.setStyle('cursor', 'pointer');
28101 this.el.unselectable();
28103 this.el.setOpacity(0);
28105 this.el.on("mousedown", this.onMouseDown, this);
28106 if(!disableTrackOver){
28107 this.el.on("mouseover", this.onMouseOver, this);
28108 this.el.on("mouseout", this.onMouseOut, this);
28113 Roo.Resizable.Handle.prototype = {
28114 afterResize : function(rz){
28118 onMouseDown : function(e){
28119 this.rz.onMouseDown(this, e);
28122 onMouseOver : function(e){
28123 this.rz.handleOver(this, e);
28126 onMouseOut : function(e){
28127 this.rz.handleOut(this, e);
28131 * Ext JS Library 1.1.1
28132 * Copyright(c) 2006-2007, Ext JS, LLC.
28134 * Originally Released Under LGPL - original licence link has changed is not relivant.
28137 * <script type="text/javascript">
28141 * @class Roo.Editor
28142 * @extends Roo.Component
28143 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28145 * Create a new Editor
28146 * @param {Roo.form.Field} field The Field object (or descendant)
28147 * @param {Object} config The config object
28149 Roo.Editor = function(field, config){
28150 Roo.Editor.superclass.constructor.call(this, config);
28151 this.field = field;
28154 * @event beforestartedit
28155 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28156 * false from the handler of this event.
28157 * @param {Editor} this
28158 * @param {Roo.Element} boundEl The underlying element bound to this editor
28159 * @param {Mixed} value The field value being set
28161 "beforestartedit" : true,
28164 * Fires when this editor is displayed
28165 * @param {Roo.Element} boundEl The underlying element bound to this editor
28166 * @param {Mixed} value The starting field value
28168 "startedit" : true,
28170 * @event beforecomplete
28171 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28172 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28173 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28174 * event will not fire since no edit actually occurred.
28175 * @param {Editor} this
28176 * @param {Mixed} value The current field value
28177 * @param {Mixed} startValue The original field value
28179 "beforecomplete" : true,
28182 * Fires after editing is complete and any changed value has been written to the underlying field.
28183 * @param {Editor} this
28184 * @param {Mixed} value The current field value
28185 * @param {Mixed} startValue The original field value
28189 * @event specialkey
28190 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28191 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28192 * @param {Roo.form.Field} this
28193 * @param {Roo.EventObject} e The event object
28195 "specialkey" : true
28199 Roo.extend(Roo.Editor, Roo.Component, {
28201 * @cfg {Boolean/String} autosize
28202 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28203 * or "height" to adopt the height only (defaults to false)
28206 * @cfg {Boolean} revertInvalid
28207 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28208 * validation fails (defaults to true)
28211 * @cfg {Boolean} ignoreNoChange
28212 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28213 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28214 * will never be ignored.
28217 * @cfg {Boolean} hideEl
28218 * False to keep the bound element visible while the editor is displayed (defaults to true)
28221 * @cfg {Mixed} value
28222 * The data value of the underlying field (defaults to "")
28226 * @cfg {String} alignment
28227 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28231 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28232 * for bottom-right shadow (defaults to "frame")
28236 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28240 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28242 completeOnEnter : false,
28244 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28246 cancelOnEsc : false,
28248 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28253 onRender : function(ct, position){
28254 this.el = new Roo.Layer({
28255 shadow: this.shadow,
28261 constrain: this.constrain
28263 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28264 if(this.field.msgTarget != 'title'){
28265 this.field.msgTarget = 'qtip';
28267 this.field.render(this.el);
28269 this.field.el.dom.setAttribute('autocomplete', 'off');
28271 this.field.on("specialkey", this.onSpecialKey, this);
28272 if(this.swallowKeys){
28273 this.field.el.swallowEvent(['keydown','keypress']);
28276 this.field.on("blur", this.onBlur, this);
28277 if(this.field.grow){
28278 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28282 onSpecialKey : function(field, e){
28283 //Roo.log('editor onSpecialKey');
28284 if(this.completeOnEnter && e.getKey() == e.ENTER){
28286 this.completeEdit();
28287 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
28290 this.fireEvent('specialkey', field, e);
28295 * Starts the editing process and shows the editor.
28296 * @param {String/HTMLElement/Element} el The element to edit
28297 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28298 * to the innerHTML of el.
28300 startEdit : function(el, value){
28302 this.completeEdit();
28304 this.boundEl = Roo.get(el);
28305 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28306 if(!this.rendered){
28307 this.render(this.parentEl || document.body);
28309 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28312 this.startValue = v;
28313 this.field.setValue(v);
28315 var sz = this.boundEl.getSize();
28316 switch(this.autoSize){
28318 this.setSize(sz.width, "");
28321 this.setSize("", sz.height);
28324 this.setSize(sz.width, sz.height);
28327 this.el.alignTo(this.boundEl, this.alignment);
28328 this.editing = true;
28330 Roo.QuickTips.disable();
28336 * Sets the height and width of this editor.
28337 * @param {Number} width The new width
28338 * @param {Number} height The new height
28340 setSize : function(w, h){
28341 this.field.setSize(w, h);
28348 * Realigns the editor to the bound field based on the current alignment config value.
28350 realign : function(){
28351 this.el.alignTo(this.boundEl, this.alignment);
28355 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28356 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28358 completeEdit : function(remainVisible){
28362 var v = this.getValue();
28363 if(this.revertInvalid !== false && !this.field.isValid()){
28364 v = this.startValue;
28365 this.cancelEdit(true);
28367 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28368 this.editing = false;
28372 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28373 this.editing = false;
28374 if(this.updateEl && this.boundEl){
28375 this.boundEl.update(v);
28377 if(remainVisible !== true){
28380 this.fireEvent("complete", this, v, this.startValue);
28385 onShow : function(){
28387 if(this.hideEl !== false){
28388 this.boundEl.hide();
28391 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28392 this.fixIEFocus = true;
28393 this.deferredFocus.defer(50, this);
28395 this.field.focus();
28397 this.fireEvent("startedit", this.boundEl, this.startValue);
28400 deferredFocus : function(){
28402 this.field.focus();
28407 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28408 * reverted to the original starting value.
28409 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28410 * cancel (defaults to false)
28412 cancelEdit : function(remainVisible){
28414 this.setValue(this.startValue);
28415 if(remainVisible !== true){
28422 onBlur : function(){
28423 if(this.allowBlur !== true && this.editing){
28424 this.completeEdit();
28429 onHide : function(){
28431 this.completeEdit();
28435 if(this.field.collapse){
28436 this.field.collapse();
28439 if(this.hideEl !== false){
28440 this.boundEl.show();
28443 Roo.QuickTips.enable();
28448 * Sets the data value of the editor
28449 * @param {Mixed} value Any valid value supported by the underlying field
28451 setValue : function(v){
28452 this.field.setValue(v);
28456 * Gets the data value of the editor
28457 * @return {Mixed} The data value
28459 getValue : function(){
28460 return this.field.getValue();
28464 * Ext JS Library 1.1.1
28465 * Copyright(c) 2006-2007, Ext JS, LLC.
28467 * Originally Released Under LGPL - original licence link has changed is not relivant.
28470 * <script type="text/javascript">
28474 * @class Roo.BasicDialog
28475 * @extends Roo.util.Observable
28476 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28478 var dlg = new Roo.BasicDialog("my-dlg", {
28487 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28488 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28489 dlg.addButton('Cancel', dlg.hide, dlg);
28492 <b>A Dialog should always be a direct child of the body element.</b>
28493 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28494 * @cfg {String} title Default text to display in the title bar (defaults to null)
28495 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28496 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28497 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28498 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28499 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28500 * (defaults to null with no animation)
28501 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28502 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28503 * property for valid values (defaults to 'all')
28504 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28505 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28506 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28507 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28508 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28509 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28510 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28511 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28512 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28513 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28514 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28515 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28516 * draggable = true (defaults to false)
28517 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28518 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28519 * shadow (defaults to false)
28520 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28521 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28522 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28523 * @cfg {Array} buttons Array of buttons
28524 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28526 * Create a new BasicDialog.
28527 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28528 * @param {Object} config Configuration options
28530 Roo.BasicDialog = function(el, config){
28531 this.el = Roo.get(el);
28532 var dh = Roo.DomHelper;
28533 if(!this.el && config && config.autoCreate){
28534 if(typeof config.autoCreate == "object"){
28535 if(!config.autoCreate.id){
28536 config.autoCreate.id = el;
28538 this.el = dh.append(document.body,
28539 config.autoCreate, true);
28541 this.el = dh.append(document.body,
28542 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28546 el.setDisplayed(true);
28547 el.hide = this.hideAction;
28549 el.addClass("x-dlg");
28551 Roo.apply(this, config);
28553 this.proxy = el.createProxy("x-dlg-proxy");
28554 this.proxy.hide = this.hideAction;
28555 this.proxy.setOpacity(.5);
28559 el.setWidth(config.width);
28562 el.setHeight(config.height);
28564 this.size = el.getSize();
28565 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28566 this.xy = [config.x,config.y];
28568 this.xy = el.getCenterXY(true);
28570 /** The header element @type Roo.Element */
28571 this.header = el.child("> .x-dlg-hd");
28572 /** The body element @type Roo.Element */
28573 this.body = el.child("> .x-dlg-bd");
28574 /** The footer element @type Roo.Element */
28575 this.footer = el.child("> .x-dlg-ft");
28578 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28581 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28584 this.header.unselectable();
28586 this.header.update(this.title);
28588 // this element allows the dialog to be focused for keyboard event
28589 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28590 this.focusEl.swallowEvent("click", true);
28592 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28594 // wrap the body and footer for special rendering
28595 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28597 this.bwrap.dom.appendChild(this.footer.dom);
28600 this.bg = this.el.createChild({
28601 tag: "div", cls:"x-dlg-bg",
28602 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28604 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28607 if(this.autoScroll !== false && !this.autoTabs){
28608 this.body.setStyle("overflow", "auto");
28611 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28613 if(this.closable !== false){
28614 this.el.addClass("x-dlg-closable");
28615 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28616 this.close.on("click", this.closeClick, this);
28617 this.close.addClassOnOver("x-dlg-close-over");
28619 if(this.collapsible !== false){
28620 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28621 this.collapseBtn.on("click", this.collapseClick, this);
28622 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28623 this.header.on("dblclick", this.collapseClick, this);
28625 if(this.resizable !== false){
28626 this.el.addClass("x-dlg-resizable");
28627 this.resizer = new Roo.Resizable(el, {
28628 minWidth: this.minWidth || 80,
28629 minHeight:this.minHeight || 80,
28630 handles: this.resizeHandles || "all",
28633 this.resizer.on("beforeresize", this.beforeResize, this);
28634 this.resizer.on("resize", this.onResize, this);
28636 if(this.draggable !== false){
28637 el.addClass("x-dlg-draggable");
28638 if (!this.proxyDrag) {
28639 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28642 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28644 dd.setHandleElId(this.header.id);
28645 dd.endDrag = this.endMove.createDelegate(this);
28646 dd.startDrag = this.startMove.createDelegate(this);
28647 dd.onDrag = this.onDrag.createDelegate(this);
28652 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28653 this.mask.enableDisplayMode("block");
28655 this.el.addClass("x-dlg-modal");
28658 this.shadow = new Roo.Shadow({
28659 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28660 offset : this.shadowOffset
28663 this.shadowOffset = 0;
28665 if(Roo.useShims && this.shim !== false){
28666 this.shim = this.el.createShim();
28667 this.shim.hide = this.hideAction;
28675 if (this.buttons) {
28676 var bts= this.buttons;
28678 Roo.each(bts, function(b) {
28687 * Fires when a key is pressed
28688 * @param {Roo.BasicDialog} this
28689 * @param {Roo.EventObject} e
28694 * Fires when this dialog is moved by the user.
28695 * @param {Roo.BasicDialog} this
28696 * @param {Number} x The new page X
28697 * @param {Number} y The new page Y
28702 * Fires when this dialog is resized by the user.
28703 * @param {Roo.BasicDialog} this
28704 * @param {Number} width The new width
28705 * @param {Number} height The new height
28709 * @event beforehide
28710 * Fires before this dialog is hidden.
28711 * @param {Roo.BasicDialog} this
28713 "beforehide" : true,
28716 * Fires when this dialog is hidden.
28717 * @param {Roo.BasicDialog} this
28721 * @event beforeshow
28722 * Fires before this dialog is shown.
28723 * @param {Roo.BasicDialog} this
28725 "beforeshow" : true,
28728 * Fires when this dialog is shown.
28729 * @param {Roo.BasicDialog} this
28733 el.on("keydown", this.onKeyDown, this);
28734 el.on("mousedown", this.toFront, this);
28735 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28737 Roo.DialogManager.register(this);
28738 Roo.BasicDialog.superclass.constructor.call(this);
28741 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28742 shadowOffset: Roo.isIE ? 6 : 5,
28745 minButtonWidth: 75,
28746 defaultButton: null,
28747 buttonAlign: "right",
28752 * Sets the dialog title text
28753 * @param {String} text The title text to display
28754 * @return {Roo.BasicDialog} this
28756 setTitle : function(text){
28757 this.header.update(text);
28762 closeClick : function(){
28767 collapseClick : function(){
28768 this[this.collapsed ? "expand" : "collapse"]();
28772 * Collapses the dialog to its minimized state (only the title bar is visible).
28773 * Equivalent to the user clicking the collapse dialog button.
28775 collapse : function(){
28776 if(!this.collapsed){
28777 this.collapsed = true;
28778 this.el.addClass("x-dlg-collapsed");
28779 this.restoreHeight = this.el.getHeight();
28780 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28785 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28786 * clicking the expand dialog button.
28788 expand : function(){
28789 if(this.collapsed){
28790 this.collapsed = false;
28791 this.el.removeClass("x-dlg-collapsed");
28792 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28797 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28798 * @return {Roo.TabPanel} The tabs component
28800 initTabs : function(){
28801 var tabs = this.getTabs();
28802 while(tabs.getTab(0)){
28805 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28807 tabs.addTab(Roo.id(dom), dom.title);
28815 beforeResize : function(){
28816 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28820 onResize : function(){
28821 this.refreshSize();
28822 this.syncBodyHeight();
28823 this.adjustAssets();
28825 this.fireEvent("resize", this, this.size.width, this.size.height);
28829 onKeyDown : function(e){
28830 if(this.isVisible()){
28831 this.fireEvent("keydown", this, e);
28836 * Resizes the dialog.
28837 * @param {Number} width
28838 * @param {Number} height
28839 * @return {Roo.BasicDialog} this
28841 resizeTo : function(width, height){
28842 this.el.setSize(width, height);
28843 this.size = {width: width, height: height};
28844 this.syncBodyHeight();
28845 if(this.fixedcenter){
28848 if(this.isVisible()){
28849 this.constrainXY();
28850 this.adjustAssets();
28852 this.fireEvent("resize", this, width, height);
28858 * Resizes the dialog to fit the specified content size.
28859 * @param {Number} width
28860 * @param {Number} height
28861 * @return {Roo.BasicDialog} this
28863 setContentSize : function(w, h){
28864 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28865 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28866 //if(!this.el.isBorderBox()){
28867 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28868 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28871 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28872 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28874 this.resizeTo(w, h);
28879 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28880 * executed in response to a particular key being pressed while the dialog is active.
28881 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28882 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28883 * @param {Function} fn The function to call
28884 * @param {Object} scope (optional) The scope of the function
28885 * @return {Roo.BasicDialog} this
28887 addKeyListener : function(key, fn, scope){
28888 var keyCode, shift, ctrl, alt;
28889 if(typeof key == "object" && !(key instanceof Array)){
28890 keyCode = key["key"];
28891 shift = key["shift"];
28892 ctrl = key["ctrl"];
28897 var handler = function(dlg, e){
28898 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
28899 var k = e.getKey();
28900 if(keyCode instanceof Array){
28901 for(var i = 0, len = keyCode.length; i < len; i++){
28902 if(keyCode[i] == k){
28903 fn.call(scope || window, dlg, k, e);
28909 fn.call(scope || window, dlg, k, e);
28914 this.on("keydown", handler);
28919 * Returns the TabPanel component (creates it if it doesn't exist).
28920 * Note: If you wish to simply check for the existence of tabs without creating them,
28921 * check for a null 'tabs' property.
28922 * @return {Roo.TabPanel} The tabs component
28924 getTabs : function(){
28926 this.el.addClass("x-dlg-auto-tabs");
28927 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
28928 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
28934 * Adds a button to the footer section of the dialog.
28935 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28936 * object or a valid Roo.DomHelper element config
28937 * @param {Function} handler The function called when the button is clicked
28938 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
28939 * @return {Roo.Button} The new button
28941 addButton : function(config, handler, scope){
28942 var dh = Roo.DomHelper;
28944 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
28946 if(!this.btnContainer){
28947 var tb = this.footer.createChild({
28949 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
28950 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28952 this.btnContainer = tb.firstChild.firstChild.firstChild;
28957 minWidth: this.minButtonWidth,
28960 if(typeof config == "string"){
28961 bconfig.text = config;
28964 bconfig.dhconfig = config;
28966 Roo.apply(bconfig, config);
28970 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
28971 bconfig.position = Math.max(0, bconfig.position);
28972 fc = this.btnContainer.childNodes[bconfig.position];
28975 var btn = new Roo.Button(
28977 this.btnContainer.insertBefore(document.createElement("td"),fc)
28978 : this.btnContainer.appendChild(document.createElement("td")),
28979 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
28982 this.syncBodyHeight();
28985 * Array of all the buttons that have been added to this dialog via addButton
28990 this.buttons.push(btn);
28995 * Sets the default button to be focused when the dialog is displayed.
28996 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
28997 * @return {Roo.BasicDialog} this
28999 setDefaultButton : function(btn){
29000 this.defaultButton = btn;
29005 getHeaderFooterHeight : function(safe){
29008 height += this.header.getHeight();
29011 var fm = this.footer.getMargins();
29012 height += (this.footer.getHeight()+fm.top+fm.bottom);
29014 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29015 height += this.centerBg.getPadding("tb");
29020 syncBodyHeight : function(){
29021 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29022 var height = this.size.height - this.getHeaderFooterHeight(false);
29023 bd.setHeight(height-bd.getMargins("tb"));
29024 var hh = this.header.getHeight();
29025 var h = this.size.height-hh;
29027 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29028 bw.setHeight(h-cb.getPadding("tb"));
29029 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29030 bd.setWidth(bw.getWidth(true));
29032 this.tabs.syncHeight();
29034 this.tabs.el.repaint();
29040 * Restores the previous state of the dialog if Roo.state is configured.
29041 * @return {Roo.BasicDialog} this
29043 restoreState : function(){
29044 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29045 if(box && box.width){
29046 this.xy = [box.x, box.y];
29047 this.resizeTo(box.width, box.height);
29053 beforeShow : function(){
29055 if(this.fixedcenter){
29056 this.xy = this.el.getCenterXY(true);
29059 Roo.get(document.body).addClass("x-body-masked");
29060 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29063 this.constrainXY();
29067 animShow : function(){
29068 var b = Roo.get(this.animateTarget).getBox();
29069 this.proxy.setSize(b.width, b.height);
29070 this.proxy.setLocation(b.x, b.y);
29072 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29073 true, .35, this.showEl.createDelegate(this));
29077 * Shows the dialog.
29078 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29079 * @return {Roo.BasicDialog} this
29081 show : function(animateTarget){
29082 if (this.fireEvent("beforeshow", this) === false){
29085 if(this.syncHeightBeforeShow){
29086 this.syncBodyHeight();
29087 }else if(this.firstShow){
29088 this.firstShow = false;
29089 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29091 this.animateTarget = animateTarget || this.animateTarget;
29092 if(!this.el.isVisible()){
29094 if(this.animateTarget && Roo.get(this.animateTarget)){
29104 showEl : function(){
29106 this.el.setXY(this.xy);
29108 this.adjustAssets(true);
29111 // IE peekaboo bug - fix found by Dave Fenwick
29115 this.fireEvent("show", this);
29119 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29120 * dialog itself will receive focus.
29122 focus : function(){
29123 if(this.defaultButton){
29124 this.defaultButton.focus();
29126 this.focusEl.focus();
29131 constrainXY : function(){
29132 if(this.constraintoviewport !== false){
29133 if(!this.viewSize){
29134 if(this.container){
29135 var s = this.container.getSize();
29136 this.viewSize = [s.width, s.height];
29138 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29141 var s = Roo.get(this.container||document).getScroll();
29143 var x = this.xy[0], y = this.xy[1];
29144 var w = this.size.width, h = this.size.height;
29145 var vw = this.viewSize[0], vh = this.viewSize[1];
29146 // only move it if it needs it
29148 // first validate right/bottom
29149 if(x + w > vw+s.left){
29153 if(y + h > vh+s.top){
29157 // then make sure top/left isn't negative
29169 if(this.isVisible()){
29170 this.el.setLocation(x, y);
29171 this.adjustAssets();
29178 onDrag : function(){
29179 if(!this.proxyDrag){
29180 this.xy = this.el.getXY();
29181 this.adjustAssets();
29186 adjustAssets : function(doShow){
29187 var x = this.xy[0], y = this.xy[1];
29188 var w = this.size.width, h = this.size.height;
29189 if(doShow === true){
29191 this.shadow.show(this.el);
29197 if(this.shadow && this.shadow.isVisible()){
29198 this.shadow.show(this.el);
29200 if(this.shim && this.shim.isVisible()){
29201 this.shim.setBounds(x, y, w, h);
29206 adjustViewport : function(w, h){
29208 w = Roo.lib.Dom.getViewWidth();
29209 h = Roo.lib.Dom.getViewHeight();
29212 this.viewSize = [w, h];
29213 if(this.modal && this.mask.isVisible()){
29214 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29215 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29217 if(this.isVisible()){
29218 this.constrainXY();
29223 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29224 * shadow, proxy, mask, etc.) Also removes all event listeners.
29225 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29227 destroy : function(removeEl){
29228 if(this.isVisible()){
29229 this.animateTarget = null;
29232 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29234 this.tabs.destroy(removeEl);
29247 for(var i = 0, len = this.buttons.length; i < len; i++){
29248 this.buttons[i].destroy();
29251 this.el.removeAllListeners();
29252 if(removeEl === true){
29253 this.el.update("");
29256 Roo.DialogManager.unregister(this);
29260 startMove : function(){
29261 if(this.proxyDrag){
29264 if(this.constraintoviewport !== false){
29265 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29270 endMove : function(){
29271 if(!this.proxyDrag){
29272 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29274 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29277 this.refreshSize();
29278 this.adjustAssets();
29280 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29284 * Brings this dialog to the front of any other visible dialogs
29285 * @return {Roo.BasicDialog} this
29287 toFront : function(){
29288 Roo.DialogManager.bringToFront(this);
29293 * Sends this dialog to the back (under) of any other visible dialogs
29294 * @return {Roo.BasicDialog} this
29296 toBack : function(){
29297 Roo.DialogManager.sendToBack(this);
29302 * Centers this dialog in the viewport
29303 * @return {Roo.BasicDialog} this
29305 center : function(){
29306 var xy = this.el.getCenterXY(true);
29307 this.moveTo(xy[0], xy[1]);
29312 * Moves the dialog's top-left corner to the specified point
29313 * @param {Number} x
29314 * @param {Number} y
29315 * @return {Roo.BasicDialog} this
29317 moveTo : function(x, y){
29319 if(this.isVisible()){
29320 this.el.setXY(this.xy);
29321 this.adjustAssets();
29327 * Aligns the dialog to the specified element
29328 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29329 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29330 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29331 * @return {Roo.BasicDialog} this
29333 alignTo : function(element, position, offsets){
29334 this.xy = this.el.getAlignToXY(element, position, offsets);
29335 if(this.isVisible()){
29336 this.el.setXY(this.xy);
29337 this.adjustAssets();
29343 * Anchors an element to another element and realigns it when the window is resized.
29344 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29345 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29346 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29347 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29348 * is a number, it is used as the buffer delay (defaults to 50ms).
29349 * @return {Roo.BasicDialog} this
29351 anchorTo : function(el, alignment, offsets, monitorScroll){
29352 var action = function(){
29353 this.alignTo(el, alignment, offsets);
29355 Roo.EventManager.onWindowResize(action, this);
29356 var tm = typeof monitorScroll;
29357 if(tm != 'undefined'){
29358 Roo.EventManager.on(window, 'scroll', action, this,
29359 {buffer: tm == 'number' ? monitorScroll : 50});
29366 * Returns true if the dialog is visible
29367 * @return {Boolean}
29369 isVisible : function(){
29370 return this.el.isVisible();
29374 animHide : function(callback){
29375 var b = Roo.get(this.animateTarget).getBox();
29377 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29379 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29380 this.hideEl.createDelegate(this, [callback]));
29384 * Hides the dialog.
29385 * @param {Function} callback (optional) Function to call when the dialog is hidden
29386 * @return {Roo.BasicDialog} this
29388 hide : function(callback){
29389 if (this.fireEvent("beforehide", this) === false){
29393 this.shadow.hide();
29398 // sometimes animateTarget seems to get set.. causing problems...
29399 // this just double checks..
29400 if(this.animateTarget && Roo.get(this.animateTarget)) {
29401 this.animHide(callback);
29404 this.hideEl(callback);
29410 hideEl : function(callback){
29414 Roo.get(document.body).removeClass("x-body-masked");
29416 this.fireEvent("hide", this);
29417 if(typeof callback == "function"){
29423 hideAction : function(){
29424 this.setLeft("-10000px");
29425 this.setTop("-10000px");
29426 this.setStyle("visibility", "hidden");
29430 refreshSize : function(){
29431 this.size = this.el.getSize();
29432 this.xy = this.el.getXY();
29433 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29437 // z-index is managed by the DialogManager and may be overwritten at any time
29438 setZIndex : function(index){
29440 this.mask.setStyle("z-index", index);
29443 this.shim.setStyle("z-index", ++index);
29446 this.shadow.setZIndex(++index);
29448 this.el.setStyle("z-index", ++index);
29450 this.proxy.setStyle("z-index", ++index);
29453 this.resizer.proxy.setStyle("z-index", ++index);
29456 this.lastZIndex = index;
29460 * Returns the element for this dialog
29461 * @return {Roo.Element} The underlying dialog Element
29463 getEl : function(){
29469 * @class Roo.DialogManager
29470 * Provides global access to BasicDialogs that have been created and
29471 * support for z-indexing (layering) multiple open dialogs.
29473 Roo.DialogManager = function(){
29475 var accessList = [];
29479 var sortDialogs = function(d1, d2){
29480 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29484 var orderDialogs = function(){
29485 accessList.sort(sortDialogs);
29486 var seed = Roo.DialogManager.zseed;
29487 for(var i = 0, len = accessList.length; i < len; i++){
29488 var dlg = accessList[i];
29490 dlg.setZIndex(seed + (i*10));
29497 * The starting z-index for BasicDialogs (defaults to 9000)
29498 * @type Number The z-index value
29503 register : function(dlg){
29504 list[dlg.id] = dlg;
29505 accessList.push(dlg);
29509 unregister : function(dlg){
29510 delete list[dlg.id];
29513 if(!accessList.indexOf){
29514 for( i = 0, len = accessList.length; i < len; i++){
29515 if(accessList[i] == dlg){
29516 accessList.splice(i, 1);
29521 i = accessList.indexOf(dlg);
29523 accessList.splice(i, 1);
29529 * Gets a registered dialog by id
29530 * @param {String/Object} id The id of the dialog or a dialog
29531 * @return {Roo.BasicDialog} this
29533 get : function(id){
29534 return typeof id == "object" ? id : list[id];
29538 * Brings the specified dialog to the front
29539 * @param {String/Object} dlg The id of the dialog or a dialog
29540 * @return {Roo.BasicDialog} this
29542 bringToFront : function(dlg){
29543 dlg = this.get(dlg);
29546 dlg._lastAccess = new Date().getTime();
29553 * Sends the specified dialog to the back
29554 * @param {String/Object} dlg The id of the dialog or a dialog
29555 * @return {Roo.BasicDialog} this
29557 sendToBack : function(dlg){
29558 dlg = this.get(dlg);
29559 dlg._lastAccess = -(new Date().getTime());
29565 * Hides all dialogs
29567 hideAll : function(){
29568 for(var id in list){
29569 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29578 * @class Roo.LayoutDialog
29579 * @extends Roo.BasicDialog
29580 * Dialog which provides adjustments for working with a layout in a Dialog.
29581 * Add your necessary layout config options to the dialog's config.<br>
29582 * Example usage (including a nested layout):
29585 dialog = new Roo.LayoutDialog("download-dlg", {
29594 // layout config merges with the dialog config
29596 tabPosition: "top",
29597 alwaysShowTabs: true
29600 dialog.addKeyListener(27, dialog.hide, dialog);
29601 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29602 dialog.addButton("Build It!", this.getDownload, this);
29604 // we can even add nested layouts
29605 var innerLayout = new Roo.BorderLayout("dl-inner", {
29615 innerLayout.beginUpdate();
29616 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29617 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29618 innerLayout.endUpdate(true);
29620 var layout = dialog.getLayout();
29621 layout.beginUpdate();
29622 layout.add("center", new Roo.ContentPanel("standard-panel",
29623 {title: "Download the Source", fitToFrame:true}));
29624 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29625 {title: "Build your own roo.js"}));
29626 layout.getRegion("center").showPanel(sp);
29627 layout.endUpdate();
29631 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29632 * @param {Object} config configuration options
29634 Roo.LayoutDialog = function(el, cfg){
29637 if (typeof(cfg) == 'undefined') {
29638 config = Roo.apply({}, el);
29639 // not sure why we use documentElement here.. - it should always be body.
29640 // IE7 borks horribly if we use documentElement.
29641 el = Roo.get( Roo.isIE ? (document.body || document.documentElement) : (document.documentElement || document.body) ).createChild();
29642 //config.autoCreate = true;
29646 config.autoTabs = false;
29647 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29648 this.body.setStyle({overflow:"hidden", position:"relative"});
29649 this.layout = new Roo.BorderLayout(this.body.dom, config);
29650 this.layout.monitorWindowResize = false;
29651 this.el.addClass("x-dlg-auto-layout");
29652 // fix case when center region overwrites center function
29653 this.center = Roo.BasicDialog.prototype.center;
29654 this.on("show", this.layout.layout, this.layout, true);
29655 if (config.items) {
29656 var xitems = config.items;
29657 delete config.items;
29658 Roo.each(xitems, this.addxtype, this);
29663 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29665 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29668 endUpdate : function(){
29669 this.layout.endUpdate();
29673 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29676 beginUpdate : function(){
29677 this.layout.beginUpdate();
29681 * Get the BorderLayout for this dialog
29682 * @return {Roo.BorderLayout}
29684 getLayout : function(){
29685 return this.layout;
29688 showEl : function(){
29689 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29691 this.layout.layout();
29696 // Use the syncHeightBeforeShow config option to control this automatically
29697 syncBodyHeight : function(){
29698 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29699 if(this.layout){this.layout.layout();}
29703 * Add an xtype element (actually adds to the layout.)
29704 * @return {Object} xdata xtype object data.
29707 addxtype : function(c) {
29708 return this.layout.addxtype(c);
29712 * Ext JS Library 1.1.1
29713 * Copyright(c) 2006-2007, Ext JS, LLC.
29715 * Originally Released Under LGPL - original licence link has changed is not relivant.
29718 * <script type="text/javascript">
29722 * @class Roo.MessageBox
29723 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29727 Roo.Msg.alert('Status', 'Changes saved successfully.');
29729 // Prompt for user data:
29730 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29732 // process text value...
29736 // Show a dialog using config options:
29738 title:'Save Changes?',
29739 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29740 buttons: Roo.Msg.YESNOCANCEL,
29747 Roo.MessageBox = function(){
29748 var dlg, opt, mask, waitTimer;
29749 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29750 var buttons, activeTextEl, bwidth;
29753 var handleButton = function(button){
29755 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29759 var handleHide = function(){
29760 if(opt && opt.cls){
29761 dlg.el.removeClass(opt.cls);
29764 Roo.TaskMgr.stop(waitTimer);
29770 var updateButtons = function(b){
29773 buttons["ok"].hide();
29774 buttons["cancel"].hide();
29775 buttons["yes"].hide();
29776 buttons["no"].hide();
29777 dlg.footer.dom.style.display = 'none';
29780 dlg.footer.dom.style.display = '';
29781 for(var k in buttons){
29782 if(typeof buttons[k] != "function"){
29785 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29786 width += buttons[k].el.getWidth()+15;
29796 var handleEsc = function(d, k, e){
29797 if(opt && opt.closable !== false){
29807 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29808 * @return {Roo.BasicDialog} The BasicDialog element
29810 getDialog : function(){
29812 dlg = new Roo.BasicDialog("x-msg-box", {
29817 constraintoviewport:false,
29819 collapsible : false,
29822 width:400, height:100,
29823 buttonAlign:"center",
29824 closeClick : function(){
29825 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29826 handleButton("no");
29828 handleButton("cancel");
29832 dlg.on("hide", handleHide);
29834 dlg.addKeyListener(27, handleEsc);
29836 var bt = this.buttonText;
29837 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29838 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29839 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29840 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29841 bodyEl = dlg.body.createChild({
29843 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>'
29845 msgEl = bodyEl.dom.firstChild;
29846 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29847 textboxEl.enableDisplayMode();
29848 textboxEl.addKeyListener([10,13], function(){
29849 if(dlg.isVisible() && opt && opt.buttons){
29850 if(opt.buttons.ok){
29851 handleButton("ok");
29852 }else if(opt.buttons.yes){
29853 handleButton("yes");
29857 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29858 textareaEl.enableDisplayMode();
29859 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29860 progressEl.enableDisplayMode();
29861 var pf = progressEl.dom.firstChild;
29863 pp = Roo.get(pf.firstChild);
29864 pp.setHeight(pf.offsetHeight);
29872 * Updates the message box body text
29873 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29874 * the XHTML-compliant non-breaking space character '&#160;')
29875 * @return {Roo.MessageBox} This message box
29877 updateText : function(text){
29878 if(!dlg.isVisible() && !opt.width){
29879 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29881 msgEl.innerHTML = text || ' ';
29882 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29883 Math.max(opt.minWidth || this.minWidth, bwidth));
29885 activeTextEl.setWidth(w);
29887 if(dlg.isVisible()){
29888 dlg.fixedcenter = false;
29890 dlg.setContentSize(w, bodyEl.getHeight());
29891 if(dlg.isVisible()){
29892 dlg.fixedcenter = true;
29898 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
29899 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
29900 * @param {Number} value Any number between 0 and 1 (e.g., .5)
29901 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
29902 * @return {Roo.MessageBox} This message box
29904 updateProgress : function(value, text){
29906 this.updateText(text);
29908 if (pp) { // weird bug on my firefox - for some reason this is not defined
29909 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
29915 * Returns true if the message box is currently displayed
29916 * @return {Boolean} True if the message box is visible, else false
29918 isVisible : function(){
29919 return dlg && dlg.isVisible();
29923 * Hides the message box if it is displayed
29926 if(this.isVisible()){
29932 * Displays a new message box, or reinitializes an existing message box, based on the config options
29933 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
29934 * The following config object properties are supported:
29936 Property Type Description
29937 ---------- --------------- ------------------------------------------------------------------------------------
29938 animEl String/Element An id or Element from which the message box should animate as it opens and
29939 closes (defaults to undefined)
29940 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
29941 cancel:'Bar'}), or false to not show any buttons (defaults to false)
29942 closable Boolean False to hide the top-right close button (defaults to true). Note that
29943 progress and wait dialogs will ignore this property and always hide the
29944 close button as they can only be closed programmatically.
29945 cls String A custom CSS class to apply to the message box element
29946 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
29947 displayed (defaults to 75)
29948 fn Function A callback function to execute after closing the dialog. The arguments to the
29949 function will be btn (the name of the button that was clicked, if applicable,
29950 e.g. "ok"), and text (the value of the active text field, if applicable).
29951 Progress and wait dialogs will ignore this option since they do not respond to
29952 user actions and can only be closed programmatically, so any required function
29953 should be called by the same code after it closes the dialog.
29954 icon String A CSS class that provides a background image to be used as an icon for
29955 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
29956 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
29957 minWidth Number The minimum width in pixels of the message box (defaults to 100)
29958 modal Boolean False to allow user interaction with the page while the message box is
29959 displayed (defaults to true)
29960 msg String A string that will replace the existing message box body text (defaults
29961 to the XHTML-compliant non-breaking space character ' ')
29962 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
29963 progress Boolean True to display a progress bar (defaults to false)
29964 progressText String The text to display inside the progress bar if progress = true (defaults to '')
29965 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
29966 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
29967 title String The title text
29968 value String The string value to set into the active textbox element if displayed
29969 wait Boolean True to display a progress bar (defaults to false)
29970 width Number The width of the dialog in pixels
29977 msg: 'Please enter your address:',
29979 buttons: Roo.MessageBox.OKCANCEL,
29982 animEl: 'addAddressBtn'
29985 * @param {Object} config Configuration options
29986 * @return {Roo.MessageBox} This message box
29988 show : function(options){
29989 if(this.isVisible()){
29992 var d = this.getDialog();
29994 d.setTitle(opt.title || " ");
29995 d.close.setDisplayed(opt.closable !== false);
29996 activeTextEl = textboxEl;
29997 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30002 textareaEl.setHeight(typeof opt.multiline == "number" ?
30003 opt.multiline : this.defaultTextHeight);
30004 activeTextEl = textareaEl;
30013 progressEl.setDisplayed(opt.progress === true);
30014 this.updateProgress(0);
30015 activeTextEl.dom.value = opt.value || "";
30017 dlg.setDefaultButton(activeTextEl);
30019 var bs = opt.buttons;
30022 db = buttons["ok"];
30023 }else if(bs && bs.yes){
30024 db = buttons["yes"];
30026 dlg.setDefaultButton(db);
30028 bwidth = updateButtons(opt.buttons);
30029 this.updateText(opt.msg);
30031 d.el.addClass(opt.cls);
30033 d.proxyDrag = opt.proxyDrag === true;
30034 d.modal = opt.modal !== false;
30035 d.mask = opt.modal !== false ? mask : false;
30036 if(!d.isVisible()){
30037 // force it to the end of the z-index stack so it gets a cursor in FF
30038 document.body.appendChild(dlg.el.dom);
30039 d.animateTarget = null;
30040 d.show(options.animEl);
30046 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30047 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30048 * and closing the message box when the process is complete.
30049 * @param {String} title The title bar text
30050 * @param {String} msg The message box body text
30051 * @return {Roo.MessageBox} This message box
30053 progress : function(title, msg){
30060 minWidth: this.minProgressWidth,
30067 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30068 * If a callback function is passed it will be called after the user clicks the button, and the
30069 * id of the button that was clicked will be passed as the only parameter to the callback
30070 * (could also be the top-right close button).
30071 * @param {String} title The title bar text
30072 * @param {String} msg The message box body text
30073 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30074 * @param {Object} scope (optional) The scope of the callback function
30075 * @return {Roo.MessageBox} This message box
30077 alert : function(title, msg, fn, scope){
30090 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30091 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30092 * You are responsible for closing the message box when the process is complete.
30093 * @param {String} msg The message box body text
30094 * @param {String} title (optional) The title bar text
30095 * @return {Roo.MessageBox} This message box
30097 wait : function(msg, title){
30108 waitTimer = Roo.TaskMgr.start({
30110 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30118 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30119 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30120 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30121 * @param {String} title The title bar text
30122 * @param {String} msg The message box body text
30123 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30124 * @param {Object} scope (optional) The scope of the callback function
30125 * @return {Roo.MessageBox} This message box
30127 confirm : function(title, msg, fn, scope){
30131 buttons: this.YESNO,
30140 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30141 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30142 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30143 * (could also be the top-right close button) and the text that was entered will be passed as the two
30144 * parameters to the callback.
30145 * @param {String} title The title bar text
30146 * @param {String} msg The message box body text
30147 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30148 * @param {Object} scope (optional) The scope of the callback function
30149 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30150 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30151 * @return {Roo.MessageBox} This message box
30153 prompt : function(title, msg, fn, scope, multiline){
30157 buttons: this.OKCANCEL,
30162 multiline: multiline,
30169 * Button config that displays a single OK button
30174 * Button config that displays Yes and No buttons
30177 YESNO : {yes:true, no:true},
30179 * Button config that displays OK and Cancel buttons
30182 OKCANCEL : {ok:true, cancel:true},
30184 * Button config that displays Yes, No and Cancel buttons
30187 YESNOCANCEL : {yes:true, no:true, cancel:true},
30190 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30193 defaultTextHeight : 75,
30195 * The maximum width in pixels of the message box (defaults to 600)
30200 * The minimum width in pixels of the message box (defaults to 100)
30205 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30206 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30209 minProgressWidth : 250,
30211 * An object containing the default button text strings that can be overriden for localized language support.
30212 * Supported properties are: ok, cancel, yes and no.
30213 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30226 * Shorthand for {@link Roo.MessageBox}
30228 Roo.Msg = Roo.MessageBox;/*
30230 * Ext JS Library 1.1.1
30231 * Copyright(c) 2006-2007, Ext JS, LLC.
30233 * Originally Released Under LGPL - original licence link has changed is not relivant.
30236 * <script type="text/javascript">
30239 * @class Roo.QuickTips
30240 * Provides attractive and customizable tooltips for any element.
30243 Roo.QuickTips = function(){
30244 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30245 var ce, bd, xy, dd;
30246 var visible = false, disabled = true, inited = false;
30247 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30249 var onOver = function(e){
30253 var t = e.getTarget();
30254 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30257 if(ce && t == ce.el){
30258 clearTimeout(hideProc);
30261 if(t && tagEls[t.id]){
30262 tagEls[t.id].el = t;
30263 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30266 var ttp, et = Roo.fly(t);
30267 var ns = cfg.namespace;
30268 if(tm.interceptTitles && t.title){
30271 t.removeAttribute("title");
30272 e.preventDefault();
30274 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30277 showProc = show.defer(tm.showDelay, tm, [{
30280 width: et.getAttributeNS(ns, cfg.width),
30281 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30282 title: et.getAttributeNS(ns, cfg.title),
30283 cls: et.getAttributeNS(ns, cfg.cls)
30288 var onOut = function(e){
30289 clearTimeout(showProc);
30290 var t = e.getTarget();
30291 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30292 hideProc = setTimeout(hide, tm.hideDelay);
30296 var onMove = function(e){
30302 if(tm.trackMouse && ce){
30307 var onDown = function(e){
30308 clearTimeout(showProc);
30309 clearTimeout(hideProc);
30311 if(tm.hideOnClick){
30314 tm.enable.defer(100, tm);
30319 var getPad = function(){
30320 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30323 var show = function(o){
30327 clearTimeout(dismissProc);
30329 if(removeCls){ // in case manually hidden
30330 el.removeClass(removeCls);
30334 el.addClass(ce.cls);
30335 removeCls = ce.cls;
30338 tipTitle.update(ce.title);
30341 tipTitle.update('');
30344 el.dom.style.width = tm.maxWidth+'px';
30345 //tipBody.dom.style.width = '';
30346 tipBodyText.update(o.text);
30347 var p = getPad(), w = ce.width;
30349 var td = tipBodyText.dom;
30350 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30351 if(aw > tm.maxWidth){
30353 }else if(aw < tm.minWidth){
30359 //tipBody.setWidth(w);
30360 el.setWidth(parseInt(w, 10) + p);
30361 if(ce.autoHide === false){
30362 close.setDisplayed(true);
30367 close.setDisplayed(false);
30373 el.avoidY = xy[1]-18;
30378 el.setStyle("visibility", "visible");
30379 el.fadeIn({callback: afterShow});
30385 var afterShow = function(){
30389 if(tm.autoDismiss && ce.autoHide !== false){
30390 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30395 var hide = function(noanim){
30396 clearTimeout(dismissProc);
30397 clearTimeout(hideProc);
30399 if(el.isVisible()){
30401 if(noanim !== true && tm.animate){
30402 el.fadeOut({callback: afterHide});
30409 var afterHide = function(){
30412 el.removeClass(removeCls);
30419 * @cfg {Number} minWidth
30420 * The minimum width of the quick tip (defaults to 40)
30424 * @cfg {Number} maxWidth
30425 * The maximum width of the quick tip (defaults to 300)
30429 * @cfg {Boolean} interceptTitles
30430 * True to automatically use the element's DOM title value if available (defaults to false)
30432 interceptTitles : false,
30434 * @cfg {Boolean} trackMouse
30435 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30437 trackMouse : false,
30439 * @cfg {Boolean} hideOnClick
30440 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30442 hideOnClick : true,
30444 * @cfg {Number} showDelay
30445 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30449 * @cfg {Number} hideDelay
30450 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30454 * @cfg {Boolean} autoHide
30455 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30456 * Used in conjunction with hideDelay.
30461 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30462 * (defaults to true). Used in conjunction with autoDismissDelay.
30464 autoDismiss : true,
30467 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30469 autoDismissDelay : 5000,
30471 * @cfg {Boolean} animate
30472 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30477 * @cfg {String} title
30478 * Title text to display (defaults to ''). This can be any valid HTML markup.
30482 * @cfg {String} text
30483 * Body text to display (defaults to ''). This can be any valid HTML markup.
30487 * @cfg {String} cls
30488 * A CSS class to apply to the base quick tip element (defaults to '').
30492 * @cfg {Number} width
30493 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30494 * minWidth or maxWidth.
30499 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30500 * or display QuickTips in a page.
30503 tm = Roo.QuickTips;
30504 cfg = tm.tagConfig;
30506 if(!Roo.isReady){ // allow calling of init() before onReady
30507 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30510 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30511 el.fxDefaults = {stopFx: true};
30512 // maximum custom styling
30513 //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>');
30514 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>');
30515 tipTitle = el.child('h3');
30516 tipTitle.enableDisplayMode("block");
30517 tipBody = el.child('div.x-tip-bd');
30518 tipBodyText = el.child('div.x-tip-bd-inner');
30519 //bdLeft = el.child('div.x-tip-bd-left');
30520 //bdRight = el.child('div.x-tip-bd-right');
30521 close = el.child('div.x-tip-close');
30522 close.enableDisplayMode("block");
30523 close.on("click", hide);
30524 var d = Roo.get(document);
30525 d.on("mousedown", onDown);
30526 d.on("mouseover", onOver);
30527 d.on("mouseout", onOut);
30528 d.on("mousemove", onMove);
30529 esc = d.addKeyListener(27, hide);
30532 dd = el.initDD("default", null, {
30533 onDrag : function(){
30537 dd.setHandleElId(tipTitle.id);
30546 * Configures a new quick tip instance and assigns it to a target element. The following config options
30549 Property Type Description
30550 ---------- --------------------- ------------------------------------------------------------------------
30551 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30553 * @param {Object} config The config object
30555 register : function(config){
30556 var cs = config instanceof Array ? config : arguments;
30557 for(var i = 0, len = cs.length; i < len; i++) {
30559 var target = c.target;
30561 if(target instanceof Array){
30562 for(var j = 0, jlen = target.length; j < jlen; j++){
30563 tagEls[target[j]] = c;
30566 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30573 * Removes this quick tip from its element and destroys it.
30574 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30576 unregister : function(el){
30577 delete tagEls[Roo.id(el)];
30581 * Enable this quick tip.
30583 enable : function(){
30584 if(inited && disabled){
30586 if(locks.length < 1){
30593 * Disable this quick tip.
30595 disable : function(){
30597 clearTimeout(showProc);
30598 clearTimeout(hideProc);
30599 clearTimeout(dismissProc);
30607 * Returns true if the quick tip is enabled, else false.
30609 isEnabled : function(){
30616 attribute : "qtip",
30626 // backwards compat
30627 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30629 * Ext JS Library 1.1.1
30630 * Copyright(c) 2006-2007, Ext JS, LLC.
30632 * Originally Released Under LGPL - original licence link has changed is not relivant.
30635 * <script type="text/javascript">
30640 * @class Roo.tree.TreePanel
30641 * @extends Roo.data.Tree
30643 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30644 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30645 * @cfg {Boolean} enableDD true to enable drag and drop
30646 * @cfg {Boolean} enableDrag true to enable just drag
30647 * @cfg {Boolean} enableDrop true to enable just drop
30648 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30649 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30650 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30651 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30652 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30653 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30654 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30655 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30656 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30657 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30658 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30659 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30660 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30661 * @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>
30662 * @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>
30665 * @param {String/HTMLElement/Element} el The container element
30666 * @param {Object} config
30668 Roo.tree.TreePanel = function(el, config){
30670 var loader = false;
30672 root = config.root;
30673 delete config.root;
30675 if (config.loader) {
30676 loader = config.loader;
30677 delete config.loader;
30680 Roo.apply(this, config);
30681 Roo.tree.TreePanel.superclass.constructor.call(this);
30682 this.el = Roo.get(el);
30683 this.el.addClass('x-tree');
30684 //console.log(root);
30686 this.setRootNode( Roo.factory(root, Roo.tree));
30689 this.loader = Roo.factory(loader, Roo.tree);
30692 * Read-only. The id of the container element becomes this TreePanel's id.
30694 this.id = this.el.id;
30697 * @event beforeload
30698 * Fires before a node is loaded, return false to cancel
30699 * @param {Node} node The node being loaded
30701 "beforeload" : true,
30704 * Fires when a node is loaded
30705 * @param {Node} node The node that was loaded
30709 * @event textchange
30710 * Fires when the text for a node is changed
30711 * @param {Node} node The node
30712 * @param {String} text The new text
30713 * @param {String} oldText The old text
30715 "textchange" : true,
30717 * @event beforeexpand
30718 * Fires before a node is expanded, return false to cancel.
30719 * @param {Node} node The node
30720 * @param {Boolean} deep
30721 * @param {Boolean} anim
30723 "beforeexpand" : true,
30725 * @event beforecollapse
30726 * Fires before a node is collapsed, return false to cancel.
30727 * @param {Node} node The node
30728 * @param {Boolean} deep
30729 * @param {Boolean} anim
30731 "beforecollapse" : true,
30734 * Fires when a node is expanded
30735 * @param {Node} node The node
30739 * @event disabledchange
30740 * Fires when the disabled status of a node changes
30741 * @param {Node} node The node
30742 * @param {Boolean} disabled
30744 "disabledchange" : true,
30747 * Fires when a node is collapsed
30748 * @param {Node} node The node
30752 * @event beforeclick
30753 * Fires before click processing on a node. Return false to cancel the default action.
30754 * @param {Node} node The node
30755 * @param {Roo.EventObject} e The event object
30757 "beforeclick":true,
30759 * @event checkchange
30760 * Fires when a node with a checkbox's checked property changes
30761 * @param {Node} this This node
30762 * @param {Boolean} checked
30764 "checkchange":true,
30767 * Fires when a node is clicked
30768 * @param {Node} node The node
30769 * @param {Roo.EventObject} e The event object
30774 * Fires when a node is double clicked
30775 * @param {Node} node The node
30776 * @param {Roo.EventObject} e The event object
30780 * @event contextmenu
30781 * Fires when a node is right clicked
30782 * @param {Node} node The node
30783 * @param {Roo.EventObject} e The event object
30785 "contextmenu":true,
30787 * @event beforechildrenrendered
30788 * Fires right before the child nodes for a node are rendered
30789 * @param {Node} node The node
30791 "beforechildrenrendered":true,
30794 * Fires when a node starts being dragged
30795 * @param {Roo.tree.TreePanel} this
30796 * @param {Roo.tree.TreeNode} node
30797 * @param {event} e The raw browser event
30799 "startdrag" : true,
30802 * Fires when a drag operation is complete
30803 * @param {Roo.tree.TreePanel} this
30804 * @param {Roo.tree.TreeNode} node
30805 * @param {event} e The raw browser event
30810 * Fires when a dragged node is dropped on a valid DD target
30811 * @param {Roo.tree.TreePanel} this
30812 * @param {Roo.tree.TreeNode} node
30813 * @param {DD} dd The dd it was dropped on
30814 * @param {event} e The raw browser event
30818 * @event beforenodedrop
30819 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30820 * passed to handlers has the following properties:<br />
30821 * <ul style="padding:5px;padding-left:16px;">
30822 * <li>tree - The TreePanel</li>
30823 * <li>target - The node being targeted for the drop</li>
30824 * <li>data - The drag data from the drag source</li>
30825 * <li>point - The point of the drop - append, above or below</li>
30826 * <li>source - The drag source</li>
30827 * <li>rawEvent - Raw mouse event</li>
30828 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30829 * to be inserted by setting them on this object.</li>
30830 * <li>cancel - Set this to true to cancel the drop.</li>
30832 * @param {Object} dropEvent
30834 "beforenodedrop" : true,
30837 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30838 * passed to handlers has the following properties:<br />
30839 * <ul style="padding:5px;padding-left:16px;">
30840 * <li>tree - The TreePanel</li>
30841 * <li>target - The node being targeted for the drop</li>
30842 * <li>data - The drag data from the drag source</li>
30843 * <li>point - The point of the drop - append, above or below</li>
30844 * <li>source - The drag source</li>
30845 * <li>rawEvent - Raw mouse event</li>
30846 * <li>dropNode - Dropped node(s).</li>
30848 * @param {Object} dropEvent
30852 * @event nodedragover
30853 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30854 * passed to handlers has the following properties:<br />
30855 * <ul style="padding:5px;padding-left:16px;">
30856 * <li>tree - The TreePanel</li>
30857 * <li>target - The node being targeted for the drop</li>
30858 * <li>data - The drag data from the drag source</li>
30859 * <li>point - The point of the drop - append, above or below</li>
30860 * <li>source - The drag source</li>
30861 * <li>rawEvent - Raw mouse event</li>
30862 * <li>dropNode - Drop node(s) provided by the source.</li>
30863 * <li>cancel - Set this to true to signal drop not allowed.</li>
30865 * @param {Object} dragOverEvent
30867 "nodedragover" : true
30870 if(this.singleExpand){
30871 this.on("beforeexpand", this.restrictExpand, this);
30874 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30875 rootVisible : true,
30876 animate: Roo.enableFx,
30879 hlDrop : Roo.enableFx,
30883 rendererTip: false,
30885 restrictExpand : function(node){
30886 var p = node.parentNode;
30888 if(p.expandedChild && p.expandedChild.parentNode == p){
30889 p.expandedChild.collapse();
30891 p.expandedChild = node;
30895 // private override
30896 setRootNode : function(node){
30897 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
30898 if(!this.rootVisible){
30899 node.ui = new Roo.tree.RootTreeNodeUI(node);
30905 * Returns the container element for this TreePanel
30907 getEl : function(){
30912 * Returns the default TreeLoader for this TreePanel
30914 getLoader : function(){
30915 return this.loader;
30921 expandAll : function(){
30922 this.root.expand(true);
30926 * Collapse all nodes
30928 collapseAll : function(){
30929 this.root.collapse(true);
30933 * Returns the selection model used by this TreePanel
30935 getSelectionModel : function(){
30936 if(!this.selModel){
30937 this.selModel = new Roo.tree.DefaultSelectionModel();
30939 return this.selModel;
30943 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
30944 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
30945 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
30948 getChecked : function(a, startNode){
30949 startNode = startNode || this.root;
30951 var f = function(){
30952 if(this.attributes.checked){
30953 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
30956 startNode.cascade(f);
30961 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30962 * @param {String} path
30963 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30964 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
30965 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
30967 expandPath : function(path, attr, callback){
30968 attr = attr || "id";
30969 var keys = path.split(this.pathSeparator);
30970 var curNode = this.root;
30971 if(curNode.attributes[attr] != keys[1]){ // invalid root
30973 callback(false, null);
30978 var f = function(){
30979 if(++index == keys.length){
30981 callback(true, curNode);
30985 var c = curNode.findChild(attr, keys[index]);
30988 callback(false, curNode);
30993 c.expand(false, false, f);
30995 curNode.expand(false, false, f);
30999 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31000 * @param {String} path
31001 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31002 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31003 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31005 selectPath : function(path, attr, callback){
31006 attr = attr || "id";
31007 var keys = path.split(this.pathSeparator);
31008 var v = keys.pop();
31009 if(keys.length > 0){
31010 var f = function(success, node){
31011 if(success && node){
31012 var n = node.findChild(attr, v);
31018 }else if(callback){
31019 callback(false, n);
31023 callback(false, n);
31027 this.expandPath(keys.join(this.pathSeparator), attr, f);
31029 this.root.select();
31031 callback(true, this.root);
31036 getTreeEl : function(){
31041 * Trigger rendering of this TreePanel
31043 render : function(){
31044 if (this.innerCt) {
31045 return this; // stop it rendering more than once!!
31048 this.innerCt = this.el.createChild({tag:"ul",
31049 cls:"x-tree-root-ct " +
31050 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31052 if(this.containerScroll){
31053 Roo.dd.ScrollManager.register(this.el);
31055 if((this.enableDD || this.enableDrop) && !this.dropZone){
31057 * The dropZone used by this tree if drop is enabled
31058 * @type Roo.tree.TreeDropZone
31060 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31061 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31064 if((this.enableDD || this.enableDrag) && !this.dragZone){
31066 * The dragZone used by this tree if drag is enabled
31067 * @type Roo.tree.TreeDragZone
31069 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31070 ddGroup: this.ddGroup || "TreeDD",
31071 scroll: this.ddScroll
31074 this.getSelectionModel().init(this);
31076 console.log("ROOT not set in tree");
31079 this.root.render();
31080 if(!this.rootVisible){
31081 this.root.renderChildren();
31087 * Ext JS Library 1.1.1
31088 * Copyright(c) 2006-2007, Ext JS, LLC.
31090 * Originally Released Under LGPL - original licence link has changed is not relivant.
31093 * <script type="text/javascript">
31098 * @class Roo.tree.DefaultSelectionModel
31099 * @extends Roo.util.Observable
31100 * The default single selection for a TreePanel.
31102 Roo.tree.DefaultSelectionModel = function(){
31103 this.selNode = null;
31107 * @event selectionchange
31108 * Fires when the selected node changes
31109 * @param {DefaultSelectionModel} this
31110 * @param {TreeNode} node the new selection
31112 "selectionchange" : true,
31115 * @event beforeselect
31116 * Fires before the selected node changes, return false to cancel the change
31117 * @param {DefaultSelectionModel} this
31118 * @param {TreeNode} node the new selection
31119 * @param {TreeNode} node the old selection
31121 "beforeselect" : true
31125 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31126 init : function(tree){
31128 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31129 tree.on("click", this.onNodeClick, this);
31132 onNodeClick : function(node, e){
31133 if (e.ctrlKey && this.selNode == node) {
31134 this.unselect(node);
31142 * @param {TreeNode} node The node to select
31143 * @return {TreeNode} The selected node
31145 select : function(node){
31146 var last = this.selNode;
31147 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31149 last.ui.onSelectedChange(false);
31151 this.selNode = node;
31152 node.ui.onSelectedChange(true);
31153 this.fireEvent("selectionchange", this, node, last);
31160 * @param {TreeNode} node The node to unselect
31162 unselect : function(node){
31163 if(this.selNode == node){
31164 this.clearSelections();
31169 * Clear all selections
31171 clearSelections : function(){
31172 var n = this.selNode;
31174 n.ui.onSelectedChange(false);
31175 this.selNode = null;
31176 this.fireEvent("selectionchange", this, null);
31182 * Get the selected node
31183 * @return {TreeNode} The selected node
31185 getSelectedNode : function(){
31186 return this.selNode;
31190 * Returns true if the node is selected
31191 * @param {TreeNode} node The node to check
31192 * @return {Boolean}
31194 isSelected : function(node){
31195 return this.selNode == node;
31199 * Selects the node above the selected node in the tree, intelligently walking the nodes
31200 * @return TreeNode The new selection
31202 selectPrevious : function(){
31203 var s = this.selNode || this.lastSelNode;
31207 var ps = s.previousSibling;
31209 if(!ps.isExpanded() || ps.childNodes.length < 1){
31210 return this.select(ps);
31212 var lc = ps.lastChild;
31213 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31216 return this.select(lc);
31218 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31219 return this.select(s.parentNode);
31225 * Selects the node above the selected node in the tree, intelligently walking the nodes
31226 * @return TreeNode The new selection
31228 selectNext : function(){
31229 var s = this.selNode || this.lastSelNode;
31233 if(s.firstChild && s.isExpanded()){
31234 return this.select(s.firstChild);
31235 }else if(s.nextSibling){
31236 return this.select(s.nextSibling);
31237 }else if(s.parentNode){
31239 s.parentNode.bubble(function(){
31240 if(this.nextSibling){
31241 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31250 onKeyDown : function(e){
31251 var s = this.selNode || this.lastSelNode;
31252 // undesirable, but required
31257 var k = e.getKey();
31265 this.selectPrevious();
31268 e.preventDefault();
31269 if(s.hasChildNodes()){
31270 if(!s.isExpanded()){
31272 }else if(s.firstChild){
31273 this.select(s.firstChild, e);
31278 e.preventDefault();
31279 if(s.hasChildNodes() && s.isExpanded()){
31281 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31282 this.select(s.parentNode, e);
31290 * @class Roo.tree.MultiSelectionModel
31291 * @extends Roo.util.Observable
31292 * Multi selection for a TreePanel.
31294 Roo.tree.MultiSelectionModel = function(){
31295 this.selNodes = [];
31299 * @event selectionchange
31300 * Fires when the selected nodes change
31301 * @param {MultiSelectionModel} this
31302 * @param {Array} nodes Array of the selected nodes
31304 "selectionchange" : true
31308 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31309 init : function(tree){
31311 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31312 tree.on("click", this.onNodeClick, this);
31315 onNodeClick : function(node, e){
31316 this.select(node, e, e.ctrlKey);
31321 * @param {TreeNode} node The node to select
31322 * @param {EventObject} e (optional) An event associated with the selection
31323 * @param {Boolean} keepExisting True to retain existing selections
31324 * @return {TreeNode} The selected node
31326 select : function(node, e, keepExisting){
31327 if(keepExisting !== true){
31328 this.clearSelections(true);
31330 if(this.isSelected(node)){
31331 this.lastSelNode = node;
31334 this.selNodes.push(node);
31335 this.selMap[node.id] = node;
31336 this.lastSelNode = node;
31337 node.ui.onSelectedChange(true);
31338 this.fireEvent("selectionchange", this, this.selNodes);
31344 * @param {TreeNode} node The node to unselect
31346 unselect : function(node){
31347 if(this.selMap[node.id]){
31348 node.ui.onSelectedChange(false);
31349 var sn = this.selNodes;
31352 index = sn.indexOf(node);
31354 for(var i = 0, len = sn.length; i < len; i++){
31362 this.selNodes.splice(index, 1);
31364 delete this.selMap[node.id];
31365 this.fireEvent("selectionchange", this, this.selNodes);
31370 * Clear all selections
31372 clearSelections : function(suppressEvent){
31373 var sn = this.selNodes;
31375 for(var i = 0, len = sn.length; i < len; i++){
31376 sn[i].ui.onSelectedChange(false);
31378 this.selNodes = [];
31380 if(suppressEvent !== true){
31381 this.fireEvent("selectionchange", this, this.selNodes);
31387 * Returns true if the node is selected
31388 * @param {TreeNode} node The node to check
31389 * @return {Boolean}
31391 isSelected : function(node){
31392 return this.selMap[node.id] ? true : false;
31396 * Returns an array of the selected nodes
31399 getSelectedNodes : function(){
31400 return this.selNodes;
31403 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31405 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31407 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31410 * Ext JS Library 1.1.1
31411 * Copyright(c) 2006-2007, Ext JS, LLC.
31413 * Originally Released Under LGPL - original licence link has changed is not relivant.
31416 * <script type="text/javascript">
31420 * @class Roo.tree.TreeNode
31421 * @extends Roo.data.Node
31422 * @cfg {String} text The text for this node
31423 * @cfg {Boolean} expanded true to start the node expanded
31424 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31425 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31426 * @cfg {Boolean} disabled true to start the node disabled
31427 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31428 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31429 * @cfg {String} cls A css class to be added to the node
31430 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31431 * @cfg {String} href URL of the link used for the node (defaults to #)
31432 * @cfg {String} hrefTarget target frame for the link
31433 * @cfg {String} qtip An Ext QuickTip for the node
31434 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31435 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31436 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31437 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31438 * (defaults to undefined with no checkbox rendered)
31440 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31442 Roo.tree.TreeNode = function(attributes){
31443 attributes = attributes || {};
31444 if(typeof attributes == "string"){
31445 attributes = {text: attributes};
31447 this.childrenRendered = false;
31448 this.rendered = false;
31449 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31450 this.expanded = attributes.expanded === true;
31451 this.isTarget = attributes.isTarget !== false;
31452 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31453 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31456 * Read-only. The text for this node. To change it use setText().
31459 this.text = attributes.text;
31461 * True if this node is disabled.
31464 this.disabled = attributes.disabled === true;
31468 * @event textchange
31469 * Fires when the text for this node is changed
31470 * @param {Node} this This node
31471 * @param {String} text The new text
31472 * @param {String} oldText The old text
31474 "textchange" : true,
31476 * @event beforeexpand
31477 * Fires before this node is expanded, return false to cancel.
31478 * @param {Node} this This node
31479 * @param {Boolean} deep
31480 * @param {Boolean} anim
31482 "beforeexpand" : true,
31484 * @event beforecollapse
31485 * Fires before this node is collapsed, return false to cancel.
31486 * @param {Node} this This node
31487 * @param {Boolean} deep
31488 * @param {Boolean} anim
31490 "beforecollapse" : true,
31493 * Fires when this node is expanded
31494 * @param {Node} this This node
31498 * @event disabledchange
31499 * Fires when the disabled status of this node changes
31500 * @param {Node} this This node
31501 * @param {Boolean} disabled
31503 "disabledchange" : true,
31506 * Fires when this node is collapsed
31507 * @param {Node} this This node
31511 * @event beforeclick
31512 * Fires before click processing. Return false to cancel the default action.
31513 * @param {Node} this This node
31514 * @param {Roo.EventObject} e The event object
31516 "beforeclick":true,
31518 * @event checkchange
31519 * Fires when a node with a checkbox's checked property changes
31520 * @param {Node} this This node
31521 * @param {Boolean} checked
31523 "checkchange":true,
31526 * Fires when this node is clicked
31527 * @param {Node} this This node
31528 * @param {Roo.EventObject} e The event object
31533 * Fires when this node is double clicked
31534 * @param {Node} this This node
31535 * @param {Roo.EventObject} e The event object
31539 * @event contextmenu
31540 * Fires when this node is right clicked
31541 * @param {Node} this This node
31542 * @param {Roo.EventObject} e The event object
31544 "contextmenu":true,
31546 * @event beforechildrenrendered
31547 * Fires right before the child nodes for this node are rendered
31548 * @param {Node} this This node
31550 "beforechildrenrendered":true
31553 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31556 * Read-only. The UI for this node
31559 this.ui = new uiClass(this);
31561 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31562 preventHScroll: true,
31564 * Returns true if this node is expanded
31565 * @return {Boolean}
31567 isExpanded : function(){
31568 return this.expanded;
31572 * Returns the UI object for this node
31573 * @return {TreeNodeUI}
31575 getUI : function(){
31579 // private override
31580 setFirstChild : function(node){
31581 var of = this.firstChild;
31582 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31583 if(this.childrenRendered && of && node != of){
31584 of.renderIndent(true, true);
31587 this.renderIndent(true, true);
31591 // private override
31592 setLastChild : function(node){
31593 var ol = this.lastChild;
31594 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31595 if(this.childrenRendered && ol && node != ol){
31596 ol.renderIndent(true, true);
31599 this.renderIndent(true, true);
31603 // these methods are overridden to provide lazy rendering support
31604 // private override
31605 appendChild : function(){
31606 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31607 if(node && this.childrenRendered){
31610 this.ui.updateExpandIcon();
31614 // private override
31615 removeChild : function(node){
31616 this.ownerTree.getSelectionModel().unselect(node);
31617 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31618 // if it's been rendered remove dom node
31619 if(this.childrenRendered){
31622 if(this.childNodes.length < 1){
31623 this.collapse(false, false);
31625 this.ui.updateExpandIcon();
31627 if(!this.firstChild) {
31628 this.childrenRendered = false;
31633 // private override
31634 insertBefore : function(node, refNode){
31635 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31636 if(newNode && refNode && this.childrenRendered){
31639 this.ui.updateExpandIcon();
31644 * Sets the text for this node
31645 * @param {String} text
31647 setText : function(text){
31648 var oldText = this.text;
31650 this.attributes.text = text;
31651 if(this.rendered){ // event without subscribing
31652 this.ui.onTextChange(this, text, oldText);
31654 this.fireEvent("textchange", this, text, oldText);
31658 * Triggers selection of this node
31660 select : function(){
31661 this.getOwnerTree().getSelectionModel().select(this);
31665 * Triggers deselection of this node
31667 unselect : function(){
31668 this.getOwnerTree().getSelectionModel().unselect(this);
31672 * Returns true if this node is selected
31673 * @return {Boolean}
31675 isSelected : function(){
31676 return this.getOwnerTree().getSelectionModel().isSelected(this);
31680 * Expand this node.
31681 * @param {Boolean} deep (optional) True to expand all children as well
31682 * @param {Boolean} anim (optional) false to cancel the default animation
31683 * @param {Function} callback (optional) A callback to be called when
31684 * expanding this node completes (does not wait for deep expand to complete).
31685 * Called with 1 parameter, this node.
31687 expand : function(deep, anim, callback){
31688 if(!this.expanded){
31689 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31692 if(!this.childrenRendered){
31693 this.renderChildren();
31695 this.expanded = true;
31696 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31697 this.ui.animExpand(function(){
31698 this.fireEvent("expand", this);
31699 if(typeof callback == "function"){
31703 this.expandChildNodes(true);
31705 }.createDelegate(this));
31709 this.fireEvent("expand", this);
31710 if(typeof callback == "function"){
31715 if(typeof callback == "function"){
31720 this.expandChildNodes(true);
31724 isHiddenRoot : function(){
31725 return this.isRoot && !this.getOwnerTree().rootVisible;
31729 * Collapse this node.
31730 * @param {Boolean} deep (optional) True to collapse all children as well
31731 * @param {Boolean} anim (optional) false to cancel the default animation
31733 collapse : function(deep, anim){
31734 if(this.expanded && !this.isHiddenRoot()){
31735 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31738 this.expanded = false;
31739 if((this.getOwnerTree().animate && anim !== false) || anim){
31740 this.ui.animCollapse(function(){
31741 this.fireEvent("collapse", this);
31743 this.collapseChildNodes(true);
31745 }.createDelegate(this));
31748 this.ui.collapse();
31749 this.fireEvent("collapse", this);
31753 var cs = this.childNodes;
31754 for(var i = 0, len = cs.length; i < len; i++) {
31755 cs[i].collapse(true, false);
31761 delayedExpand : function(delay){
31762 if(!this.expandProcId){
31763 this.expandProcId = this.expand.defer(delay, this);
31768 cancelExpand : function(){
31769 if(this.expandProcId){
31770 clearTimeout(this.expandProcId);
31772 this.expandProcId = false;
31776 * Toggles expanded/collapsed state of the node
31778 toggle : function(){
31787 * Ensures all parent nodes are expanded
31789 ensureVisible : function(callback){
31790 var tree = this.getOwnerTree();
31791 tree.expandPath(this.parentNode.getPath(), false, function(){
31792 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31793 Roo.callback(callback);
31794 }.createDelegate(this));
31798 * Expand all child nodes
31799 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31801 expandChildNodes : function(deep){
31802 var cs = this.childNodes;
31803 for(var i = 0, len = cs.length; i < len; i++) {
31804 cs[i].expand(deep);
31809 * Collapse all child nodes
31810 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31812 collapseChildNodes : function(deep){
31813 var cs = this.childNodes;
31814 for(var i = 0, len = cs.length; i < len; i++) {
31815 cs[i].collapse(deep);
31820 * Disables this node
31822 disable : function(){
31823 this.disabled = true;
31825 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31826 this.ui.onDisableChange(this, true);
31828 this.fireEvent("disabledchange", this, true);
31832 * Enables this node
31834 enable : function(){
31835 this.disabled = false;
31836 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31837 this.ui.onDisableChange(this, false);
31839 this.fireEvent("disabledchange", this, false);
31843 renderChildren : function(suppressEvent){
31844 if(suppressEvent !== false){
31845 this.fireEvent("beforechildrenrendered", this);
31847 var cs = this.childNodes;
31848 for(var i = 0, len = cs.length; i < len; i++){
31849 cs[i].render(true);
31851 this.childrenRendered = true;
31855 sort : function(fn, scope){
31856 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31857 if(this.childrenRendered){
31858 var cs = this.childNodes;
31859 for(var i = 0, len = cs.length; i < len; i++){
31860 cs[i].render(true);
31866 render : function(bulkRender){
31867 this.ui.render(bulkRender);
31868 if(!this.rendered){
31869 this.rendered = true;
31871 this.expanded = false;
31872 this.expand(false, false);
31878 renderIndent : function(deep, refresh){
31880 this.ui.childIndent = null;
31882 this.ui.renderIndent();
31883 if(deep === true && this.childrenRendered){
31884 var cs = this.childNodes;
31885 for(var i = 0, len = cs.length; i < len; i++){
31886 cs[i].renderIndent(true, refresh);
31892 * Ext JS Library 1.1.1
31893 * Copyright(c) 2006-2007, Ext JS, LLC.
31895 * Originally Released Under LGPL - original licence link has changed is not relivant.
31898 * <script type="text/javascript">
31902 * @class Roo.tree.AsyncTreeNode
31903 * @extends Roo.tree.TreeNode
31904 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
31906 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31908 Roo.tree.AsyncTreeNode = function(config){
31909 this.loaded = false;
31910 this.loading = false;
31911 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
31913 * @event beforeload
31914 * Fires before this node is loaded, return false to cancel
31915 * @param {Node} this This node
31917 this.addEvents({'beforeload':true, 'load': true});
31920 * Fires when this node is loaded
31921 * @param {Node} this This node
31924 * The loader used by this node (defaults to using the tree's defined loader)
31929 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
31930 expand : function(deep, anim, callback){
31931 if(this.loading){ // if an async load is already running, waiting til it's done
31933 var f = function(){
31934 if(!this.loading){ // done loading
31935 clearInterval(timer);
31936 this.expand(deep, anim, callback);
31938 }.createDelegate(this);
31939 timer = setInterval(f, 200);
31943 if(this.fireEvent("beforeload", this) === false){
31946 this.loading = true;
31947 this.ui.beforeLoad(this);
31948 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
31950 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
31954 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
31958 * Returns true if this node is currently loading
31959 * @return {Boolean}
31961 isLoading : function(){
31962 return this.loading;
31965 loadComplete : function(deep, anim, callback){
31966 this.loading = false;
31967 this.loaded = true;
31968 this.ui.afterLoad(this);
31969 this.fireEvent("load", this);
31970 this.expand(deep, anim, callback);
31974 * Returns true if this node has been loaded
31975 * @return {Boolean}
31977 isLoaded : function(){
31978 return this.loaded;
31981 hasChildNodes : function(){
31982 if(!this.isLeaf() && !this.loaded){
31985 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
31990 * Trigger a reload for this node
31991 * @param {Function} callback
31993 reload : function(callback){
31994 this.collapse(false, false);
31995 while(this.firstChild){
31996 this.removeChild(this.firstChild);
31998 this.childrenRendered = false;
31999 this.loaded = false;
32000 if(this.isHiddenRoot()){
32001 this.expanded = false;
32003 this.expand(false, false, callback);
32007 * Ext JS Library 1.1.1
32008 * Copyright(c) 2006-2007, Ext JS, LLC.
32010 * Originally Released Under LGPL - original licence link has changed is not relivant.
32013 * <script type="text/javascript">
32017 * @class Roo.tree.TreeNodeUI
32019 * @param {Object} node The node to render
32020 * The TreeNode UI implementation is separate from the
32021 * tree implementation. Unless you are customizing the tree UI,
32022 * you should never have to use this directly.
32024 Roo.tree.TreeNodeUI = function(node){
32026 this.rendered = false;
32027 this.animating = false;
32028 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32031 Roo.tree.TreeNodeUI.prototype = {
32032 removeChild : function(node){
32034 this.ctNode.removeChild(node.ui.getEl());
32038 beforeLoad : function(){
32039 this.addClass("x-tree-node-loading");
32042 afterLoad : function(){
32043 this.removeClass("x-tree-node-loading");
32046 onTextChange : function(node, text, oldText){
32048 this.textNode.innerHTML = text;
32052 onDisableChange : function(node, state){
32053 this.disabled = state;
32055 this.addClass("x-tree-node-disabled");
32057 this.removeClass("x-tree-node-disabled");
32061 onSelectedChange : function(state){
32064 this.addClass("x-tree-selected");
32067 this.removeClass("x-tree-selected");
32071 onMove : function(tree, node, oldParent, newParent, index, refNode){
32072 this.childIndent = null;
32074 var targetNode = newParent.ui.getContainer();
32075 if(!targetNode){//target not rendered
32076 this.holder = document.createElement("div");
32077 this.holder.appendChild(this.wrap);
32080 var insertBefore = refNode ? refNode.ui.getEl() : null;
32082 targetNode.insertBefore(this.wrap, insertBefore);
32084 targetNode.appendChild(this.wrap);
32086 this.node.renderIndent(true);
32090 addClass : function(cls){
32092 Roo.fly(this.elNode).addClass(cls);
32096 removeClass : function(cls){
32098 Roo.fly(this.elNode).removeClass(cls);
32102 remove : function(){
32104 this.holder = document.createElement("div");
32105 this.holder.appendChild(this.wrap);
32109 fireEvent : function(){
32110 return this.node.fireEvent.apply(this.node, arguments);
32113 initEvents : function(){
32114 this.node.on("move", this.onMove, this);
32115 var E = Roo.EventManager;
32116 var a = this.anchor;
32118 var el = Roo.fly(a, '_treeui');
32120 if(Roo.isOpera){ // opera render bug ignores the CSS
32121 el.setStyle("text-decoration", "none");
32124 el.on("click", this.onClick, this);
32125 el.on("dblclick", this.onDblClick, this);
32128 Roo.EventManager.on(this.checkbox,
32129 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32132 el.on("contextmenu", this.onContextMenu, this);
32134 var icon = Roo.fly(this.iconNode);
32135 icon.on("click", this.onClick, this);
32136 icon.on("dblclick", this.onDblClick, this);
32137 icon.on("contextmenu", this.onContextMenu, this);
32138 E.on(this.ecNode, "click", this.ecClick, this, true);
32140 if(this.node.disabled){
32141 this.addClass("x-tree-node-disabled");
32143 if(this.node.hidden){
32144 this.addClass("x-tree-node-disabled");
32146 var ot = this.node.getOwnerTree();
32147 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32148 if(dd && (!this.node.isRoot || ot.rootVisible)){
32149 Roo.dd.Registry.register(this.elNode, {
32151 handles: this.getDDHandles(),
32157 getDDHandles : function(){
32158 return [this.iconNode, this.textNode];
32163 this.wrap.style.display = "none";
32169 this.wrap.style.display = "";
32173 onContextMenu : function(e){
32174 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32175 e.preventDefault();
32177 this.fireEvent("contextmenu", this.node, e);
32181 onClick : function(e){
32186 if(this.fireEvent("beforeclick", this.node, e) !== false){
32187 if(!this.disabled && this.node.attributes.href){
32188 this.fireEvent("click", this.node, e);
32191 e.preventDefault();
32196 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32197 this.node.toggle();
32200 this.fireEvent("click", this.node, e);
32206 onDblClick : function(e){
32207 e.preventDefault();
32212 this.toggleCheck();
32214 if(!this.animating && this.node.hasChildNodes()){
32215 this.node.toggle();
32217 this.fireEvent("dblclick", this.node, e);
32220 onCheckChange : function(){
32221 var checked = this.checkbox.checked;
32222 this.node.attributes.checked = checked;
32223 this.fireEvent('checkchange', this.node, checked);
32226 ecClick : function(e){
32227 if(!this.animating && this.node.hasChildNodes()){
32228 this.node.toggle();
32232 startDrop : function(){
32233 this.dropping = true;
32236 // delayed drop so the click event doesn't get fired on a drop
32237 endDrop : function(){
32238 setTimeout(function(){
32239 this.dropping = false;
32240 }.createDelegate(this), 50);
32243 expand : function(){
32244 this.updateExpandIcon();
32245 this.ctNode.style.display = "";
32248 focus : function(){
32249 if(!this.node.preventHScroll){
32250 try{this.anchor.focus();
32252 }else if(!Roo.isIE){
32254 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32255 var l = noscroll.scrollLeft;
32256 this.anchor.focus();
32257 noscroll.scrollLeft = l;
32262 toggleCheck : function(value){
32263 var cb = this.checkbox;
32265 cb.checked = (value === undefined ? !cb.checked : value);
32271 this.anchor.blur();
32275 animExpand : function(callback){
32276 var ct = Roo.get(this.ctNode);
32278 if(!this.node.hasChildNodes()){
32279 this.updateExpandIcon();
32280 this.ctNode.style.display = "";
32281 Roo.callback(callback);
32284 this.animating = true;
32285 this.updateExpandIcon();
32288 callback : function(){
32289 this.animating = false;
32290 Roo.callback(callback);
32293 duration: this.node.ownerTree.duration || .25
32297 highlight : function(){
32298 var tree = this.node.getOwnerTree();
32299 Roo.fly(this.wrap).highlight(
32300 tree.hlColor || "C3DAF9",
32301 {endColor: tree.hlBaseColor}
32305 collapse : function(){
32306 this.updateExpandIcon();
32307 this.ctNode.style.display = "none";
32310 animCollapse : function(callback){
32311 var ct = Roo.get(this.ctNode);
32312 ct.enableDisplayMode('block');
32315 this.animating = true;
32316 this.updateExpandIcon();
32319 callback : function(){
32320 this.animating = false;
32321 Roo.callback(callback);
32324 duration: this.node.ownerTree.duration || .25
32328 getContainer : function(){
32329 return this.ctNode;
32332 getEl : function(){
32336 appendDDGhost : function(ghostNode){
32337 ghostNode.appendChild(this.elNode.cloneNode(true));
32340 getDDRepairXY : function(){
32341 return Roo.lib.Dom.getXY(this.iconNode);
32344 onRender : function(){
32348 render : function(bulkRender){
32349 var n = this.node, a = n.attributes;
32350 var targetNode = n.parentNode ?
32351 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32353 if(!this.rendered){
32354 this.rendered = true;
32356 this.renderElements(n, a, targetNode, bulkRender);
32359 if(this.textNode.setAttributeNS){
32360 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32362 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32365 this.textNode.setAttribute("ext:qtip", a.qtip);
32367 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32370 }else if(a.qtipCfg){
32371 a.qtipCfg.target = Roo.id(this.textNode);
32372 Roo.QuickTips.register(a.qtipCfg);
32375 if(!this.node.expanded){
32376 this.updateExpandIcon();
32379 if(bulkRender === true) {
32380 targetNode.appendChild(this.wrap);
32385 renderElements : function(n, a, targetNode, bulkRender){
32386 // add some indent caching, this helps performance when rendering a large tree
32387 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32388 var t = n.getOwnerTree();
32389 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32390 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32391 var cb = typeof a.checked == 'boolean';
32392 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32393 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32394 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32395 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32396 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32397 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32398 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32399 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32400 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32401 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32404 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32405 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32406 n.nextSibling.ui.getEl(), buf.join(""));
32408 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32411 this.elNode = this.wrap.childNodes[0];
32412 this.ctNode = this.wrap.childNodes[1];
32413 var cs = this.elNode.childNodes;
32414 this.indentNode = cs[0];
32415 this.ecNode = cs[1];
32416 this.iconNode = cs[2];
32419 this.checkbox = cs[3];
32422 this.anchor = cs[index];
32423 this.textNode = cs[index].firstChild;
32426 getAnchor : function(){
32427 return this.anchor;
32430 getTextEl : function(){
32431 return this.textNode;
32434 getIconEl : function(){
32435 return this.iconNode;
32438 isChecked : function(){
32439 return this.checkbox ? this.checkbox.checked : false;
32442 updateExpandIcon : function(){
32444 var n = this.node, c1, c2;
32445 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32446 var hasChild = n.hasChildNodes();
32450 c1 = "x-tree-node-collapsed";
32451 c2 = "x-tree-node-expanded";
32454 c1 = "x-tree-node-expanded";
32455 c2 = "x-tree-node-collapsed";
32458 this.removeClass("x-tree-node-leaf");
32459 this.wasLeaf = false;
32461 if(this.c1 != c1 || this.c2 != c2){
32462 Roo.fly(this.elNode).replaceClass(c1, c2);
32463 this.c1 = c1; this.c2 = c2;
32467 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32470 this.wasLeaf = true;
32473 var ecc = "x-tree-ec-icon "+cls;
32474 if(this.ecc != ecc){
32475 this.ecNode.className = ecc;
32481 getChildIndent : function(){
32482 if(!this.childIndent){
32486 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32488 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32490 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32495 this.childIndent = buf.join("");
32497 return this.childIndent;
32500 renderIndent : function(){
32503 var p = this.node.parentNode;
32505 indent = p.ui.getChildIndent();
32507 if(this.indentMarkup != indent){ // don't rerender if not required
32508 this.indentNode.innerHTML = indent;
32509 this.indentMarkup = indent;
32511 this.updateExpandIcon();
32516 Roo.tree.RootTreeNodeUI = function(){
32517 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32519 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32520 render : function(){
32521 if(!this.rendered){
32522 var targetNode = this.node.ownerTree.innerCt.dom;
32523 this.node.expanded = true;
32524 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32525 this.wrap = this.ctNode = targetNode.firstChild;
32528 collapse : function(){
32530 expand : function(){
32534 * Ext JS Library 1.1.1
32535 * Copyright(c) 2006-2007, Ext JS, LLC.
32537 * Originally Released Under LGPL - original licence link has changed is not relivant.
32540 * <script type="text/javascript">
32543 * @class Roo.tree.TreeLoader
32544 * @extends Roo.util.Observable
32545 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32546 * nodes from a specified URL. The response must be a javascript Array definition
32547 * who's elements are node definition objects. eg:
32549 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32550 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32553 * A server request is sent, and child nodes are loaded only when a node is expanded.
32554 * The loading node's id is passed to the server under the parameter name "node" to
32555 * enable the server to produce the correct child nodes.
32557 * To pass extra parameters, an event handler may be attached to the "beforeload"
32558 * event, and the parameters specified in the TreeLoader's baseParams property:
32560 myTreeLoader.on("beforeload", function(treeLoader, node) {
32561 this.baseParams.category = node.attributes.category;
32564 * This would pass an HTTP parameter called "category" to the server containing
32565 * the value of the Node's "category" attribute.
32567 * Creates a new Treeloader.
32568 * @param {Object} config A config object containing config properties.
32570 Roo.tree.TreeLoader = function(config){
32571 this.baseParams = {};
32572 this.requestMethod = "POST";
32573 Roo.apply(this, config);
32578 * @event beforeload
32579 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32580 * @param {Object} This TreeLoader object.
32581 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32582 * @param {Object} callback The callback function specified in the {@link #load} call.
32587 * Fires when the node has been successfuly loaded.
32588 * @param {Object} This TreeLoader object.
32589 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32590 * @param {Object} response The response object containing the data from the server.
32594 * @event loadexception
32595 * Fires if the network request failed.
32596 * @param {Object} This TreeLoader object.
32597 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32598 * @param {Object} response The response object containing the data from the server.
32600 loadexception : true,
32603 * Fires before a node is created, enabling you to return custom Node types
32604 * @param {Object} This TreeLoader object.
32605 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32610 Roo.tree.TreeLoader.superclass.constructor.call(this);
32613 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32615 * @cfg {String} dataUrl The URL from which to request a Json string which
32616 * specifies an array of node definition object representing the child nodes
32620 * @cfg {Object} baseParams (optional) An object containing properties which
32621 * specify HTTP parameters to be passed to each request for child nodes.
32624 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32625 * created by this loader. If the attributes sent by the server have an attribute in this object,
32626 * they take priority.
32629 * @cfg {Object} uiProviders (optional) An object containing properties which
32631 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32632 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32633 * <i>uiProvider</i> attribute of a returned child node is a string rather
32634 * than a reference to a TreeNodeUI implementation, this that string value
32635 * is used as a property name in the uiProviders object. You can define the provider named
32636 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32641 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32642 * child nodes before loading.
32644 clearOnLoad : true,
32647 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32648 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32649 * Grid query { data : [ .....] }
32654 * @cfg {String} queryParam (optional)
32655 * Name of the query as it will be passed on the querystring (defaults to 'node')
32656 * eg. the request will be ?node=[id]
32663 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32664 * This is called automatically when a node is expanded, but may be used to reload
32665 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32666 * @param {Roo.tree.TreeNode} node
32667 * @param {Function} callback
32669 load : function(node, callback){
32670 if(this.clearOnLoad){
32671 while(node.firstChild){
32672 node.removeChild(node.firstChild);
32675 if(node.attributes.children){ // preloaded json children
32676 var cs = node.attributes.children;
32677 for(var i = 0, len = cs.length; i < len; i++){
32678 node.appendChild(this.createNode(cs[i]));
32680 if(typeof callback == "function"){
32683 }else if(this.dataUrl){
32684 this.requestData(node, callback);
32688 getParams: function(node){
32689 var buf = [], bp = this.baseParams;
32690 for(var key in bp){
32691 if(typeof bp[key] != "function"){
32692 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32695 var n = this.queryParam === false ? 'node' : this.queryParam;
32696 buf.push(n + "=", encodeURIComponent(node.id));
32697 return buf.join("");
32700 requestData : function(node, callback){
32701 if(this.fireEvent("beforeload", this, node, callback) !== false){
32702 this.transId = Roo.Ajax.request({
32703 method:this.requestMethod,
32704 url: this.dataUrl||this.url,
32705 success: this.handleResponse,
32706 failure: this.handleFailure,
32708 argument: {callback: callback, node: node},
32709 params: this.getParams(node)
32712 // if the load is cancelled, make sure we notify
32713 // the node that we are done
32714 if(typeof callback == "function"){
32720 isLoading : function(){
32721 return this.transId ? true : false;
32724 abort : function(){
32725 if(this.isLoading()){
32726 Roo.Ajax.abort(this.transId);
32731 createNode : function(attr){
32732 // apply baseAttrs, nice idea Corey!
32733 if(this.baseAttrs){
32734 Roo.applyIf(attr, this.baseAttrs);
32736 if(this.applyLoader !== false){
32737 attr.loader = this;
32739 // uiProvider = depreciated..
32741 if(typeof(attr.uiProvider) == 'string'){
32742 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32743 /** eval:var:attr */ eval(attr.uiProvider);
32745 if(typeof(this.uiProviders['default']) != 'undefined') {
32746 attr.uiProvider = this.uiProviders['default'];
32749 this.fireEvent('create', this, attr);
32751 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32753 new Roo.tree.TreeNode(attr) :
32754 new Roo.tree.AsyncTreeNode(attr));
32757 processResponse : function(response, node, callback){
32758 var json = response.responseText;
32761 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32762 if (this.root !== false) {
32766 for(var i = 0, len = o.length; i < len; i++){
32767 var n = this.createNode(o[i]);
32769 node.appendChild(n);
32772 if(typeof callback == "function"){
32773 callback(this, node);
32776 this.handleFailure(response);
32780 handleResponse : function(response){
32781 this.transId = false;
32782 var a = response.argument;
32783 this.processResponse(response, a.node, a.callback);
32784 this.fireEvent("load", this, a.node, response);
32787 handleFailure : function(response){
32788 this.transId = false;
32789 var a = response.argument;
32790 this.fireEvent("loadexception", this, a.node, response);
32791 if(typeof a.callback == "function"){
32792 a.callback(this, a.node);
32797 * Ext JS Library 1.1.1
32798 * Copyright(c) 2006-2007, Ext JS, LLC.
32800 * Originally Released Under LGPL - original licence link has changed is not relivant.
32803 * <script type="text/javascript">
32807 * @class Roo.tree.TreeFilter
32808 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32809 * @param {TreePanel} tree
32810 * @param {Object} config (optional)
32812 Roo.tree.TreeFilter = function(tree, config){
32814 this.filtered = {};
32815 Roo.apply(this, config);
32818 Roo.tree.TreeFilter.prototype = {
32825 * Filter the data by a specific attribute.
32826 * @param {String/RegExp} value Either string that the attribute value
32827 * should start with or a RegExp to test against the attribute
32828 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32829 * @param {TreeNode} startNode (optional) The node to start the filter at.
32831 filter : function(value, attr, startNode){
32832 attr = attr || "text";
32834 if(typeof value == "string"){
32835 var vlen = value.length;
32836 // auto clear empty filter
32837 if(vlen == 0 && this.clearBlank){
32841 value = value.toLowerCase();
32843 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32845 }else if(value.exec){ // regex?
32847 return value.test(n.attributes[attr]);
32850 throw 'Illegal filter type, must be string or regex';
32852 this.filterBy(f, null, startNode);
32856 * Filter by a function. The passed function will be called with each
32857 * node in the tree (or from the startNode). If the function returns true, the node is kept
32858 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32859 * @param {Function} fn The filter function
32860 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32862 filterBy : function(fn, scope, startNode){
32863 startNode = startNode || this.tree.root;
32864 if(this.autoClear){
32867 var af = this.filtered, rv = this.reverse;
32868 var f = function(n){
32869 if(n == startNode){
32875 var m = fn.call(scope || n, n);
32883 startNode.cascade(f);
32886 if(typeof id != "function"){
32888 if(n && n.parentNode){
32889 n.parentNode.removeChild(n);
32897 * Clears the current filter. Note: with the "remove" option
32898 * set a filter cannot be cleared.
32900 clear : function(){
32902 var af = this.filtered;
32904 if(typeof id != "function"){
32911 this.filtered = {};
32916 * Ext JS Library 1.1.1
32917 * Copyright(c) 2006-2007, Ext JS, LLC.
32919 * Originally Released Under LGPL - original licence link has changed is not relivant.
32922 * <script type="text/javascript">
32927 * @class Roo.tree.TreeSorter
32928 * Provides sorting of nodes in a TreePanel
32930 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
32931 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
32932 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
32933 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
32934 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
32935 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
32937 * @param {TreePanel} tree
32938 * @param {Object} config
32940 Roo.tree.TreeSorter = function(tree, config){
32941 Roo.apply(this, config);
32942 tree.on("beforechildrenrendered", this.doSort, this);
32943 tree.on("append", this.updateSort, this);
32944 tree.on("insert", this.updateSort, this);
32946 var dsc = this.dir && this.dir.toLowerCase() == "desc";
32947 var p = this.property || "text";
32948 var sortType = this.sortType;
32949 var fs = this.folderSort;
32950 var cs = this.caseSensitive === true;
32951 var leafAttr = this.leafAttr || 'leaf';
32953 this.sortFn = function(n1, n2){
32955 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
32958 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
32962 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
32963 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
32965 return dsc ? +1 : -1;
32967 return dsc ? -1 : +1;
32974 Roo.tree.TreeSorter.prototype = {
32975 doSort : function(node){
32976 node.sort(this.sortFn);
32979 compareNodes : function(n1, n2){
32980 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
32983 updateSort : function(tree, node){
32984 if(node.childrenRendered){
32985 this.doSort.defer(1, this, [node]);
32990 * Ext JS Library 1.1.1
32991 * Copyright(c) 2006-2007, Ext JS, LLC.
32993 * Originally Released Under LGPL - original licence link has changed is not relivant.
32996 * <script type="text/javascript">
32999 if(Roo.dd.DropZone){
33001 Roo.tree.TreeDropZone = function(tree, config){
33002 this.allowParentInsert = false;
33003 this.allowContainerDrop = false;
33004 this.appendOnly = false;
33005 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33007 this.lastInsertClass = "x-tree-no-status";
33008 this.dragOverData = {};
33011 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33012 ddGroup : "TreeDD",
33014 expandDelay : 1000,
33016 expandNode : function(node){
33017 if(node.hasChildNodes() && !node.isExpanded()){
33018 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33022 queueExpand : function(node){
33023 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33026 cancelExpand : function(){
33027 if(this.expandProcId){
33028 clearTimeout(this.expandProcId);
33029 this.expandProcId = false;
33033 isValidDropPoint : function(n, pt, dd, e, data){
33034 if(!n || !data){ return false; }
33035 var targetNode = n.node;
33036 var dropNode = data.node;
33037 // default drop rules
33038 if(!(targetNode && targetNode.isTarget && pt)){
33041 if(pt == "append" && targetNode.allowChildren === false){
33044 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33047 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33050 // reuse the object
33051 var overEvent = this.dragOverData;
33052 overEvent.tree = this.tree;
33053 overEvent.target = targetNode;
33054 overEvent.data = data;
33055 overEvent.point = pt;
33056 overEvent.source = dd;
33057 overEvent.rawEvent = e;
33058 overEvent.dropNode = dropNode;
33059 overEvent.cancel = false;
33060 var result = this.tree.fireEvent("nodedragover", overEvent);
33061 return overEvent.cancel === false && result !== false;
33064 getDropPoint : function(e, n, dd){
33067 return tn.allowChildren !== false ? "append" : false; // always append for root
33069 var dragEl = n.ddel;
33070 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33071 var y = Roo.lib.Event.getPageY(e);
33072 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33074 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33075 var noAppend = tn.allowChildren === false;
33076 if(this.appendOnly || tn.parentNode.allowChildren === false){
33077 return noAppend ? false : "append";
33079 var noBelow = false;
33080 if(!this.allowParentInsert){
33081 noBelow = tn.hasChildNodes() && tn.isExpanded();
33083 var q = (b - t) / (noAppend ? 2 : 3);
33084 if(y >= t && y < (t + q)){
33086 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33093 onNodeEnter : function(n, dd, e, data){
33094 this.cancelExpand();
33097 onNodeOver : function(n, dd, e, data){
33098 var pt = this.getDropPoint(e, n, dd);
33101 // auto node expand check
33102 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33103 this.queueExpand(node);
33104 }else if(pt != "append"){
33105 this.cancelExpand();
33108 // set the insert point style on the target node
33109 var returnCls = this.dropNotAllowed;
33110 if(this.isValidDropPoint(n, pt, dd, e, data)){
33115 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33116 cls = "x-tree-drag-insert-above";
33117 }else if(pt == "below"){
33118 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33119 cls = "x-tree-drag-insert-below";
33121 returnCls = "x-tree-drop-ok-append";
33122 cls = "x-tree-drag-append";
33124 if(this.lastInsertClass != cls){
33125 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33126 this.lastInsertClass = cls;
33133 onNodeOut : function(n, dd, e, data){
33134 this.cancelExpand();
33135 this.removeDropIndicators(n);
33138 onNodeDrop : function(n, dd, e, data){
33139 var point = this.getDropPoint(e, n, dd);
33140 var targetNode = n.node;
33141 targetNode.ui.startDrop();
33142 if(!this.isValidDropPoint(n, point, dd, e, data)){
33143 targetNode.ui.endDrop();
33146 // first try to find the drop node
33147 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33150 target: targetNode,
33155 dropNode: dropNode,
33158 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33159 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33160 targetNode.ui.endDrop();
33163 // allow target changing
33164 targetNode = dropEvent.target;
33165 if(point == "append" && !targetNode.isExpanded()){
33166 targetNode.expand(false, null, function(){
33167 this.completeDrop(dropEvent);
33168 }.createDelegate(this));
33170 this.completeDrop(dropEvent);
33175 completeDrop : function(de){
33176 var ns = de.dropNode, p = de.point, t = de.target;
33177 if(!(ns instanceof Array)){
33181 for(var i = 0, len = ns.length; i < len; i++){
33184 t.parentNode.insertBefore(n, t);
33185 }else if(p == "below"){
33186 t.parentNode.insertBefore(n, t.nextSibling);
33192 if(this.tree.hlDrop){
33196 this.tree.fireEvent("nodedrop", de);
33199 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33200 if(this.tree.hlDrop){
33201 dropNode.ui.focus();
33202 dropNode.ui.highlight();
33204 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33207 getTree : function(){
33211 removeDropIndicators : function(n){
33214 Roo.fly(el).removeClass([
33215 "x-tree-drag-insert-above",
33216 "x-tree-drag-insert-below",
33217 "x-tree-drag-append"]);
33218 this.lastInsertClass = "_noclass";
33222 beforeDragDrop : function(target, e, id){
33223 this.cancelExpand();
33227 afterRepair : function(data){
33228 if(data && Roo.enableFx){
33229 data.node.ui.highlight();
33238 * Ext JS Library 1.1.1
33239 * Copyright(c) 2006-2007, Ext JS, LLC.
33241 * Originally Released Under LGPL - original licence link has changed is not relivant.
33244 * <script type="text/javascript">
33248 if(Roo.dd.DragZone){
33249 Roo.tree.TreeDragZone = function(tree, config){
33250 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33254 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33255 ddGroup : "TreeDD",
33257 onBeforeDrag : function(data, e){
33259 return n && n.draggable && !n.disabled;
33262 onInitDrag : function(e){
33263 var data = this.dragData;
33264 this.tree.getSelectionModel().select(data.node);
33265 this.proxy.update("");
33266 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33267 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33270 getRepairXY : function(e, data){
33271 return data.node.ui.getDDRepairXY();
33274 onEndDrag : function(data, e){
33275 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33278 onValidDrop : function(dd, e, id){
33279 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33283 beforeInvalidDrop : function(e, id){
33284 // this scrolls the original position back into view
33285 var sm = this.tree.getSelectionModel();
33286 sm.clearSelections();
33287 sm.select(this.dragData.node);
33292 * Ext JS Library 1.1.1
33293 * Copyright(c) 2006-2007, Ext JS, LLC.
33295 * Originally Released Under LGPL - original licence link has changed is not relivant.
33298 * <script type="text/javascript">
33301 * @class Roo.tree.TreeEditor
33302 * @extends Roo.Editor
33303 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33304 * as the editor field.
33306 * @param {TreePanel} tree
33307 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33309 Roo.tree.TreeEditor = function(tree, config){
33310 config = config || {};
33311 var field = config.events ? config : new Roo.form.TextField(config);
33312 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33316 tree.on('beforeclick', this.beforeNodeClick, this);
33317 tree.getTreeEl().on('mousedown', this.hide, this);
33318 this.on('complete', this.updateNode, this);
33319 this.on('beforestartedit', this.fitToTree, this);
33320 this.on('startedit', this.bindScroll, this, {delay:10});
33321 this.on('specialkey', this.onSpecialKey, this);
33324 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33326 * @cfg {String} alignment
33327 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33333 * @cfg {Boolean} hideEl
33334 * True to hide the bound element while the editor is displayed (defaults to false)
33338 * @cfg {String} cls
33339 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33341 cls: "x-small-editor x-tree-editor",
33343 * @cfg {Boolean} shim
33344 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33350 * @cfg {Number} maxWidth
33351 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33352 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33353 * scroll and client offsets into account prior to each edit.
33360 fitToTree : function(ed, el){
33361 var td = this.tree.getTreeEl().dom, nd = el.dom;
33362 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33363 td.scrollLeft = nd.offsetLeft;
33367 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33368 this.setSize(w, '');
33372 triggerEdit : function(node){
33373 this.completeEdit();
33374 this.editNode = node;
33375 this.startEdit(node.ui.textNode, node.text);
33379 bindScroll : function(){
33380 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33384 beforeNodeClick : function(node, e){
33385 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33386 this.lastClick = new Date();
33387 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33389 this.triggerEdit(node);
33395 updateNode : function(ed, value){
33396 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33397 this.editNode.setText(value);
33401 onHide : function(){
33402 Roo.tree.TreeEditor.superclass.onHide.call(this);
33404 this.editNode.ui.focus();
33409 onSpecialKey : function(field, e){
33410 var k = e.getKey();
33414 }else if(k == e.ENTER && !e.hasModifier()){
33416 this.completeEdit();
33419 });//<Script type="text/javascript">
33422 * Ext JS Library 1.1.1
33423 * Copyright(c) 2006-2007, Ext JS, LLC.
33425 * Originally Released Under LGPL - original licence link has changed is not relivant.
33428 * <script type="text/javascript">
33432 * Not documented??? - probably should be...
33435 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33436 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33438 renderElements : function(n, a, targetNode, bulkRender){
33439 //consel.log("renderElements?");
33440 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33442 var t = n.getOwnerTree();
33443 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33445 var cols = t.columns;
33446 var bw = t.borderWidth;
33448 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33449 var cb = typeof a.checked == "boolean";
33450 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33451 var colcls = 'x-t-' + tid + '-c0';
33453 '<li class="x-tree-node">',
33456 '<div class="x-tree-node-el ', a.cls,'">',
33458 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33461 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33462 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33463 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33464 (a.icon ? ' x-tree-node-inline-icon' : ''),
33465 (a.iconCls ? ' '+a.iconCls : ''),
33466 '" unselectable="on" />',
33467 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33468 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33470 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33471 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33472 '<span unselectable="on" qtip="' + tx + '">',
33476 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33477 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33479 for(var i = 1, len = cols.length; i < len; i++){
33481 colcls = 'x-t-' + tid + '-c' +i;
33482 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33483 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33484 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33490 '<div class="x-clear"></div></div>',
33491 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33494 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33495 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33496 n.nextSibling.ui.getEl(), buf.join(""));
33498 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33500 var el = this.wrap.firstChild;
33502 this.elNode = el.firstChild;
33503 this.ranchor = el.childNodes[1];
33504 this.ctNode = this.wrap.childNodes[1];
33505 var cs = el.firstChild.childNodes;
33506 this.indentNode = cs[0];
33507 this.ecNode = cs[1];
33508 this.iconNode = cs[2];
33511 this.checkbox = cs[3];
33514 this.anchor = cs[index];
33516 this.textNode = cs[index].firstChild;
33518 //el.on("click", this.onClick, this);
33519 //el.on("dblclick", this.onDblClick, this);
33522 // console.log(this);
33524 initEvents : function(){
33525 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33528 var a = this.ranchor;
33530 var el = Roo.get(a);
33532 if(Roo.isOpera){ // opera render bug ignores the CSS
33533 el.setStyle("text-decoration", "none");
33536 el.on("click", this.onClick, this);
33537 el.on("dblclick", this.onDblClick, this);
33538 el.on("contextmenu", this.onContextMenu, this);
33542 /*onSelectedChange : function(state){
33545 this.addClass("x-tree-selected");
33548 this.removeClass("x-tree-selected");
33551 addClass : function(cls){
33553 Roo.fly(this.elRow).addClass(cls);
33559 removeClass : function(cls){
33561 Roo.fly(this.elRow).removeClass(cls);
33567 });//<Script type="text/javascript">
33571 * Ext JS Library 1.1.1
33572 * Copyright(c) 2006-2007, Ext JS, LLC.
33574 * Originally Released Under LGPL - original licence link has changed is not relivant.
33577 * <script type="text/javascript">
33582 * @class Roo.tree.ColumnTree
33583 * @extends Roo.data.TreePanel
33584 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33585 * @cfg {int} borderWidth compined right/left border allowance
33587 * @param {String/HTMLElement/Element} el The container element
33588 * @param {Object} config
33590 Roo.tree.ColumnTree = function(el, config)
33592 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33596 * Fire this event on a container when it resizes
33597 * @param {int} w Width
33598 * @param {int} h Height
33602 this.on('resize', this.onResize, this);
33605 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33609 borderWidth: Roo.isBorderBox ? 0 : 2,
33612 render : function(){
33613 // add the header.....
33615 Roo.tree.ColumnTree.superclass.render.apply(this);
33617 this.el.addClass('x-column-tree');
33619 this.headers = this.el.createChild(
33620 {cls:'x-tree-headers'},this.innerCt.dom);
33622 var cols = this.columns, c;
33623 var totalWidth = 0;
33625 var len = cols.length;
33626 for(var i = 0; i < len; i++){
33628 totalWidth += c.width;
33629 this.headEls.push(this.headers.createChild({
33630 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33632 cls:'x-tree-hd-text',
33635 style:'width:'+(c.width-this.borderWidth)+'px;'
33638 this.headers.createChild({cls:'x-clear'});
33639 // prevent floats from wrapping when clipped
33640 this.headers.setWidth(totalWidth);
33641 //this.innerCt.setWidth(totalWidth);
33642 this.innerCt.setStyle({ overflow: 'auto' });
33643 this.onResize(this.width, this.height);
33647 onResize : function(w,h)
33652 this.innerCt.setWidth(this.width);
33653 this.innerCt.setHeight(this.height-20);
33656 var cols = this.columns, c;
33657 var totalWidth = 0;
33659 var len = cols.length;
33660 for(var i = 0; i < len; i++){
33662 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33663 // it's the expander..
33664 expEl = this.headEls[i];
33667 totalWidth += c.width;
33671 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33673 this.headers.setWidth(w-20);
33682 * Ext JS Library 1.1.1
33683 * Copyright(c) 2006-2007, Ext JS, LLC.
33685 * Originally Released Under LGPL - original licence link has changed is not relivant.
33688 * <script type="text/javascript">
33692 * @class Roo.menu.Menu
33693 * @extends Roo.util.Observable
33694 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33695 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33697 * Creates a new Menu
33698 * @param {Object} config Configuration options
33700 Roo.menu.Menu = function(config){
33701 Roo.apply(this, config);
33702 this.id = this.id || Roo.id();
33705 * @event beforeshow
33706 * Fires before this menu is displayed
33707 * @param {Roo.menu.Menu} this
33711 * @event beforehide
33712 * Fires before this menu is hidden
33713 * @param {Roo.menu.Menu} this
33718 * Fires after this menu is displayed
33719 * @param {Roo.menu.Menu} this
33724 * Fires after this menu is hidden
33725 * @param {Roo.menu.Menu} this
33730 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33731 * @param {Roo.menu.Menu} this
33732 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33733 * @param {Roo.EventObject} e
33738 * Fires when the mouse is hovering over this menu
33739 * @param {Roo.menu.Menu} this
33740 * @param {Roo.EventObject} e
33741 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33746 * Fires when the mouse exits this menu
33747 * @param {Roo.menu.Menu} this
33748 * @param {Roo.EventObject} e
33749 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33754 * Fires when a menu item contained in this menu is clicked
33755 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33756 * @param {Roo.EventObject} e
33760 if (this.registerMenu) {
33761 Roo.menu.MenuMgr.register(this);
33764 var mis = this.items;
33765 this.items = new Roo.util.MixedCollection();
33767 this.add.apply(this, mis);
33771 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33773 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33777 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33778 * for bottom-right shadow (defaults to "sides")
33782 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33783 * this menu (defaults to "tl-tr?")
33785 subMenuAlign : "tl-tr?",
33787 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33788 * relative to its element of origin (defaults to "tl-bl?")
33790 defaultAlign : "tl-bl?",
33792 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33794 allowOtherMenus : false,
33796 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33798 registerMenu : true,
33803 render : function(){
33807 var el = this.el = new Roo.Layer({
33809 shadow:this.shadow,
33811 parentEl: this.parentEl || document.body,
33815 this.keyNav = new Roo.menu.MenuNav(this);
33818 el.addClass("x-menu-plain");
33821 el.addClass(this.cls);
33823 // generic focus element
33824 this.focusEl = el.createChild({
33825 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33827 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33828 ul.on("click", this.onClick, this);
33829 ul.on("mouseover", this.onMouseOver, this);
33830 ul.on("mouseout", this.onMouseOut, this);
33831 this.items.each(function(item){
33832 var li = document.createElement("li");
33833 li.className = "x-menu-list-item";
33834 ul.dom.appendChild(li);
33835 item.render(li, this);
33842 autoWidth : function(){
33843 var el = this.el, ul = this.ul;
33847 var w = this.width;
33850 }else if(Roo.isIE){
33851 el.setWidth(this.minWidth);
33852 var t = el.dom.offsetWidth; // force recalc
33853 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33858 delayAutoWidth : function(){
33861 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33863 this.awTask.delay(20);
33868 findTargetItem : function(e){
33869 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33870 if(t && t.menuItemId){
33871 return this.items.get(t.menuItemId);
33876 onClick : function(e){
33878 if(t = this.findTargetItem(e)){
33880 this.fireEvent("click", this, t, e);
33885 setActiveItem : function(item, autoExpand){
33886 if(item != this.activeItem){
33887 if(this.activeItem){
33888 this.activeItem.deactivate();
33890 this.activeItem = item;
33891 item.activate(autoExpand);
33892 }else if(autoExpand){
33898 tryActivate : function(start, step){
33899 var items = this.items;
33900 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
33901 var item = items.get(i);
33902 if(!item.disabled && item.canActivate){
33903 this.setActiveItem(item, false);
33911 onMouseOver : function(e){
33913 if(t = this.findTargetItem(e)){
33914 if(t.canActivate && !t.disabled){
33915 this.setActiveItem(t, true);
33918 this.fireEvent("mouseover", this, e, t);
33922 onMouseOut : function(e){
33924 if(t = this.findTargetItem(e)){
33925 if(t == this.activeItem && t.shouldDeactivate(e)){
33926 this.activeItem.deactivate();
33927 delete this.activeItem;
33930 this.fireEvent("mouseout", this, e, t);
33934 * Read-only. Returns true if the menu is currently displayed, else false.
33937 isVisible : function(){
33938 return this.el && !this.hidden;
33942 * Displays this menu relative to another element
33943 * @param {String/HTMLElement/Roo.Element} element The element to align to
33944 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
33945 * the element (defaults to this.defaultAlign)
33946 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33948 show : function(el, pos, parentMenu){
33949 this.parentMenu = parentMenu;
33953 this.fireEvent("beforeshow", this);
33954 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
33958 * Displays this menu at a specific xy position
33959 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
33960 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33962 showAt : function(xy, parentMenu, /* private: */_e){
33963 this.parentMenu = parentMenu;
33968 this.fireEvent("beforeshow", this);
33969 xy = this.el.adjustForConstraints(xy);
33973 this.hidden = false;
33975 this.fireEvent("show", this);
33978 focus : function(){
33980 this.doFocus.defer(50, this);
33984 doFocus : function(){
33986 this.focusEl.focus();
33991 * Hides this menu and optionally all parent menus
33992 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
33994 hide : function(deep){
33995 if(this.el && this.isVisible()){
33996 this.fireEvent("beforehide", this);
33997 if(this.activeItem){
33998 this.activeItem.deactivate();
33999 this.activeItem = null;
34002 this.hidden = true;
34003 this.fireEvent("hide", this);
34005 if(deep === true && this.parentMenu){
34006 this.parentMenu.hide(true);
34011 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34012 * Any of the following are valid:
34014 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34015 * <li>An HTMLElement object which will be converted to a menu item</li>
34016 * <li>A menu item config object that will be created as a new menu item</li>
34017 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34018 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34023 var menu = new Roo.menu.Menu();
34025 // Create a menu item to add by reference
34026 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34028 // Add a bunch of items at once using different methods.
34029 // Only the last item added will be returned.
34030 var item = menu.add(
34031 menuItem, // add existing item by ref
34032 'Dynamic Item', // new TextItem
34033 '-', // new separator
34034 { text: 'Config Item' } // new item by config
34037 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34038 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34041 var a = arguments, l = a.length, item;
34042 for(var i = 0; i < l; i++){
34044 if ((typeof(el) == "object") && el.xtype && el.xns) {
34045 el = Roo.factory(el, Roo.menu);
34048 if(el.render){ // some kind of Item
34049 item = this.addItem(el);
34050 }else if(typeof el == "string"){ // string
34051 if(el == "separator" || el == "-"){
34052 item = this.addSeparator();
34054 item = this.addText(el);
34056 }else if(el.tagName || el.el){ // element
34057 item = this.addElement(el);
34058 }else if(typeof el == "object"){ // must be menu item config?
34059 item = this.addMenuItem(el);
34066 * Returns this menu's underlying {@link Roo.Element} object
34067 * @return {Roo.Element} The element
34069 getEl : function(){
34077 * Adds a separator bar to the menu
34078 * @return {Roo.menu.Item} The menu item that was added
34080 addSeparator : function(){
34081 return this.addItem(new Roo.menu.Separator());
34085 * Adds an {@link Roo.Element} object to the menu
34086 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34087 * @return {Roo.menu.Item} The menu item that was added
34089 addElement : function(el){
34090 return this.addItem(new Roo.menu.BaseItem(el));
34094 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34095 * @param {Roo.menu.Item} item The menu item to add
34096 * @return {Roo.menu.Item} The menu item that was added
34098 addItem : function(item){
34099 this.items.add(item);
34101 var li = document.createElement("li");
34102 li.className = "x-menu-list-item";
34103 this.ul.dom.appendChild(li);
34104 item.render(li, this);
34105 this.delayAutoWidth();
34111 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34112 * @param {Object} config A MenuItem config object
34113 * @return {Roo.menu.Item} The menu item that was added
34115 addMenuItem : function(config){
34116 if(!(config instanceof Roo.menu.Item)){
34117 if(typeof config.checked == "boolean"){ // must be check menu item config?
34118 config = new Roo.menu.CheckItem(config);
34120 config = new Roo.menu.Item(config);
34123 return this.addItem(config);
34127 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34128 * @param {String} text The text to display in the menu item
34129 * @return {Roo.menu.Item} The menu item that was added
34131 addText : function(text){
34132 return this.addItem(new Roo.menu.TextItem({ text : text }));
34136 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34137 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34138 * @param {Roo.menu.Item} item The menu item to add
34139 * @return {Roo.menu.Item} The menu item that was added
34141 insert : function(index, item){
34142 this.items.insert(index, item);
34144 var li = document.createElement("li");
34145 li.className = "x-menu-list-item";
34146 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34147 item.render(li, this);
34148 this.delayAutoWidth();
34154 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34155 * @param {Roo.menu.Item} item The menu item to remove
34157 remove : function(item){
34158 this.items.removeKey(item.id);
34163 * Removes and destroys all items in the menu
34165 removeAll : function(){
34167 while(f = this.items.first()){
34173 // MenuNav is a private utility class used internally by the Menu
34174 Roo.menu.MenuNav = function(menu){
34175 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34176 this.scope = this.menu = menu;
34179 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34180 doRelay : function(e, h){
34181 var k = e.getKey();
34182 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34183 this.menu.tryActivate(0, 1);
34186 return h.call(this.scope || this, e, this.menu);
34189 up : function(e, m){
34190 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34191 m.tryActivate(m.items.length-1, -1);
34195 down : function(e, m){
34196 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34197 m.tryActivate(0, 1);
34201 right : function(e, m){
34203 m.activeItem.expandMenu(true);
34207 left : function(e, m){
34209 if(m.parentMenu && m.parentMenu.activeItem){
34210 m.parentMenu.activeItem.activate();
34214 enter : function(e, m){
34216 e.stopPropagation();
34217 m.activeItem.onClick(e);
34218 m.fireEvent("click", this, m.activeItem);
34224 * Ext JS Library 1.1.1
34225 * Copyright(c) 2006-2007, Ext JS, LLC.
34227 * Originally Released Under LGPL - original licence link has changed is not relivant.
34230 * <script type="text/javascript">
34234 * @class Roo.menu.MenuMgr
34235 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34238 Roo.menu.MenuMgr = function(){
34239 var menus, active, groups = {}, attached = false, lastShow = new Date();
34241 // private - called when first menu is created
34244 active = new Roo.util.MixedCollection();
34245 Roo.get(document).addKeyListener(27, function(){
34246 if(active.length > 0){
34253 function hideAll(){
34254 if(active && active.length > 0){
34255 var c = active.clone();
34256 c.each(function(m){
34263 function onHide(m){
34265 if(active.length < 1){
34266 Roo.get(document).un("mousedown", onMouseDown);
34272 function onShow(m){
34273 var last = active.last();
34274 lastShow = new Date();
34277 Roo.get(document).on("mousedown", onMouseDown);
34281 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34282 m.parentMenu.activeChild = m;
34283 }else if(last && last.isVisible()){
34284 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34289 function onBeforeHide(m){
34291 m.activeChild.hide();
34293 if(m.autoHideTimer){
34294 clearTimeout(m.autoHideTimer);
34295 delete m.autoHideTimer;
34300 function onBeforeShow(m){
34301 var pm = m.parentMenu;
34302 if(!pm && !m.allowOtherMenus){
34304 }else if(pm && pm.activeChild && active != m){
34305 pm.activeChild.hide();
34310 function onMouseDown(e){
34311 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34317 function onBeforeCheck(mi, state){
34319 var g = groups[mi.group];
34320 for(var i = 0, l = g.length; i < l; i++){
34322 g[i].setChecked(false);
34331 * Hides all menus that are currently visible
34333 hideAll : function(){
34338 register : function(menu){
34342 menus[menu.id] = menu;
34343 menu.on("beforehide", onBeforeHide);
34344 menu.on("hide", onHide);
34345 menu.on("beforeshow", onBeforeShow);
34346 menu.on("show", onShow);
34347 var g = menu.group;
34348 if(g && menu.events["checkchange"]){
34352 groups[g].push(menu);
34353 menu.on("checkchange", onCheck);
34358 * Returns a {@link Roo.menu.Menu} object
34359 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34360 * be used to generate and return a new Menu instance.
34362 get : function(menu){
34363 if(typeof menu == "string"){ // menu id
34364 return menus[menu];
34365 }else if(menu.events){ // menu instance
34367 }else if(typeof menu.length == 'number'){ // array of menu items?
34368 return new Roo.menu.Menu({items:menu});
34369 }else{ // otherwise, must be a config
34370 return new Roo.menu.Menu(menu);
34375 unregister : function(menu){
34376 delete menus[menu.id];
34377 menu.un("beforehide", onBeforeHide);
34378 menu.un("hide", onHide);
34379 menu.un("beforeshow", onBeforeShow);
34380 menu.un("show", onShow);
34381 var g = menu.group;
34382 if(g && menu.events["checkchange"]){
34383 groups[g].remove(menu);
34384 menu.un("checkchange", onCheck);
34389 registerCheckable : function(menuItem){
34390 var g = menuItem.group;
34395 groups[g].push(menuItem);
34396 menuItem.on("beforecheckchange", onBeforeCheck);
34401 unregisterCheckable : function(menuItem){
34402 var g = menuItem.group;
34404 groups[g].remove(menuItem);
34405 menuItem.un("beforecheckchange", onBeforeCheck);
34411 * Ext JS Library 1.1.1
34412 * Copyright(c) 2006-2007, Ext JS, LLC.
34414 * Originally Released Under LGPL - original licence link has changed is not relivant.
34417 * <script type="text/javascript">
34422 * @class Roo.menu.BaseItem
34423 * @extends Roo.Component
34424 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34425 * management and base configuration options shared by all menu components.
34427 * Creates a new BaseItem
34428 * @param {Object} config Configuration options
34430 Roo.menu.BaseItem = function(config){
34431 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34436 * Fires when this item is clicked
34437 * @param {Roo.menu.BaseItem} this
34438 * @param {Roo.EventObject} e
34443 * Fires when this item is activated
34444 * @param {Roo.menu.BaseItem} this
34448 * @event deactivate
34449 * Fires when this item is deactivated
34450 * @param {Roo.menu.BaseItem} this
34456 this.on("click", this.handler, this.scope, true);
34460 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34462 * @cfg {Function} handler
34463 * A function that will handle the click event of this menu item (defaults to undefined)
34466 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34468 canActivate : false,
34470 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34472 activeClass : "x-menu-item-active",
34474 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34476 hideOnClick : true,
34478 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34483 ctype: "Roo.menu.BaseItem",
34486 actionMode : "container",
34489 render : function(container, parentMenu){
34490 this.parentMenu = parentMenu;
34491 Roo.menu.BaseItem.superclass.render.call(this, container);
34492 this.container.menuItemId = this.id;
34496 onRender : function(container, position){
34497 this.el = Roo.get(this.el);
34498 container.dom.appendChild(this.el.dom);
34502 onClick : function(e){
34503 if(!this.disabled && this.fireEvent("click", this, e) !== false
34504 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34505 this.handleClick(e);
34512 activate : function(){
34516 var li = this.container;
34517 li.addClass(this.activeClass);
34518 this.region = li.getRegion().adjust(2, 2, -2, -2);
34519 this.fireEvent("activate", this);
34524 deactivate : function(){
34525 this.container.removeClass(this.activeClass);
34526 this.fireEvent("deactivate", this);
34530 shouldDeactivate : function(e){
34531 return !this.region || !this.region.contains(e.getPoint());
34535 handleClick : function(e){
34536 if(this.hideOnClick){
34537 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34542 expandMenu : function(autoActivate){
34547 hideMenu : function(){
34552 * Ext JS Library 1.1.1
34553 * Copyright(c) 2006-2007, Ext JS, LLC.
34555 * Originally Released Under LGPL - original licence link has changed is not relivant.
34558 * <script type="text/javascript">
34562 * @class Roo.menu.Adapter
34563 * @extends Roo.menu.BaseItem
34564 * 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.
34565 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34567 * Creates a new Adapter
34568 * @param {Object} config Configuration options
34570 Roo.menu.Adapter = function(component, config){
34571 Roo.menu.Adapter.superclass.constructor.call(this, config);
34572 this.component = component;
34574 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34576 canActivate : true,
34579 onRender : function(container, position){
34580 this.component.render(container);
34581 this.el = this.component.getEl();
34585 activate : function(){
34589 this.component.focus();
34590 this.fireEvent("activate", this);
34595 deactivate : function(){
34596 this.fireEvent("deactivate", this);
34600 disable : function(){
34601 this.component.disable();
34602 Roo.menu.Adapter.superclass.disable.call(this);
34606 enable : function(){
34607 this.component.enable();
34608 Roo.menu.Adapter.superclass.enable.call(this);
34612 * Ext JS Library 1.1.1
34613 * Copyright(c) 2006-2007, Ext JS, LLC.
34615 * Originally Released Under LGPL - original licence link has changed is not relivant.
34618 * <script type="text/javascript">
34622 * @class Roo.menu.TextItem
34623 * @extends Roo.menu.BaseItem
34624 * Adds a static text string to a menu, usually used as either a heading or group separator.
34625 * Note: old style constructor with text is still supported.
34628 * Creates a new TextItem
34629 * @param {Object} cfg Configuration
34631 Roo.menu.TextItem = function(cfg){
34632 if (typeof(cfg) == 'string') {
34635 Roo.apply(this,cfg);
34638 Roo.menu.TextItem.superclass.constructor.call(this);
34641 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34643 * @cfg {Boolean} text Text to show on item.
34648 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34650 hideOnClick : false,
34652 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34654 itemCls : "x-menu-text",
34657 onRender : function(){
34658 var s = document.createElement("span");
34659 s.className = this.itemCls;
34660 s.innerHTML = this.text;
34662 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34666 * Ext JS Library 1.1.1
34667 * Copyright(c) 2006-2007, Ext JS, LLC.
34669 * Originally Released Under LGPL - original licence link has changed is not relivant.
34672 * <script type="text/javascript">
34676 * @class Roo.menu.Separator
34677 * @extends Roo.menu.BaseItem
34678 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34679 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34681 * @param {Object} config Configuration options
34683 Roo.menu.Separator = function(config){
34684 Roo.menu.Separator.superclass.constructor.call(this, config);
34687 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34689 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34691 itemCls : "x-menu-sep",
34693 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34695 hideOnClick : false,
34698 onRender : function(li){
34699 var s = document.createElement("span");
34700 s.className = this.itemCls;
34701 s.innerHTML = " ";
34703 li.addClass("x-menu-sep-li");
34704 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34708 * Ext JS Library 1.1.1
34709 * Copyright(c) 2006-2007, Ext JS, LLC.
34711 * Originally Released Under LGPL - original licence link has changed is not relivant.
34714 * <script type="text/javascript">
34717 * @class Roo.menu.Item
34718 * @extends Roo.menu.BaseItem
34719 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34720 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34721 * activation and click handling.
34723 * Creates a new Item
34724 * @param {Object} config Configuration options
34726 Roo.menu.Item = function(config){
34727 Roo.menu.Item.superclass.constructor.call(this, config);
34729 this.menu = Roo.menu.MenuMgr.get(this.menu);
34732 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34735 * @cfg {String} text
34736 * The text to show on the menu item.
34740 * @cfg {String} HTML to render in menu
34741 * The text to show on the menu item (HTML version).
34745 * @cfg {String} icon
34746 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34750 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34752 itemCls : "x-menu-item",
34754 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34756 canActivate : true,
34758 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34761 // doc'd in BaseItem
34765 ctype: "Roo.menu.Item",
34768 onRender : function(container, position){
34769 var el = document.createElement("a");
34770 el.hideFocus = true;
34771 el.unselectable = "on";
34772 el.href = this.href || "#";
34773 if(this.hrefTarget){
34774 el.target = this.hrefTarget;
34776 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34778 var html = this.html.length ? this.html : String.format('{0}',this.text);
34780 el.innerHTML = String.format(
34781 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
34782 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
34784 Roo.menu.Item.superclass.onRender.call(this, container, position);
34788 * Sets the text to display in this menu item
34789 * @param {String} text The text to display
34790 * @param {Boolean} isHTML true to indicate text is pure html.
34792 setText : function(text, isHTML){
34800 var html = this.html.length ? this.html : String.format('{0}',this.text);
34802 this.el.update(String.format(
34803 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
34804 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34805 this.parentMenu.autoWidth();
34810 handleClick : function(e){
34811 if(!this.href){ // if no link defined, stop the event automatically
34814 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34818 activate : function(autoExpand){
34819 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34829 shouldDeactivate : function(e){
34830 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34831 if(this.menu && this.menu.isVisible()){
34832 return !this.menu.getEl().getRegion().contains(e.getPoint());
34840 deactivate : function(){
34841 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34846 expandMenu : function(autoActivate){
34847 if(!this.disabled && this.menu){
34848 clearTimeout(this.hideTimer);
34849 delete this.hideTimer;
34850 if(!this.menu.isVisible() && !this.showTimer){
34851 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34852 }else if (this.menu.isVisible() && autoActivate){
34853 this.menu.tryActivate(0, 1);
34859 deferExpand : function(autoActivate){
34860 delete this.showTimer;
34861 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34863 this.menu.tryActivate(0, 1);
34868 hideMenu : function(){
34869 clearTimeout(this.showTimer);
34870 delete this.showTimer;
34871 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34872 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34877 deferHide : function(){
34878 delete this.hideTimer;
34883 * Ext JS Library 1.1.1
34884 * Copyright(c) 2006-2007, Ext JS, LLC.
34886 * Originally Released Under LGPL - original licence link has changed is not relivant.
34889 * <script type="text/javascript">
34893 * @class Roo.menu.CheckItem
34894 * @extends Roo.menu.Item
34895 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
34897 * Creates a new CheckItem
34898 * @param {Object} config Configuration options
34900 Roo.menu.CheckItem = function(config){
34901 Roo.menu.CheckItem.superclass.constructor.call(this, config);
34904 * @event beforecheckchange
34905 * Fires before the checked value is set, providing an opportunity to cancel if needed
34906 * @param {Roo.menu.CheckItem} this
34907 * @param {Boolean} checked The new checked value that will be set
34909 "beforecheckchange" : true,
34911 * @event checkchange
34912 * Fires after the checked value has been set
34913 * @param {Roo.menu.CheckItem} this
34914 * @param {Boolean} checked The checked value that was set
34916 "checkchange" : true
34918 if(this.checkHandler){
34919 this.on('checkchange', this.checkHandler, this.scope);
34922 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
34924 * @cfg {String} group
34925 * All check items with the same group name will automatically be grouped into a single-select
34926 * radio button group (defaults to '')
34929 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
34931 itemCls : "x-menu-item x-menu-check-item",
34933 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
34935 groupClass : "x-menu-group-item",
34938 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
34939 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
34940 * initialized with checked = true will be rendered as checked.
34945 ctype: "Roo.menu.CheckItem",
34948 onRender : function(c){
34949 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
34951 this.el.addClass(this.groupClass);
34953 Roo.menu.MenuMgr.registerCheckable(this);
34955 this.checked = false;
34956 this.setChecked(true, true);
34961 destroy : function(){
34963 Roo.menu.MenuMgr.unregisterCheckable(this);
34965 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
34969 * Set the checked state of this item
34970 * @param {Boolean} checked The new checked value
34971 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
34973 setChecked : function(state, suppressEvent){
34974 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
34975 if(this.container){
34976 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
34978 this.checked = state;
34979 if(suppressEvent !== true){
34980 this.fireEvent("checkchange", this, state);
34986 handleClick : function(e){
34987 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
34988 this.setChecked(!this.checked);
34990 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
34994 * Ext JS Library 1.1.1
34995 * Copyright(c) 2006-2007, Ext JS, LLC.
34997 * Originally Released Under LGPL - original licence link has changed is not relivant.
35000 * <script type="text/javascript">
35004 * @class Roo.menu.DateItem
35005 * @extends Roo.menu.Adapter
35006 * A menu item that wraps the {@link Roo.DatPicker} component.
35008 * Creates a new DateItem
35009 * @param {Object} config Configuration options
35011 Roo.menu.DateItem = function(config){
35012 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35013 /** The Roo.DatePicker object @type Roo.DatePicker */
35014 this.picker = this.component;
35015 this.addEvents({select: true});
35017 this.picker.on("render", function(picker){
35018 picker.getEl().swallowEvent("click");
35019 picker.container.addClass("x-menu-date-item");
35022 this.picker.on("select", this.onSelect, this);
35025 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35027 onSelect : function(picker, date){
35028 this.fireEvent("select", this, date, picker);
35029 Roo.menu.DateItem.superclass.handleClick.call(this);
35033 * Ext JS Library 1.1.1
35034 * Copyright(c) 2006-2007, Ext JS, LLC.
35036 * Originally Released Under LGPL - original licence link has changed is not relivant.
35039 * <script type="text/javascript">
35043 * @class Roo.menu.ColorItem
35044 * @extends Roo.menu.Adapter
35045 * A menu item that wraps the {@link Roo.ColorPalette} component.
35047 * Creates a new ColorItem
35048 * @param {Object} config Configuration options
35050 Roo.menu.ColorItem = function(config){
35051 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35052 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35053 this.palette = this.component;
35054 this.relayEvents(this.palette, ["select"]);
35055 if(this.selectHandler){
35056 this.on('select', this.selectHandler, this.scope);
35059 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35061 * Ext JS Library 1.1.1
35062 * Copyright(c) 2006-2007, Ext JS, LLC.
35064 * Originally Released Under LGPL - original licence link has changed is not relivant.
35067 * <script type="text/javascript">
35072 * @class Roo.menu.DateMenu
35073 * @extends Roo.menu.Menu
35074 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35076 * Creates a new DateMenu
35077 * @param {Object} config Configuration options
35079 Roo.menu.DateMenu = function(config){
35080 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35082 var di = new Roo.menu.DateItem(config);
35085 * The {@link Roo.DatePicker} instance for this DateMenu
35088 this.picker = di.picker;
35091 * @param {DatePicker} picker
35092 * @param {Date} date
35094 this.relayEvents(di, ["select"]);
35096 this.on('beforeshow', function(){
35098 this.picker.hideMonthPicker(true);
35102 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35106 * Ext JS Library 1.1.1
35107 * Copyright(c) 2006-2007, Ext JS, LLC.
35109 * Originally Released Under LGPL - original licence link has changed is not relivant.
35112 * <script type="text/javascript">
35117 * @class Roo.menu.ColorMenu
35118 * @extends Roo.menu.Menu
35119 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35121 * Creates a new ColorMenu
35122 * @param {Object} config Configuration options
35124 Roo.menu.ColorMenu = function(config){
35125 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35127 var ci = new Roo.menu.ColorItem(config);
35130 * The {@link Roo.ColorPalette} instance for this ColorMenu
35131 * @type ColorPalette
35133 this.palette = ci.palette;
35136 * @param {ColorPalette} palette
35137 * @param {String} color
35139 this.relayEvents(ci, ["select"]);
35141 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35143 * Ext JS Library 1.1.1
35144 * Copyright(c) 2006-2007, Ext JS, LLC.
35146 * Originally Released Under LGPL - original licence link has changed is not relivant.
35149 * <script type="text/javascript">
35153 * @class Roo.form.Field
35154 * @extends Roo.BoxComponent
35155 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35157 * Creates a new Field
35158 * @param {Object} config Configuration options
35160 Roo.form.Field = function(config){
35161 Roo.form.Field.superclass.constructor.call(this, config);
35164 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35166 * @cfg {String} fieldLabel Label to use when rendering a form.
35169 * @cfg {String} qtip Mouse over tip
35173 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35175 invalidClass : "x-form-invalid",
35177 * @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")
35179 invalidText : "The value in this field is invalid",
35181 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35183 focusClass : "x-form-focus",
35185 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35186 automatic validation (defaults to "keyup").
35188 validationEvent : "keyup",
35190 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35192 validateOnBlur : true,
35194 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35196 validationDelay : 250,
35198 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35199 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35201 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35203 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35205 fieldClass : "x-form-field",
35207 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35210 ----------- ----------------------------------------------------------------------
35211 qtip Display a quick tip when the user hovers over the field
35212 title Display a default browser title attribute popup
35213 under Add a block div beneath the field containing the error text
35214 side Add an error icon to the right of the field with a popup on hover
35215 [element id] Add the error text directly to the innerHTML of the specified element
35218 msgTarget : 'qtip',
35220 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35225 * @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.
35230 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35235 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35237 inputType : undefined,
35240 * @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).
35242 tabIndex : undefined,
35245 isFormField : true,
35250 * @property {Roo.Element} fieldEl
35251 * Element Containing the rendered Field (with label etc.)
35254 * @cfg {Mixed} value A value to initialize this field with.
35259 * @cfg {String} name The field's HTML name attribute.
35262 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35266 initComponent : function(){
35267 Roo.form.Field.superclass.initComponent.call(this);
35271 * Fires when this field receives input focus.
35272 * @param {Roo.form.Field} this
35277 * Fires when this field loses input focus.
35278 * @param {Roo.form.Field} this
35282 * @event specialkey
35283 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35284 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35285 * @param {Roo.form.Field} this
35286 * @param {Roo.EventObject} e The event object
35291 * Fires just before the field blurs if the field value has changed.
35292 * @param {Roo.form.Field} this
35293 * @param {Mixed} newValue The new value
35294 * @param {Mixed} oldValue The original value
35299 * Fires after the field has been marked as invalid.
35300 * @param {Roo.form.Field} this
35301 * @param {String} msg The validation message
35306 * Fires after the field has been validated with no errors.
35307 * @param {Roo.form.Field} this
35312 * Fires after the key up
35313 * @param {Roo.form.Field} this
35314 * @param {Roo.EventObject} e The event Object
35321 * Returns the name attribute of the field if available
35322 * @return {String} name The field name
35324 getName: function(){
35325 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35329 onRender : function(ct, position){
35330 Roo.form.Field.superclass.onRender.call(this, ct, position);
35332 var cfg = this.getAutoCreate();
35334 cfg.name = this.name || this.id;
35336 if(this.inputType){
35337 cfg.type = this.inputType;
35339 this.el = ct.createChild(cfg, position);
35341 var type = this.el.dom.type;
35343 if(type == 'password'){
35346 this.el.addClass('x-form-'+type);
35349 this.el.dom.readOnly = true;
35351 if(this.tabIndex !== undefined){
35352 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35355 this.el.addClass([this.fieldClass, this.cls]);
35360 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35361 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35362 * @return {Roo.form.Field} this
35364 applyTo : function(target){
35365 this.allowDomMove = false;
35366 this.el = Roo.get(target);
35367 this.render(this.el.dom.parentNode);
35372 initValue : function(){
35373 if(this.value !== undefined){
35374 this.setValue(this.value);
35375 }else if(this.el.dom.value.length > 0){
35376 this.setValue(this.el.dom.value);
35381 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35383 isDirty : function() {
35384 if(this.disabled) {
35387 return String(this.getValue()) !== String(this.originalValue);
35391 afterRender : function(){
35392 Roo.form.Field.superclass.afterRender.call(this);
35397 fireKey : function(e){
35398 //Roo.log('field ' + e.getKey());
35399 if(e.isNavKeyPress()){
35400 this.fireEvent("specialkey", this, e);
35405 * Resets the current field value to the originally loaded value and clears any validation messages
35407 reset : function(){
35408 this.setValue(this.originalValue);
35409 this.clearInvalid();
35413 initEvents : function(){
35414 // safari killled keypress - so keydown is now used..
35415 this.el.on("keydown" , this.fireKey, this);
35416 this.el.on("focus", this.onFocus, this);
35417 this.el.on("blur", this.onBlur, this);
35418 this.el.relayEvent('keyup', this);
35420 // reference to original value for reset
35421 this.originalValue = this.getValue();
35425 onFocus : function(){
35426 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35427 this.el.addClass(this.focusClass);
35429 if(!this.hasFocus){
35430 this.hasFocus = true;
35431 this.startValue = this.getValue();
35432 this.fireEvent("focus", this);
35436 beforeBlur : Roo.emptyFn,
35439 onBlur : function(){
35441 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35442 this.el.removeClass(this.focusClass);
35444 this.hasFocus = false;
35445 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35448 var v = this.getValue();
35449 if(String(v) !== String(this.startValue)){
35450 this.fireEvent('change', this, v, this.startValue);
35452 this.fireEvent("blur", this);
35456 * Returns whether or not the field value is currently valid
35457 * @param {Boolean} preventMark True to disable marking the field invalid
35458 * @return {Boolean} True if the value is valid, else false
35460 isValid : function(preventMark){
35464 var restore = this.preventMark;
35465 this.preventMark = preventMark === true;
35466 var v = this.validateValue(this.processValue(this.getRawValue()));
35467 this.preventMark = restore;
35472 * Validates the field value
35473 * @return {Boolean} True if the value is valid, else false
35475 validate : function(){
35476 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35477 this.clearInvalid();
35483 processValue : function(value){
35488 // Subclasses should provide the validation implementation by overriding this
35489 validateValue : function(value){
35494 * Mark this field as invalid
35495 * @param {String} msg The validation message
35497 markInvalid : function(msg){
35498 if(!this.rendered || this.preventMark){ // not rendered
35501 this.el.addClass(this.invalidClass);
35502 msg = msg || this.invalidText;
35503 switch(this.msgTarget){
35505 this.el.dom.qtip = msg;
35506 this.el.dom.qclass = 'x-form-invalid-tip';
35507 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35508 Roo.QuickTips.enable();
35512 this.el.dom.title = msg;
35516 var elp = this.el.findParent('.x-form-element', 5, true);
35517 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35518 this.errorEl.setWidth(elp.getWidth(true)-20);
35520 this.errorEl.update(msg);
35521 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35524 if(!this.errorIcon){
35525 var elp = this.el.findParent('.x-form-element', 5, true);
35526 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35528 this.alignErrorIcon();
35529 this.errorIcon.dom.qtip = msg;
35530 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35531 this.errorIcon.show();
35532 this.on('resize', this.alignErrorIcon, this);
35535 var t = Roo.getDom(this.msgTarget);
35537 t.style.display = this.msgDisplay;
35540 this.fireEvent('invalid', this, msg);
35544 alignErrorIcon : function(){
35545 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35549 * Clear any invalid styles/messages for this field
35551 clearInvalid : function(){
35552 if(!this.rendered || this.preventMark){ // not rendered
35555 this.el.removeClass(this.invalidClass);
35556 switch(this.msgTarget){
35558 this.el.dom.qtip = '';
35561 this.el.dom.title = '';
35565 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35569 if(this.errorIcon){
35570 this.errorIcon.dom.qtip = '';
35571 this.errorIcon.hide();
35572 this.un('resize', this.alignErrorIcon, this);
35576 var t = Roo.getDom(this.msgTarget);
35578 t.style.display = 'none';
35581 this.fireEvent('valid', this);
35585 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35586 * @return {Mixed} value The field value
35588 getRawValue : function(){
35589 var v = this.el.getValue();
35590 if(v === this.emptyText){
35597 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35598 * @return {Mixed} value The field value
35600 getValue : function(){
35601 var v = this.el.getValue();
35602 if(v === this.emptyText || v === undefined){
35609 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35610 * @param {Mixed} value The value to set
35612 setRawValue : function(v){
35613 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35617 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35618 * @param {Mixed} value The value to set
35620 setValue : function(v){
35623 this.el.dom.value = (v === null || v === undefined ? '' : v);
35628 adjustSize : function(w, h){
35629 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35630 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35634 adjustWidth : function(tag, w){
35635 tag = tag.toLowerCase();
35636 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35637 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35638 if(tag == 'input'){
35641 if(tag = 'textarea'){
35644 }else if(Roo.isOpera){
35645 if(tag == 'input'){
35648 if(tag = 'textarea'){
35658 // anything other than normal should be considered experimental
35659 Roo.form.Field.msgFx = {
35661 show: function(msgEl, f){
35662 msgEl.setDisplayed('block');
35665 hide : function(msgEl, f){
35666 msgEl.setDisplayed(false).update('');
35671 show: function(msgEl, f){
35672 msgEl.slideIn('t', {stopFx:true});
35675 hide : function(msgEl, f){
35676 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35681 show: function(msgEl, f){
35682 msgEl.fixDisplay();
35683 msgEl.alignTo(f.el, 'tl-tr');
35684 msgEl.slideIn('l', {stopFx:true});
35687 hide : function(msgEl, f){
35688 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35693 * Ext JS Library 1.1.1
35694 * Copyright(c) 2006-2007, Ext JS, LLC.
35696 * Originally Released Under LGPL - original licence link has changed is not relivant.
35699 * <script type="text/javascript">
35704 * @class Roo.form.TextField
35705 * @extends Roo.form.Field
35706 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35707 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35709 * Creates a new TextField
35710 * @param {Object} config Configuration options
35712 Roo.form.TextField = function(config){
35713 Roo.form.TextField.superclass.constructor.call(this, config);
35717 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35718 * according to the default logic, but this event provides a hook for the developer to apply additional
35719 * logic at runtime to resize the field if needed.
35720 * @param {Roo.form.Field} this This text field
35721 * @param {Number} width The new field width
35727 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35729 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35733 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35737 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35741 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35745 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35749 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35751 disableKeyFilter : false,
35753 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35757 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35761 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35763 maxLength : Number.MAX_VALUE,
35765 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35767 minLengthText : "The minimum length for this field is {0}",
35769 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35771 maxLengthText : "The maximum length for this field is {0}",
35773 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35775 selectOnFocus : false,
35777 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35779 blankText : "This field is required",
35781 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35782 * If available, this function will be called only after the basic validators all return true, and will be passed the
35783 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35787 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35788 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35789 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35793 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35797 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35801 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35802 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35804 emptyClass : 'x-form-empty-field',
35807 initEvents : function(){
35808 Roo.form.TextField.superclass.initEvents.call(this);
35809 if(this.validationEvent == 'keyup'){
35810 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35811 this.el.on('keyup', this.filterValidation, this);
35813 else if(this.validationEvent !== false){
35814 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35816 if(this.selectOnFocus || this.emptyText){
35817 this.on("focus", this.preFocus, this);
35818 if(this.emptyText){
35819 this.on('blur', this.postBlur, this);
35820 this.applyEmptyText();
35823 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35824 this.el.on("keypress", this.filterKeys, this);
35827 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35828 this.el.on("click", this.autoSize, this);
35832 processValue : function(value){
35833 if(this.stripCharsRe){
35834 var newValue = value.replace(this.stripCharsRe, '');
35835 if(newValue !== value){
35836 this.setRawValue(newValue);
35843 filterValidation : function(e){
35844 if(!e.isNavKeyPress()){
35845 this.validationTask.delay(this.validationDelay);
35850 onKeyUp : function(e){
35851 if(!e.isNavKeyPress()){
35857 * Resets the current field value to the originally-loaded value and clears any validation messages.
35858 * Also adds emptyText and emptyClass if the original value was blank.
35860 reset : function(){
35861 Roo.form.TextField.superclass.reset.call(this);
35862 this.applyEmptyText();
35865 applyEmptyText : function(){
35866 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35867 this.setRawValue(this.emptyText);
35868 this.el.addClass(this.emptyClass);
35873 preFocus : function(){
35874 if(this.emptyText){
35875 if(this.el.dom.value == this.emptyText){
35876 this.setRawValue('');
35878 this.el.removeClass(this.emptyClass);
35880 if(this.selectOnFocus){
35881 this.el.dom.select();
35886 postBlur : function(){
35887 this.applyEmptyText();
35891 filterKeys : function(e){
35892 var k = e.getKey();
35893 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
35896 var c = e.getCharCode(), cc = String.fromCharCode(c);
35897 if(Roo.isIE && (e.isSpecialKey() || !cc)){
35900 if(!this.maskRe.test(cc)){
35905 setValue : function(v){
35906 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
35907 this.el.removeClass(this.emptyClass);
35909 Roo.form.TextField.superclass.setValue.apply(this, arguments);
35910 this.applyEmptyText();
35915 * Validates a value according to the field's validation rules and marks the field as invalid
35916 * if the validation fails
35917 * @param {Mixed} value The value to validate
35918 * @return {Boolean} True if the value is valid, else false
35920 validateValue : function(value){
35921 if(value.length < 1 || value === this.emptyText){ // if it's blank
35922 if(this.allowBlank){
35923 this.clearInvalid();
35926 this.markInvalid(this.blankText);
35930 if(value.length < this.minLength){
35931 this.markInvalid(String.format(this.minLengthText, this.minLength));
35934 if(value.length > this.maxLength){
35935 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
35939 var vt = Roo.form.VTypes;
35940 if(!vt[this.vtype](value, this)){
35941 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
35945 if(typeof this.validator == "function"){
35946 var msg = this.validator(value);
35948 this.markInvalid(msg);
35952 if(this.regex && !this.regex.test(value)){
35953 this.markInvalid(this.regexText);
35960 * Selects text in this field
35961 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
35962 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
35964 selectText : function(start, end){
35965 var v = this.getRawValue();
35967 start = start === undefined ? 0 : start;
35968 end = end === undefined ? v.length : end;
35969 var d = this.el.dom;
35970 if(d.setSelectionRange){
35971 d.setSelectionRange(start, end);
35972 }else if(d.createTextRange){
35973 var range = d.createTextRange();
35974 range.moveStart("character", start);
35975 range.moveEnd("character", v.length-end);
35982 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
35983 * This only takes effect if grow = true, and fires the autosize event.
35985 autoSize : function(){
35986 if(!this.grow || !this.rendered){
35990 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
35993 var v = el.dom.value;
35994 var d = document.createElement('div');
35995 d.appendChild(document.createTextNode(v));
35999 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36000 this.el.setWidth(w);
36001 this.fireEvent("autosize", this, w);
36005 * Ext JS Library 1.1.1
36006 * Copyright(c) 2006-2007, Ext JS, LLC.
36008 * Originally Released Under LGPL - original licence link has changed is not relivant.
36011 * <script type="text/javascript">
36015 * @class Roo.form.Hidden
36016 * @extends Roo.form.TextField
36017 * Simple Hidden element used on forms
36019 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36022 * Creates a new Hidden form element.
36023 * @param {Object} config Configuration options
36028 // easy hidden field...
36029 Roo.form.Hidden = function(config){
36030 Roo.form.Hidden.superclass.constructor.call(this, config);
36033 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36035 inputType: 'hidden',
36038 labelSeparator: '',
36040 itemCls : 'x-form-item-display-none'
36048 * Ext JS Library 1.1.1
36049 * Copyright(c) 2006-2007, Ext JS, LLC.
36051 * Originally Released Under LGPL - original licence link has changed is not relivant.
36054 * <script type="text/javascript">
36058 * @class Roo.form.TriggerField
36059 * @extends Roo.form.TextField
36060 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36061 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36062 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36063 * for which you can provide a custom implementation. For example:
36065 var trigger = new Roo.form.TriggerField();
36066 trigger.onTriggerClick = myTriggerFn;
36067 trigger.applyTo('my-field');
36070 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36071 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36072 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36073 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36075 * Create a new TriggerField.
36076 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36077 * to the base TextField)
36079 Roo.form.TriggerField = function(config){
36080 this.mimicing = false;
36081 Roo.form.TriggerField.superclass.constructor.call(this, config);
36084 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36086 * @cfg {String} triggerClass A CSS class to apply to the trigger
36089 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36090 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36092 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36094 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36098 /** @cfg {Boolean} grow @hide */
36099 /** @cfg {Number} growMin @hide */
36100 /** @cfg {Number} growMax @hide */
36106 autoSize: Roo.emptyFn,
36110 deferHeight : true,
36113 actionMode : 'wrap',
36115 onResize : function(w, h){
36116 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36117 if(typeof w == 'number'){
36118 var x = w - this.trigger.getWidth();
36119 this.el.setWidth(this.adjustWidth('input', x));
36120 this.trigger.setStyle('left', x+'px');
36125 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36128 getResizeEl : function(){
36133 getPositionEl : function(){
36138 alignErrorIcon : function(){
36139 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36143 onRender : function(ct, position){
36144 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36145 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36146 this.trigger = this.wrap.createChild(this.triggerConfig ||
36147 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36148 if(this.hideTrigger){
36149 this.trigger.setDisplayed(false);
36151 this.initTrigger();
36153 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36158 initTrigger : function(){
36159 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36160 this.trigger.addClassOnOver('x-form-trigger-over');
36161 this.trigger.addClassOnClick('x-form-trigger-click');
36165 onDestroy : function(){
36167 this.trigger.removeAllListeners();
36168 this.trigger.remove();
36171 this.wrap.remove();
36173 Roo.form.TriggerField.superclass.onDestroy.call(this);
36177 onFocus : function(){
36178 Roo.form.TriggerField.superclass.onFocus.call(this);
36179 if(!this.mimicing){
36180 this.wrap.addClass('x-trigger-wrap-focus');
36181 this.mimicing = true;
36182 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36183 if(this.monitorTab){
36184 this.el.on("keydown", this.checkTab, this);
36190 checkTab : function(e){
36191 if(e.getKey() == e.TAB){
36192 this.triggerBlur();
36197 onBlur : function(){
36202 mimicBlur : function(e, t){
36203 if(!this.wrap.contains(t) && this.validateBlur()){
36204 this.triggerBlur();
36209 triggerBlur : function(){
36210 this.mimicing = false;
36211 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36212 if(this.monitorTab){
36213 this.el.un("keydown", this.checkTab, this);
36215 this.wrap.removeClass('x-trigger-wrap-focus');
36216 Roo.form.TriggerField.superclass.onBlur.call(this);
36220 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36221 validateBlur : function(e, t){
36226 onDisable : function(){
36227 Roo.form.TriggerField.superclass.onDisable.call(this);
36229 this.wrap.addClass('x-item-disabled');
36234 onEnable : function(){
36235 Roo.form.TriggerField.superclass.onEnable.call(this);
36237 this.wrap.removeClass('x-item-disabled');
36242 onShow : function(){
36243 var ae = this.getActionEl();
36246 ae.dom.style.display = '';
36247 ae.dom.style.visibility = 'visible';
36253 onHide : function(){
36254 var ae = this.getActionEl();
36255 ae.dom.style.display = 'none';
36259 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36260 * by an implementing function.
36262 * @param {EventObject} e
36264 onTriggerClick : Roo.emptyFn
36267 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36268 // to be extended by an implementing class. For an example of implementing this class, see the custom
36269 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36270 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36271 initComponent : function(){
36272 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36274 this.triggerConfig = {
36275 tag:'span', cls:'x-form-twin-triggers', cn:[
36276 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36277 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36281 getTrigger : function(index){
36282 return this.triggers[index];
36285 initTrigger : function(){
36286 var ts = this.trigger.select('.x-form-trigger', true);
36287 this.wrap.setStyle('overflow', 'hidden');
36288 var triggerField = this;
36289 ts.each(function(t, all, index){
36290 t.hide = function(){
36291 var w = triggerField.wrap.getWidth();
36292 this.dom.style.display = 'none';
36293 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36295 t.show = function(){
36296 var w = triggerField.wrap.getWidth();
36297 this.dom.style.display = '';
36298 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36300 var triggerIndex = 'Trigger'+(index+1);
36302 if(this['hide'+triggerIndex]){
36303 t.dom.style.display = 'none';
36305 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36306 t.addClassOnOver('x-form-trigger-over');
36307 t.addClassOnClick('x-form-trigger-click');
36309 this.triggers = ts.elements;
36312 onTrigger1Click : Roo.emptyFn,
36313 onTrigger2Click : Roo.emptyFn
36316 * Ext JS Library 1.1.1
36317 * Copyright(c) 2006-2007, Ext JS, LLC.
36319 * Originally Released Under LGPL - original licence link has changed is not relivant.
36322 * <script type="text/javascript">
36326 * @class Roo.form.TextArea
36327 * @extends Roo.form.TextField
36328 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36329 * support for auto-sizing.
36331 * Creates a new TextArea
36332 * @param {Object} config Configuration options
36334 Roo.form.TextArea = function(config){
36335 Roo.form.TextArea.superclass.constructor.call(this, config);
36336 // these are provided exchanges for backwards compat
36337 // minHeight/maxHeight were replaced by growMin/growMax to be
36338 // compatible with TextField growing config values
36339 if(this.minHeight !== undefined){
36340 this.growMin = this.minHeight;
36342 if(this.maxHeight !== undefined){
36343 this.growMax = this.maxHeight;
36347 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36349 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36353 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36357 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36358 * in the field (equivalent to setting overflow: hidden, defaults to false)
36360 preventScrollbars: false,
36362 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36363 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36367 onRender : function(ct, position){
36369 this.defaultAutoCreate = {
36371 style:"width:300px;height:60px;",
36372 autocomplete: "off"
36375 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36377 this.textSizeEl = Roo.DomHelper.append(document.body, {
36378 tag: "pre", cls: "x-form-grow-sizer"
36380 if(this.preventScrollbars){
36381 this.el.setStyle("overflow", "hidden");
36383 this.el.setHeight(this.growMin);
36387 onDestroy : function(){
36388 if(this.textSizeEl){
36389 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36391 Roo.form.TextArea.superclass.onDestroy.call(this);
36395 onKeyUp : function(e){
36396 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36402 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36403 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36405 autoSize : function(){
36406 if(!this.grow || !this.textSizeEl){
36410 var v = el.dom.value;
36411 var ts = this.textSizeEl;
36414 ts.appendChild(document.createTextNode(v));
36417 Roo.fly(ts).setWidth(this.el.getWidth());
36419 v = "  ";
36422 v = v.replace(/\n/g, '<p> </p>');
36424 v += " \n ";
36427 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36428 if(h != this.lastHeight){
36429 this.lastHeight = h;
36430 this.el.setHeight(h);
36431 this.fireEvent("autosize", this, h);
36436 * Ext JS Library 1.1.1
36437 * Copyright(c) 2006-2007, Ext JS, LLC.
36439 * Originally Released Under LGPL - original licence link has changed is not relivant.
36442 * <script type="text/javascript">
36447 * @class Roo.form.NumberField
36448 * @extends Roo.form.TextField
36449 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36451 * Creates a new NumberField
36452 * @param {Object} config Configuration options
36454 Roo.form.NumberField = function(config){
36455 Roo.form.NumberField.superclass.constructor.call(this, config);
36458 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36460 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36462 fieldClass: "x-form-field x-form-num-field",
36464 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36466 allowDecimals : true,
36468 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36470 decimalSeparator : ".",
36472 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36474 decimalPrecision : 2,
36476 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36478 allowNegative : true,
36480 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36482 minValue : Number.NEGATIVE_INFINITY,
36484 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36486 maxValue : Number.MAX_VALUE,
36488 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36490 minText : "The minimum value for this field is {0}",
36492 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36494 maxText : "The maximum value for this field is {0}",
36496 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36497 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36499 nanText : "{0} is not a valid number",
36502 initEvents : function(){
36503 Roo.form.NumberField.superclass.initEvents.call(this);
36504 var allowed = "0123456789";
36505 if(this.allowDecimals){
36506 allowed += this.decimalSeparator;
36508 if(this.allowNegative){
36511 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36512 var keyPress = function(e){
36513 var k = e.getKey();
36514 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36517 var c = e.getCharCode();
36518 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36522 this.el.on("keypress", keyPress, this);
36526 validateValue : function(value){
36527 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36530 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36533 var num = this.parseValue(value);
36535 this.markInvalid(String.format(this.nanText, value));
36538 if(num < this.minValue){
36539 this.markInvalid(String.format(this.minText, this.minValue));
36542 if(num > this.maxValue){
36543 this.markInvalid(String.format(this.maxText, this.maxValue));
36549 getValue : function(){
36550 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36554 parseValue : function(value){
36555 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36556 return isNaN(value) ? '' : value;
36560 fixPrecision : function(value){
36561 var nan = isNaN(value);
36562 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36563 return nan ? '' : value;
36565 return parseFloat(value).toFixed(this.decimalPrecision);
36568 setValue : function(v){
36569 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36573 decimalPrecisionFcn : function(v){
36574 return Math.floor(v);
36577 beforeBlur : function(){
36578 var v = this.parseValue(this.getRawValue());
36580 this.setValue(this.fixPrecision(v));
36585 * Ext JS Library 1.1.1
36586 * Copyright(c) 2006-2007, Ext JS, LLC.
36588 * Originally Released Under LGPL - original licence link has changed is not relivant.
36591 * <script type="text/javascript">
36595 * @class Roo.form.DateField
36596 * @extends Roo.form.TriggerField
36597 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36599 * Create a new DateField
36600 * @param {Object} config
36602 Roo.form.DateField = function(config){
36603 Roo.form.DateField.superclass.constructor.call(this, config);
36609 * Fires when a date is selected
36610 * @param {Roo.form.DateField} combo This combo box
36611 * @param {Date} date The date selected
36618 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36619 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36620 this.ddMatch = null;
36621 if(this.disabledDates){
36622 var dd = this.disabledDates;
36624 for(var i = 0; i < dd.length; i++){
36626 if(i != dd.length-1) re += "|";
36628 this.ddMatch = new RegExp(re + ")");
36632 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36634 * @cfg {String} format
36635 * The default date format string which can be overriden for localization support. The format must be
36636 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36640 * @cfg {String} altFormats
36641 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36642 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36644 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36646 * @cfg {Array} disabledDays
36647 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36649 disabledDays : null,
36651 * @cfg {String} disabledDaysText
36652 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36654 disabledDaysText : "Disabled",
36656 * @cfg {Array} disabledDates
36657 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36658 * expression so they are very powerful. Some examples:
36660 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36661 * <li>["03/08", "09/16"] would disable those days for every year</li>
36662 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36663 * <li>["03/../2006"] would disable every day in March 2006</li>
36664 * <li>["^03"] would disable every day in every March</li>
36666 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36667 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36669 disabledDates : null,
36671 * @cfg {String} disabledDatesText
36672 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36674 disabledDatesText : "Disabled",
36676 * @cfg {Date/String} minValue
36677 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36678 * valid format (defaults to null).
36682 * @cfg {Date/String} maxValue
36683 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36684 * valid format (defaults to null).
36688 * @cfg {String} minText
36689 * The error text to display when the date in the cell is before minValue (defaults to
36690 * 'The date in this field must be after {minValue}').
36692 minText : "The date in this field must be equal to or after {0}",
36694 * @cfg {String} maxText
36695 * The error text to display when the date in the cell is after maxValue (defaults to
36696 * 'The date in this field must be before {maxValue}').
36698 maxText : "The date in this field must be equal to or before {0}",
36700 * @cfg {String} invalidText
36701 * The error text to display when the date in the field is invalid (defaults to
36702 * '{value} is not a valid date - it must be in the format {format}').
36704 invalidText : "{0} is not a valid date - it must be in the format {1}",
36706 * @cfg {String} triggerClass
36707 * An additional CSS class used to style the trigger button. The trigger will always get the
36708 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36709 * which displays a calendar icon).
36711 triggerClass : 'x-form-date-trigger',
36715 * @cfg {bool} useIso
36716 * if enabled, then the date field will use a hidden field to store the
36717 * real value as iso formated date. default (false)
36721 * @cfg {String/Object} autoCreate
36722 * A DomHelper element spec, or true for a default element spec (defaults to
36723 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36726 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36729 hiddenField: false,
36731 onRender : function(ct, position)
36733 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36735 this.el.dom.removeAttribute('name');
36736 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36738 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36739 // prevent input submission
36740 this.hiddenName = this.name;
36747 validateValue : function(value)
36749 value = this.formatDate(value);
36750 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36753 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36756 var svalue = value;
36757 value = this.parseDate(value);
36759 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36762 var time = value.getTime();
36763 if(this.minValue && time < this.minValue.getTime()){
36764 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36767 if(this.maxValue && time > this.maxValue.getTime()){
36768 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36771 if(this.disabledDays){
36772 var day = value.getDay();
36773 for(var i = 0; i < this.disabledDays.length; i++) {
36774 if(day === this.disabledDays[i]){
36775 this.markInvalid(this.disabledDaysText);
36780 var fvalue = this.formatDate(value);
36781 if(this.ddMatch && this.ddMatch.test(fvalue)){
36782 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36789 // Provides logic to override the default TriggerField.validateBlur which just returns true
36790 validateBlur : function(){
36791 return !this.menu || !this.menu.isVisible();
36795 * Returns the current date value of the date field.
36796 * @return {Date} The date value
36798 getValue : function(){
36800 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36804 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36805 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36806 * (the default format used is "m/d/y").
36809 //All of these calls set the same date value (May 4, 2006)
36811 //Pass a date object:
36812 var dt = new Date('5/4/06');
36813 dateField.setValue(dt);
36815 //Pass a date string (default format):
36816 dateField.setValue('5/4/06');
36818 //Pass a date string (custom format):
36819 dateField.format = 'Y-m-d';
36820 dateField.setValue('2006-5-4');
36822 * @param {String/Date} date The date or valid date string
36824 setValue : function(date){
36825 if (this.hiddenField) {
36826 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36828 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36832 parseDate : function(value){
36833 if(!value || value instanceof Date){
36836 var v = Date.parseDate(value, this.format);
36837 if(!v && this.altFormats){
36838 if(!this.altFormatsArray){
36839 this.altFormatsArray = this.altFormats.split("|");
36841 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36842 v = Date.parseDate(value, this.altFormatsArray[i]);
36849 formatDate : function(date, fmt){
36850 return (!date || !(date instanceof Date)) ?
36851 date : date.dateFormat(fmt || this.format);
36856 select: function(m, d){
36858 this.fireEvent('select', this, d);
36860 show : function(){ // retain focus styling
36864 this.focus.defer(10, this);
36865 var ml = this.menuListeners;
36866 this.menu.un("select", ml.select, this);
36867 this.menu.un("show", ml.show, this);
36868 this.menu.un("hide", ml.hide, this);
36873 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36874 onTriggerClick : function(){
36878 if(this.menu == null){
36879 this.menu = new Roo.menu.DateMenu();
36881 Roo.apply(this.menu.picker, {
36882 showClear: this.allowBlank,
36883 minDate : this.minValue,
36884 maxDate : this.maxValue,
36885 disabledDatesRE : this.ddMatch,
36886 disabledDatesText : this.disabledDatesText,
36887 disabledDays : this.disabledDays,
36888 disabledDaysText : this.disabledDaysText,
36889 format : this.format,
36890 minText : String.format(this.minText, this.formatDate(this.minValue)),
36891 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
36893 this.menu.on(Roo.apply({}, this.menuListeners, {
36896 this.menu.picker.setValue(this.getValue() || new Date());
36897 this.menu.show(this.el, "tl-bl?");
36900 beforeBlur : function(){
36901 var v = this.parseDate(this.getRawValue());
36907 /** @cfg {Boolean} grow @hide */
36908 /** @cfg {Number} growMin @hide */
36909 /** @cfg {Number} growMax @hide */
36916 * Ext JS Library 1.1.1
36917 * Copyright(c) 2006-2007, Ext JS, LLC.
36919 * Originally Released Under LGPL - original licence link has changed is not relivant.
36922 * <script type="text/javascript">
36927 * @class Roo.form.ComboBox
36928 * @extends Roo.form.TriggerField
36929 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
36931 * Create a new ComboBox.
36932 * @param {Object} config Configuration options
36934 Roo.form.ComboBox = function(config){
36935 Roo.form.ComboBox.superclass.constructor.call(this, config);
36939 * Fires when the dropdown list is expanded
36940 * @param {Roo.form.ComboBox} combo This combo box
36945 * Fires when the dropdown list is collapsed
36946 * @param {Roo.form.ComboBox} combo This combo box
36950 * @event beforeselect
36951 * Fires before a list item is selected. Return false to cancel the selection.
36952 * @param {Roo.form.ComboBox} combo This combo box
36953 * @param {Roo.data.Record} record The data record returned from the underlying store
36954 * @param {Number} index The index of the selected item in the dropdown list
36956 'beforeselect' : true,
36959 * Fires when a list item is selected
36960 * @param {Roo.form.ComboBox} combo This combo box
36961 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
36962 * @param {Number} index The index of the selected item in the dropdown list
36966 * @event beforequery
36967 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
36968 * The event object passed has these properties:
36969 * @param {Roo.form.ComboBox} combo This combo box
36970 * @param {String} query The query
36971 * @param {Boolean} forceAll true to force "all" query
36972 * @param {Boolean} cancel true to cancel the query
36973 * @param {Object} e The query event object
36975 'beforequery': true,
36978 * Fires when the 'add' icon is pressed (add a listener to enable add button)
36979 * @param {Roo.form.ComboBox} combo This combo box
36984 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
36985 * @param {Roo.form.ComboBox} combo This combo box
36986 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
36992 if(this.transform){
36993 this.allowDomMove = false;
36994 var s = Roo.getDom(this.transform);
36995 if(!this.hiddenName){
36996 this.hiddenName = s.name;
36999 this.mode = 'local';
37000 var d = [], opts = s.options;
37001 for(var i = 0, len = opts.length;i < len; i++){
37003 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37005 this.value = value;
37007 d.push([value, o.text]);
37009 this.store = new Roo.data.SimpleStore({
37011 fields: ['value', 'text'],
37014 this.valueField = 'value';
37015 this.displayField = 'text';
37017 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37018 if(!this.lazyRender){
37019 this.target = true;
37020 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37021 s.parentNode.removeChild(s); // remove it
37022 this.render(this.el.parentNode);
37024 s.parentNode.removeChild(s); // remove it
37029 this.store = Roo.factory(this.store, Roo.data);
37032 this.selectedIndex = -1;
37033 if(this.mode == 'local'){
37034 if(config.queryDelay === undefined){
37035 this.queryDelay = 10;
37037 if(config.minChars === undefined){
37043 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37045 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37048 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37049 * rendering into an Roo.Editor, defaults to false)
37052 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37053 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37056 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37059 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37060 * the dropdown list (defaults to undefined, with no header element)
37064 * @cfg {String/Roo.Template} tpl The template to use to render the output
37068 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37070 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37072 listWidth: undefined,
37074 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37075 * mode = 'remote' or 'text' if mode = 'local')
37077 displayField: undefined,
37079 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37080 * mode = 'remote' or 'value' if mode = 'local').
37081 * Note: use of a valueField requires the user make a selection
37082 * in order for a value to be mapped.
37084 valueField: undefined,
37086 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37087 * field's data value (defaults to the underlying DOM element's name)
37089 hiddenName: undefined,
37091 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37095 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37097 selectedClass: 'x-combo-selected',
37099 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37100 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37101 * which displays a downward arrow icon).
37103 triggerClass : 'x-form-arrow-trigger',
37105 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37109 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37110 * anchor positions (defaults to 'tl-bl')
37112 listAlign: 'tl-bl?',
37114 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37118 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37119 * query specified by the allQuery config option (defaults to 'query')
37121 triggerAction: 'query',
37123 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37124 * (defaults to 4, does not apply if editable = false)
37128 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37129 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37133 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37134 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37138 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37139 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37143 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37144 * when editable = true (defaults to false)
37146 selectOnFocus:false,
37148 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37150 queryParam: 'query',
37152 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37153 * when mode = 'remote' (defaults to 'Loading...')
37155 loadingText: 'Loading...',
37157 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37161 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37165 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37166 * traditional select (defaults to true)
37170 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37174 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37178 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37179 * listWidth has a higher value)
37183 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37184 * allow the user to set arbitrary text into the field (defaults to false)
37186 forceSelection:false,
37188 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37189 * if typeAhead = true (defaults to 250)
37191 typeAheadDelay : 250,
37193 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37194 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37196 valueNotFoundText : undefined,
37198 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37200 blockFocus : false,
37203 * @cfg {Boolean} disableClear Disable showing of clear button.
37205 disableClear : false,
37207 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37209 alwaysQuery : false,
37217 onRender : function(ct, position){
37218 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37219 if(this.hiddenName){
37220 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37222 this.hiddenField.value =
37223 this.hiddenValue !== undefined ? this.hiddenValue :
37224 this.value !== undefined ? this.value : '';
37226 // prevent input submission
37227 this.el.dom.removeAttribute('name');
37230 this.el.dom.setAttribute('autocomplete', 'off');
37233 var cls = 'x-combo-list';
37235 this.list = new Roo.Layer({
37236 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37239 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37240 this.list.setWidth(lw);
37241 this.list.swallowEvent('mousewheel');
37242 this.assetHeight = 0;
37245 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37246 this.assetHeight += this.header.getHeight();
37249 this.innerList = this.list.createChild({cls:cls+'-inner'});
37250 this.innerList.on('mouseover', this.onViewOver, this);
37251 this.innerList.on('mousemove', this.onViewMove, this);
37252 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37254 if(this.allowBlank && !this.pageSize && !this.disableClear){
37255 this.footer = this.list.createChild({cls:cls+'-ft'});
37256 this.pageTb = new Roo.Toolbar(this.footer);
37260 this.footer = this.list.createChild({cls:cls+'-ft'});
37261 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37262 {pageSize: this.pageSize});
37266 if (this.pageTb && this.allowBlank && !this.disableClear) {
37268 this.pageTb.add(new Roo.Toolbar.Fill(), {
37269 cls: 'x-btn-icon x-btn-clear',
37271 handler: function()
37274 _this.clearValue();
37275 _this.onSelect(false, -1);
37280 this.assetHeight += this.footer.getHeight();
37285 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37288 this.view = new Roo.View(this.innerList, this.tpl, {
37289 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37292 this.view.on('click', this.onViewClick, this);
37294 this.store.on('beforeload', this.onBeforeLoad, this);
37295 this.store.on('load', this.onLoad, this);
37296 this.store.on('loadexception', this.collapse, this);
37298 if(this.resizable){
37299 this.resizer = new Roo.Resizable(this.list, {
37300 pinned:true, handles:'se'
37302 this.resizer.on('resize', function(r, w, h){
37303 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37304 this.listWidth = w;
37305 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37306 this.restrictHeight();
37308 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37310 if(!this.editable){
37311 this.editable = true;
37312 this.setEditable(false);
37316 if (typeof(this.events.add.listeners) != 'undefined') {
37318 this.addicon = this.wrap.createChild(
37319 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37321 this.addicon.on('click', function(e) {
37322 this.fireEvent('add', this);
37325 if (typeof(this.events.edit.listeners) != 'undefined') {
37327 this.editicon = this.wrap.createChild(
37328 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37329 if (this.addicon) {
37330 this.editicon.setStyle('margin-left', '40px');
37332 this.editicon.on('click', function(e) {
37334 // we fire even if inothing is selected..
37335 this.fireEvent('edit', this, this.lastData );
37345 initEvents : function(){
37346 Roo.form.ComboBox.superclass.initEvents.call(this);
37348 this.keyNav = new Roo.KeyNav(this.el, {
37349 "up" : function(e){
37350 this.inKeyMode = true;
37354 "down" : function(e){
37355 if(!this.isExpanded()){
37356 this.onTriggerClick();
37358 this.inKeyMode = true;
37363 "enter" : function(e){
37364 this.onViewClick();
37368 "esc" : function(e){
37372 "tab" : function(e){
37373 this.onViewClick(false);
37379 doRelay : function(foo, bar, hname){
37380 if(hname == 'down' || this.scope.isExpanded()){
37381 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37388 this.queryDelay = Math.max(this.queryDelay || 10,
37389 this.mode == 'local' ? 10 : 250);
37390 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37391 if(this.typeAhead){
37392 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37394 if(this.editable !== false){
37395 this.el.on("keyup", this.onKeyUp, this);
37397 if(this.forceSelection){
37398 this.on('blur', this.doForce, this);
37402 onDestroy : function(){
37404 this.view.setStore(null);
37405 this.view.el.removeAllListeners();
37406 this.view.el.remove();
37407 this.view.purgeListeners();
37410 this.list.destroy();
37413 this.store.un('beforeload', this.onBeforeLoad, this);
37414 this.store.un('load', this.onLoad, this);
37415 this.store.un('loadexception', this.collapse, this);
37417 Roo.form.ComboBox.superclass.onDestroy.call(this);
37421 fireKey : function(e){
37422 if(e.isNavKeyPress() && !this.list.isVisible()){
37423 this.fireEvent("specialkey", this, e);
37428 onResize: function(w, h){
37429 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37431 if(typeof w != 'number'){
37432 // we do not handle it!?!?
37435 var tw = this.trigger.getWidth();
37436 tw += this.addicon ? this.addicon.getWidth() : 0;
37437 tw += this.editicon ? this.editicon.getWidth() : 0;
37439 this.el.setWidth( this.adjustWidth('input', x));
37441 this.trigger.setStyle('left', x+'px');
37443 if(this.list && this.listWidth === undefined){
37444 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37445 this.list.setWidth(lw);
37446 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37454 * Allow or prevent the user from directly editing the field text. If false is passed,
37455 * the user will only be able to select from the items defined in the dropdown list. This method
37456 * is the runtime equivalent of setting the 'editable' config option at config time.
37457 * @param {Boolean} value True to allow the user to directly edit the field text
37459 setEditable : function(value){
37460 if(value == this.editable){
37463 this.editable = value;
37465 this.el.dom.setAttribute('readOnly', true);
37466 this.el.on('mousedown', this.onTriggerClick, this);
37467 this.el.addClass('x-combo-noedit');
37469 this.el.dom.setAttribute('readOnly', false);
37470 this.el.un('mousedown', this.onTriggerClick, this);
37471 this.el.removeClass('x-combo-noedit');
37476 onBeforeLoad : function(){
37477 if(!this.hasFocus){
37480 this.innerList.update(this.loadingText ?
37481 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37482 this.restrictHeight();
37483 this.selectedIndex = -1;
37487 onLoad : function(){
37488 if(!this.hasFocus){
37491 if(this.store.getCount() > 0){
37493 this.restrictHeight();
37494 if(this.lastQuery == this.allQuery){
37496 this.el.dom.select();
37498 if(!this.selectByValue(this.value, true)){
37499 this.select(0, true);
37503 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37504 this.taTask.delay(this.typeAheadDelay);
37508 this.onEmptyResults();
37514 onTypeAhead : function(){
37515 if(this.store.getCount() > 0){
37516 var r = this.store.getAt(0);
37517 var newValue = r.data[this.displayField];
37518 var len = newValue.length;
37519 var selStart = this.getRawValue().length;
37520 if(selStart != len){
37521 this.setRawValue(newValue);
37522 this.selectText(selStart, newValue.length);
37528 onSelect : function(record, index){
37529 if(this.fireEvent('beforeselect', this, record, index) !== false){
37530 this.setFromData(index > -1 ? record.data : false);
37532 this.fireEvent('select', this, record, index);
37537 * Returns the currently selected field value or empty string if no value is set.
37538 * @return {String} value The selected value
37540 getValue : function(){
37541 if(this.valueField){
37542 return typeof this.value != 'undefined' ? this.value : '';
37544 return Roo.form.ComboBox.superclass.getValue.call(this);
37549 * Clears any text/value currently set in the field
37551 clearValue : function(){
37552 if(this.hiddenField){
37553 this.hiddenField.value = '';
37556 this.setRawValue('');
37557 this.lastSelectionText = '';
37558 this.applyEmptyText();
37562 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37563 * will be displayed in the field. If the value does not match the data value of an existing item,
37564 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37565 * Otherwise the field will be blank (although the value will still be set).
37566 * @param {String} value The value to match
37568 setValue : function(v){
37570 if(this.valueField){
37571 var r = this.findRecord(this.valueField, v);
37573 text = r.data[this.displayField];
37574 }else if(this.valueNotFoundText !== undefined){
37575 text = this.valueNotFoundText;
37578 this.lastSelectionText = text;
37579 if(this.hiddenField){
37580 this.hiddenField.value = v;
37582 Roo.form.ComboBox.superclass.setValue.call(this, text);
37586 * @property {Object} the last set data for the element
37591 * Sets the value of the field based on a object which is related to the record format for the store.
37592 * @param {Object} value the value to set as. or false on reset?
37594 setFromData : function(o){
37595 var dv = ''; // display value
37596 var vv = ''; // value value..
37598 if (this.displayField) {
37599 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37601 // this is an error condition!!!
37602 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
37605 if(this.valueField){
37606 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37608 if(this.hiddenField){
37609 this.hiddenField.value = vv;
37611 this.lastSelectionText = dv;
37612 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37616 // no hidden field.. - we store the value in 'value', but still display
37617 // display field!!!!
37618 this.lastSelectionText = dv;
37619 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37625 reset : function(){
37626 // overridden so that last data is reset..
37627 this.setValue(this.originalValue);
37628 this.clearInvalid();
37629 this.lastData = false;
37632 findRecord : function(prop, value){
37634 if(this.store.getCount() > 0){
37635 this.store.each(function(r){
37636 if(r.data[prop] == value){
37646 onViewMove : function(e, t){
37647 this.inKeyMode = false;
37651 onViewOver : function(e, t){
37652 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37655 var item = this.view.findItemFromChild(t);
37657 var index = this.view.indexOf(item);
37658 this.select(index, false);
37663 onViewClick : function(doFocus){
37664 var index = this.view.getSelectedIndexes()[0];
37665 var r = this.store.getAt(index);
37667 this.onSelect(r, index);
37669 if(doFocus !== false && !this.blockFocus){
37675 restrictHeight : function(){
37676 this.innerList.dom.style.height = '';
37677 var inner = this.innerList.dom;
37678 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37679 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37680 this.list.beginUpdate();
37681 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37682 this.list.alignTo(this.el, this.listAlign);
37683 this.list.endUpdate();
37687 onEmptyResults : function(){
37692 * Returns true if the dropdown list is expanded, else false.
37694 isExpanded : function(){
37695 return this.list.isVisible();
37699 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37700 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37701 * @param {String} value The data value of the item to select
37702 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37703 * selected item if it is not currently in view (defaults to true)
37704 * @return {Boolean} True if the value matched an item in the list, else false
37706 selectByValue : function(v, scrollIntoView){
37707 if(v !== undefined && v !== null){
37708 var r = this.findRecord(this.valueField || this.displayField, v);
37710 this.select(this.store.indexOf(r), scrollIntoView);
37718 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37719 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37720 * @param {Number} index The zero-based index of the list item to select
37721 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37722 * selected item if it is not currently in view (defaults to true)
37724 select : function(index, scrollIntoView){
37725 this.selectedIndex = index;
37726 this.view.select(index);
37727 if(scrollIntoView !== false){
37728 var el = this.view.getNode(index);
37730 this.innerList.scrollChildIntoView(el, false);
37736 selectNext : function(){
37737 var ct = this.store.getCount();
37739 if(this.selectedIndex == -1){
37741 }else if(this.selectedIndex < ct-1){
37742 this.select(this.selectedIndex+1);
37748 selectPrev : function(){
37749 var ct = this.store.getCount();
37751 if(this.selectedIndex == -1){
37753 }else if(this.selectedIndex != 0){
37754 this.select(this.selectedIndex-1);
37760 onKeyUp : function(e){
37761 if(this.editable !== false && !e.isSpecialKey()){
37762 this.lastKey = e.getKey();
37763 this.dqTask.delay(this.queryDelay);
37768 validateBlur : function(){
37769 return !this.list || !this.list.isVisible();
37773 initQuery : function(){
37774 this.doQuery(this.getRawValue());
37778 doForce : function(){
37779 if(this.el.dom.value.length > 0){
37780 this.el.dom.value =
37781 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37782 this.applyEmptyText();
37787 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37788 * query allowing the query action to be canceled if needed.
37789 * @param {String} query The SQL query to execute
37790 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37791 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37792 * saved in the current store (defaults to false)
37794 doQuery : function(q, forceAll){
37795 if(q === undefined || q === null){
37800 forceAll: forceAll,
37804 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37808 forceAll = qe.forceAll;
37809 if(forceAll === true || (q.length >= this.minChars)){
37810 if(this.lastQuery != q || this.alwaysQuery){
37811 this.lastQuery = q;
37812 if(this.mode == 'local'){
37813 this.selectedIndex = -1;
37815 this.store.clearFilter();
37817 this.store.filter(this.displayField, q);
37821 this.store.baseParams[this.queryParam] = q;
37823 params: this.getParams(q)
37828 this.selectedIndex = -1;
37835 getParams : function(q){
37837 //p[this.queryParam] = q;
37840 p.limit = this.pageSize;
37846 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37848 collapse : function(){
37849 if(!this.isExpanded()){
37853 Roo.get(document).un('mousedown', this.collapseIf, this);
37854 Roo.get(document).un('mousewheel', this.collapseIf, this);
37855 if (!this.editable) {
37856 Roo.get(document).un('keydown', this.listKeyPress, this);
37858 this.fireEvent('collapse', this);
37862 collapseIf : function(e){
37863 if(!e.within(this.wrap) && !e.within(this.list)){
37869 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37871 expand : function(){
37872 if(this.isExpanded() || !this.hasFocus){
37875 this.list.alignTo(this.el, this.listAlign);
37877 Roo.get(document).on('mousedown', this.collapseIf, this);
37878 Roo.get(document).on('mousewheel', this.collapseIf, this);
37879 if (!this.editable) {
37880 Roo.get(document).on('keydown', this.listKeyPress, this);
37883 this.fireEvent('expand', this);
37887 // Implements the default empty TriggerField.onTriggerClick function
37888 onTriggerClick : function(){
37892 if(this.isExpanded()){
37894 if (!this.blockFocus) {
37899 this.hasFocus = true;
37900 if(this.triggerAction == 'all') {
37901 this.doQuery(this.allQuery, true);
37903 this.doQuery(this.getRawValue());
37905 if (!this.blockFocus) {
37910 listKeyPress : function(e)
37912 //Roo.log('listkeypress');
37913 // scroll to first matching element based on key pres..
37914 if (e.isSpecialKey()) {
37917 var k = String.fromCharCode(e.getKey()).toUpperCase();
37920 var csel = this.view.getSelectedNodes();
37921 var cselitem = false;
37923 var ix = this.view.indexOf(csel[0]);
37924 cselitem = this.store.getAt(ix);
37925 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
37931 this.store.each(function(v) {
37933 // start at existing selection.
37934 if (cselitem.id == v.id) {
37940 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
37941 match = this.store.indexOf(v);
37946 if (match === false) {
37947 return true; // no more action?
37950 this.view.select(match);
37951 var sn = Roo.get(this.view.getSelectedNodes()[0])
37952 sn.scrollIntoView(sn.dom.parentNode, false);
37956 * @cfg {Boolean} grow
37960 * @cfg {Number} growMin
37964 * @cfg {Number} growMax
37973 * Ext JS Library 1.1.1
37974 * Copyright(c) 2006-2007, Ext JS, LLC.
37976 * Originally Released Under LGPL - original licence link has changed is not relivant.
37979 * <script type="text/javascript">
37982 * @class Roo.form.Checkbox
37983 * @extends Roo.form.Field
37984 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
37986 * Creates a new Checkbox
37987 * @param {Object} config Configuration options
37989 Roo.form.Checkbox = function(config){
37990 Roo.form.Checkbox.superclass.constructor.call(this, config);
37994 * Fires when the checkbox is checked or unchecked.
37995 * @param {Roo.form.Checkbox} this This checkbox
37996 * @param {Boolean} checked The new checked value
38002 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38004 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38006 focusClass : undefined,
38008 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38010 fieldClass: "x-form-field",
38012 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38016 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38017 * {tag: "input", type: "checkbox", autocomplete: "off"})
38019 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38021 * @cfg {String} boxLabel The text that appears beside the checkbox
38025 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38029 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38031 valueOff: '0', // value when not checked..
38033 actionMode : 'viewEl',
38036 itemCls : 'x-menu-check-item x-form-item',
38037 groupClass : 'x-menu-group-item',
38038 inputType : 'hidden',
38041 inSetChecked: false, // check that we are not calling self...
38043 inputElement: false, // real input element?
38044 basedOn: false, // ????
38046 isFormField: true, // not sure where this is needed!!!!
38048 onResize : function(){
38049 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38050 if(!this.boxLabel){
38051 this.el.alignTo(this.wrap, 'c-c');
38055 initEvents : function(){
38056 Roo.form.Checkbox.superclass.initEvents.call(this);
38057 this.el.on("click", this.onClick, this);
38058 this.el.on("change", this.onClick, this);
38062 getResizeEl : function(){
38066 getPositionEl : function(){
38071 onRender : function(ct, position){
38072 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38074 if(this.inputValue !== undefined){
38075 this.el.dom.value = this.inputValue;
38078 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38079 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38080 var viewEl = this.wrap.createChild({
38081 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38082 this.viewEl = viewEl;
38083 this.wrap.on('click', this.onClick, this);
38085 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38086 this.el.on('propertychange', this.setFromHidden, this); //ie
38091 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38092 // viewEl.on('click', this.onClick, this);
38094 //if(this.checked){
38095 this.setChecked(this.checked);
38097 //this.checked = this.el.dom;
38103 initValue : Roo.emptyFn,
38106 * Returns the checked state of the checkbox.
38107 * @return {Boolean} True if checked, else false
38109 getValue : function(){
38111 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38113 return this.valueOff;
38118 onClick : function(){
38119 this.setChecked(!this.checked);
38121 //if(this.el.dom.checked != this.checked){
38122 // this.setValue(this.el.dom.checked);
38127 * Sets the checked state of the checkbox.
38128 * On is always based on a string comparison between inputValue and the param.
38129 * @param {Boolean/String} value - the value to set
38130 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38132 setValue : function(v,suppressEvent){
38135 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38136 //if(this.el && this.el.dom){
38137 // this.el.dom.checked = this.checked;
38138 // this.el.dom.defaultChecked = this.checked;
38140 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38141 //this.fireEvent("check", this, this.checked);
38144 setChecked : function(state,suppressEvent)
38146 if (this.inSetChecked) {
38147 this.checked = state;
38153 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38155 this.checked = state;
38156 if(suppressEvent !== true){
38157 this.fireEvent('check', this, state);
38159 this.inSetChecked = true;
38160 this.el.dom.value = state ? this.inputValue : this.valueOff;
38161 this.inSetChecked = false;
38164 // handle setting of hidden value by some other method!!?!?
38165 setFromHidden: function()
38170 //console.log("SET FROM HIDDEN");
38171 //alert('setFrom hidden');
38172 this.setValue(this.el.dom.value);
38175 onDestroy : function()
38178 Roo.get(this.viewEl).remove();
38181 Roo.form.Checkbox.superclass.onDestroy.call(this);
38186 * Ext JS Library 1.1.1
38187 * Copyright(c) 2006-2007, Ext JS, LLC.
38189 * Originally Released Under LGPL - original licence link has changed is not relivant.
38192 * <script type="text/javascript">
38196 * @class Roo.form.Radio
38197 * @extends Roo.form.Checkbox
38198 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38199 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38201 * Creates a new Radio
38202 * @param {Object} config Configuration options
38204 Roo.form.Radio = function(){
38205 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38207 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38208 inputType: 'radio',
38211 * If this radio is part of a group, it will return the selected value
38214 getGroupValue : function(){
38215 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38217 });//<script type="text/javascript">
38220 * Ext JS Library 1.1.1
38221 * Copyright(c) 2006-2007, Ext JS, LLC.
38222 * licensing@extjs.com
38224 * http://www.extjs.com/license
38230 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38231 * - IE ? - no idea how much works there.
38239 * @class Ext.form.HtmlEditor
38240 * @extends Ext.form.Field
38241 * Provides a lightweight HTML Editor component.
38242 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
38244 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38245 * supported by this editor.</b><br/><br/>
38246 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38247 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38249 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38251 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38255 * @cfg {String} createLinkText The default text for the create link prompt
38257 createLinkText : 'Please enter the URL for the link:',
38259 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38261 defaultLinkValue : 'http:/'+'/',
38267 // private properties
38268 validationEvent : false,
38270 initialized : false,
38272 sourceEditMode : false,
38273 onFocus : Roo.emptyFn,
38275 hideMode:'offsets',
38276 defaultAutoCreate : {
38278 style:"width:500px;height:300px;",
38279 autocomplete: "off"
38283 initComponent : function(){
38286 * @event initialize
38287 * Fires when the editor is fully initialized (including the iframe)
38288 * @param {HtmlEditor} this
38293 * Fires when the editor is first receives the focus. Any insertion must wait
38294 * until after this event.
38295 * @param {HtmlEditor} this
38299 * @event beforesync
38300 * Fires before the textarea is updated with content from the editor iframe. Return false
38301 * to cancel the sync.
38302 * @param {HtmlEditor} this
38303 * @param {String} html
38307 * @event beforepush
38308 * Fires before the iframe editor is updated with content from the textarea. Return false
38309 * to cancel the push.
38310 * @param {HtmlEditor} this
38311 * @param {String} html
38316 * Fires when the textarea is updated with content from the editor iframe.
38317 * @param {HtmlEditor} this
38318 * @param {String} html
38323 * Fires when the iframe editor is updated with content from the textarea.
38324 * @param {HtmlEditor} this
38325 * @param {String} html
38329 * @event editmodechange
38330 * Fires when the editor switches edit modes
38331 * @param {HtmlEditor} this
38332 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38334 editmodechange: true,
38336 * @event editorevent
38337 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38338 * @param {HtmlEditor} this
38345 * Protected method that will not generally be called directly. It
38346 * is called when the editor creates its toolbar. Override this method if you need to
38347 * add custom toolbar buttons.
38348 * @param {HtmlEditor} editor
38350 createToolbar : function(editor){
38351 if (!editor.toolbars || !editor.toolbars.length) {
38352 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38355 for (var i =0 ; i < editor.toolbars.length;i++) {
38356 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38357 editor.toolbars[i].init(editor);
38364 * Protected method that will not generally be called directly. It
38365 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38366 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38368 getDocMarkup : function(){
38369 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
38373 onRender : function(ct, position){
38374 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38375 this.el.dom.style.border = '0 none';
38376 this.el.dom.setAttribute('tabIndex', -1);
38377 this.el.addClass('x-hidden');
38378 if(Roo.isIE){ // fix IE 1px bogus margin
38379 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38381 this.wrap = this.el.wrap({
38382 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38385 this.frameId = Roo.id();
38386 this.createToolbar(this);
38393 var iframe = this.wrap.createChild({
38396 name: this.frameId,
38397 frameBorder : 'no',
38398 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38401 // console.log(iframe);
38402 //this.wrap.dom.appendChild(iframe);
38404 this.iframe = iframe.dom;
38406 this.assignDocWin();
38408 this.doc.designMode = 'on';
38411 this.doc.write(this.getDocMarkup());
38415 var task = { // must defer to wait for browser to be ready
38417 //console.log("run task?" + this.doc.readyState);
38418 this.assignDocWin();
38419 if(this.doc.body || this.doc.readyState == 'complete'){
38421 this.doc.designMode="on";
38425 Roo.TaskMgr.stop(task);
38426 this.initEditor.defer(10, this);
38433 Roo.TaskMgr.start(task);
38436 this.setSize(this.el.getSize());
38441 onResize : function(w, h){
38442 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38443 if(this.el && this.iframe){
38444 if(typeof w == 'number'){
38445 var aw = w - this.wrap.getFrameWidth('lr');
38446 this.el.setWidth(this.adjustWidth('textarea', aw));
38447 this.iframe.style.width = aw + 'px';
38449 if(typeof h == 'number'){
38451 for (var i =0; i < this.toolbars.length;i++) {
38452 // fixme - ask toolbars for heights?
38453 tbh += this.toolbars[i].tb.el.getHeight();
38459 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38460 this.el.setHeight(this.adjustWidth('textarea', ah));
38461 this.iframe.style.height = ah + 'px';
38463 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38470 * Toggles the editor between standard and source edit mode.
38471 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38473 toggleSourceEdit : function(sourceEditMode){
38475 this.sourceEditMode = sourceEditMode === true;
38477 if(this.sourceEditMode){
38480 this.iframe.className = 'x-hidden';
38481 this.el.removeClass('x-hidden');
38482 this.el.dom.removeAttribute('tabIndex');
38487 this.iframe.className = '';
38488 this.el.addClass('x-hidden');
38489 this.el.dom.setAttribute('tabIndex', -1);
38492 this.setSize(this.wrap.getSize());
38493 this.fireEvent('editmodechange', this, this.sourceEditMode);
38496 // private used internally
38497 createLink : function(){
38498 var url = prompt(this.createLinkText, this.defaultLinkValue);
38499 if(url && url != 'http:/'+'/'){
38500 this.relayCmd('createlink', url);
38504 // private (for BoxComponent)
38505 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38507 // private (for BoxComponent)
38508 getResizeEl : function(){
38512 // private (for BoxComponent)
38513 getPositionEl : function(){
38518 initEvents : function(){
38519 this.originalValue = this.getValue();
38523 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38526 markInvalid : Roo.emptyFn,
38528 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38531 clearInvalid : Roo.emptyFn,
38533 setValue : function(v){
38534 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38539 * Protected method that will not generally be called directly. If you need/want
38540 * custom HTML cleanup, this is the method you should override.
38541 * @param {String} html The HTML to be cleaned
38542 * return {String} The cleaned HTML
38544 cleanHtml : function(html){
38545 html = String(html);
38546 if(html.length > 5){
38547 if(Roo.isSafari){ // strip safari nonsense
38548 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38551 if(html == ' '){
38558 * Protected method that will not generally be called directly. Syncs the contents
38559 * of the editor iframe with the textarea.
38561 syncValue : function(){
38562 if(this.initialized){
38563 var bd = (this.doc.body || this.doc.documentElement);
38564 var html = bd.innerHTML;
38566 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38567 var m = bs.match(/text-align:(.*?);/i);
38569 html = '<div style="'+m[0]+'">' + html + '</div>';
38572 html = this.cleanHtml(html);
38573 if(this.fireEvent('beforesync', this, html) !== false){
38574 this.el.dom.value = html;
38575 this.fireEvent('sync', this, html);
38581 * Protected method that will not generally be called directly. Pushes the value of the textarea
38582 * into the iframe editor.
38584 pushValue : function(){
38585 if(this.initialized){
38586 var v = this.el.dom.value;
38590 if(this.fireEvent('beforepush', this, v) !== false){
38591 (this.doc.body || this.doc.documentElement).innerHTML = v;
38592 this.fireEvent('push', this, v);
38598 deferFocus : function(){
38599 this.focus.defer(10, this);
38603 focus : function(){
38604 if(this.win && !this.sourceEditMode){
38611 assignDocWin: function()
38613 var iframe = this.iframe;
38616 this.doc = iframe.contentWindow.document;
38617 this.win = iframe.contentWindow;
38619 if (!Roo.get(this.frameId)) {
38622 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38623 this.win = Roo.get(this.frameId).dom.contentWindow;
38628 initEditor : function(){
38629 //console.log("INIT EDITOR");
38630 this.assignDocWin();
38634 this.doc.designMode="on";
38636 this.doc.write(this.getDocMarkup());
38639 var dbody = (this.doc.body || this.doc.documentElement);
38640 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38641 // this copies styles from the containing element into thsi one..
38642 // not sure why we need all of this..
38643 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38644 ss['background-attachment'] = 'fixed'; // w3c
38645 dbody.bgProperties = 'fixed'; // ie
38646 Roo.DomHelper.applyStyles(dbody, ss);
38647 Roo.EventManager.on(this.doc, {
38648 'mousedown': this.onEditorEvent,
38649 'dblclick': this.onEditorEvent,
38650 'click': this.onEditorEvent,
38651 'keyup': this.onEditorEvent,
38656 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
38658 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38659 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38661 this.initialized = true;
38663 this.fireEvent('initialize', this);
38668 onDestroy : function(){
38674 for (var i =0; i < this.toolbars.length;i++) {
38675 // fixme - ask toolbars for heights?
38676 this.toolbars[i].onDestroy();
38679 this.wrap.dom.innerHTML = '';
38680 this.wrap.remove();
38685 onFirstFocus : function(){
38687 this.assignDocWin();
38690 this.activated = true;
38691 for (var i =0; i < this.toolbars.length;i++) {
38692 this.toolbars[i].onFirstFocus();
38695 if(Roo.isGecko){ // prevent silly gecko errors
38697 var s = this.win.getSelection();
38698 if(!s.focusNode || s.focusNode.nodeType != 3){
38699 var r = s.getRangeAt(0);
38700 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38705 this.execCmd('useCSS', true);
38706 this.execCmd('styleWithCSS', false);
38709 this.fireEvent('activate', this);
38713 adjustFont: function(btn){
38714 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38715 //if(Roo.isSafari){ // safari
38718 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38719 if(Roo.isSafari){ // safari
38720 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38721 v = (v < 10) ? 10 : v;
38722 v = (v > 48) ? 48 : v;
38723 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38728 v = Math.max(1, v+adjust);
38730 this.execCmd('FontSize', v );
38733 onEditorEvent : function(e){
38734 this.fireEvent('editorevent', this, e);
38735 // this.updateToolbar();
38739 insertTag : function(tg)
38741 // could be a bit smarter... -> wrap the current selected tRoo..
38743 this.execCmd("formatblock", tg);
38747 insertText : function(txt)
38751 range = this.createRange();
38752 range.deleteContents();
38753 //alert(Sender.getAttribute('label'));
38755 range.insertNode(this.doc.createTextNode(txt));
38759 relayBtnCmd : function(btn){
38760 this.relayCmd(btn.cmd);
38764 * Executes a Midas editor command on the editor document and performs necessary focus and
38765 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38766 * @param {String} cmd The Midas command
38767 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38769 relayCmd : function(cmd, value){
38771 this.execCmd(cmd, value);
38772 this.fireEvent('editorevent', this);
38773 //this.updateToolbar();
38778 * Executes a Midas editor command directly on the editor document.
38779 * For visual commands, you should use {@link #relayCmd} instead.
38780 * <b>This should only be called after the editor is initialized.</b>
38781 * @param {String} cmd The Midas command
38782 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38784 execCmd : function(cmd, value){
38785 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38791 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38793 * @param {String} text
38795 insertAtCursor : function(text){
38796 if(!this.activated){
38801 var r = this.doc.selection.createRange();
38808 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
38810 this.execCmd('InsertHTML', text);
38815 mozKeyPress : function(e){
38817 var c = e.getCharCode(), cmd;
38820 c = String.fromCharCode(c).toLowerCase();
38831 this.cleanUpPaste.defer(100, this);
38839 e.preventDefault();
38847 fixKeys : function(){ // load time branching for fastest keydown performance
38849 return function(e){
38850 var k = e.getKey(), r;
38853 r = this.doc.selection.createRange();
38856 r.pasteHTML('    ');
38863 r = this.doc.selection.createRange();
38865 var target = r.parentElement();
38866 if(!target || target.tagName.toLowerCase() != 'li'){
38868 r.pasteHTML('<br />');
38874 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38875 this.cleanUpPaste.defer(100, this);
38881 }else if(Roo.isOpera){
38882 return function(e){
38883 var k = e.getKey();
38887 this.execCmd('InsertHTML','    ');
38890 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38891 this.cleanUpPaste.defer(100, this);
38896 }else if(Roo.isSafari){
38897 return function(e){
38898 var k = e.getKey();
38902 this.execCmd('InsertText','\t');
38906 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
38907 this.cleanUpPaste.defer(100, this);
38915 getAllAncestors: function()
38917 var p = this.getSelectedNode();
38920 a.push(p); // push blank onto stack..
38921 p = this.getParentElement();
38925 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
38929 a.push(this.doc.body);
38933 lastSelNode : false,
38936 getSelection : function()
38938 this.assignDocWin();
38939 return Roo.isIE ? this.doc.selection : this.win.getSelection();
38942 getSelectedNode: function()
38944 // this may only work on Gecko!!!
38946 // should we cache this!!!!
38951 var range = this.createRange(this.getSelection());
38954 var parent = range.parentElement();
38956 var testRange = range.duplicate();
38957 testRange.moveToElementText(parent);
38958 if (testRange.inRange(range)) {
38961 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
38964 parent = parent.parentElement;
38970 var ar = range.endContainer.childNodes;
38972 ar = range.commonAncestorContainer.childNodes;
38973 //alert(ar.length);
38976 var other_nodes = [];
38977 var has_other_nodes = false;
38978 for (var i=0;i<ar.length;i++) {
38979 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
38982 // fullly contained node.
38984 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
38989 // probably selected..
38990 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
38991 other_nodes.push(ar[i]);
38994 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
38999 has_other_nodes = true;
39001 if (!nodes.length && other_nodes.length) {
39002 nodes= other_nodes;
39004 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39010 createRange: function(sel)
39012 // this has strange effects when using with
39013 // top toolbar - not sure if it's a great idea.
39014 //this.editor.contentWindow.focus();
39015 if (typeof sel != "undefined") {
39017 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39019 return this.doc.createRange();
39022 return this.doc.createRange();
39025 getParentElement: function()
39028 this.assignDocWin();
39029 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39031 var range = this.createRange(sel);
39034 var p = range.commonAncestorContainer;
39035 while (p.nodeType == 3) { // text node
39047 // BC Hacks - cause I cant work out what i was trying to do..
39048 rangeIntersectsNode : function(range, node)
39050 var nodeRange = node.ownerDocument.createRange();
39052 nodeRange.selectNode(node);
39055 nodeRange.selectNodeContents(node);
39058 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
39059 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
39061 rangeCompareNode : function(range, node) {
39062 var nodeRange = node.ownerDocument.createRange();
39064 nodeRange.selectNode(node);
39066 nodeRange.selectNodeContents(node);
39068 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
39069 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
39071 if (nodeIsBefore && !nodeIsAfter)
39073 if (!nodeIsBefore && nodeIsAfter)
39075 if (nodeIsBefore && nodeIsAfter)
39081 // private? - in a new class?
39082 cleanUpPaste : function()
39084 // cleans up the whole document..
39085 // console.log('cleanuppaste');
39086 this.cleanUpChildren(this.doc.body)
39090 cleanUpChildren : function (n)
39092 if (!n.childNodes.length) {
39095 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39096 this.cleanUpChild(n.childNodes[i]);
39103 cleanUpChild : function (node)
39105 //console.log(node);
39106 if (node.nodeName == "#text") {
39107 // clean up silly Windows -- stuff?
39110 if (node.nodeName == "#comment") {
39111 node.parentNode.removeChild(node);
39112 // clean up silly Windows -- stuff?
39116 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39118 node.parentNode.removeChild(node);
39122 if (!node.attributes || !node.attributes.length) {
39123 this.cleanUpChildren(node);
39127 function cleanAttr(n,v)
39130 if (v.match(/^\./) || v.match(/^\//)) {
39133 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39136 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39137 node.removeAttribute(n);
39141 function cleanStyle(n,v)
39143 if (v.match(/expression/)) { //XSS?? should we even bother..
39144 node.removeAttribute(n);
39149 var parts = v.split(/;/);
39150 Roo.each(parts, function(p) {
39151 p = p.replace(/\s+/g,'');
39155 var l = p.split(':').shift().replace(/\s+/g,'');
39157 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39158 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39159 node.removeAttribute(n);
39168 for (var i = node.attributes.length-1; i > -1 ; i--) {
39169 var a = node.attributes[i];
39171 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39172 node.removeAttribute(a.name);
39175 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39176 cleanAttr(a.name,a.value); // fixme..
39179 if (a.name == 'style') {
39180 cleanStyle(a.name,a.value);
39182 /// clean up MS crap..
39183 if (a.name == 'class') {
39184 if (a.value.match(/^Mso/)) {
39185 node.className = '';
39195 this.cleanUpChildren(node);
39201 // hide stuff that is not compatible
39215 * @event specialkey
39219 * @cfg {String} fieldClass @hide
39222 * @cfg {String} focusClass @hide
39225 * @cfg {String} autoCreate @hide
39228 * @cfg {String} inputType @hide
39231 * @cfg {String} invalidClass @hide
39234 * @cfg {String} invalidText @hide
39237 * @cfg {String} msgFx @hide
39240 * @cfg {String} validateOnBlur @hide
39244 Roo.form.HtmlEditor.white = [
39245 'area', 'br', 'img', 'input', 'hr', 'wbr',
39247 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39248 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39249 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39250 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39251 'table', 'ul', 'xmp',
39253 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39256 'dir', 'menu', 'ol', 'ul', 'dl',
39262 Roo.form.HtmlEditor.black = [
39263 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39265 'base', 'basefont', 'bgsound', 'blink', 'body',
39266 'frame', 'frameset', 'head', 'html', 'ilayer',
39267 'iframe', 'layer', 'link', 'meta', 'object',
39268 'script', 'style' ,'title', 'xml' // clean later..
39270 Roo.form.HtmlEditor.clean = [
39271 'script', 'style', 'title', 'xml'
39276 Roo.form.HtmlEditor.ablack = [
39280 Roo.form.HtmlEditor.aclean = [
39281 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39285 Roo.form.HtmlEditor.pwhite= [
39286 'http', 'https', 'mailto'
39289 Roo.form.HtmlEditor.cwhite= [
39294 // <script type="text/javascript">
39297 * Ext JS Library 1.1.1
39298 * Copyright(c) 2006-2007, Ext JS, LLC.
39304 * @class Roo.form.HtmlEditorToolbar1
39309 new Roo.form.HtmlEditor({
39312 new Roo.form.HtmlEditorToolbar1({
39313 disable : { fonts: 1 , format: 1, ..., ... , ...],
39319 * @cfg {Object} disable List of elements to disable..
39320 * @cfg {Array} btns List of additional buttons.
39324 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39327 Roo.form.HtmlEditor.ToolbarStandard = function(config)
39330 Roo.apply(this, config);
39331 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39332 // dont call parent... till later.
39335 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
39343 * @cfg {Object} disable List of toolbar elements to disable
39348 * @cfg {Array} fontFamilies An array of available font families
39366 // "á" , ?? a acute?
39371 "°" // , // degrees
39373 // "é" , // e ecute
39374 // "ú" , // u ecute?
39377 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
39378 "input:submit", "input:button", "select", "textarea", "label" ],
39381 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
39383 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
39386 * @cfg {String} defaultFont default font to use.
39388 defaultFont: 'tahoma',
39390 fontSelect : false,
39393 formatCombo : false,
39395 init : function(editor)
39397 this.editor = editor;
39400 var fid = editor.frameId;
39402 function btn(id, toggle, handler){
39403 var xid = fid + '-'+ id ;
39407 cls : 'x-btn-icon x-edit-'+id,
39408 enableToggle:toggle !== false,
39409 scope: editor, // was editor...
39410 handler:handler||editor.relayBtnCmd,
39411 clickEvent:'mousedown',
39412 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39419 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
39421 // stop form submits
39422 tb.el.on('click', function(e){
39423 e.preventDefault(); // what does this do?
39426 if(!this.disable.font && !Roo.isSafari){
39427 /* why no safari for fonts
39428 editor.fontSelect = tb.el.createChild({
39431 cls:'x-font-select',
39432 html: editor.createFontOptions()
39434 editor.fontSelect.on('change', function(){
39435 var font = editor.fontSelect.dom.value;
39436 editor.relayCmd('fontname', font);
39437 editor.deferFocus();
39440 editor.fontSelect.dom,
39445 if(!this.disable.formats){
39446 this.formatCombo = new Roo.form.ComboBox({
39447 store: new Roo.data.SimpleStore({
39450 data : this.formats // from states.js
39453 //autoCreate : {tag: "div", size: "20"},
39454 displayField:'tag',
39458 triggerAction: 'all',
39459 emptyText:'Add tag',
39460 selectOnFocus:true,
39463 'select': function(c, r, i) {
39464 editor.insertTag(r.get('tag'));
39470 tb.addField(this.formatCombo);
39474 if(!this.disable.format){
39481 if(!this.disable.fontSize){
39486 btn('increasefontsize', false, editor.adjustFont),
39487 btn('decreasefontsize', false, editor.adjustFont)
39492 if(this.disable.colors){
39495 id:editor.frameId +'-forecolor',
39496 cls:'x-btn-icon x-edit-forecolor',
39497 clickEvent:'mousedown',
39498 tooltip: this.buttonTips['forecolor'] || undefined,
39500 menu : new Roo.menu.ColorMenu({
39501 allowReselect: true,
39502 focus: Roo.emptyFn,
39505 selectHandler: function(cp, color){
39506 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
39507 editor.deferFocus();
39510 clickEvent:'mousedown'
39513 id:editor.frameId +'backcolor',
39514 cls:'x-btn-icon x-edit-backcolor',
39515 clickEvent:'mousedown',
39516 tooltip: this.buttonTips['backcolor'] || undefined,
39518 menu : new Roo.menu.ColorMenu({
39519 focus: Roo.emptyFn,
39522 allowReselect: true,
39523 selectHandler: function(cp, color){
39525 editor.execCmd('useCSS', false);
39526 editor.execCmd('hilitecolor', color);
39527 editor.execCmd('useCSS', true);
39528 editor.deferFocus();
39530 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
39531 Roo.isSafari || Roo.isIE ? '#'+color : color);
39532 editor.deferFocus();
39536 clickEvent:'mousedown'
39541 // now add all the items...
39544 if(!this.disable.alignments){
39547 btn('justifyleft'),
39548 btn('justifycenter'),
39549 btn('justifyright')
39553 //if(!Roo.isSafari){
39554 if(!this.disable.links){
39557 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
39561 if(!this.disable.lists){
39564 btn('insertorderedlist'),
39565 btn('insertunorderedlist')
39568 if(!this.disable.sourceEdit){
39571 btn('sourceedit', true, function(btn){
39572 this.toggleSourceEdit(btn.pressed);
39579 // special menu.. - needs to be tidied up..
39580 if (!this.disable.special) {
39583 cls: 'x-edit-none',
39588 for (var i =0; i < this.specialChars.length; i++) {
39589 smenu.menu.items.push({
39591 html: this.specialChars[i],
39592 handler: function(a,b) {
39593 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
39606 for(var i =0; i< this.btns.length;i++) {
39607 var b = this.btns[i];
39608 b.cls = 'x-edit-none';
39617 // disable everything...
39619 this.tb.items.each(function(item){
39620 if(item.id != editor.frameId+ '-sourceedit'){
39624 this.rendered = true;
39626 // the all the btns;
39627 editor.on('editorevent', this.updateToolbar, this);
39628 // other toolbars need to implement this..
39629 //editor.on('editmodechange', this.updateToolbar, this);
39635 * Protected method that will not generally be called directly. It triggers
39636 * a toolbar update by reading the markup state of the current selection in the editor.
39638 updateToolbar: function(){
39640 if(!this.editor.activated){
39641 this.editor.onFirstFocus();
39645 var btns = this.tb.items.map,
39646 doc = this.editor.doc,
39647 frameId = this.editor.frameId;
39649 if(!this.disable.font && !Roo.isSafari){
39651 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39652 if(name != this.fontSelect.dom.value){
39653 this.fontSelect.dom.value = name;
39657 if(!this.disable.format){
39658 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39659 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39660 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39662 if(!this.disable.alignments){
39663 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39664 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39665 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39667 if(!Roo.isSafari && !this.disable.lists){
39668 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39669 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39672 var ans = this.editor.getAllAncestors();
39673 if (this.formatCombo) {
39676 var store = this.formatCombo.store;
39677 this.formatCombo.setValue("");
39678 for (var i =0; i < ans.length;i++) {
39679 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
39681 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39689 // hides menus... - so this cant be on a menu...
39690 Roo.menu.MenuMgr.hideAll();
39692 //this.editorsyncValue();
39696 createFontOptions : function(){
39697 var buf = [], fs = this.fontFamilies, ff, lc;
39698 for(var i = 0, len = fs.length; i< len; i++){
39700 lc = ff.toLowerCase();
39702 '<option value="',lc,'" style="font-family:',ff,';"',
39703 (this.defaultFont == lc ? ' selected="true">' : '>'),
39708 return buf.join('');
39711 toggleSourceEdit : function(sourceEditMode){
39712 if(sourceEditMode === undefined){
39713 sourceEditMode = !this.sourceEditMode;
39715 this.sourceEditMode = sourceEditMode === true;
39716 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39717 // just toggle the button?
39718 if(btn.pressed !== this.editor.sourceEditMode){
39719 btn.toggle(this.editor.sourceEditMode);
39723 if(this.sourceEditMode){
39724 this.tb.items.each(function(item){
39725 if(item.cmd != 'sourceedit'){
39731 if(this.initialized){
39732 this.tb.items.each(function(item){
39738 // tell the editor that it's been pressed..
39739 this.editor.toggleSourceEdit(sourceEditMode);
39743 * Object collection of toolbar tooltips for the buttons in the editor. The key
39744 * is the command id associated with that button and the value is a valid QuickTips object.
39749 title: 'Bold (Ctrl+B)',
39750 text: 'Make the selected text bold.',
39751 cls: 'x-html-editor-tip'
39754 title: 'Italic (Ctrl+I)',
39755 text: 'Make the selected text italic.',
39756 cls: 'x-html-editor-tip'
39764 title: 'Bold (Ctrl+B)',
39765 text: 'Make the selected text bold.',
39766 cls: 'x-html-editor-tip'
39769 title: 'Italic (Ctrl+I)',
39770 text: 'Make the selected text italic.',
39771 cls: 'x-html-editor-tip'
39774 title: 'Underline (Ctrl+U)',
39775 text: 'Underline the selected text.',
39776 cls: 'x-html-editor-tip'
39778 increasefontsize : {
39779 title: 'Grow Text',
39780 text: 'Increase the font size.',
39781 cls: 'x-html-editor-tip'
39783 decreasefontsize : {
39784 title: 'Shrink Text',
39785 text: 'Decrease the font size.',
39786 cls: 'x-html-editor-tip'
39789 title: 'Text Highlight Color',
39790 text: 'Change the background color of the selected text.',
39791 cls: 'x-html-editor-tip'
39794 title: 'Font Color',
39795 text: 'Change the color of the selected text.',
39796 cls: 'x-html-editor-tip'
39799 title: 'Align Text Left',
39800 text: 'Align text to the left.',
39801 cls: 'x-html-editor-tip'
39804 title: 'Center Text',
39805 text: 'Center text in the editor.',
39806 cls: 'x-html-editor-tip'
39809 title: 'Align Text Right',
39810 text: 'Align text to the right.',
39811 cls: 'x-html-editor-tip'
39813 insertunorderedlist : {
39814 title: 'Bullet List',
39815 text: 'Start a bulleted list.',
39816 cls: 'x-html-editor-tip'
39818 insertorderedlist : {
39819 title: 'Numbered List',
39820 text: 'Start a numbered list.',
39821 cls: 'x-html-editor-tip'
39824 title: 'Hyperlink',
39825 text: 'Make the selected text a hyperlink.',
39826 cls: 'x-html-editor-tip'
39829 title: 'Source Edit',
39830 text: 'Switch to source editing mode.',
39831 cls: 'x-html-editor-tip'
39835 onDestroy : function(){
39838 this.tb.items.each(function(item){
39840 item.menu.removeAll();
39842 item.menu.el.destroy();
39850 onFirstFocus: function() {
39851 this.tb.items.each(function(item){
39860 // <script type="text/javascript">
39863 * Ext JS Library 1.1.1
39864 * Copyright(c) 2006-2007, Ext JS, LLC.
39871 * @class Roo.form.HtmlEditor.ToolbarContext
39876 new Roo.form.HtmlEditor({
39879 new Roo.form.HtmlEditor.ToolbarStandard(),
39880 new Roo.form.HtmlEditor.ToolbarContext()
39885 * @config : {Object} disable List of elements to disable.. (not done yet.)
39890 Roo.form.HtmlEditor.ToolbarContext = function(config)
39893 Roo.apply(this, config);
39894 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39895 // dont call parent... till later.
39897 Roo.form.HtmlEditor.ToolbarContext.types = {
39909 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
39971 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
39976 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40040 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40048 * @cfg {Object} disable List of toolbar elements to disable
40057 init : function(editor)
40059 this.editor = editor;
40062 var fid = editor.frameId;
40064 function btn(id, toggle, handler){
40065 var xid = fid + '-'+ id ;
40069 cls : 'x-btn-icon x-edit-'+id,
40070 enableToggle:toggle !== false,
40071 scope: editor, // was editor...
40072 handler:handler||editor.relayBtnCmd,
40073 clickEvent:'mousedown',
40074 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40078 // create a new element.
40079 var wdiv = editor.wrap.createChild({
40081 }, editor.wrap.dom.firstChild.nextSibling, true);
40083 // can we do this more than once??
40085 // stop form submits
40088 // disable everything...
40089 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40090 this.toolbars = {};
40092 for (var i in ty) {
40094 this.toolbars[i] = this.buildToolbar(ty[i],i);
40096 this.tb = this.toolbars.BODY;
40100 this.rendered = true;
40102 // the all the btns;
40103 editor.on('editorevent', this.updateToolbar, this);
40104 // other toolbars need to implement this..
40105 //editor.on('editmodechange', this.updateToolbar, this);
40111 * Protected method that will not generally be called directly. It triggers
40112 * a toolbar update by reading the markup state of the current selection in the editor.
40114 updateToolbar: function(){
40116 if(!this.editor.activated){
40117 this.editor.onFirstFocus();
40122 var ans = this.editor.getAllAncestors();
40125 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40126 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40127 sel = sel ? sel : this.editor.doc.body;
40128 sel = sel.tagName.length ? sel : this.editor.doc.body;
40129 var tn = sel.tagName.toUpperCase();
40130 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40131 tn = sel.tagName.toUpperCase();
40132 if (this.tb.name == tn) {
40133 return; // no change
40136 ///console.log("show: " + tn);
40137 this.tb = this.toolbars[tn];
40139 this.tb.fields.each(function(e) {
40140 e.setValue(sel.getAttribute(e.name));
40142 this.tb.selectedNode = sel;
40145 Roo.menu.MenuMgr.hideAll();
40147 //this.editorsyncValue();
40152 onDestroy : function(){
40155 this.tb.items.each(function(item){
40157 item.menu.removeAll();
40159 item.menu.el.destroy();
40167 onFirstFocus: function() {
40168 // need to do this for all the toolbars..
40169 this.tb.items.each(function(item){
40173 buildToolbar: function(tlist, nm)
40175 var editor = this.editor;
40176 // create a new element.
40177 var wdiv = editor.wrap.createChild({
40179 }, editor.wrap.dom.firstChild.nextSibling, true);
40182 var tb = new Roo.Toolbar(wdiv);
40183 tb.add(nm+ ": ");
40184 for (var i in tlist) {
40185 var item = tlist[i];
40186 tb.add(item.title + ": ");
40191 tb.addField( new Roo.form.ComboBox({
40192 store: new Roo.data.SimpleStore({
40195 data : item.opts // from states.js
40198 displayField:'val',
40202 triggerAction: 'all',
40203 emptyText:'Select',
40204 selectOnFocus:true,
40205 width: item.width ? item.width : 130,
40207 'select': function(c, r, i) {
40208 tb.selectedNode.setAttribute(c.name, r.get('val'));
40219 tb.addField( new Roo.form.TextField({
40222 //allowBlank:false,
40227 tb.addField( new Roo.form.TextField({
40233 'change' : function(f, nv, ov) {
40234 tb.selectedNode.setAttribute(f.name, nv);
40240 tb.el.on('click', function(e){
40241 e.preventDefault(); // what does this do?
40243 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
40246 // dont need to disable them... as they will get hidden
40263 * Ext JS Library 1.1.1
40264 * Copyright(c) 2006-2007, Ext JS, LLC.
40266 * Originally Released Under LGPL - original licence link has changed is not relivant.
40269 * <script type="text/javascript">
40273 * @class Roo.form.BasicForm
40274 * @extends Roo.util.Observable
40275 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
40277 * @param {String/HTMLElement/Roo.Element} el The form element or its id
40278 * @param {Object} config Configuration options
40280 Roo.form.BasicForm = function(el, config){
40281 this.allItems = [];
40282 this.childForms = [];
40283 Roo.apply(this, config);
40285 * The Roo.form.Field items in this form.
40286 * @type MixedCollection
40290 this.items = new Roo.util.MixedCollection(false, function(o){
40291 return o.id || (o.id = Roo.id());
40295 * @event beforeaction
40296 * Fires before any action is performed. Return false to cancel the action.
40297 * @param {Form} this
40298 * @param {Action} action The action to be performed
40300 beforeaction: true,
40302 * @event actionfailed
40303 * Fires when an action fails.
40304 * @param {Form} this
40305 * @param {Action} action The action that failed
40307 actionfailed : true,
40309 * @event actioncomplete
40310 * Fires when an action is completed.
40311 * @param {Form} this
40312 * @param {Action} action The action that completed
40314 actioncomplete : true
40319 Roo.form.BasicForm.superclass.constructor.call(this);
40322 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
40324 * @cfg {String} method
40325 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
40328 * @cfg {DataReader} reader
40329 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
40330 * This is optional as there is built-in support for processing JSON.
40333 * @cfg {DataReader} errorReader
40334 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
40335 * This is completely optional as there is built-in support for processing JSON.
40338 * @cfg {String} url
40339 * The URL to use for form actions if one isn't supplied in the action options.
40342 * @cfg {Boolean} fileUpload
40343 * Set to true if this form is a file upload.
40346 * @cfg {Object} baseParams
40347 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
40350 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
40355 activeAction : null,
40358 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
40359 * or setValues() data instead of when the form was first created.
40361 trackResetOnLoad : false,
40365 * childForms - used for multi-tab forms
40368 childForms : false,
40371 * allItems - full list of fields.
40377 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
40378 * element by passing it or its id or mask the form itself by passing in true.
40381 waitMsgTarget : undefined,
40384 initEl : function(el){
40385 this.el = Roo.get(el);
40386 this.id = this.el.id || Roo.id();
40387 this.el.on('submit', this.onSubmit, this);
40388 this.el.addClass('x-form');
40392 onSubmit : function(e){
40397 * Returns true if client-side validation on the form is successful.
40400 isValid : function(){
40402 this.items.each(function(f){
40411 * Returns true if any fields in this form have changed since their original load.
40414 isDirty : function(){
40416 this.items.each(function(f){
40426 * Performs a predefined action (submit or load) or custom actions you define on this form.
40427 * @param {String} actionName The name of the action type
40428 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
40429 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
40430 * accept other config options):
40432 Property Type Description
40433 ---------------- --------------- ----------------------------------------------------------------------------------
40434 url String The url for the action (defaults to the form's url)
40435 method String The form method to use (defaults to the form's method, or POST if not defined)
40436 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
40437 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
40438 validate the form on the client (defaults to false)
40440 * @return {BasicForm} this
40442 doAction : function(action, options){
40443 if(typeof action == 'string'){
40444 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
40446 if(this.fireEvent('beforeaction', this, action) !== false){
40447 this.beforeAction(action);
40448 action.run.defer(100, action);
40454 * Shortcut to do a submit action.
40455 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40456 * @return {BasicForm} this
40458 submit : function(options){
40459 this.doAction('submit', options);
40464 * Shortcut to do a load action.
40465 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
40466 * @return {BasicForm} this
40468 load : function(options){
40469 this.doAction('load', options);
40474 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
40475 * @param {Record} record The record to edit
40476 * @return {BasicForm} this
40478 updateRecord : function(record){
40479 record.beginEdit();
40480 var fs = record.fields;
40481 fs.each(function(f){
40482 var field = this.findField(f.name);
40484 record.set(f.name, field.getValue());
40492 * Loads an Roo.data.Record into this form.
40493 * @param {Record} record The record to load
40494 * @return {BasicForm} this
40496 loadRecord : function(record){
40497 this.setValues(record.data);
40502 beforeAction : function(action){
40503 var o = action.options;
40505 if(this.waitMsgTarget === true){
40506 this.el.mask(o.waitMsg, 'x-mask-loading');
40507 }else if(this.waitMsgTarget){
40508 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
40509 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
40511 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
40517 afterAction : function(action, success){
40518 this.activeAction = null;
40519 var o = action.options;
40521 if(this.waitMsgTarget === true){
40523 }else if(this.waitMsgTarget){
40524 this.waitMsgTarget.unmask();
40526 Roo.MessageBox.updateProgress(1);
40527 Roo.MessageBox.hide();
40534 Roo.callback(o.success, o.scope, [this, action]);
40535 this.fireEvent('actioncomplete', this, action);
40537 Roo.callback(o.failure, o.scope, [this, action]);
40538 this.fireEvent('actionfailed', this, action);
40543 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
40544 * @param {String} id The value to search for
40547 findField : function(id){
40548 var field = this.items.get(id);
40550 this.items.each(function(f){
40551 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
40557 return field || null;
40561 * Add a secondary form to this one,
40562 * Used to provide tabbed forms. One form is primary, with hidden values
40563 * which mirror the elements from the other forms.
40565 * @param {Roo.form.Form} form to add.
40568 addForm : function(form)
40571 if (this.childForms.indexOf(form) > -1) {
40575 this.childForms.push(form);
40577 Roo.each(form.allItems, function (fe) {
40579 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
40580 if (this.findField(n)) { // already added..
40583 var add = new Roo.form.Hidden({
40586 add.render(this.el);
40593 * Mark fields in this form invalid in bulk.
40594 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
40595 * @return {BasicForm} this
40597 markInvalid : function(errors){
40598 if(errors instanceof Array){
40599 for(var i = 0, len = errors.length; i < len; i++){
40600 var fieldError = errors[i];
40601 var f = this.findField(fieldError.id);
40603 f.markInvalid(fieldError.msg);
40609 if(typeof errors[id] != 'function' && (field = this.findField(id))){
40610 field.markInvalid(errors[id]);
40614 Roo.each(this.childForms || [], function (f) {
40615 f.markInvalid(errors);
40622 * Set values for fields in this form in bulk.
40623 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
40624 * @return {BasicForm} this
40626 setValues : function(values){
40627 if(values instanceof Array){ // array of objects
40628 for(var i = 0, len = values.length; i < len; i++){
40630 var f = this.findField(v.id);
40632 f.setValue(v.value);
40633 if(this.trackResetOnLoad){
40634 f.originalValue = f.getValue();
40638 }else{ // object hash
40641 if(typeof values[id] != 'function' && (field = this.findField(id))){
40643 if (field.setFromData &&
40644 field.valueField &&
40645 field.displayField &&
40646 // combos' with local stores can
40647 // be queried via setValue()
40648 // to set their value..
40649 (field.store && !field.store.isLocal)
40653 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40654 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40655 field.setFromData(sd);
40658 field.setValue(values[id]);
40662 if(this.trackResetOnLoad){
40663 field.originalValue = field.getValue();
40669 Roo.each(this.childForms || [], function (f) {
40670 f.setValues(values);
40677 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40678 * they are returned as an array.
40679 * @param {Boolean} asString
40682 getValues : function(asString){
40683 if (this.childForms) {
40684 // copy values from the child forms
40685 Roo.each(this.childForms, function (f) {
40686 this.setValues(f.getValues());
40692 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40693 if(asString === true){
40696 return Roo.urlDecode(fs);
40700 * Returns the fields in this form as an object with key/value pairs.
40701 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
40704 getFieldValues : function()
40706 if (this.childForms) {
40707 // copy values from the child forms
40708 Roo.each(this.childForms, function (f) {
40709 this.setValues(f.getValues());
40714 this.items.each(function(f){
40715 if (!f.getName()) {
40718 var v = f.getValue();
40719 if ((typeof(v) == 'object') && f.getRawValue) {
40720 v = f.getRawValue() ; // dates..
40722 ret[f.getName()] = v;
40729 * Clears all invalid messages in this form.
40730 * @return {BasicForm} this
40732 clearInvalid : function(){
40733 this.items.each(function(f){
40737 Roo.each(this.childForms || [], function (f) {
40746 * Resets this form.
40747 * @return {BasicForm} this
40749 reset : function(){
40750 this.items.each(function(f){
40754 Roo.each(this.childForms || [], function (f) {
40763 * Add Roo.form components to this form.
40764 * @param {Field} field1
40765 * @param {Field} field2 (optional)
40766 * @param {Field} etc (optional)
40767 * @return {BasicForm} this
40770 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40776 * Removes a field from the items collection (does NOT remove its markup).
40777 * @param {Field} field
40778 * @return {BasicForm} this
40780 remove : function(field){
40781 this.items.remove(field);
40786 * Looks at the fields in this form, checks them for an id attribute,
40787 * and calls applyTo on the existing dom element with that id.
40788 * @return {BasicForm} this
40790 render : function(){
40791 this.items.each(function(f){
40792 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40800 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40801 * @param {Object} values
40802 * @return {BasicForm} this
40804 applyToFields : function(o){
40805 this.items.each(function(f){
40812 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40813 * @param {Object} values
40814 * @return {BasicForm} this
40816 applyIfToFields : function(o){
40817 this.items.each(function(f){
40825 Roo.BasicForm = Roo.form.BasicForm;/*
40827 * Ext JS Library 1.1.1
40828 * Copyright(c) 2006-2007, Ext JS, LLC.
40830 * Originally Released Under LGPL - original licence link has changed is not relivant.
40833 * <script type="text/javascript">
40837 * @class Roo.form.Form
40838 * @extends Roo.form.BasicForm
40839 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40841 * @param {Object} config Configuration options
40843 Roo.form.Form = function(config){
40845 if (config.items) {
40846 xitems = config.items;
40847 delete config.items;
40851 Roo.form.Form.superclass.constructor.call(this, null, config);
40852 this.url = this.url || this.action;
40854 this.root = new Roo.form.Layout(Roo.applyIf({
40858 this.active = this.root;
40860 * Array of all the buttons that have been added to this form via {@link addButton}
40864 this.allItems = [];
40867 * @event clientvalidation
40868 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40869 * @param {Form} this
40870 * @param {Boolean} valid true if the form has passed client-side validation
40872 clientvalidation: true,
40875 * Fires when the form is rendered
40876 * @param {Roo.form.Form} form
40881 if (this.progressUrl) {
40882 // push a hidden field onto the list of fields..
40886 name : 'UPLOAD_IDENTIFIER'
40891 Roo.each(xitems, this.addxtype, this);
40897 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
40899 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
40902 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
40905 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
40907 buttonAlign:'center',
40910 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
40915 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
40916 * This property cascades to child containers if not set.
40921 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
40922 * fires a looping event with that state. This is required to bind buttons to the valid
40923 * state using the config value formBind:true on the button.
40925 monitorValid : false,
40928 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
40933 * @cfg {String} progressUrl - Url to return progress data
40936 progressUrl : false,
40939 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
40940 * fields are added and the column is closed. If no fields are passed the column remains open
40941 * until end() is called.
40942 * @param {Object} config The config to pass to the column
40943 * @param {Field} field1 (optional)
40944 * @param {Field} field2 (optional)
40945 * @param {Field} etc (optional)
40946 * @return Column The column container object
40948 column : function(c){
40949 var col = new Roo.form.Column(c);
40951 if(arguments.length > 1){ // duplicate code required because of Opera
40952 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40959 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
40960 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
40961 * until end() is called.
40962 * @param {Object} config The config to pass to the fieldset
40963 * @param {Field} field1 (optional)
40964 * @param {Field} field2 (optional)
40965 * @param {Field} etc (optional)
40966 * @return FieldSet The fieldset container object
40968 fieldset : function(c){
40969 var fs = new Roo.form.FieldSet(c);
40971 if(arguments.length > 1){ // duplicate code required because of Opera
40972 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40979 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
40980 * fields are added and the container is closed. If no fields are passed the container remains open
40981 * until end() is called.
40982 * @param {Object} config The config to pass to the Layout
40983 * @param {Field} field1 (optional)
40984 * @param {Field} field2 (optional)
40985 * @param {Field} etc (optional)
40986 * @return Layout The container object
40988 container : function(c){
40989 var l = new Roo.form.Layout(c);
40991 if(arguments.length > 1){ // duplicate code required because of Opera
40992 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40999 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41000 * @param {Object} container A Roo.form.Layout or subclass of Layout
41001 * @return {Form} this
41003 start : function(c){
41004 // cascade label info
41005 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
41006 this.active.stack.push(c);
41007 c.ownerCt = this.active;
41013 * Closes the current open container
41014 * @return {Form} this
41017 if(this.active == this.root){
41020 this.active = this.active.ownerCt;
41025 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
41026 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
41027 * as the label of the field.
41028 * @param {Field} field1
41029 * @param {Field} field2 (optional)
41030 * @param {Field} etc. (optional)
41031 * @return {Form} this
41034 this.active.stack.push.apply(this.active.stack, arguments);
41035 this.allItems.push.apply(this.allItems,arguments);
41037 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
41038 if(a[i].isFormField){
41043 Roo.form.Form.superclass.add.apply(this, r);
41053 * Find any element that has been added to a form, using it's ID or name
41054 * This can include framesets, columns etc. along with regular fields..
41055 * @param {String} id - id or name to find.
41057 * @return {Element} e - or false if nothing found.
41059 findbyId : function(id)
41065 Ext.each(this.allItems, function(f){
41066 if (f.id == id || f.name == id ){
41077 * Render this form into the passed container. This should only be called once!
41078 * @param {String/HTMLElement/Element} container The element this component should be rendered into
41079 * @return {Form} this
41081 render : function(ct)
41087 var o = this.autoCreate || {
41089 method : this.method || 'POST',
41090 id : this.id || Roo.id()
41092 this.initEl(ct.createChild(o));
41094 this.root.render(this.el);
41098 this.items.each(function(f){
41099 f.render('x-form-el-'+f.id);
41102 if(this.buttons.length > 0){
41103 // tables are required to maintain order and for correct IE layout
41104 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
41105 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
41106 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
41108 var tr = tb.getElementsByTagName('tr')[0];
41109 for(var i = 0, len = this.buttons.length; i < len; i++) {
41110 var b = this.buttons[i];
41111 var td = document.createElement('td');
41112 td.className = 'x-form-btn-td';
41113 b.render(tr.appendChild(td));
41116 if(this.monitorValid){ // initialize after render
41117 this.startMonitoring();
41119 this.fireEvent('rendered', this);
41124 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
41125 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
41126 * object or a valid Roo.DomHelper element config
41127 * @param {Function} handler The function called when the button is clicked
41128 * @param {Object} scope (optional) The scope of the handler function
41129 * @return {Roo.Button}
41131 addButton : function(config, handler, scope){
41135 minWidth: this.minButtonWidth,
41138 if(typeof config == "string"){
41141 Roo.apply(bc, config);
41143 var btn = new Roo.Button(null, bc);
41144 this.buttons.push(btn);
41149 * Adds a series of form elements (using the xtype property as the factory method.
41150 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
41151 * @param {Object} config
41154 addxtype : function()
41156 var ar = Array.prototype.slice.call(arguments, 0);
41158 for(var i = 0; i < ar.length; i++) {
41160 continue; // skip -- if this happends something invalid got sent, we
41161 // should ignore it, as basically that interface element will not show up
41162 // and that should be pretty obvious!!
41165 if (Roo.form[ar[i].xtype]) {
41167 var fe = Roo.factory(ar[i], Roo.form);
41173 fe.store.form = this;
41178 this.allItems.push(fe);
41179 if (fe.items && fe.addxtype) {
41180 fe.addxtype.apply(fe, fe.items);
41190 // console.log('adding ' + ar[i].xtype);
41192 if (ar[i].xtype == 'Button') {
41193 //console.log('adding button');
41194 //console.log(ar[i]);
41195 this.addButton(ar[i]);
41196 this.allItems.push(fe);
41200 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
41201 alert('end is not supported on xtype any more, use items');
41203 // //console.log('adding end');
41211 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
41212 * option "monitorValid"
41214 startMonitoring : function(){
41217 Roo.TaskMgr.start({
41218 run : this.bindHandler,
41219 interval : this.monitorPoll || 200,
41226 * Stops monitoring of the valid state of this form
41228 stopMonitoring : function(){
41229 this.bound = false;
41233 bindHandler : function(){
41235 return false; // stops binding
41238 this.items.each(function(f){
41239 if(!f.isValid(true)){
41244 for(var i = 0, len = this.buttons.length; i < len; i++){
41245 var btn = this.buttons[i];
41246 if(btn.formBind === true && btn.disabled === valid){
41247 btn.setDisabled(!valid);
41250 this.fireEvent('clientvalidation', this, valid);
41264 Roo.Form = Roo.form.Form;
41267 * Ext JS Library 1.1.1
41268 * Copyright(c) 2006-2007, Ext JS, LLC.
41270 * Originally Released Under LGPL - original licence link has changed is not relivant.
41273 * <script type="text/javascript">
41277 * @class Roo.form.Action
41278 * Internal Class used to handle form actions
41280 * @param {Roo.form.BasicForm} el The form element or its id
41281 * @param {Object} config Configuration options
41285 // define the action interface
41286 Roo.form.Action = function(form, options){
41288 this.options = options || {};
41291 * Client Validation Failed
41294 Roo.form.Action.CLIENT_INVALID = 'client';
41296 * Server Validation Failed
41299 Roo.form.Action.SERVER_INVALID = 'server';
41301 * Connect to Server Failed
41304 Roo.form.Action.CONNECT_FAILURE = 'connect';
41306 * Reading Data from Server Failed
41309 Roo.form.Action.LOAD_FAILURE = 'load';
41311 Roo.form.Action.prototype = {
41313 failureType : undefined,
41314 response : undefined,
41315 result : undefined,
41317 // interface method
41318 run : function(options){
41322 // interface method
41323 success : function(response){
41327 // interface method
41328 handleResponse : function(response){
41332 // default connection failure
41333 failure : function(response){
41334 this.response = response;
41335 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41336 this.form.afterAction(this, false);
41339 processResponse : function(response){
41340 this.response = response;
41341 if(!response.responseText){
41344 this.result = this.handleResponse(response);
41345 return this.result;
41348 // utility functions used internally
41349 getUrl : function(appendParams){
41350 var url = this.options.url || this.form.url || this.form.el.dom.action;
41352 var p = this.getParams();
41354 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
41360 getMethod : function(){
41361 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
41364 getParams : function(){
41365 var bp = this.form.baseParams;
41366 var p = this.options.params;
41368 if(typeof p == "object"){
41369 p = Roo.urlEncode(Roo.applyIf(p, bp));
41370 }else if(typeof p == 'string' && bp){
41371 p += '&' + Roo.urlEncode(bp);
41374 p = Roo.urlEncode(bp);
41379 createCallback : function(){
41381 success: this.success,
41382 failure: this.failure,
41384 timeout: (this.form.timeout*1000),
41385 upload: this.form.fileUpload ? this.success : undefined
41390 Roo.form.Action.Submit = function(form, options){
41391 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
41394 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
41397 haveProgress : false,
41398 uploadComplete : false,
41400 // uploadProgress indicator.
41401 uploadProgress : function()
41403 if (!this.form.progressUrl) {
41407 if (!this.haveProgress) {
41408 Roo.MessageBox.progress("Uploading", "Uploading");
41410 if (this.uploadComplete) {
41411 Roo.MessageBox.hide();
41415 this.haveProgress = true;
41417 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
41419 var c = new Roo.data.Connection();
41421 url : this.form.progressUrl,
41426 success : function(req){
41427 //console.log(data);
41431 rdata = Roo.decode(req.responseText)
41433 Roo.log("Invalid data from server..");
41437 if (!rdata || !rdata.success) {
41441 var data = rdata.data;
41443 if (this.uploadComplete) {
41444 Roo.MessageBox.hide();
41449 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
41450 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
41453 this.uploadProgress.defer(2000,this);
41456 failure: function(data) {
41457 Roo.log('progress url failed ');
41468 // run get Values on the form, so it syncs any secondary forms.
41469 this.form.getValues();
41471 var o = this.options;
41472 var method = this.getMethod();
41473 var isPost = method == 'POST';
41474 if(o.clientValidation === false || this.form.isValid()){
41476 if (this.form.progressUrl) {
41477 this.form.findField('UPLOAD_IDENTIFIER').setValue(
41478 (new Date() * 1) + '' + Math.random());
41482 Roo.Ajax.request(Roo.apply(this.createCallback(), {
41483 form:this.form.el.dom,
41484 url:this.getUrl(!isPost),
41486 params:isPost ? this.getParams() : null,
41487 isUpload: this.form.fileUpload
41490 this.uploadProgress();
41492 }else if (o.clientValidation !== false){ // client validation failed
41493 this.failureType = Roo.form.Action.CLIENT_INVALID;
41494 this.form.afterAction(this, false);
41498 success : function(response)
41500 this.uploadComplete= true;
41501 if (this.haveProgress) {
41502 Roo.MessageBox.hide();
41505 var result = this.processResponse(response);
41506 if(result === true || result.success){
41507 this.form.afterAction(this, true);
41511 this.form.markInvalid(result.errors);
41512 this.failureType = Roo.form.Action.SERVER_INVALID;
41514 this.form.afterAction(this, false);
41516 failure : function(response)
41518 this.uploadComplete= true;
41519 if (this.haveProgress) {
41520 Roo.MessageBox.hide();
41523 this.response = response;
41524 this.failureType = Roo.form.Action.CONNECT_FAILURE;
41525 this.form.afterAction(this, false);
41528 handleResponse : function(response){
41529 if(this.form.errorReader){
41530 var rs = this.form.errorReader.read(response);
41533 for(var i = 0, len = rs.records.length; i < len; i++) {
41534 var r = rs.records[i];
41535 errors[i] = r.data;
41538 if(errors.length < 1){
41542 success : rs.success,
41548 ret = Roo.decode(response.responseText);
41552 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
41562 Roo.form.Action.Load = function(form, options){
41563 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
41564 this.reader = this.form.reader;
41567 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
41571 Roo.Ajax.request(Roo.apply(
41572 this.createCallback(), {
41573 method:this.getMethod(),
41574 url:this.getUrl(false),
41575 params:this.getParams()
41579 success : function(response){
41580 var result = this.processResponse(response);
41581 if(result === true || !result.success || !result.data){
41582 this.failureType = Roo.form.Action.LOAD_FAILURE;
41583 this.form.afterAction(this, false);
41586 this.form.clearInvalid();
41587 this.form.setValues(result.data);
41588 this.form.afterAction(this, true);
41591 handleResponse : function(response){
41592 if(this.form.reader){
41593 var rs = this.form.reader.read(response);
41594 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
41596 success : rs.success,
41600 return Roo.decode(response.responseText);
41604 Roo.form.Action.ACTION_TYPES = {
41605 'load' : Roo.form.Action.Load,
41606 'submit' : Roo.form.Action.Submit
41609 * Ext JS Library 1.1.1
41610 * Copyright(c) 2006-2007, Ext JS, LLC.
41612 * Originally Released Under LGPL - original licence link has changed is not relivant.
41615 * <script type="text/javascript">
41619 * @class Roo.form.Layout
41620 * @extends Roo.Component
41621 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
41623 * @param {Object} config Configuration options
41625 Roo.form.Layout = function(config){
41627 if (config.items) {
41628 xitems = config.items;
41629 delete config.items;
41631 Roo.form.Layout.superclass.constructor.call(this, config);
41633 Roo.each(xitems, this.addxtype, this);
41637 Roo.extend(Roo.form.Layout, Roo.Component, {
41639 * @cfg {String/Object} autoCreate
41640 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
41643 * @cfg {String/Object/Function} style
41644 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
41645 * a function which returns such a specification.
41648 * @cfg {String} labelAlign
41649 * Valid values are "left," "top" and "right" (defaults to "left")
41652 * @cfg {Number} labelWidth
41653 * Fixed width in pixels of all field labels (defaults to undefined)
41656 * @cfg {Boolean} clear
41657 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
41661 * @cfg {String} labelSeparator
41662 * The separator to use after field labels (defaults to ':')
41664 labelSeparator : ':',
41666 * @cfg {Boolean} hideLabels
41667 * True to suppress the display of field labels in this layout (defaults to false)
41669 hideLabels : false,
41672 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
41677 onRender : function(ct, position){
41678 if(this.el){ // from markup
41679 this.el = Roo.get(this.el);
41680 }else { // generate
41681 var cfg = this.getAutoCreate();
41682 this.el = ct.createChild(cfg, position);
41685 this.el.applyStyles(this.style);
41687 if(this.labelAlign){
41688 this.el.addClass('x-form-label-'+this.labelAlign);
41690 if(this.hideLabels){
41691 this.labelStyle = "display:none";
41692 this.elementStyle = "padding-left:0;";
41694 if(typeof this.labelWidth == 'number'){
41695 this.labelStyle = "width:"+this.labelWidth+"px;";
41696 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
41698 if(this.labelAlign == 'top'){
41699 this.labelStyle = "width:auto;";
41700 this.elementStyle = "padding-left:0;";
41703 var stack = this.stack;
41704 var slen = stack.length;
41706 if(!this.fieldTpl){
41707 var t = new Roo.Template(
41708 '<div class="x-form-item {5}">',
41709 '<label for="{0}" style="{2}">{1}{4}</label>',
41710 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41712 '</div><div class="x-form-clear-left"></div>'
41714 t.disableFormats = true;
41716 Roo.form.Layout.prototype.fieldTpl = t;
41718 for(var i = 0; i < slen; i++) {
41719 if(stack[i].isFormField){
41720 this.renderField(stack[i]);
41722 this.renderComponent(stack[i]);
41727 this.el.createChild({cls:'x-form-clear'});
41732 renderField : function(f){
41733 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
41736 f.labelStyle||this.labelStyle||'', //2
41737 this.elementStyle||'', //3
41738 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
41739 f.itemCls||this.itemCls||'' //5
41740 ], true).getPrevSibling());
41744 renderComponent : function(c){
41745 c.render(c.isLayout ? this.el : this.el.createChild());
41748 * Adds a object form elements (using the xtype property as the factory method.)
41749 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
41750 * @param {Object} config
41752 addxtype : function(o)
41754 // create the lement.
41755 o.form = this.form;
41756 var fe = Roo.factory(o, Roo.form);
41757 this.form.allItems.push(fe);
41758 this.stack.push(fe);
41760 if (fe.isFormField) {
41761 this.form.items.add(fe);
41769 * @class Roo.form.Column
41770 * @extends Roo.form.Layout
41771 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
41773 * @param {Object} config Configuration options
41775 Roo.form.Column = function(config){
41776 Roo.form.Column.superclass.constructor.call(this, config);
41779 Roo.extend(Roo.form.Column, Roo.form.Layout, {
41781 * @cfg {Number/String} width
41782 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41785 * @cfg {String/Object} autoCreate
41786 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41790 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41793 onRender : function(ct, position){
41794 Roo.form.Column.superclass.onRender.call(this, ct, position);
41796 this.el.setWidth(this.width);
41803 * @class Roo.form.Row
41804 * @extends Roo.form.Layout
41805 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41807 * @param {Object} config Configuration options
41811 Roo.form.Row = function(config){
41812 Roo.form.Row.superclass.constructor.call(this, config);
41815 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41817 * @cfg {Number/String} width
41818 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41821 * @cfg {Number/String} height
41822 * The fixed height of the column in pixels or CSS value (defaults to "auto")
41824 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41828 onRender : function(ct, position){
41829 //console.log('row render');
41831 var t = new Roo.Template(
41832 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
41833 '<label for="{0}" style="{2}">{1}{4}</label>',
41834 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41838 t.disableFormats = true;
41840 Roo.form.Layout.prototype.rowTpl = t;
41842 this.fieldTpl = this.rowTpl;
41844 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
41845 var labelWidth = 100;
41847 if ((this.labelAlign != 'top')) {
41848 if (typeof this.labelWidth == 'number') {
41849 labelWidth = this.labelWidth
41851 this.padWidth = 20 + labelWidth;
41855 Roo.form.Column.superclass.onRender.call(this, ct, position);
41857 this.el.setWidth(this.width);
41860 this.el.setHeight(this.height);
41865 renderField : function(f){
41866 f.fieldEl = this.fieldTpl.append(this.el, [
41867 f.id, f.fieldLabel,
41868 f.labelStyle||this.labelStyle||'',
41869 this.elementStyle||'',
41870 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
41871 f.itemCls||this.itemCls||'',
41872 f.width ? f.width + this.padWidth : 160 + this.padWidth
41879 * @class Roo.form.FieldSet
41880 * @extends Roo.form.Layout
41881 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
41883 * @param {Object} config Configuration options
41885 Roo.form.FieldSet = function(config){
41886 Roo.form.FieldSet.superclass.constructor.call(this, config);
41889 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
41891 * @cfg {String} legend
41892 * The text to display as the legend for the FieldSet (defaults to '')
41895 * @cfg {String/Object} autoCreate
41896 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
41900 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
41903 onRender : function(ct, position){
41904 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
41906 this.setLegend(this.legend);
41911 setLegend : function(text){
41913 this.el.child('legend').update(text);
41918 * Ext JS Library 1.1.1
41919 * Copyright(c) 2006-2007, Ext JS, LLC.
41921 * Originally Released Under LGPL - original licence link has changed is not relivant.
41924 * <script type="text/javascript">
41927 * @class Roo.form.VTypes
41928 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
41931 Roo.form.VTypes = function(){
41932 // closure these in so they are only created once.
41933 var alpha = /^[a-zA-Z_]+$/;
41934 var alphanum = /^[a-zA-Z0-9_]+$/;
41935 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
41936 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
41938 // All these messages and functions are configurable
41941 * The function used to validate email addresses
41942 * @param {String} value The email address
41944 'email' : function(v){
41945 return email.test(v);
41948 * The error text to display when the email validation function returns false
41951 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
41953 * The keystroke filter mask to be applied on email input
41956 'emailMask' : /[a-z0-9_\.\-@]/i,
41959 * The function used to validate URLs
41960 * @param {String} value The URL
41962 'url' : function(v){
41963 return url.test(v);
41966 * The error text to display when the url validation function returns false
41969 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
41972 * The function used to validate alpha values
41973 * @param {String} value The value
41975 'alpha' : function(v){
41976 return alpha.test(v);
41979 * The error text to display when the alpha validation function returns false
41982 'alphaText' : 'This field should only contain letters and _',
41984 * The keystroke filter mask to be applied on alpha input
41987 'alphaMask' : /[a-z_]/i,
41990 * The function used to validate alphanumeric values
41991 * @param {String} value The value
41993 'alphanum' : function(v){
41994 return alphanum.test(v);
41997 * The error text to display when the alphanumeric validation function returns false
42000 'alphanumText' : 'This field should only contain letters, numbers and _',
42002 * The keystroke filter mask to be applied on alphanumeric input
42005 'alphanumMask' : /[a-z0-9_]/i
42007 }();//<script type="text/javascript">
42010 * @class Roo.form.FCKeditor
42011 * @extends Roo.form.TextArea
42012 * Wrapper around the FCKEditor http://www.fckeditor.net
42014 * Creates a new FCKeditor
42015 * @param {Object} config Configuration options
42017 Roo.form.FCKeditor = function(config){
42018 Roo.form.FCKeditor.superclass.constructor.call(this, config);
42021 * @event editorinit
42022 * Fired when the editor is initialized - you can add extra handlers here..
42023 * @param {FCKeditor} this
42024 * @param {Object} the FCK object.
42031 Roo.form.FCKeditor.editors = { };
42032 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
42034 //defaultAutoCreate : {
42035 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
42039 * @cfg {Object} fck options - see fck manual for details.
42044 * @cfg {Object} fck toolbar set (Basic or Default)
42046 toolbarSet : 'Basic',
42048 * @cfg {Object} fck BasePath
42050 basePath : '/fckeditor/',
42058 onRender : function(ct, position)
42061 this.defaultAutoCreate = {
42063 style:"width:300px;height:60px;",
42064 autocomplete: "off"
42067 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
42070 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
42071 if(this.preventScrollbars){
42072 this.el.setStyle("overflow", "hidden");
42074 this.el.setHeight(this.growMin);
42077 //console.log('onrender' + this.getId() );
42078 Roo.form.FCKeditor.editors[this.getId()] = this;
42081 this.replaceTextarea() ;
42085 getEditor : function() {
42086 return this.fckEditor;
42089 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
42090 * @param {Mixed} value The value to set
42094 setValue : function(value)
42096 //console.log('setValue: ' + value);
42098 if(typeof(value) == 'undefined') { // not sure why this is happending...
42101 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42103 //if(!this.el || !this.getEditor()) {
42104 // this.value = value;
42105 //this.setValue.defer(100,this,[value]);
42109 if(!this.getEditor()) {
42113 this.getEditor().SetData(value);
42120 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
42121 * @return {Mixed} value The field value
42123 getValue : function()
42126 if (this.frame && this.frame.dom.style.display == 'none') {
42127 return Roo.form.FCKeditor.superclass.getValue.call(this);
42130 if(!this.el || !this.getEditor()) {
42132 // this.getValue.defer(100,this);
42137 var value=this.getEditor().GetData();
42138 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
42139 return Roo.form.FCKeditor.superclass.getValue.call(this);
42145 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
42146 * @return {Mixed} value The field value
42148 getRawValue : function()
42150 if (this.frame && this.frame.dom.style.display == 'none') {
42151 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42154 if(!this.el || !this.getEditor()) {
42155 //this.getRawValue.defer(100,this);
42162 var value=this.getEditor().GetData();
42163 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
42164 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
42168 setSize : function(w,h) {
42172 //if (this.frame && this.frame.dom.style.display == 'none') {
42173 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42176 //if(!this.el || !this.getEditor()) {
42177 // this.setSize.defer(100,this, [w,h]);
42183 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
42185 this.frame.dom.setAttribute('width', w);
42186 this.frame.dom.setAttribute('height', h);
42187 this.frame.setSize(w,h);
42191 toggleSourceEdit : function(value) {
42195 this.el.dom.style.display = value ? '' : 'none';
42196 this.frame.dom.style.display = value ? 'none' : '';
42201 focus: function(tag)
42203 if (this.frame.dom.style.display == 'none') {
42204 return Roo.form.FCKeditor.superclass.focus.call(this);
42206 if(!this.el || !this.getEditor()) {
42207 this.focus.defer(100,this, [tag]);
42214 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
42215 this.getEditor().Focus();
42217 if (!this.getEditor().Selection.GetSelection()) {
42218 this.focus.defer(100,this, [tag]);
42223 var r = this.getEditor().EditorDocument.createRange();
42224 r.setStart(tgs[0],0);
42225 r.setEnd(tgs[0],0);
42226 this.getEditor().Selection.GetSelection().removeAllRanges();
42227 this.getEditor().Selection.GetSelection().addRange(r);
42228 this.getEditor().Focus();
42235 replaceTextarea : function()
42237 if ( document.getElementById( this.getId() + '___Frame' ) )
42239 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
42241 // We must check the elements firstly using the Id and then the name.
42242 var oTextarea = document.getElementById( this.getId() );
42244 var colElementsByName = document.getElementsByName( this.getId() ) ;
42246 oTextarea.style.display = 'none' ;
42248 if ( oTextarea.tabIndex ) {
42249 this.TabIndex = oTextarea.tabIndex ;
42252 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
42253 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
42254 this.frame = Roo.get(this.getId() + '___Frame')
42257 _getConfigHtml : function()
42261 for ( var o in this.fckconfig ) {
42262 sConfig += sConfig.length > 0 ? '&' : '';
42263 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
42266 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
42270 _getIFrameHtml : function()
42272 var sFile = 'fckeditor.html' ;
42273 /* no idea what this is about..
42276 if ( (/fcksource=true/i).test( window.top.location.search ) )
42277 sFile = 'fckeditor.original.html' ;
42282 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
42283 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
42286 var html = '<iframe id="' + this.getId() +
42287 '___Frame" src="' + sLink +
42288 '" width="' + this.width +
42289 '" height="' + this.height + '"' +
42290 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
42291 ' frameborder="0" scrolling="no"></iframe>' ;
42296 _insertHtmlBefore : function( html, element )
42298 if ( element.insertAdjacentHTML ) {
42300 element.insertAdjacentHTML( 'beforeBegin', html ) ;
42302 var oRange = document.createRange() ;
42303 oRange.setStartBefore( element ) ;
42304 var oFragment = oRange.createContextualFragment( html );
42305 element.parentNode.insertBefore( oFragment, element ) ;
42318 //Roo.reg('fckeditor', Roo.form.FCKeditor);
42320 function FCKeditor_OnComplete(editorInstance){
42321 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
42322 f.fckEditor = editorInstance;
42323 //console.log("loaded");
42324 f.fireEvent('editorinit', f, editorInstance);
42344 //<script type="text/javascript">
42346 * @class Roo.form.GridField
42347 * @extends Roo.form.Field
42348 * Embed a grid (or editable grid into a form)
42351 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
42353 * xgrid.store = Roo.data.Store
42354 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
42355 * xgrid.store.reader = Roo.data.JsonReader
42359 * Creates a new GridField
42360 * @param {Object} config Configuration options
42362 Roo.form.GridField = function(config){
42363 Roo.form.GridField.superclass.constructor.call(this, config);
42367 Roo.extend(Roo.form.GridField, Roo.form.Field, {
42369 * @cfg {Number} width - used to restrict width of grid..
42373 * @cfg {Number} height - used to restrict height of grid..
42377 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
42383 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42384 * {tag: "input", type: "checkbox", autocomplete: "off"})
42386 // defaultAutoCreate : { tag: 'div' },
42387 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42389 * @cfg {String} addTitle Text to include for adding a title.
42393 onResize : function(){
42394 Roo.form.Field.superclass.onResize.apply(this, arguments);
42397 initEvents : function(){
42398 // Roo.form.Checkbox.superclass.initEvents.call(this);
42399 // has no events...
42404 getResizeEl : function(){
42408 getPositionEl : function(){
42413 onRender : function(ct, position){
42415 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
42416 var style = this.style;
42419 Roo.form.GridField.superclass.onRender.call(this, ct, position);
42420 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
42421 this.viewEl = this.wrap.createChild({ tag: 'div' });
42423 this.viewEl.applyStyles(style);
42426 this.viewEl.setWidth(this.width);
42429 this.viewEl.setHeight(this.height);
42431 //if(this.inputValue !== undefined){
42432 //this.setValue(this.value);
42435 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
42438 this.grid.render();
42439 this.grid.getDataSource().on('remove', this.refreshValue, this);
42440 this.grid.getDataSource().on('update', this.refreshValue, this);
42441 this.grid.on('afteredit', this.refreshValue, this);
42447 * Sets the value of the item.
42448 * @param {String} either an object or a string..
42450 setValue : function(v){
42452 v = v || []; // empty set..
42453 // this does not seem smart - it really only affects memoryproxy grids..
42454 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
42455 var ds = this.grid.getDataSource();
42456 // assumes a json reader..
42458 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
42459 ds.loadData( data);
42461 Roo.form.GridField.superclass.setValue.call(this, v);
42462 this.refreshValue();
42463 // should load data in the grid really....
42467 refreshValue: function() {
42469 this.grid.getDataSource().each(function(r) {
42472 this.el.dom.value = Roo.encode(val);
42480 * Ext JS Library 1.1.1
42481 * Copyright(c) 2006-2007, Ext JS, LLC.
42483 * Originally Released Under LGPL - original licence link has changed is not relivant.
42486 * <script type="text/javascript">
42489 * @class Roo.form.DisplayField
42490 * @extends Roo.form.Field
42491 * A generic Field to display non-editable data.
42493 * Creates a new Display Field item.
42494 * @param {Object} config Configuration options
42496 Roo.form.DisplayField = function(config){
42497 Roo.form.DisplayField.superclass.constructor.call(this, config);
42501 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
42502 inputType: 'hidden',
42508 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42510 focusClass : undefined,
42512 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42514 fieldClass: 'x-form-field',
42517 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
42519 valueRenderer: undefined,
42523 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42524 * {tag: "input", type: "checkbox", autocomplete: "off"})
42527 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
42529 onResize : function(){
42530 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
42534 initEvents : function(){
42535 // Roo.form.Checkbox.superclass.initEvents.call(this);
42536 // has no events...
42541 getResizeEl : function(){
42545 getPositionEl : function(){
42550 onRender : function(ct, position){
42552 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
42553 //if(this.inputValue !== undefined){
42554 this.wrap = this.el.wrap();
42556 this.viewEl = this.wrap.createChild({ tag: 'div'});
42558 if (this.bodyStyle) {
42559 this.viewEl.applyStyles(this.bodyStyle);
42561 //this.viewEl.setStyle('padding', '2px');
42563 this.setValue(this.value);
42568 initValue : Roo.emptyFn,
42573 onClick : function(){
42578 * Sets the checked state of the checkbox.
42579 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
42581 setValue : function(v){
42583 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
42584 // this might be called before we have a dom element..
42585 if (!this.viewEl) {
42588 this.viewEl.dom.innerHTML = html;
42589 Roo.form.DisplayField.superclass.setValue.call(this, v);
42592 });//<script type="text/javasscript">
42596 * @class Roo.DDView
42597 * A DnD enabled version of Roo.View.
42598 * @param {Element/String} container The Element in which to create the View.
42599 * @param {String} tpl The template string used to create the markup for each element of the View
42600 * @param {Object} config The configuration properties. These include all the config options of
42601 * {@link Roo.View} plus some specific to this class.<br>
42603 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
42604 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
42606 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
42607 .x-view-drag-insert-above {
42608 border-top:1px dotted #3366cc;
42610 .x-view-drag-insert-below {
42611 border-bottom:1px dotted #3366cc;
42617 Roo.DDView = function(container, tpl, config) {
42618 Roo.DDView.superclass.constructor.apply(this, arguments);
42619 this.getEl().setStyle("outline", "0px none");
42620 this.getEl().unselectable();
42621 if (this.dragGroup) {
42622 this.setDraggable(this.dragGroup.split(","));
42624 if (this.dropGroup) {
42625 this.setDroppable(this.dropGroup.split(","));
42627 if (this.deletable) {
42628 this.setDeletable();
42630 this.isDirtyFlag = false;
42636 Roo.extend(Roo.DDView, Roo.View, {
42637 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
42638 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
42639 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
42640 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
42644 reset: Roo.emptyFn,
42646 clearInvalid: Roo.form.Field.prototype.clearInvalid,
42648 validate: function() {
42652 destroy: function() {
42653 this.purgeListeners();
42654 this.getEl.removeAllListeners();
42655 this.getEl().remove();
42656 if (this.dragZone) {
42657 if (this.dragZone.destroy) {
42658 this.dragZone.destroy();
42661 if (this.dropZone) {
42662 if (this.dropZone.destroy) {
42663 this.dropZone.destroy();
42668 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
42669 getName: function() {
42673 /** Loads the View from a JSON string representing the Records to put into the Store. */
42674 setValue: function(v) {
42676 throw "DDView.setValue(). DDView must be constructed with a valid Store";
42679 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
42680 this.store.proxy = new Roo.data.MemoryProxy(data);
42684 /** @return {String} a parenthesised list of the ids of the Records in the View. */
42685 getValue: function() {
42687 this.store.each(function(rec) {
42688 result += rec.id + ',';
42690 return result.substr(0, result.length - 1) + ')';
42693 getIds: function() {
42694 var i = 0, result = new Array(this.store.getCount());
42695 this.store.each(function(rec) {
42696 result[i++] = rec.id;
42701 isDirty: function() {
42702 return this.isDirtyFlag;
42706 * Part of the Roo.dd.DropZone interface. If no target node is found, the
42707 * whole Element becomes the target, and this causes the drop gesture to append.
42709 getTargetFromEvent : function(e) {
42710 var target = e.getTarget();
42711 while ((target !== null) && (target.parentNode != this.el.dom)) {
42712 target = target.parentNode;
42715 target = this.el.dom.lastChild || this.el.dom;
42721 * Create the drag data which consists of an object which has the property "ddel" as
42722 * the drag proxy element.
42724 getDragData : function(e) {
42725 var target = this.findItemFromChild(e.getTarget());
42727 this.handleSelection(e);
42728 var selNodes = this.getSelectedNodes();
42731 copy: this.copy || (this.allowCopy && e.ctrlKey),
42735 var selectedIndices = this.getSelectedIndexes();
42736 for (var i = 0; i < selectedIndices.length; i++) {
42737 dragData.records.push(this.store.getAt(selectedIndices[i]));
42739 if (selNodes.length == 1) {
42740 dragData.ddel = target.cloneNode(true); // the div element
42742 var div = document.createElement('div'); // create the multi element drag "ghost"
42743 div.className = 'multi-proxy';
42744 for (var i = 0, len = selNodes.length; i < len; i++) {
42745 div.appendChild(selNodes[i].cloneNode(true));
42747 dragData.ddel = div;
42749 //console.log(dragData)
42750 //console.log(dragData.ddel.innerHTML)
42753 //console.log('nodragData')
42757 /** Specify to which ddGroup items in this DDView may be dragged. */
42758 setDraggable: function(ddGroup) {
42759 if (ddGroup instanceof Array) {
42760 Roo.each(ddGroup, this.setDraggable, this);
42763 if (this.dragZone) {
42764 this.dragZone.addToGroup(ddGroup);
42766 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
42767 containerScroll: true,
42771 // Draggability implies selection. DragZone's mousedown selects the element.
42772 if (!this.multiSelect) { this.singleSelect = true; }
42774 // Wire the DragZone's handlers up to methods in *this*
42775 this.dragZone.getDragData = this.getDragData.createDelegate(this);
42779 /** Specify from which ddGroup this DDView accepts drops. */
42780 setDroppable: function(ddGroup) {
42781 if (ddGroup instanceof Array) {
42782 Roo.each(ddGroup, this.setDroppable, this);
42785 if (this.dropZone) {
42786 this.dropZone.addToGroup(ddGroup);
42788 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
42789 containerScroll: true,
42793 // Wire the DropZone's handlers up to methods in *this*
42794 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
42795 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
42796 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
42797 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
42798 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
42802 /** Decide whether to drop above or below a View node. */
42803 getDropPoint : function(e, n, dd){
42804 if (n == this.el.dom) { return "above"; }
42805 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
42806 var c = t + (b - t) / 2;
42807 var y = Roo.lib.Event.getPageY(e);
42815 onNodeEnter : function(n, dd, e, data){
42819 onNodeOver : function(n, dd, e, data){
42820 var pt = this.getDropPoint(e, n, dd);
42821 // set the insert point style on the target node
42822 var dragElClass = this.dropNotAllowed;
42825 if (pt == "above"){
42826 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
42827 targetElClass = "x-view-drag-insert-above";
42829 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
42830 targetElClass = "x-view-drag-insert-below";
42832 if (this.lastInsertClass != targetElClass){
42833 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
42834 this.lastInsertClass = targetElClass;
42837 return dragElClass;
42840 onNodeOut : function(n, dd, e, data){
42841 this.removeDropIndicators(n);
42844 onNodeDrop : function(n, dd, e, data){
42845 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
42848 var pt = this.getDropPoint(e, n, dd);
42849 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
42850 if (pt == "below") { insertAt++; }
42851 for (var i = 0; i < data.records.length; i++) {
42852 var r = data.records[i];
42853 var dup = this.store.getById(r.id);
42854 if (dup && (dd != this.dragZone)) {
42855 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
42858 this.store.insert(insertAt++, r.copy());
42860 data.source.isDirtyFlag = true;
42862 this.store.insert(insertAt++, r);
42864 this.isDirtyFlag = true;
42867 this.dragZone.cachedTarget = null;
42871 removeDropIndicators : function(n){
42873 Roo.fly(n).removeClass([
42874 "x-view-drag-insert-above",
42875 "x-view-drag-insert-below"]);
42876 this.lastInsertClass = "_noclass";
42881 * Utility method. Add a delete option to the DDView's context menu.
42882 * @param {String} imageUrl The URL of the "delete" icon image.
42884 setDeletable: function(imageUrl) {
42885 if (!this.singleSelect && !this.multiSelect) {
42886 this.singleSelect = true;
42888 var c = this.getContextMenu();
42889 this.contextMenu.on("itemclick", function(item) {
42892 this.remove(this.getSelectedIndexes());
42896 this.contextMenu.add({
42903 /** Return the context menu for this DDView. */
42904 getContextMenu: function() {
42905 if (!this.contextMenu) {
42906 // Create the View's context menu
42907 this.contextMenu = new Roo.menu.Menu({
42908 id: this.id + "-contextmenu"
42910 this.el.on("contextmenu", this.showContextMenu, this);
42912 return this.contextMenu;
42915 disableContextMenu: function() {
42916 if (this.contextMenu) {
42917 this.el.un("contextmenu", this.showContextMenu, this);
42921 showContextMenu: function(e, item) {
42922 item = this.findItemFromChild(e.getTarget());
42925 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
42926 this.contextMenu.showAt(e.getXY());
42931 * Remove {@link Roo.data.Record}s at the specified indices.
42932 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
42934 remove: function(selectedIndices) {
42935 selectedIndices = [].concat(selectedIndices);
42936 for (var i = 0; i < selectedIndices.length; i++) {
42937 var rec = this.store.getAt(selectedIndices[i]);
42938 this.store.remove(rec);
42943 * Double click fires the event, but also, if this is draggable, and there is only one other
42944 * related DropZone, it transfers the selected node.
42946 onDblClick : function(e){
42947 var item = this.findItemFromChild(e.getTarget());
42949 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
42952 if (this.dragGroup) {
42953 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
42954 while (targets.indexOf(this.dropZone) > -1) {
42955 targets.remove(this.dropZone);
42957 if (targets.length == 1) {
42958 this.dragZone.cachedTarget = null;
42959 var el = Roo.get(targets[0].getEl());
42960 var box = el.getBox(true);
42961 targets[0].onNodeDrop(el.dom, {
42963 xy: [box.x, box.y + box.height - 1]
42964 }, null, this.getDragData(e));
42970 handleSelection: function(e) {
42971 this.dragZone.cachedTarget = null;
42972 var item = this.findItemFromChild(e.getTarget());
42974 this.clearSelections(true);
42977 if (item && (this.multiSelect || this.singleSelect)){
42978 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
42979 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
42980 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
42981 this.unselect(item);
42983 this.select(item, this.multiSelect && e.ctrlKey);
42984 this.lastSelection = item;
42989 onItemClick : function(item, index, e){
42990 if(this.fireEvent("beforeclick", this, index, item, e) === false){
42996 unselect : function(nodeInfo, suppressEvent){
42997 var node = this.getNode(nodeInfo);
42998 if(node && this.isSelected(node)){
42999 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
43000 Roo.fly(node).removeClass(this.selectedClass);
43001 this.selections.remove(node);
43002 if(!suppressEvent){
43003 this.fireEvent("selectionchange", this, this.selections);
43011 * Ext JS Library 1.1.1
43012 * Copyright(c) 2006-2007, Ext JS, LLC.
43014 * Originally Released Under LGPL - original licence link has changed is not relivant.
43017 * <script type="text/javascript">
43021 * @class Roo.LayoutManager
43022 * @extends Roo.util.Observable
43023 * Base class for layout managers.
43025 Roo.LayoutManager = function(container, config){
43026 Roo.LayoutManager.superclass.constructor.call(this);
43027 this.el = Roo.get(container);
43028 // ie scrollbar fix
43029 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
43030 document.body.scroll = "no";
43031 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
43032 this.el.position('relative');
43034 this.id = this.el.id;
43035 this.el.addClass("x-layout-container");
43036 /** false to disable window resize monitoring @type Boolean */
43037 this.monitorWindowResize = true;
43042 * Fires when a layout is performed.
43043 * @param {Roo.LayoutManager} this
43047 * @event regionresized
43048 * Fires when the user resizes a region.
43049 * @param {Roo.LayoutRegion} region The resized region
43050 * @param {Number} newSize The new size (width for east/west, height for north/south)
43052 "regionresized" : true,
43054 * @event regioncollapsed
43055 * Fires when a region is collapsed.
43056 * @param {Roo.LayoutRegion} region The collapsed region
43058 "regioncollapsed" : true,
43060 * @event regionexpanded
43061 * Fires when a region is expanded.
43062 * @param {Roo.LayoutRegion} region The expanded region
43064 "regionexpanded" : true
43066 this.updating = false;
43067 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
43070 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
43072 * Returns true if this layout is currently being updated
43073 * @return {Boolean}
43075 isUpdating : function(){
43076 return this.updating;
43080 * Suspend the LayoutManager from doing auto-layouts while
43081 * making multiple add or remove calls
43083 beginUpdate : function(){
43084 this.updating = true;
43088 * Restore auto-layouts and optionally disable the manager from performing a layout
43089 * @param {Boolean} noLayout true to disable a layout update
43091 endUpdate : function(noLayout){
43092 this.updating = false;
43098 layout: function(){
43102 onRegionResized : function(region, newSize){
43103 this.fireEvent("regionresized", region, newSize);
43107 onRegionCollapsed : function(region){
43108 this.fireEvent("regioncollapsed", region);
43111 onRegionExpanded : function(region){
43112 this.fireEvent("regionexpanded", region);
43116 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
43117 * performs box-model adjustments.
43118 * @return {Object} The size as an object {width: (the width), height: (the height)}
43120 getViewSize : function(){
43122 if(this.el.dom != document.body){
43123 size = this.el.getSize();
43125 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
43127 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
43128 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
43133 * Returns the Element this layout is bound to.
43134 * @return {Roo.Element}
43136 getEl : function(){
43141 * Returns the specified region.
43142 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
43143 * @return {Roo.LayoutRegion}
43145 getRegion : function(target){
43146 return this.regions[target.toLowerCase()];
43149 onWindowResize : function(){
43150 if(this.monitorWindowResize){
43156 * Ext JS Library 1.1.1
43157 * Copyright(c) 2006-2007, Ext JS, LLC.
43159 * Originally Released Under LGPL - original licence link has changed is not relivant.
43162 * <script type="text/javascript">
43165 * @class Roo.BorderLayout
43166 * @extends Roo.LayoutManager
43167 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
43168 * please see: <br><br>
43169 * <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>
43170 * <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>
43173 var layout = new Roo.BorderLayout(document.body, {
43207 preferredTabWidth: 150
43212 var CP = Roo.ContentPanel;
43214 layout.beginUpdate();
43215 layout.add("north", new CP("north", "North"));
43216 layout.add("south", new CP("south", {title: "South", closable: true}));
43217 layout.add("west", new CP("west", {title: "West"}));
43218 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
43219 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
43220 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
43221 layout.getRegion("center").showPanel("center1");
43222 layout.endUpdate();
43225 <b>The container the layout is rendered into can be either the body element or any other element.
43226 If it is not the body element, the container needs to either be an absolute positioned element,
43227 or you will need to add "position:relative" to the css of the container. You will also need to specify
43228 the container size if it is not the body element.</b>
43231 * Create a new BorderLayout
43232 * @param {String/HTMLElement/Element} container The container this layout is bound to
43233 * @param {Object} config Configuration options
43235 Roo.BorderLayout = function(container, config){
43236 config = config || {};
43237 Roo.BorderLayout.superclass.constructor.call(this, container, config);
43238 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
43239 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
43240 var target = this.factory.validRegions[i];
43241 if(config[target]){
43242 this.addRegion(target, config[target]);
43247 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
43249 * Creates and adds a new region if it doesn't already exist.
43250 * @param {String} target The target region key (north, south, east, west or center).
43251 * @param {Object} config The regions config object
43252 * @return {BorderLayoutRegion} The new region
43254 addRegion : function(target, config){
43255 if(!this.regions[target]){
43256 var r = this.factory.create(target, this, config);
43257 this.bindRegion(target, r);
43259 return this.regions[target];
43263 bindRegion : function(name, r){
43264 this.regions[name] = r;
43265 r.on("visibilitychange", this.layout, this);
43266 r.on("paneladded", this.layout, this);
43267 r.on("panelremoved", this.layout, this);
43268 r.on("invalidated", this.layout, this);
43269 r.on("resized", this.onRegionResized, this);
43270 r.on("collapsed", this.onRegionCollapsed, this);
43271 r.on("expanded", this.onRegionExpanded, this);
43275 * Performs a layout update.
43277 layout : function(){
43278 if(this.updating) return;
43279 var size = this.getViewSize();
43280 var w = size.width;
43281 var h = size.height;
43286 //var x = 0, y = 0;
43288 var rs = this.regions;
43289 var north = rs["north"];
43290 var south = rs["south"];
43291 var west = rs["west"];
43292 var east = rs["east"];
43293 var center = rs["center"];
43294 //if(this.hideOnLayout){ // not supported anymore
43295 //c.el.setStyle("display", "none");
43297 if(north && north.isVisible()){
43298 var b = north.getBox();
43299 var m = north.getMargins();
43300 b.width = w - (m.left+m.right);
43303 centerY = b.height + b.y + m.bottom;
43304 centerH -= centerY;
43305 north.updateBox(this.safeBox(b));
43307 if(south && south.isVisible()){
43308 var b = south.getBox();
43309 var m = south.getMargins();
43310 b.width = w - (m.left+m.right);
43312 var totalHeight = (b.height + m.top + m.bottom);
43313 b.y = h - totalHeight + m.top;
43314 centerH -= totalHeight;
43315 south.updateBox(this.safeBox(b));
43317 if(west && west.isVisible()){
43318 var b = west.getBox();
43319 var m = west.getMargins();
43320 b.height = centerH - (m.top+m.bottom);
43322 b.y = centerY + m.top;
43323 var totalWidth = (b.width + m.left + m.right);
43324 centerX += totalWidth;
43325 centerW -= totalWidth;
43326 west.updateBox(this.safeBox(b));
43328 if(east && east.isVisible()){
43329 var b = east.getBox();
43330 var m = east.getMargins();
43331 b.height = centerH - (m.top+m.bottom);
43332 var totalWidth = (b.width + m.left + m.right);
43333 b.x = w - totalWidth + m.left;
43334 b.y = centerY + m.top;
43335 centerW -= totalWidth;
43336 east.updateBox(this.safeBox(b));
43339 var m = center.getMargins();
43341 x: centerX + m.left,
43342 y: centerY + m.top,
43343 width: centerW - (m.left+m.right),
43344 height: centerH - (m.top+m.bottom)
43346 //if(this.hideOnLayout){
43347 //center.el.setStyle("display", "block");
43349 center.updateBox(this.safeBox(centerBox));
43352 this.fireEvent("layout", this);
43356 safeBox : function(box){
43357 box.width = Math.max(0, box.width);
43358 box.height = Math.max(0, box.height);
43363 * Adds a ContentPanel (or subclass) to this layout.
43364 * @param {String} target The target region key (north, south, east, west or center).
43365 * @param {Roo.ContentPanel} panel The panel to add
43366 * @return {Roo.ContentPanel} The added panel
43368 add : function(target, panel){
43370 target = target.toLowerCase();
43371 return this.regions[target].add(panel);
43375 * Remove a ContentPanel (or subclass) to this layout.
43376 * @param {String} target The target region key (north, south, east, west or center).
43377 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
43378 * @return {Roo.ContentPanel} The removed panel
43380 remove : function(target, panel){
43381 target = target.toLowerCase();
43382 return this.regions[target].remove(panel);
43386 * Searches all regions for a panel with the specified id
43387 * @param {String} panelId
43388 * @return {Roo.ContentPanel} The panel or null if it wasn't found
43390 findPanel : function(panelId){
43391 var rs = this.regions;
43392 for(var target in rs){
43393 if(typeof rs[target] != "function"){
43394 var p = rs[target].getPanel(panelId);
43404 * Searches all regions for a panel with the specified id and activates (shows) it.
43405 * @param {String/ContentPanel} panelId The panels id or the panel itself
43406 * @return {Roo.ContentPanel} The shown panel or null
43408 showPanel : function(panelId) {
43409 var rs = this.regions;
43410 for(var target in rs){
43411 var r = rs[target];
43412 if(typeof r != "function"){
43413 if(r.hasPanel(panelId)){
43414 return r.showPanel(panelId);
43422 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
43423 * @param {Roo.state.Provider} provider (optional) An alternate state provider
43425 restoreState : function(provider){
43427 provider = Roo.state.Manager;
43429 var sm = new Roo.LayoutStateManager();
43430 sm.init(this, provider);
43434 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
43435 * object should contain properties for each region to add ContentPanels to, and each property's value should be
43436 * a valid ContentPanel config object. Example:
43438 // Create the main layout
43439 var layout = new Roo.BorderLayout('main-ct', {
43450 // Create and add multiple ContentPanels at once via configs
43453 id: 'source-files',
43455 title:'Ext Source Files',
43468 * @param {Object} regions An object containing ContentPanel configs by region name
43470 batchAdd : function(regions){
43471 this.beginUpdate();
43472 for(var rname in regions){
43473 var lr = this.regions[rname];
43475 this.addTypedPanels(lr, regions[rname]);
43482 addTypedPanels : function(lr, ps){
43483 if(typeof ps == 'string'){
43484 lr.add(new Roo.ContentPanel(ps));
43486 else if(ps instanceof Array){
43487 for(var i =0, len = ps.length; i < len; i++){
43488 this.addTypedPanels(lr, ps[i]);
43491 else if(!ps.events){ // raw config?
43493 delete ps.el; // prevent conflict
43494 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
43496 else { // panel object assumed!
43501 * Adds a xtype elements to the layout.
43505 xtype : 'ContentPanel',
43512 xtype : 'NestedLayoutPanel',
43518 items : [ ... list of content panels or nested layout panels.. ]
43522 * @param {Object} cfg Xtype definition of item to add.
43524 addxtype : function(cfg)
43526 // basically accepts a pannel...
43527 // can accept a layout region..!?!?
43528 // console.log('BorderLayout add ' + cfg.xtype)
43530 if (!cfg.xtype.match(/Panel$/)) {
43534 var region = cfg.region;
43540 xitems = cfg.items;
43547 case 'ContentPanel': // ContentPanel (el, cfg)
43548 case 'ScrollPanel': // ContentPanel (el, cfg)
43549 if(cfg.autoCreate) {
43550 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43552 var el = this.el.createChild();
43553 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
43556 this.add(region, ret);
43560 case 'TreePanel': // our new panel!
43561 cfg.el = this.el.createChild();
43562 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
43563 this.add(region, ret);
43566 case 'NestedLayoutPanel':
43567 // create a new Layout (which is a Border Layout...
43568 var el = this.el.createChild();
43569 var clayout = cfg.layout;
43571 clayout.items = clayout.items || [];
43572 // replace this exitems with the clayout ones..
43573 xitems = clayout.items;
43576 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
43577 cfg.background = false;
43579 var layout = new Roo.BorderLayout(el, clayout);
43581 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
43582 //console.log('adding nested layout panel ' + cfg.toSource());
43583 this.add(region, ret);
43589 // needs grid and region
43591 //var el = this.getRegion(region).el.createChild();
43592 var el = this.el.createChild();
43593 // create the grid first...
43595 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
43597 if (region == 'center' && this.active ) {
43598 cfg.background = false;
43600 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
43602 this.add(region, ret);
43603 if (cfg.background) {
43604 ret.on('activate', function(gp) {
43605 if (!gp.grid.rendered) {
43618 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
43620 // GridPanel (grid, cfg)
43623 this.beginUpdate();
43625 Roo.each(xitems, function(i) {
43635 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
43636 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
43637 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
43638 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
43641 var CP = Roo.ContentPanel;
43643 var layout = Roo.BorderLayout.create({
43647 panels: [new CP("north", "North")]
43656 panels: [new CP("west", {title: "West"})]
43665 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
43674 panels: [new CP("south", {title: "South", closable: true})]
43681 preferredTabWidth: 150,
43683 new CP("center1", {title: "Close Me", closable: true}),
43684 new CP("center2", {title: "Center Panel", closable: false})
43689 layout.getRegion("center").showPanel("center1");
43694 Roo.BorderLayout.create = function(config, targetEl){
43695 var layout = new Roo.BorderLayout(targetEl || document.body, config);
43696 layout.beginUpdate();
43697 var regions = Roo.BorderLayout.RegionFactory.validRegions;
43698 for(var j = 0, jlen = regions.length; j < jlen; j++){
43699 var lr = regions[j];
43700 if(layout.regions[lr] && config[lr].panels){
43701 var r = layout.regions[lr];
43702 var ps = config[lr].panels;
43703 layout.addTypedPanels(r, ps);
43706 layout.endUpdate();
43711 Roo.BorderLayout.RegionFactory = {
43713 validRegions : ["north","south","east","west","center"],
43716 create : function(target, mgr, config){
43717 target = target.toLowerCase();
43718 if(config.lightweight || config.basic){
43719 return new Roo.BasicLayoutRegion(mgr, config, target);
43723 return new Roo.NorthLayoutRegion(mgr, config);
43725 return new Roo.SouthLayoutRegion(mgr, config);
43727 return new Roo.EastLayoutRegion(mgr, config);
43729 return new Roo.WestLayoutRegion(mgr, config);
43731 return new Roo.CenterLayoutRegion(mgr, config);
43733 throw 'Layout region "'+target+'" not supported.';
43737 * Ext JS Library 1.1.1
43738 * Copyright(c) 2006-2007, Ext JS, LLC.
43740 * Originally Released Under LGPL - original licence link has changed is not relivant.
43743 * <script type="text/javascript">
43747 * @class Roo.BasicLayoutRegion
43748 * @extends Roo.util.Observable
43749 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
43750 * and does not have a titlebar, tabs or any other features. All it does is size and position
43751 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
43753 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
43755 this.position = pos;
43758 * @scope Roo.BasicLayoutRegion
43762 * @event beforeremove
43763 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
43764 * @param {Roo.LayoutRegion} this
43765 * @param {Roo.ContentPanel} panel The panel
43766 * @param {Object} e The cancel event object
43768 "beforeremove" : true,
43770 * @event invalidated
43771 * Fires when the layout for this region is changed.
43772 * @param {Roo.LayoutRegion} this
43774 "invalidated" : true,
43776 * @event visibilitychange
43777 * Fires when this region is shown or hidden
43778 * @param {Roo.LayoutRegion} this
43779 * @param {Boolean} visibility true or false
43781 "visibilitychange" : true,
43783 * @event paneladded
43784 * Fires when a panel is added.
43785 * @param {Roo.LayoutRegion} this
43786 * @param {Roo.ContentPanel} panel The panel
43788 "paneladded" : true,
43790 * @event panelremoved
43791 * Fires when a panel is removed.
43792 * @param {Roo.LayoutRegion} this
43793 * @param {Roo.ContentPanel} panel The panel
43795 "panelremoved" : true,
43798 * Fires when this region is collapsed.
43799 * @param {Roo.LayoutRegion} this
43801 "collapsed" : true,
43804 * Fires when this region is expanded.
43805 * @param {Roo.LayoutRegion} this
43810 * Fires when this region is slid into view.
43811 * @param {Roo.LayoutRegion} this
43813 "slideshow" : true,
43816 * Fires when this region slides out of view.
43817 * @param {Roo.LayoutRegion} this
43819 "slidehide" : true,
43821 * @event panelactivated
43822 * Fires when a panel is activated.
43823 * @param {Roo.LayoutRegion} this
43824 * @param {Roo.ContentPanel} panel The activated panel
43826 "panelactivated" : true,
43829 * Fires when the user resizes this region.
43830 * @param {Roo.LayoutRegion} this
43831 * @param {Number} newSize The new size (width for east/west, height for north/south)
43835 /** A collection of panels in this region. @type Roo.util.MixedCollection */
43836 this.panels = new Roo.util.MixedCollection();
43837 this.panels.getKey = this.getPanelId.createDelegate(this);
43839 this.activePanel = null;
43840 // ensure listeners are added...
43842 if (config.listeners || config.events) {
43843 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
43844 listeners : config.listeners || {},
43845 events : config.events || {}
43849 if(skipConfig !== true){
43850 this.applyConfig(config);
43854 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
43855 getPanelId : function(p){
43859 applyConfig : function(config){
43860 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43861 this.config = config;
43866 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
43867 * the width, for horizontal (north, south) the height.
43868 * @param {Number} newSize The new width or height
43870 resizeTo : function(newSize){
43871 var el = this.el ? this.el :
43872 (this.activePanel ? this.activePanel.getEl() : null);
43874 switch(this.position){
43877 el.setWidth(newSize);
43878 this.fireEvent("resized", this, newSize);
43882 el.setHeight(newSize);
43883 this.fireEvent("resized", this, newSize);
43889 getBox : function(){
43890 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
43893 getMargins : function(){
43894 return this.margins;
43897 updateBox : function(box){
43899 var el = this.activePanel.getEl();
43900 el.dom.style.left = box.x + "px";
43901 el.dom.style.top = box.y + "px";
43902 this.activePanel.setSize(box.width, box.height);
43906 * Returns the container element for this region.
43907 * @return {Roo.Element}
43909 getEl : function(){
43910 return this.activePanel;
43914 * Returns true if this region is currently visible.
43915 * @return {Boolean}
43917 isVisible : function(){
43918 return this.activePanel ? true : false;
43921 setActivePanel : function(panel){
43922 panel = this.getPanel(panel);
43923 if(this.activePanel && this.activePanel != panel){
43924 this.activePanel.setActiveState(false);
43925 this.activePanel.getEl().setLeftTop(-10000,-10000);
43927 this.activePanel = panel;
43928 panel.setActiveState(true);
43930 panel.setSize(this.box.width, this.box.height);
43932 this.fireEvent("panelactivated", this, panel);
43933 this.fireEvent("invalidated");
43937 * Show the specified panel.
43938 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
43939 * @return {Roo.ContentPanel} The shown panel or null
43941 showPanel : function(panel){
43942 if(panel = this.getPanel(panel)){
43943 this.setActivePanel(panel);
43949 * Get the active panel for this region.
43950 * @return {Roo.ContentPanel} The active panel or null
43952 getActivePanel : function(){
43953 return this.activePanel;
43957 * Add the passed ContentPanel(s)
43958 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43959 * @return {Roo.ContentPanel} The panel added (if only one was added)
43961 add : function(panel){
43962 if(arguments.length > 1){
43963 for(var i = 0, len = arguments.length; i < len; i++) {
43964 this.add(arguments[i]);
43968 if(this.hasPanel(panel)){
43969 this.showPanel(panel);
43972 var el = panel.getEl();
43973 if(el.dom.parentNode != this.mgr.el.dom){
43974 this.mgr.el.dom.appendChild(el.dom);
43976 if(panel.setRegion){
43977 panel.setRegion(this);
43979 this.panels.add(panel);
43980 el.setStyle("position", "absolute");
43981 if(!panel.background){
43982 this.setActivePanel(panel);
43983 if(this.config.initialSize && this.panels.getCount()==1){
43984 this.resizeTo(this.config.initialSize);
43987 this.fireEvent("paneladded", this, panel);
43992 * Returns true if the panel is in this region.
43993 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43994 * @return {Boolean}
43996 hasPanel : function(panel){
43997 if(typeof panel == "object"){ // must be panel obj
43998 panel = panel.getId();
44000 return this.getPanel(panel) ? true : false;
44004 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44005 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44006 * @param {Boolean} preservePanel Overrides the config preservePanel option
44007 * @return {Roo.ContentPanel} The panel that was removed
44009 remove : function(panel, preservePanel){
44010 panel = this.getPanel(panel);
44015 this.fireEvent("beforeremove", this, panel, e);
44016 if(e.cancel === true){
44019 var panelId = panel.getId();
44020 this.panels.removeKey(panelId);
44025 * Returns the panel specified or null if it's not in this region.
44026 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
44027 * @return {Roo.ContentPanel}
44029 getPanel : function(id){
44030 if(typeof id == "object"){ // must be panel obj
44033 return this.panels.get(id);
44037 * Returns this regions position (north/south/east/west/center).
44040 getPosition: function(){
44041 return this.position;
44045 * Ext JS Library 1.1.1
44046 * Copyright(c) 2006-2007, Ext JS, LLC.
44048 * Originally Released Under LGPL - original licence link has changed is not relivant.
44051 * <script type="text/javascript">
44055 * @class Roo.LayoutRegion
44056 * @extends Roo.BasicLayoutRegion
44057 * This class represents a region in a layout manager.
44058 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
44059 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
44060 * @cfg {Boolean} floatable False to disable floating (defaults to true)
44061 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
44062 * @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})
44063 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
44064 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
44065 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
44066 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
44067 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
44068 * @cfg {String} title The title for the region (overrides panel titles)
44069 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
44070 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
44071 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
44072 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
44073 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
44074 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
44075 * the space available, similar to FireFox 1.5 tabs (defaults to false)
44076 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
44077 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
44078 * @cfg {Boolean} showPin True to show a pin button
44079 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
44080 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
44081 * @cfg {Boolean} disableTabTips True to disable tab tooltips
44082 * @cfg {Number} width For East/West panels
44083 * @cfg {Number} height For North/South panels
44084 * @cfg {Boolean} split To show the splitter
44086 Roo.LayoutRegion = function(mgr, config, pos){
44087 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
44088 var dh = Roo.DomHelper;
44089 /** This region's container element
44090 * @type Roo.Element */
44091 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
44092 /** This region's title element
44093 * @type Roo.Element */
44095 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
44096 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
44097 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
44099 this.titleEl.enableDisplayMode();
44100 /** This region's title text element
44101 * @type HTMLElement */
44102 this.titleTextEl = this.titleEl.dom.firstChild;
44103 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
44104 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
44105 this.closeBtn.enableDisplayMode();
44106 this.closeBtn.on("click", this.closeClicked, this);
44107 this.closeBtn.hide();
44109 this.createBody(config);
44110 this.visible = true;
44111 this.collapsed = false;
44113 if(config.hideWhenEmpty){
44115 this.on("paneladded", this.validateVisibility, this);
44116 this.on("panelremoved", this.validateVisibility, this);
44118 this.applyConfig(config);
44121 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
44123 createBody : function(){
44124 /** This region's body element
44125 * @type Roo.Element */
44126 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
44129 applyConfig : function(c){
44130 if(c.collapsible && this.position != "center" && !this.collapsedEl){
44131 var dh = Roo.DomHelper;
44132 if(c.titlebar !== false){
44133 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
44134 this.collapseBtn.on("click", this.collapse, this);
44135 this.collapseBtn.enableDisplayMode();
44137 if(c.showPin === true || this.showPin){
44138 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
44139 this.stickBtn.enableDisplayMode();
44140 this.stickBtn.on("click", this.expand, this);
44141 this.stickBtn.hide();
44144 /** This region's collapsed element
44145 * @type Roo.Element */
44146 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
44147 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
44149 if(c.floatable !== false){
44150 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
44151 this.collapsedEl.on("click", this.collapseClick, this);
44154 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
44155 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
44156 id: "message", unselectable: "on", style:{"float":"left"}});
44157 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
44159 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
44160 this.expandBtn.on("click", this.expand, this);
44162 if(this.collapseBtn){
44163 this.collapseBtn.setVisible(c.collapsible == true);
44165 this.cmargins = c.cmargins || this.cmargins ||
44166 (this.position == "west" || this.position == "east" ?
44167 {top: 0, left: 2, right:2, bottom: 0} :
44168 {top: 2, left: 0, right:0, bottom: 2});
44169 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
44170 this.bottomTabs = c.tabPosition != "top";
44171 this.autoScroll = c.autoScroll || false;
44172 if(this.autoScroll){
44173 this.bodyEl.setStyle("overflow", "auto");
44175 this.bodyEl.setStyle("overflow", "hidden");
44177 //if(c.titlebar !== false){
44178 if((!c.titlebar && !c.title) || c.titlebar === false){
44179 this.titleEl.hide();
44181 this.titleEl.show();
44183 this.titleTextEl.innerHTML = c.title;
44187 this.duration = c.duration || .30;
44188 this.slideDuration = c.slideDuration || .45;
44191 this.collapse(true);
44198 * Returns true if this region is currently visible.
44199 * @return {Boolean}
44201 isVisible : function(){
44202 return this.visible;
44206 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
44207 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
44209 setCollapsedTitle : function(title){
44210 title = title || " ";
44211 if(this.collapsedTitleTextEl){
44212 this.collapsedTitleTextEl.innerHTML = title;
44216 getBox : function(){
44218 if(!this.collapsed){
44219 b = this.el.getBox(false, true);
44221 b = this.collapsedEl.getBox(false, true);
44226 getMargins : function(){
44227 return this.collapsed ? this.cmargins : this.margins;
44230 highlight : function(){
44231 this.el.addClass("x-layout-panel-dragover");
44234 unhighlight : function(){
44235 this.el.removeClass("x-layout-panel-dragover");
44238 updateBox : function(box){
44240 if(!this.collapsed){
44241 this.el.dom.style.left = box.x + "px";
44242 this.el.dom.style.top = box.y + "px";
44243 this.updateBody(box.width, box.height);
44245 this.collapsedEl.dom.style.left = box.x + "px";
44246 this.collapsedEl.dom.style.top = box.y + "px";
44247 this.collapsedEl.setSize(box.width, box.height);
44250 this.tabs.autoSizeTabs();
44254 updateBody : function(w, h){
44256 this.el.setWidth(w);
44257 w -= this.el.getBorderWidth("rl");
44258 if(this.config.adjustments){
44259 w += this.config.adjustments[0];
44263 this.el.setHeight(h);
44264 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
44265 h -= this.el.getBorderWidth("tb");
44266 if(this.config.adjustments){
44267 h += this.config.adjustments[1];
44269 this.bodyEl.setHeight(h);
44271 h = this.tabs.syncHeight(h);
44274 if(this.panelSize){
44275 w = w !== null ? w : this.panelSize.width;
44276 h = h !== null ? h : this.panelSize.height;
44278 if(this.activePanel){
44279 var el = this.activePanel.getEl();
44280 w = w !== null ? w : el.getWidth();
44281 h = h !== null ? h : el.getHeight();
44282 this.panelSize = {width: w, height: h};
44283 this.activePanel.setSize(w, h);
44285 if(Roo.isIE && this.tabs){
44286 this.tabs.el.repaint();
44291 * Returns the container element for this region.
44292 * @return {Roo.Element}
44294 getEl : function(){
44299 * Hides this region.
44302 if(!this.collapsed){
44303 this.el.dom.style.left = "-2000px";
44306 this.collapsedEl.dom.style.left = "-2000px";
44307 this.collapsedEl.hide();
44309 this.visible = false;
44310 this.fireEvent("visibilitychange", this, false);
44314 * Shows this region if it was previously hidden.
44317 if(!this.collapsed){
44320 this.collapsedEl.show();
44322 this.visible = true;
44323 this.fireEvent("visibilitychange", this, true);
44326 closeClicked : function(){
44327 if(this.activePanel){
44328 this.remove(this.activePanel);
44332 collapseClick : function(e){
44334 e.stopPropagation();
44337 e.stopPropagation();
44343 * Collapses this region.
44344 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
44346 collapse : function(skipAnim){
44347 if(this.collapsed) return;
44348 this.collapsed = true;
44350 this.split.el.hide();
44352 if(this.config.animate && skipAnim !== true){
44353 this.fireEvent("invalidated", this);
44354 this.animateCollapse();
44356 this.el.setLocation(-20000,-20000);
44358 this.collapsedEl.show();
44359 this.fireEvent("collapsed", this);
44360 this.fireEvent("invalidated", this);
44364 animateCollapse : function(){
44369 * Expands this region if it was previously collapsed.
44370 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
44371 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
44373 expand : function(e, skipAnim){
44374 if(e) e.stopPropagation();
44375 if(!this.collapsed || this.el.hasActiveFx()) return;
44377 this.afterSlideIn();
44380 this.collapsed = false;
44381 if(this.config.animate && skipAnim !== true){
44382 this.animateExpand();
44386 this.split.el.show();
44388 this.collapsedEl.setLocation(-2000,-2000);
44389 this.collapsedEl.hide();
44390 this.fireEvent("invalidated", this);
44391 this.fireEvent("expanded", this);
44395 animateExpand : function(){
44399 initTabs : function(){
44400 this.bodyEl.setStyle("overflow", "hidden");
44401 var ts = new Roo.TabPanel(this.bodyEl.dom, {
44402 tabPosition: this.bottomTabs ? 'bottom' : 'top',
44403 disableTooltips: this.config.disableTabTips
44405 if(this.config.hideTabs){
44406 ts.stripWrap.setDisplayed(false);
44409 ts.resizeTabs = this.config.resizeTabs === true;
44410 ts.minTabWidth = this.config.minTabWidth || 40;
44411 ts.maxTabWidth = this.config.maxTabWidth || 250;
44412 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
44413 ts.monitorResize = false;
44414 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44415 ts.bodyEl.addClass('x-layout-tabs-body');
44416 this.panels.each(this.initPanelAsTab, this);
44419 initPanelAsTab : function(panel){
44420 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
44421 this.config.closeOnTab && panel.isClosable());
44422 if(panel.tabTip !== undefined){
44423 ti.setTooltip(panel.tabTip);
44425 ti.on("activate", function(){
44426 this.setActivePanel(panel);
44428 if(this.config.closeOnTab){
44429 ti.on("beforeclose", function(t, e){
44431 this.remove(panel);
44437 updatePanelTitle : function(panel, title){
44438 if(this.activePanel == panel){
44439 this.updateTitle(title);
44442 var ti = this.tabs.getTab(panel.getEl().id);
44444 if(panel.tabTip !== undefined){
44445 ti.setTooltip(panel.tabTip);
44450 updateTitle : function(title){
44451 if(this.titleTextEl && !this.config.title){
44452 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
44456 setActivePanel : function(panel){
44457 panel = this.getPanel(panel);
44458 if(this.activePanel && this.activePanel != panel){
44459 this.activePanel.setActiveState(false);
44461 this.activePanel = panel;
44462 panel.setActiveState(true);
44463 if(this.panelSize){
44464 panel.setSize(this.panelSize.width, this.panelSize.height);
44467 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
44469 this.updateTitle(panel.getTitle());
44471 this.fireEvent("invalidated", this);
44473 this.fireEvent("panelactivated", this, panel);
44477 * Shows the specified panel.
44478 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
44479 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
44481 showPanel : function(panel){
44482 if(panel = this.getPanel(panel)){
44484 var tab = this.tabs.getTab(panel.getEl().id);
44485 if(tab.isHidden()){
44486 this.tabs.unhideTab(tab.id);
44490 this.setActivePanel(panel);
44497 * Get the active panel for this region.
44498 * @return {Roo.ContentPanel} The active panel or null
44500 getActivePanel : function(){
44501 return this.activePanel;
44504 validateVisibility : function(){
44505 if(this.panels.getCount() < 1){
44506 this.updateTitle(" ");
44507 this.closeBtn.hide();
44510 if(!this.isVisible()){
44517 * Adds the passed ContentPanel(s) to this region.
44518 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
44519 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
44521 add : function(panel){
44522 if(arguments.length > 1){
44523 for(var i = 0, len = arguments.length; i < len; i++) {
44524 this.add(arguments[i]);
44528 if(this.hasPanel(panel)){
44529 this.showPanel(panel);
44532 panel.setRegion(this);
44533 this.panels.add(panel);
44534 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
44535 this.bodyEl.dom.appendChild(panel.getEl().dom);
44536 if(panel.background !== true){
44537 this.setActivePanel(panel);
44539 this.fireEvent("paneladded", this, panel);
44545 this.initPanelAsTab(panel);
44547 if(panel.background !== true){
44548 this.tabs.activate(panel.getEl().id);
44550 this.fireEvent("paneladded", this, panel);
44555 * Hides the tab for the specified panel.
44556 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44558 hidePanel : function(panel){
44559 if(this.tabs && (panel = this.getPanel(panel))){
44560 this.tabs.hideTab(panel.getEl().id);
44565 * Unhides the tab for a previously hidden panel.
44566 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44568 unhidePanel : function(panel){
44569 if(this.tabs && (panel = this.getPanel(panel))){
44570 this.tabs.unhideTab(panel.getEl().id);
44574 clearPanels : function(){
44575 while(this.panels.getCount() > 0){
44576 this.remove(this.panels.first());
44581 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
44582 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
44583 * @param {Boolean} preservePanel Overrides the config preservePanel option
44584 * @return {Roo.ContentPanel} The panel that was removed
44586 remove : function(panel, preservePanel){
44587 panel = this.getPanel(panel);
44592 this.fireEvent("beforeremove", this, panel, e);
44593 if(e.cancel === true){
44596 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
44597 var panelId = panel.getId();
44598 this.panels.removeKey(panelId);
44600 document.body.appendChild(panel.getEl().dom);
44603 this.tabs.removeTab(panel.getEl().id);
44604 }else if (!preservePanel){
44605 this.bodyEl.dom.removeChild(panel.getEl().dom);
44607 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
44608 var p = this.panels.first();
44609 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
44610 tempEl.appendChild(p.getEl().dom);
44611 this.bodyEl.update("");
44612 this.bodyEl.dom.appendChild(p.getEl().dom);
44614 this.updateTitle(p.getTitle());
44616 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
44617 this.setActivePanel(p);
44619 panel.setRegion(null);
44620 if(this.activePanel == panel){
44621 this.activePanel = null;
44623 if(this.config.autoDestroy !== false && preservePanel !== true){
44624 try{panel.destroy();}catch(e){}
44626 this.fireEvent("panelremoved", this, panel);
44631 * Returns the TabPanel component used by this region
44632 * @return {Roo.TabPanel}
44634 getTabs : function(){
44638 createTool : function(parentEl, className){
44639 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
44640 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
44641 btn.addClassOnOver("x-layout-tools-button-over");
44646 * Ext JS Library 1.1.1
44647 * Copyright(c) 2006-2007, Ext JS, LLC.
44649 * Originally Released Under LGPL - original licence link has changed is not relivant.
44652 * <script type="text/javascript">
44658 * @class Roo.SplitLayoutRegion
44659 * @extends Roo.LayoutRegion
44660 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
44662 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
44663 this.cursor = cursor;
44664 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
44667 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
44668 splitTip : "Drag to resize.",
44669 collapsibleSplitTip : "Drag to resize. Double click to hide.",
44670 useSplitTips : false,
44672 applyConfig : function(config){
44673 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
44676 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
44677 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
44678 /** The SplitBar for this region
44679 * @type Roo.SplitBar */
44680 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
44681 this.split.on("moved", this.onSplitMove, this);
44682 this.split.useShim = config.useShim === true;
44683 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
44684 if(this.useSplitTips){
44685 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
44687 if(config.collapsible){
44688 this.split.el.on("dblclick", this.collapse, this);
44691 if(typeof config.minSize != "undefined"){
44692 this.split.minSize = config.minSize;
44694 if(typeof config.maxSize != "undefined"){
44695 this.split.maxSize = config.maxSize;
44697 if(config.hideWhenEmpty || config.hidden || config.collapsed){
44698 this.hideSplitter();
44703 getHMaxSize : function(){
44704 var cmax = this.config.maxSize || 10000;
44705 var center = this.mgr.getRegion("center");
44706 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
44709 getVMaxSize : function(){
44710 var cmax = this.config.maxSize || 10000;
44711 var center = this.mgr.getRegion("center");
44712 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
44715 onSplitMove : function(split, newSize){
44716 this.fireEvent("resized", this, newSize);
44720 * Returns the {@link Roo.SplitBar} for this region.
44721 * @return {Roo.SplitBar}
44723 getSplitBar : function(){
44728 this.hideSplitter();
44729 Roo.SplitLayoutRegion.superclass.hide.call(this);
44732 hideSplitter : function(){
44734 this.split.el.setLocation(-2000,-2000);
44735 this.split.el.hide();
44741 this.split.el.show();
44743 Roo.SplitLayoutRegion.superclass.show.call(this);
44746 beforeSlide: function(){
44747 if(Roo.isGecko){// firefox overflow auto bug workaround
44748 this.bodyEl.clip();
44749 if(this.tabs) this.tabs.bodyEl.clip();
44750 if(this.activePanel){
44751 this.activePanel.getEl().clip();
44753 if(this.activePanel.beforeSlide){
44754 this.activePanel.beforeSlide();
44760 afterSlide : function(){
44761 if(Roo.isGecko){// firefox overflow auto bug workaround
44762 this.bodyEl.unclip();
44763 if(this.tabs) this.tabs.bodyEl.unclip();
44764 if(this.activePanel){
44765 this.activePanel.getEl().unclip();
44766 if(this.activePanel.afterSlide){
44767 this.activePanel.afterSlide();
44773 initAutoHide : function(){
44774 if(this.autoHide !== false){
44775 if(!this.autoHideHd){
44776 var st = new Roo.util.DelayedTask(this.slideIn, this);
44777 this.autoHideHd = {
44778 "mouseout": function(e){
44779 if(!e.within(this.el, true)){
44783 "mouseover" : function(e){
44789 this.el.on(this.autoHideHd);
44793 clearAutoHide : function(){
44794 if(this.autoHide !== false){
44795 this.el.un("mouseout", this.autoHideHd.mouseout);
44796 this.el.un("mouseover", this.autoHideHd.mouseover);
44800 clearMonitor : function(){
44801 Roo.get(document).un("click", this.slideInIf, this);
44804 // these names are backwards but not changed for compat
44805 slideOut : function(){
44806 if(this.isSlid || this.el.hasActiveFx()){
44809 this.isSlid = true;
44810 if(this.collapseBtn){
44811 this.collapseBtn.hide();
44813 this.closeBtnState = this.closeBtn.getStyle('display');
44814 this.closeBtn.hide();
44816 this.stickBtn.show();
44819 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
44820 this.beforeSlide();
44821 this.el.setStyle("z-index", 10001);
44822 this.el.slideIn(this.getSlideAnchor(), {
44823 callback: function(){
44825 this.initAutoHide();
44826 Roo.get(document).on("click", this.slideInIf, this);
44827 this.fireEvent("slideshow", this);
44834 afterSlideIn : function(){
44835 this.clearAutoHide();
44836 this.isSlid = false;
44837 this.clearMonitor();
44838 this.el.setStyle("z-index", "");
44839 if(this.collapseBtn){
44840 this.collapseBtn.show();
44842 this.closeBtn.setStyle('display', this.closeBtnState);
44844 this.stickBtn.hide();
44846 this.fireEvent("slidehide", this);
44849 slideIn : function(cb){
44850 if(!this.isSlid || this.el.hasActiveFx()){
44854 this.isSlid = false;
44855 this.beforeSlide();
44856 this.el.slideOut(this.getSlideAnchor(), {
44857 callback: function(){
44858 this.el.setLeftTop(-10000, -10000);
44860 this.afterSlideIn();
44868 slideInIf : function(e){
44869 if(!e.within(this.el)){
44874 animateCollapse : function(){
44875 this.beforeSlide();
44876 this.el.setStyle("z-index", 20000);
44877 var anchor = this.getSlideAnchor();
44878 this.el.slideOut(anchor, {
44879 callback : function(){
44880 this.el.setStyle("z-index", "");
44881 this.collapsedEl.slideIn(anchor, {duration:.3});
44883 this.el.setLocation(-10000,-10000);
44885 this.fireEvent("collapsed", this);
44892 animateExpand : function(){
44893 this.beforeSlide();
44894 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
44895 this.el.setStyle("z-index", 20000);
44896 this.collapsedEl.hide({
44899 this.el.slideIn(this.getSlideAnchor(), {
44900 callback : function(){
44901 this.el.setStyle("z-index", "");
44904 this.split.el.show();
44906 this.fireEvent("invalidated", this);
44907 this.fireEvent("expanded", this);
44935 getAnchor : function(){
44936 return this.anchors[this.position];
44939 getCollapseAnchor : function(){
44940 return this.canchors[this.position];
44943 getSlideAnchor : function(){
44944 return this.sanchors[this.position];
44947 getAlignAdj : function(){
44948 var cm = this.cmargins;
44949 switch(this.position){
44965 getExpandAdj : function(){
44966 var c = this.collapsedEl, cm = this.cmargins;
44967 switch(this.position){
44969 return [-(cm.right+c.getWidth()+cm.left), 0];
44972 return [cm.right+c.getWidth()+cm.left, 0];
44975 return [0, -(cm.top+cm.bottom+c.getHeight())];
44978 return [0, cm.top+cm.bottom+c.getHeight()];
44984 * Ext JS Library 1.1.1
44985 * Copyright(c) 2006-2007, Ext JS, LLC.
44987 * Originally Released Under LGPL - original licence link has changed is not relivant.
44990 * <script type="text/javascript">
44993 * These classes are private internal classes
44995 Roo.CenterLayoutRegion = function(mgr, config){
44996 Roo.LayoutRegion.call(this, mgr, config, "center");
44997 this.visible = true;
44998 this.minWidth = config.minWidth || 20;
44999 this.minHeight = config.minHeight || 20;
45002 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
45004 // center panel can't be hidden
45008 // center panel can't be hidden
45011 getMinWidth: function(){
45012 return this.minWidth;
45015 getMinHeight: function(){
45016 return this.minHeight;
45021 Roo.NorthLayoutRegion = function(mgr, config){
45022 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
45024 this.split.placement = Roo.SplitBar.TOP;
45025 this.split.orientation = Roo.SplitBar.VERTICAL;
45026 this.split.el.addClass("x-layout-split-v");
45028 var size = config.initialSize || config.height;
45029 if(typeof size != "undefined"){
45030 this.el.setHeight(size);
45033 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
45034 orientation: Roo.SplitBar.VERTICAL,
45035 getBox : function(){
45036 if(this.collapsed){
45037 return this.collapsedEl.getBox();
45039 var box = this.el.getBox();
45041 box.height += this.split.el.getHeight();
45046 updateBox : function(box){
45047 if(this.split && !this.collapsed){
45048 box.height -= this.split.el.getHeight();
45049 this.split.el.setLeft(box.x);
45050 this.split.el.setTop(box.y+box.height);
45051 this.split.el.setWidth(box.width);
45053 if(this.collapsed){
45054 this.updateBody(box.width, null);
45056 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45060 Roo.SouthLayoutRegion = function(mgr, config){
45061 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
45063 this.split.placement = Roo.SplitBar.BOTTOM;
45064 this.split.orientation = Roo.SplitBar.VERTICAL;
45065 this.split.el.addClass("x-layout-split-v");
45067 var size = config.initialSize || config.height;
45068 if(typeof size != "undefined"){
45069 this.el.setHeight(size);
45072 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
45073 orientation: Roo.SplitBar.VERTICAL,
45074 getBox : function(){
45075 if(this.collapsed){
45076 return this.collapsedEl.getBox();
45078 var box = this.el.getBox();
45080 var sh = this.split.el.getHeight();
45087 updateBox : function(box){
45088 if(this.split && !this.collapsed){
45089 var sh = this.split.el.getHeight();
45092 this.split.el.setLeft(box.x);
45093 this.split.el.setTop(box.y-sh);
45094 this.split.el.setWidth(box.width);
45096 if(this.collapsed){
45097 this.updateBody(box.width, null);
45099 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45103 Roo.EastLayoutRegion = function(mgr, config){
45104 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
45106 this.split.placement = Roo.SplitBar.RIGHT;
45107 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45108 this.split.el.addClass("x-layout-split-h");
45110 var size = config.initialSize || config.width;
45111 if(typeof size != "undefined"){
45112 this.el.setWidth(size);
45115 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
45116 orientation: Roo.SplitBar.HORIZONTAL,
45117 getBox : function(){
45118 if(this.collapsed){
45119 return this.collapsedEl.getBox();
45121 var box = this.el.getBox();
45123 var sw = this.split.el.getWidth();
45130 updateBox : function(box){
45131 if(this.split && !this.collapsed){
45132 var sw = this.split.el.getWidth();
45134 this.split.el.setLeft(box.x);
45135 this.split.el.setTop(box.y);
45136 this.split.el.setHeight(box.height);
45139 if(this.collapsed){
45140 this.updateBody(null, box.height);
45142 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45146 Roo.WestLayoutRegion = function(mgr, config){
45147 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
45149 this.split.placement = Roo.SplitBar.LEFT;
45150 this.split.orientation = Roo.SplitBar.HORIZONTAL;
45151 this.split.el.addClass("x-layout-split-h");
45153 var size = config.initialSize || config.width;
45154 if(typeof size != "undefined"){
45155 this.el.setWidth(size);
45158 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
45159 orientation: Roo.SplitBar.HORIZONTAL,
45160 getBox : function(){
45161 if(this.collapsed){
45162 return this.collapsedEl.getBox();
45164 var box = this.el.getBox();
45166 box.width += this.split.el.getWidth();
45171 updateBox : function(box){
45172 if(this.split && !this.collapsed){
45173 var sw = this.split.el.getWidth();
45175 this.split.el.setLeft(box.x+box.width);
45176 this.split.el.setTop(box.y);
45177 this.split.el.setHeight(box.height);
45179 if(this.collapsed){
45180 this.updateBody(null, box.height);
45182 Roo.LayoutRegion.prototype.updateBox.call(this, box);
45187 * Ext JS Library 1.1.1
45188 * Copyright(c) 2006-2007, Ext JS, LLC.
45190 * Originally Released Under LGPL - original licence link has changed is not relivant.
45193 * <script type="text/javascript">
45198 * Private internal class for reading and applying state
45200 Roo.LayoutStateManager = function(layout){
45201 // default empty state
45210 Roo.LayoutStateManager.prototype = {
45211 init : function(layout, provider){
45212 this.provider = provider;
45213 var state = provider.get(layout.id+"-layout-state");
45215 var wasUpdating = layout.isUpdating();
45217 layout.beginUpdate();
45219 for(var key in state){
45220 if(typeof state[key] != "function"){
45221 var rstate = state[key];
45222 var r = layout.getRegion(key);
45225 r.resizeTo(rstate.size);
45227 if(rstate.collapsed == true){
45230 r.expand(null, true);
45236 layout.endUpdate();
45238 this.state = state;
45240 this.layout = layout;
45241 layout.on("regionresized", this.onRegionResized, this);
45242 layout.on("regioncollapsed", this.onRegionCollapsed, this);
45243 layout.on("regionexpanded", this.onRegionExpanded, this);
45246 storeState : function(){
45247 this.provider.set(this.layout.id+"-layout-state", this.state);
45250 onRegionResized : function(region, newSize){
45251 this.state[region.getPosition()].size = newSize;
45255 onRegionCollapsed : function(region){
45256 this.state[region.getPosition()].collapsed = true;
45260 onRegionExpanded : function(region){
45261 this.state[region.getPosition()].collapsed = false;
45266 * Ext JS Library 1.1.1
45267 * Copyright(c) 2006-2007, Ext JS, LLC.
45269 * Originally Released Under LGPL - original licence link has changed is not relivant.
45272 * <script type="text/javascript">
45275 * @class Roo.ContentPanel
45276 * @extends Roo.util.Observable
45277 * A basic ContentPanel element.
45278 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
45279 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
45280 * @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
45281 * @cfg {Boolean} closable True if the panel can be closed/removed
45282 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
45283 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
45284 * @cfg {Toolbar} toolbar A toolbar for this panel
45285 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
45286 * @cfg {String} title The title for this panel
45287 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
45288 * @cfg {String} url Calls {@link #setUrl} with this value
45289 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
45290 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
45291 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
45293 * Create a new ContentPanel.
45294 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
45295 * @param {String/Object} config A string to set only the title or a config object
45296 * @param {String} content (optional) Set the HTML content for this panel
45297 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
45299 Roo.ContentPanel = function(el, config, content){
45303 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
45307 if (config && config.parentLayout) {
45308 el = config.parentLayout.el.createChild();
45311 if(el.autoCreate){ // xtype is available if this is called from factory
45315 this.el = Roo.get(el);
45316 if(!this.el && config && config.autoCreate){
45317 if(typeof config.autoCreate == "object"){
45318 if(!config.autoCreate.id){
45319 config.autoCreate.id = config.id||el;
45321 this.el = Roo.DomHelper.append(document.body,
45322 config.autoCreate, true);
45324 this.el = Roo.DomHelper.append(document.body,
45325 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
45328 this.closable = false;
45329 this.loaded = false;
45330 this.active = false;
45331 if(typeof config == "string"){
45332 this.title = config;
45334 Roo.apply(this, config);
45337 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
45338 this.wrapEl = this.el.wrap();
45339 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
45346 this.resizeEl = Roo.get(this.resizeEl, true);
45348 this.resizeEl = this.el;
45353 * Fires when this panel is activated.
45354 * @param {Roo.ContentPanel} this
45358 * @event deactivate
45359 * Fires when this panel is activated.
45360 * @param {Roo.ContentPanel} this
45362 "deactivate" : true,
45366 * Fires when this panel is resized if fitToFrame is true.
45367 * @param {Roo.ContentPanel} this
45368 * @param {Number} width The width after any component adjustments
45369 * @param {Number} height The height after any component adjustments
45373 if(this.autoScroll){
45374 this.resizeEl.setStyle("overflow", "auto");
45376 // fix randome scrolling
45377 this.el.on('scroll', function() {
45378 this.scrollTo('top',0);
45381 content = content || this.content;
45383 this.setContent(content);
45385 if(config && config.url){
45386 this.setUrl(this.url, this.params, this.loadOnce);
45391 Roo.ContentPanel.superclass.constructor.call(this);
45394 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
45396 setRegion : function(region){
45397 this.region = region;
45399 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
45401 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
45406 * Returns the toolbar for this Panel if one was configured.
45407 * @return {Roo.Toolbar}
45409 getToolbar : function(){
45410 return this.toolbar;
45413 setActiveState : function(active){
45414 this.active = active;
45416 this.fireEvent("deactivate", this);
45418 this.fireEvent("activate", this);
45422 * Updates this panel's element
45423 * @param {String} content The new content
45424 * @param {Boolean} loadScripts (optional) true to look for and process scripts
45426 setContent : function(content, loadScripts){
45427 this.el.update(content, loadScripts);
45430 ignoreResize : function(w, h){
45431 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
45434 this.lastSize = {width: w, height: h};
45439 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
45440 * @return {Roo.UpdateManager} The UpdateManager
45442 getUpdateManager : function(){
45443 return this.el.getUpdateManager();
45446 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
45447 * @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:
45450 url: "your-url.php",
45451 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
45452 callback: yourFunction,
45453 scope: yourObject, //(optional scope)
45456 text: "Loading...",
45461 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
45462 * 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.
45463 * @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}
45464 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
45465 * @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.
45466 * @return {Roo.ContentPanel} this
45469 var um = this.el.getUpdateManager();
45470 um.update.apply(um, arguments);
45476 * 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.
45477 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
45478 * @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)
45479 * @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)
45480 * @return {Roo.UpdateManager} The UpdateManager
45482 setUrl : function(url, params, loadOnce){
45483 if(this.refreshDelegate){
45484 this.removeListener("activate", this.refreshDelegate);
45486 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
45487 this.on("activate", this.refreshDelegate);
45488 return this.el.getUpdateManager();
45491 _handleRefresh : function(url, params, loadOnce){
45492 if(!loadOnce || !this.loaded){
45493 var updater = this.el.getUpdateManager();
45494 updater.update(url, params, this._setLoaded.createDelegate(this));
45498 _setLoaded : function(){
45499 this.loaded = true;
45503 * Returns this panel's id
45506 getId : function(){
45511 * Returns this panel's element - used by regiosn to add.
45512 * @return {Roo.Element}
45514 getEl : function(){
45515 return this.wrapEl || this.el;
45518 adjustForComponents : function(width, height){
45519 if(this.resizeEl != this.el){
45520 width -= this.el.getFrameWidth('lr');
45521 height -= this.el.getFrameWidth('tb');
45524 var te = this.toolbar.getEl();
45525 height -= te.getHeight();
45526 te.setWidth(width);
45528 if(this.adjustments){
45529 width += this.adjustments[0];
45530 height += this.adjustments[1];
45532 return {"width": width, "height": height};
45535 setSize : function(width, height){
45536 if(this.fitToFrame && !this.ignoreResize(width, height)){
45537 if(this.fitContainer && this.resizeEl != this.el){
45538 this.el.setSize(width, height);
45540 var size = this.adjustForComponents(width, height);
45541 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
45542 this.fireEvent('resize', this, size.width, size.height);
45547 * Returns this panel's title
45550 getTitle : function(){
45555 * Set this panel's title
45556 * @param {String} title
45558 setTitle : function(title){
45559 this.title = title;
45561 this.region.updatePanelTitle(this, title);
45566 * Returns true is this panel was configured to be closable
45567 * @return {Boolean}
45569 isClosable : function(){
45570 return this.closable;
45573 beforeSlide : function(){
45575 this.resizeEl.clip();
45578 afterSlide : function(){
45580 this.resizeEl.unclip();
45584 * Force a content refresh from the URL specified in the {@link #setUrl} method.
45585 * Will fail silently if the {@link #setUrl} method has not been called.
45586 * This does not activate the panel, just updates its content.
45588 refresh : function(){
45589 if(this.refreshDelegate){
45590 this.loaded = false;
45591 this.refreshDelegate();
45596 * Destroys this panel
45598 destroy : function(){
45599 this.el.removeAllListeners();
45600 var tempEl = document.createElement("span");
45601 tempEl.appendChild(this.el.dom);
45602 tempEl.innerHTML = "";
45608 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
45618 * @param {Object} cfg Xtype definition of item to add.
45621 addxtype : function(cfg) {
45623 if (cfg.xtype.match(/^Form$/)) {
45624 var el = this.el.createChild();
45626 this.form = new Roo.form.Form(cfg);
45629 if ( this.form.allItems.length) this.form.render(el.dom);
45632 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
45634 cfg.el = this.el.appendChild(document.createElement("div"));
45636 var ret = new Roo[cfg.xtype](cfg);
45637 ret.render(false, ''); // render blank..
45647 * @class Roo.GridPanel
45648 * @extends Roo.ContentPanel
45650 * Create a new GridPanel.
45651 * @param {Roo.grid.Grid} grid The grid for this panel
45652 * @param {String/Object} config A string to set only the panel's title, or a config object
45654 Roo.GridPanel = function(grid, config){
45657 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
45658 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
45660 this.wrapper.dom.appendChild(grid.getGridEl().dom);
45662 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
45665 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
45667 // xtype created footer. - not sure if will work as we normally have to render first..
45668 if (this.footer && !this.footer.el && this.footer.xtype) {
45670 this.footer.container = this.grid.getView().getFooterPanel(true);
45671 this.footer.dataSource = this.grid.dataSource;
45672 this.footer = Roo.factory(this.footer, Roo);
45676 grid.monitorWindowResize = false; // turn off autosizing
45677 grid.autoHeight = false;
45678 grid.autoWidth = false;
45680 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
45683 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
45684 getId : function(){
45685 return this.grid.id;
45689 * Returns the grid for this panel
45690 * @return {Roo.grid.Grid}
45692 getGrid : function(){
45696 setSize : function(width, height){
45697 if(!this.ignoreResize(width, height)){
45698 var grid = this.grid;
45699 var size = this.adjustForComponents(width, height);
45700 grid.getGridEl().setSize(size.width, size.height);
45705 beforeSlide : function(){
45706 this.grid.getView().scroller.clip();
45709 afterSlide : function(){
45710 this.grid.getView().scroller.unclip();
45713 destroy : function(){
45714 this.grid.destroy();
45716 Roo.GridPanel.superclass.destroy.call(this);
45722 * @class Roo.NestedLayoutPanel
45723 * @extends Roo.ContentPanel
45725 * Create a new NestedLayoutPanel.
45728 * @param {Roo.BorderLayout} layout The layout for this panel
45729 * @param {String/Object} config A string to set only the title or a config object
45731 Roo.NestedLayoutPanel = function(layout, config)
45733 // construct with only one argument..
45734 /* FIXME - implement nicer consturctors
45735 if (layout.layout) {
45737 layout = config.layout;
45738 delete config.layout;
45740 if (layout.xtype && !layout.getEl) {
45741 // then layout needs constructing..
45742 layout = Roo.factory(layout, Roo);
45747 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
45749 layout.monitorWindowResize = false; // turn off autosizing
45750 this.layout = layout;
45751 this.layout.getEl().addClass("x-layout-nested-layout");
45758 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
45760 setSize : function(width, height){
45761 if(!this.ignoreResize(width, height)){
45762 var size = this.adjustForComponents(width, height);
45763 var el = this.layout.getEl();
45764 el.setSize(size.width, size.height);
45765 var touch = el.dom.offsetWidth;
45766 this.layout.layout();
45767 // ie requires a double layout on the first pass
45768 if(Roo.isIE && !this.initialized){
45769 this.initialized = true;
45770 this.layout.layout();
45775 // activate all subpanels if not currently active..
45777 setActiveState : function(active){
45778 this.active = active;
45780 this.fireEvent("deactivate", this);
45784 this.fireEvent("activate", this);
45785 // not sure if this should happen before or after..
45786 if (!this.layout) {
45787 return; // should not happen..
45790 for (var r in this.layout.regions) {
45791 reg = this.layout.getRegion(r);
45792 if (reg.getActivePanel()) {
45793 //reg.showPanel(reg.getActivePanel()); // force it to activate..
45794 reg.setActivePanel(reg.getActivePanel());
45797 if (!reg.panels.length) {
45800 reg.showPanel(reg.getPanel(0));
45809 * Returns the nested BorderLayout for this panel
45810 * @return {Roo.BorderLayout}
45812 getLayout : function(){
45813 return this.layout;
45817 * Adds a xtype elements to the layout of the nested panel
45821 xtype : 'ContentPanel',
45828 xtype : 'NestedLayoutPanel',
45834 items : [ ... list of content panels or nested layout panels.. ]
45838 * @param {Object} cfg Xtype definition of item to add.
45840 addxtype : function(cfg) {
45841 return this.layout.addxtype(cfg);
45846 Roo.ScrollPanel = function(el, config, content){
45847 config = config || {};
45848 config.fitToFrame = true;
45849 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
45851 this.el.dom.style.overflow = "hidden";
45852 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
45853 this.el.removeClass("x-layout-inactive-content");
45854 this.el.on("mousewheel", this.onWheel, this);
45856 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
45857 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
45858 up.unselectable(); down.unselectable();
45859 up.on("click", this.scrollUp, this);
45860 down.on("click", this.scrollDown, this);
45861 up.addClassOnOver("x-scroller-btn-over");
45862 down.addClassOnOver("x-scroller-btn-over");
45863 up.addClassOnClick("x-scroller-btn-click");
45864 down.addClassOnClick("x-scroller-btn-click");
45865 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
45867 this.resizeEl = this.el;
45868 this.el = wrap; this.up = up; this.down = down;
45871 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
45873 wheelIncrement : 5,
45874 scrollUp : function(){
45875 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
45878 scrollDown : function(){
45879 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
45882 afterScroll : function(){
45883 var el = this.resizeEl;
45884 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
45885 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45886 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
45889 setSize : function(){
45890 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
45891 this.afterScroll();
45894 onWheel : function(e){
45895 var d = e.getWheelDelta();
45896 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
45897 this.afterScroll();
45901 setContent : function(content, loadScripts){
45902 this.resizeEl.update(content, loadScripts);
45916 * @class Roo.TreePanel
45917 * @extends Roo.ContentPanel
45919 * Create a new TreePanel. - defaults to fit/scoll contents.
45920 * @param {String/Object} config A string to set only the panel's title, or a config object
45921 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
45923 Roo.TreePanel = function(config){
45924 var el = config.el;
45925 var tree = config.tree;
45926 delete config.tree;
45927 delete config.el; // hopefull!
45929 // wrapper for IE7 strict & safari scroll issue
45931 var treeEl = el.createChild();
45932 config.resizeEl = treeEl;
45936 Roo.TreePanel.superclass.constructor.call(this, el, config);
45939 this.tree = new Roo.tree.TreePanel(treeEl , tree);
45940 //console.log(tree);
45941 this.on('activate', function()
45943 if (this.tree.rendered) {
45946 //console.log('render tree');
45947 this.tree.render();
45950 this.on('resize', function (cp, w, h) {
45951 this.tree.innerCt.setWidth(w);
45952 this.tree.innerCt.setHeight(h);
45953 this.tree.innerCt.setStyle('overflow-y', 'auto');
45960 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
45977 * Ext JS Library 1.1.1
45978 * Copyright(c) 2006-2007, Ext JS, LLC.
45980 * Originally Released Under LGPL - original licence link has changed is not relivant.
45983 * <script type="text/javascript">
45988 * @class Roo.ReaderLayout
45989 * @extends Roo.BorderLayout
45990 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
45991 * center region containing two nested regions (a top one for a list view and one for item preview below),
45992 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
45993 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
45994 * expedites the setup of the overall layout and regions for this common application style.
45997 var reader = new Roo.ReaderLayout();
45998 var CP = Roo.ContentPanel; // shortcut for adding
46000 reader.beginUpdate();
46001 reader.add("north", new CP("north", "North"));
46002 reader.add("west", new CP("west", {title: "West"}));
46003 reader.add("east", new CP("east", {title: "East"}));
46005 reader.regions.listView.add(new CP("listView", "List"));
46006 reader.regions.preview.add(new CP("preview", "Preview"));
46007 reader.endUpdate();
46010 * Create a new ReaderLayout
46011 * @param {Object} config Configuration options
46012 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
46013 * document.body if omitted)
46015 Roo.ReaderLayout = function(config, renderTo){
46016 var c = config || {size:{}};
46017 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
46018 north: c.north !== false ? Roo.apply({
46022 }, c.north) : false,
46023 west: c.west !== false ? Roo.apply({
46031 margins:{left:5,right:0,bottom:5,top:5},
46032 cmargins:{left:5,right:5,bottom:5,top:5}
46033 }, c.west) : false,
46034 east: c.east !== false ? Roo.apply({
46042 margins:{left:0,right:5,bottom:5,top:5},
46043 cmargins:{left:5,right:5,bottom:5,top:5}
46044 }, c.east) : false,
46045 center: Roo.apply({
46046 tabPosition: 'top',
46050 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
46054 this.el.addClass('x-reader');
46056 this.beginUpdate();
46058 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
46059 south: c.preview !== false ? Roo.apply({
46066 cmargins:{top:5,left:0, right:0, bottom:0}
46067 }, c.preview) : false,
46068 center: Roo.apply({
46074 this.add('center', new Roo.NestedLayoutPanel(inner,
46075 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
46079 this.regions.preview = inner.getRegion('south');
46080 this.regions.listView = inner.getRegion('center');
46083 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
46085 * Ext JS Library 1.1.1
46086 * Copyright(c) 2006-2007, Ext JS, LLC.
46088 * Originally Released Under LGPL - original licence link has changed is not relivant.
46091 * <script type="text/javascript">
46095 * @class Roo.grid.Grid
46096 * @extends Roo.util.Observable
46097 * This class represents the primary interface of a component based grid control.
46098 * <br><br>Usage:<pre><code>
46099 var grid = new Roo.grid.Grid("my-container-id", {
46102 selModel: mySelectionModel,
46103 autoSizeColumns: true,
46104 monitorWindowResize: false,
46105 trackMouseOver: true
46110 * <b>Common Problems:</b><br/>
46111 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
46112 * element will correct this<br/>
46113 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
46114 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
46115 * are unpredictable.<br/>
46116 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
46117 * grid to calculate dimensions/offsets.<br/>
46119 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
46120 * The container MUST have some type of size defined for the grid to fill. The container will be
46121 * automatically set to position relative if it isn't already.
46122 * @param {Object} config A config object that sets properties on this grid.
46124 Roo.grid.Grid = function(container, config){
46125 // initialize the container
46126 this.container = Roo.get(container);
46127 this.container.update("");
46128 this.container.setStyle("overflow", "hidden");
46129 this.container.addClass('x-grid-container');
46131 this.id = this.container.id;
46133 Roo.apply(this, config);
46134 // check and correct shorthanded configs
46136 this.dataSource = this.ds;
46140 this.colModel = this.cm;
46144 this.selModel = this.sm;
46148 if (this.selModel) {
46149 this.selModel = Roo.factory(this.selModel, Roo.grid);
46150 this.sm = this.selModel;
46151 this.sm.xmodule = this.xmodule || false;
46153 if (typeof(this.colModel.config) == 'undefined') {
46154 this.colModel = new Roo.grid.ColumnModel(this.colModel);
46155 this.cm = this.colModel;
46156 this.cm.xmodule = this.xmodule || false;
46158 if (this.dataSource) {
46159 this.dataSource= Roo.factory(this.dataSource, Roo.data);
46160 this.ds = this.dataSource;
46161 this.ds.xmodule = this.xmodule || false;
46168 this.container.setWidth(this.width);
46172 this.container.setHeight(this.height);
46179 * The raw click event for the entire grid.
46180 * @param {Roo.EventObject} e
46185 * The raw dblclick event for the entire grid.
46186 * @param {Roo.EventObject} e
46190 * @event contextmenu
46191 * The raw contextmenu event for the entire grid.
46192 * @param {Roo.EventObject} e
46194 "contextmenu" : true,
46197 * The raw mousedown event for the entire grid.
46198 * @param {Roo.EventObject} e
46200 "mousedown" : true,
46203 * The raw mouseup event for the entire grid.
46204 * @param {Roo.EventObject} e
46209 * The raw mouseover event for the entire grid.
46210 * @param {Roo.EventObject} e
46212 "mouseover" : true,
46215 * The raw mouseout event for the entire grid.
46216 * @param {Roo.EventObject} e
46221 * The raw keypress event for the entire grid.
46222 * @param {Roo.EventObject} e
46227 * The raw keydown event for the entire grid.
46228 * @param {Roo.EventObject} e
46236 * Fires when a cell is clicked
46237 * @param {Grid} this
46238 * @param {Number} rowIndex
46239 * @param {Number} columnIndex
46240 * @param {Roo.EventObject} e
46242 "cellclick" : true,
46244 * @event celldblclick
46245 * Fires when a cell is double clicked
46246 * @param {Grid} this
46247 * @param {Number} rowIndex
46248 * @param {Number} columnIndex
46249 * @param {Roo.EventObject} e
46251 "celldblclick" : true,
46254 * Fires when a row is clicked
46255 * @param {Grid} this
46256 * @param {Number} rowIndex
46257 * @param {Roo.EventObject} e
46261 * @event rowdblclick
46262 * Fires when a row is double clicked
46263 * @param {Grid} this
46264 * @param {Number} rowIndex
46265 * @param {Roo.EventObject} e
46267 "rowdblclick" : true,
46269 * @event headerclick
46270 * Fires when a header is clicked
46271 * @param {Grid} this
46272 * @param {Number} columnIndex
46273 * @param {Roo.EventObject} e
46275 "headerclick" : true,
46277 * @event headerdblclick
46278 * Fires when a header cell is double clicked
46279 * @param {Grid} this
46280 * @param {Number} columnIndex
46281 * @param {Roo.EventObject} e
46283 "headerdblclick" : true,
46285 * @event rowcontextmenu
46286 * Fires when a row is right clicked
46287 * @param {Grid} this
46288 * @param {Number} rowIndex
46289 * @param {Roo.EventObject} e
46291 "rowcontextmenu" : true,
46293 * @event cellcontextmenu
46294 * Fires when a cell is right clicked
46295 * @param {Grid} this
46296 * @param {Number} rowIndex
46297 * @param {Number} cellIndex
46298 * @param {Roo.EventObject} e
46300 "cellcontextmenu" : true,
46302 * @event headercontextmenu
46303 * Fires when a header is right clicked
46304 * @param {Grid} this
46305 * @param {Number} columnIndex
46306 * @param {Roo.EventObject} e
46308 "headercontextmenu" : true,
46310 * @event bodyscroll
46311 * Fires when the body element is scrolled
46312 * @param {Number} scrollLeft
46313 * @param {Number} scrollTop
46315 "bodyscroll" : true,
46317 * @event columnresize
46318 * Fires when the user resizes a column
46319 * @param {Number} columnIndex
46320 * @param {Number} newSize
46322 "columnresize" : true,
46324 * @event columnmove
46325 * Fires when the user moves a column
46326 * @param {Number} oldIndex
46327 * @param {Number} newIndex
46329 "columnmove" : true,
46332 * Fires when row(s) start being dragged
46333 * @param {Grid} this
46334 * @param {Roo.GridDD} dd The drag drop object
46335 * @param {event} e The raw browser event
46337 "startdrag" : true,
46340 * Fires when a drag operation is complete
46341 * @param {Grid} this
46342 * @param {Roo.GridDD} dd The drag drop object
46343 * @param {event} e The raw browser event
46348 * Fires when dragged row(s) are dropped on a valid DD target
46349 * @param {Grid} this
46350 * @param {Roo.GridDD} dd The drag drop object
46351 * @param {String} targetId The target drag drop object
46352 * @param {event} e The raw browser event
46357 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
46358 * @param {Grid} this
46359 * @param {Roo.GridDD} dd The drag drop object
46360 * @param {String} targetId The target drag drop object
46361 * @param {event} e The raw browser event
46366 * Fires when the dragged row(s) first cross another DD target while being dragged
46367 * @param {Grid} this
46368 * @param {Roo.GridDD} dd The drag drop object
46369 * @param {String} targetId The target drag drop object
46370 * @param {event} e The raw browser event
46372 "dragenter" : true,
46375 * Fires when the dragged row(s) leave another DD target while being dragged
46376 * @param {Grid} this
46377 * @param {Roo.GridDD} dd The drag drop object
46378 * @param {String} targetId The target drag drop object
46379 * @param {event} e The raw browser event
46384 * Fires when the grid is rendered
46385 * @param {Grid} grid
46390 Roo.grid.Grid.superclass.constructor.call(this);
46392 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
46395 * @cfg {String} ddGroup - drag drop group.
46399 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
46401 minColumnWidth : 25,
46404 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
46405 * <b>on initial render.</b> It is more efficient to explicitly size the columns
46406 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
46408 autoSizeColumns : false,
46411 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
46413 autoSizeHeaders : true,
46416 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
46418 monitorWindowResize : true,
46421 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
46422 * rows measured to get a columns size. Default is 0 (all rows).
46424 maxRowsToMeasure : 0,
46427 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
46429 trackMouseOver : true,
46432 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
46436 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
46438 enableDragDrop : false,
46441 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
46443 enableColumnMove : true,
46446 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
46448 enableColumnHide : true,
46451 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
46453 enableRowHeightSync : false,
46456 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
46461 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
46463 autoHeight : false,
46466 * @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.
46468 autoExpandColumn : false,
46471 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
46474 autoExpandMin : 50,
46477 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
46479 autoExpandMax : 1000,
46482 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
46487 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
46491 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
46498 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
46499 * of a fixed width. Default is false.
46502 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
46505 * Called once after all setup has been completed and the grid is ready to be rendered.
46506 * @return {Roo.grid.Grid} this
46508 render : function(){
46509 var c = this.container;
46510 // try to detect autoHeight/width mode
46511 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
46512 this.autoHeight = true;
46514 var view = this.getView();
46517 c.on("click", this.onClick, this);
46518 c.on("dblclick", this.onDblClick, this);
46519 c.on("contextmenu", this.onContextMenu, this);
46520 c.on("keydown", this.onKeyDown, this);
46522 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
46524 this.getSelectionModel().init(this);
46529 this.loadMask = new Roo.LoadMask(this.container,
46530 Roo.apply({store:this.dataSource}, this.loadMask));
46534 if (this.toolbar && this.toolbar.xtype) {
46535 this.toolbar.container = this.getView().getHeaderPanel(true);
46536 this.toolbar = new Ext.Toolbar(this.toolbar);
46538 if (this.footer && this.footer.xtype) {
46539 this.footer.dataSource = this.getDataSource();
46540 this.footer.container = this.getView().getFooterPanel(true);
46541 this.footer = Roo.factory(this.footer, Roo);
46543 if (this.dropTarget && this.dropTarget.xtype) {
46544 delete this.dropTarget.xtype;
46545 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
46549 this.rendered = true;
46550 this.fireEvent('render', this);
46555 * Reconfigures the grid to use a different Store and Column Model.
46556 * The View will be bound to the new objects and refreshed.
46557 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
46558 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
46560 reconfigure : function(dataSource, colModel){
46562 this.loadMask.destroy();
46563 this.loadMask = new Roo.LoadMask(this.container,
46564 Roo.apply({store:dataSource}, this.loadMask));
46566 this.view.bind(dataSource, colModel);
46567 this.dataSource = dataSource;
46568 this.colModel = colModel;
46569 this.view.refresh(true);
46573 onKeyDown : function(e){
46574 this.fireEvent("keydown", e);
46578 * Destroy this grid.
46579 * @param {Boolean} removeEl True to remove the element
46581 destroy : function(removeEl, keepListeners){
46583 this.loadMask.destroy();
46585 var c = this.container;
46586 c.removeAllListeners();
46587 this.view.destroy();
46588 this.colModel.purgeListeners();
46589 if(!keepListeners){
46590 this.purgeListeners();
46593 if(removeEl === true){
46599 processEvent : function(name, e){
46600 this.fireEvent(name, e);
46601 var t = e.getTarget();
46603 var header = v.findHeaderIndex(t);
46604 if(header !== false){
46605 this.fireEvent("header" + name, this, header, e);
46607 var row = v.findRowIndex(t);
46608 var cell = v.findCellIndex(t);
46610 this.fireEvent("row" + name, this, row, e);
46611 if(cell !== false){
46612 this.fireEvent("cell" + name, this, row, cell, e);
46619 onClick : function(e){
46620 this.processEvent("click", e);
46624 onContextMenu : function(e, t){
46625 this.processEvent("contextmenu", e);
46629 onDblClick : function(e){
46630 this.processEvent("dblclick", e);
46634 walkCells : function(row, col, step, fn, scope){
46635 var cm = this.colModel, clen = cm.getColumnCount();
46636 var ds = this.dataSource, rlen = ds.getCount(), first = true;
46648 if(fn.call(scope || this, row, col, cm) === true){
46666 if(fn.call(scope || this, row, col, cm) === true){
46678 getSelections : function(){
46679 return this.selModel.getSelections();
46683 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
46684 * but if manual update is required this method will initiate it.
46686 autoSize : function(){
46688 this.view.layout();
46689 if(this.view.adjustForScroll){
46690 this.view.adjustForScroll();
46696 * Returns the grid's underlying element.
46697 * @return {Element} The element
46699 getGridEl : function(){
46700 return this.container;
46703 // private for compatibility, overridden by editor grid
46704 stopEditing : function(){},
46707 * Returns the grid's SelectionModel.
46708 * @return {SelectionModel}
46710 getSelectionModel : function(){
46711 if(!this.selModel){
46712 this.selModel = new Roo.grid.RowSelectionModel();
46714 return this.selModel;
46718 * Returns the grid's DataSource.
46719 * @return {DataSource}
46721 getDataSource : function(){
46722 return this.dataSource;
46726 * Returns the grid's ColumnModel.
46727 * @return {ColumnModel}
46729 getColumnModel : function(){
46730 return this.colModel;
46734 * Returns the grid's GridView object.
46735 * @return {GridView}
46737 getView : function(){
46739 this.view = new Roo.grid.GridView(this.viewConfig);
46744 * Called to get grid's drag proxy text, by default returns this.ddText.
46747 getDragDropText : function(){
46748 var count = this.selModel.getCount();
46749 return String.format(this.ddText, count, count == 1 ? '' : 's');
46753 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
46754 * %0 is replaced with the number of selected rows.
46757 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
46759 * Ext JS Library 1.1.1
46760 * Copyright(c) 2006-2007, Ext JS, LLC.
46762 * Originally Released Under LGPL - original licence link has changed is not relivant.
46765 * <script type="text/javascript">
46768 Roo.grid.AbstractGridView = function(){
46772 "beforerowremoved" : true,
46773 "beforerowsinserted" : true,
46774 "beforerefresh" : true,
46775 "rowremoved" : true,
46776 "rowsinserted" : true,
46777 "rowupdated" : true,
46780 Roo.grid.AbstractGridView.superclass.constructor.call(this);
46783 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
46784 rowClass : "x-grid-row",
46785 cellClass : "x-grid-cell",
46786 tdClass : "x-grid-td",
46787 hdClass : "x-grid-hd",
46788 splitClass : "x-grid-hd-split",
46790 init: function(grid){
46792 var cid = this.grid.getGridEl().id;
46793 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
46794 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
46795 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
46796 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
46799 getColumnRenderers : function(){
46800 var renderers = [];
46801 var cm = this.grid.colModel;
46802 var colCount = cm.getColumnCount();
46803 for(var i = 0; i < colCount; i++){
46804 renderers[i] = cm.getRenderer(i);
46809 getColumnIds : function(){
46811 var cm = this.grid.colModel;
46812 var colCount = cm.getColumnCount();
46813 for(var i = 0; i < colCount; i++){
46814 ids[i] = cm.getColumnId(i);
46819 getDataIndexes : function(){
46820 if(!this.indexMap){
46821 this.indexMap = this.buildIndexMap();
46823 return this.indexMap.colToData;
46826 getColumnIndexByDataIndex : function(dataIndex){
46827 if(!this.indexMap){
46828 this.indexMap = this.buildIndexMap();
46830 return this.indexMap.dataToCol[dataIndex];
46834 * Set a css style for a column dynamically.
46835 * @param {Number} colIndex The index of the column
46836 * @param {String} name The css property name
46837 * @param {String} value The css value
46839 setCSSStyle : function(colIndex, name, value){
46840 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
46841 Roo.util.CSS.updateRule(selector, name, value);
46844 generateRules : function(cm){
46845 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
46846 Roo.util.CSS.removeStyleSheet(rulesId);
46847 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46848 var cid = cm.getColumnId(i);
46849 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
46850 this.tdSelector, cid, " {\n}\n",
46851 this.hdSelector, cid, " {\n}\n",
46852 this.splitSelector, cid, " {\n}\n");
46854 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
46858 * Ext JS Library 1.1.1
46859 * Copyright(c) 2006-2007, Ext JS, LLC.
46861 * Originally Released Under LGPL - original licence link has changed is not relivant.
46864 * <script type="text/javascript">
46868 // This is a support class used internally by the Grid components
46869 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
46871 this.view = grid.getView();
46872 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46873 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
46875 this.setHandleElId(Roo.id(hd));
46876 this.setOuterHandleElId(Roo.id(hd2));
46878 this.scroll = false;
46880 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
46882 getDragData : function(e){
46883 var t = Roo.lib.Event.getTarget(e);
46884 var h = this.view.findHeaderCell(t);
46886 return {ddel: h.firstChild, header:h};
46891 onInitDrag : function(e){
46892 this.view.headersDisabled = true;
46893 var clone = this.dragData.ddel.cloneNode(true);
46894 clone.id = Roo.id();
46895 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
46896 this.proxy.update(clone);
46900 afterValidDrop : function(){
46902 setTimeout(function(){
46903 v.headersDisabled = false;
46907 afterInvalidDrop : function(){
46909 setTimeout(function(){
46910 v.headersDisabled = false;
46916 * Ext JS Library 1.1.1
46917 * Copyright(c) 2006-2007, Ext JS, LLC.
46919 * Originally Released Under LGPL - original licence link has changed is not relivant.
46922 * <script type="text/javascript">
46925 // This is a support class used internally by the Grid components
46926 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
46928 this.view = grid.getView();
46929 // split the proxies so they don't interfere with mouse events
46930 this.proxyTop = Roo.DomHelper.append(document.body, {
46931 cls:"col-move-top", html:" "
46933 this.proxyBottom = Roo.DomHelper.append(document.body, {
46934 cls:"col-move-bottom", html:" "
46936 this.proxyTop.hide = this.proxyBottom.hide = function(){
46937 this.setLeftTop(-100,-100);
46938 this.setStyle("visibility", "hidden");
46940 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
46941 // temporarily disabled
46942 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
46943 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
46945 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
46946 proxyOffsets : [-4, -9],
46947 fly: Roo.Element.fly,
46949 getTargetFromEvent : function(e){
46950 var t = Roo.lib.Event.getTarget(e);
46951 var cindex = this.view.findCellIndex(t);
46952 if(cindex !== false){
46953 return this.view.getHeaderCell(cindex);
46957 nextVisible : function(h){
46958 var v = this.view, cm = this.grid.colModel;
46961 if(!cm.isHidden(v.getCellIndex(h))){
46969 prevVisible : function(h){
46970 var v = this.view, cm = this.grid.colModel;
46973 if(!cm.isHidden(v.getCellIndex(h))){
46981 positionIndicator : function(h, n, e){
46982 var x = Roo.lib.Event.getPageX(e);
46983 var r = Roo.lib.Dom.getRegion(n.firstChild);
46984 var px, pt, py = r.top + this.proxyOffsets[1];
46985 if((r.right - x) <= (r.right-r.left)/2){
46986 px = r.right+this.view.borderWidth;
46992 var oldIndex = this.view.getCellIndex(h);
46993 var newIndex = this.view.getCellIndex(n);
46995 if(this.grid.colModel.isFixed(newIndex)){
46999 var locked = this.grid.colModel.isLocked(newIndex);
47004 if(oldIndex < newIndex){
47007 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
47010 px += this.proxyOffsets[0];
47011 this.proxyTop.setLeftTop(px, py);
47012 this.proxyTop.show();
47013 if(!this.bottomOffset){
47014 this.bottomOffset = this.view.mainHd.getHeight();
47016 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
47017 this.proxyBottom.show();
47021 onNodeEnter : function(n, dd, e, data){
47022 if(data.header != n){
47023 this.positionIndicator(data.header, n, e);
47027 onNodeOver : function(n, dd, e, data){
47028 var result = false;
47029 if(data.header != n){
47030 result = this.positionIndicator(data.header, n, e);
47033 this.proxyTop.hide();
47034 this.proxyBottom.hide();
47036 return result ? this.dropAllowed : this.dropNotAllowed;
47039 onNodeOut : function(n, dd, e, data){
47040 this.proxyTop.hide();
47041 this.proxyBottom.hide();
47044 onNodeDrop : function(n, dd, e, data){
47045 var h = data.header;
47047 var cm = this.grid.colModel;
47048 var x = Roo.lib.Event.getPageX(e);
47049 var r = Roo.lib.Dom.getRegion(n.firstChild);
47050 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
47051 var oldIndex = this.view.getCellIndex(h);
47052 var newIndex = this.view.getCellIndex(n);
47053 var locked = cm.isLocked(newIndex);
47057 if(oldIndex < newIndex){
47060 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
47063 cm.setLocked(oldIndex, locked, true);
47064 cm.moveColumn(oldIndex, newIndex);
47065 this.grid.fireEvent("columnmove", oldIndex, newIndex);
47073 * Ext JS Library 1.1.1
47074 * Copyright(c) 2006-2007, Ext JS, LLC.
47076 * Originally Released Under LGPL - original licence link has changed is not relivant.
47079 * <script type="text/javascript">
47083 * @class Roo.grid.GridView
47084 * @extends Roo.util.Observable
47087 * @param {Object} config
47089 Roo.grid.GridView = function(config){
47090 Roo.grid.GridView.superclass.constructor.call(this);
47093 Roo.apply(this, config);
47096 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
47099 * Override this function to apply custom css classes to rows during rendering
47100 * @param {Record} record The record
47101 * @param {Number} index
47102 * @method getRowClass
47104 rowClass : "x-grid-row",
47106 cellClass : "x-grid-col",
47108 tdClass : "x-grid-td",
47110 hdClass : "x-grid-hd",
47112 splitClass : "x-grid-split",
47114 sortClasses : ["sort-asc", "sort-desc"],
47116 enableMoveAnim : false,
47120 dh : Roo.DomHelper,
47122 fly : Roo.Element.fly,
47124 css : Roo.util.CSS,
47130 scrollIncrement : 22,
47132 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
47134 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
47136 bind : function(ds, cm){
47138 this.ds.un("load", this.onLoad, this);
47139 this.ds.un("datachanged", this.onDataChange, this);
47140 this.ds.un("add", this.onAdd, this);
47141 this.ds.un("remove", this.onRemove, this);
47142 this.ds.un("update", this.onUpdate, this);
47143 this.ds.un("clear", this.onClear, this);
47146 ds.on("load", this.onLoad, this);
47147 ds.on("datachanged", this.onDataChange, this);
47148 ds.on("add", this.onAdd, this);
47149 ds.on("remove", this.onRemove, this);
47150 ds.on("update", this.onUpdate, this);
47151 ds.on("clear", this.onClear, this);
47156 this.cm.un("widthchange", this.onColWidthChange, this);
47157 this.cm.un("headerchange", this.onHeaderChange, this);
47158 this.cm.un("hiddenchange", this.onHiddenChange, this);
47159 this.cm.un("columnmoved", this.onColumnMove, this);
47160 this.cm.un("columnlockchange", this.onColumnLock, this);
47163 this.generateRules(cm);
47164 cm.on("widthchange", this.onColWidthChange, this);
47165 cm.on("headerchange", this.onHeaderChange, this);
47166 cm.on("hiddenchange", this.onHiddenChange, this);
47167 cm.on("columnmoved", this.onColumnMove, this);
47168 cm.on("columnlockchange", this.onColumnLock, this);
47173 init: function(grid){
47174 Roo.grid.GridView.superclass.init.call(this, grid);
47176 this.bind(grid.dataSource, grid.colModel);
47178 grid.on("headerclick", this.handleHeaderClick, this);
47180 if(grid.trackMouseOver){
47181 grid.on("mouseover", this.onRowOver, this);
47182 grid.on("mouseout", this.onRowOut, this);
47184 grid.cancelTextSelection = function(){};
47185 this.gridId = grid.id;
47187 var tpls = this.templates || {};
47190 tpls.master = new Roo.Template(
47191 '<div class="x-grid" hidefocus="true">',
47192 '<div class="x-grid-topbar"></div>',
47193 '<div class="x-grid-scroller"><div></div></div>',
47194 '<div class="x-grid-locked">',
47195 '<div class="x-grid-header">{lockedHeader}</div>',
47196 '<div class="x-grid-body">{lockedBody}</div>',
47198 '<div class="x-grid-viewport">',
47199 '<div class="x-grid-header">{header}</div>',
47200 '<div class="x-grid-body">{body}</div>',
47202 '<div class="x-grid-bottombar"></div>',
47203 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
47204 '<div class="x-grid-resize-proxy"> </div>',
47207 tpls.master.disableformats = true;
47211 tpls.header = new Roo.Template(
47212 '<table border="0" cellspacing="0" cellpadding="0">',
47213 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
47216 tpls.header.disableformats = true;
47218 tpls.header.compile();
47221 tpls.hcell = new Roo.Template(
47222 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
47223 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
47226 tpls.hcell.disableFormats = true;
47228 tpls.hcell.compile();
47231 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
47232 tpls.hsplit.disableFormats = true;
47234 tpls.hsplit.compile();
47237 tpls.body = new Roo.Template(
47238 '<table border="0" cellspacing="0" cellpadding="0">',
47239 "<tbody>{rows}</tbody>",
47242 tpls.body.disableFormats = true;
47244 tpls.body.compile();
47247 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
47248 tpls.row.disableFormats = true;
47250 tpls.row.compile();
47253 tpls.cell = new Roo.Template(
47254 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
47255 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
47258 tpls.cell.disableFormats = true;
47260 tpls.cell.compile();
47262 this.templates = tpls;
47265 // remap these for backwards compat
47266 onColWidthChange : function(){
47267 this.updateColumns.apply(this, arguments);
47269 onHeaderChange : function(){
47270 this.updateHeaders.apply(this, arguments);
47272 onHiddenChange : function(){
47273 this.handleHiddenChange.apply(this, arguments);
47275 onColumnMove : function(){
47276 this.handleColumnMove.apply(this, arguments);
47278 onColumnLock : function(){
47279 this.handleLockChange.apply(this, arguments);
47282 onDataChange : function(){
47284 this.updateHeaderSortState();
47287 onClear : function(){
47291 onUpdate : function(ds, record){
47292 this.refreshRow(record);
47295 refreshRow : function(record){
47296 var ds = this.ds, index;
47297 if(typeof record == 'number'){
47299 record = ds.getAt(index);
47301 index = ds.indexOf(record);
47303 this.insertRows(ds, index, index, true);
47304 this.onRemove(ds, record, index+1, true);
47305 this.syncRowHeights(index, index);
47307 this.fireEvent("rowupdated", this, index, record);
47310 onAdd : function(ds, records, index){
47311 this.insertRows(ds, index, index + (records.length-1));
47314 onRemove : function(ds, record, index, isUpdate){
47315 if(isUpdate !== true){
47316 this.fireEvent("beforerowremoved", this, index, record);
47318 var bt = this.getBodyTable(), lt = this.getLockedTable();
47319 if(bt.rows[index]){
47320 bt.firstChild.removeChild(bt.rows[index]);
47322 if(lt.rows[index]){
47323 lt.firstChild.removeChild(lt.rows[index]);
47325 if(isUpdate !== true){
47326 this.stripeRows(index);
47327 this.syncRowHeights(index, index);
47329 this.fireEvent("rowremoved", this, index, record);
47333 onLoad : function(){
47334 this.scrollToTop();
47338 * Scrolls the grid to the top
47340 scrollToTop : function(){
47342 this.scroller.dom.scrollTop = 0;
47348 * Gets a panel in the header of the grid that can be used for toolbars etc.
47349 * After modifying the contents of this panel a call to grid.autoSize() may be
47350 * required to register any changes in size.
47351 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
47352 * @return Roo.Element
47354 getHeaderPanel : function(doShow){
47356 this.headerPanel.show();
47358 return this.headerPanel;
47362 * Gets a panel in the footer of the grid that can be used for toolbars etc.
47363 * After modifying the contents of this panel a call to grid.autoSize() may be
47364 * required to register any changes in size.
47365 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
47366 * @return Roo.Element
47368 getFooterPanel : function(doShow){
47370 this.footerPanel.show();
47372 return this.footerPanel;
47375 initElements : function(){
47376 var E = Roo.Element;
47377 var el = this.grid.getGridEl().dom.firstChild;
47378 var cs = el.childNodes;
47380 this.el = new E(el);
47381 this.headerPanel = new E(el.firstChild);
47382 this.headerPanel.enableDisplayMode("block");
47384 this.scroller = new E(cs[1]);
47385 this.scrollSizer = new E(this.scroller.dom.firstChild);
47387 this.lockedWrap = new E(cs[2]);
47388 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
47389 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
47391 this.mainWrap = new E(cs[3]);
47392 this.mainHd = new E(this.mainWrap.dom.firstChild);
47393 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
47395 this.footerPanel = new E(cs[4]);
47396 this.footerPanel.enableDisplayMode("block");
47398 this.focusEl = new E(cs[5]);
47399 this.focusEl.swallowEvent("click", true);
47400 this.resizeProxy = new E(cs[6]);
47402 this.headerSelector = String.format(
47403 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
47404 this.lockedHd.id, this.mainHd.id
47407 this.splitterSelector = String.format(
47408 '#{0} div.x-grid-split, #{1} div.x-grid-split',
47409 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
47412 idToCssName : function(s)
47414 return s.replace(/[^a-z0-9]+/ig, '-');
47417 getHeaderCell : function(index){
47418 return Roo.DomQuery.select(this.headerSelector)[index];
47421 getHeaderCellMeasure : function(index){
47422 return this.getHeaderCell(index).firstChild;
47425 getHeaderCellText : function(index){
47426 return this.getHeaderCell(index).firstChild.firstChild;
47429 getLockedTable : function(){
47430 return this.lockedBody.dom.firstChild;
47433 getBodyTable : function(){
47434 return this.mainBody.dom.firstChild;
47437 getLockedRow : function(index){
47438 return this.getLockedTable().rows[index];
47441 getRow : function(index){
47442 return this.getBodyTable().rows[index];
47445 getRowComposite : function(index){
47447 this.rowEl = new Roo.CompositeElementLite();
47449 var els = [], lrow, mrow;
47450 if(lrow = this.getLockedRow(index)){
47453 if(mrow = this.getRow(index)){
47456 this.rowEl.elements = els;
47460 getCell : function(rowIndex, colIndex){
47461 var locked = this.cm.getLockedCount();
47463 if(colIndex < locked){
47464 source = this.lockedBody.dom.firstChild;
47466 source = this.mainBody.dom.firstChild;
47467 colIndex -= locked;
47469 return source.rows[rowIndex].childNodes[colIndex];
47472 getCellText : function(rowIndex, colIndex){
47473 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
47476 getCellBox : function(cell){
47477 var b = this.fly(cell).getBox();
47478 if(Roo.isOpera){ // opera fails to report the Y
47479 b.y = cell.offsetTop + this.mainBody.getY();
47484 getCellIndex : function(cell){
47485 var id = String(cell.className).match(this.cellRE);
47487 return parseInt(id[1], 10);
47492 findHeaderIndex : function(n){
47493 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47494 return r ? this.getCellIndex(r) : false;
47497 findHeaderCell : function(n){
47498 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
47499 return r ? r : false;
47502 findRowIndex : function(n){
47506 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
47507 return r ? r.rowIndex : false;
47510 findCellIndex : function(node){
47511 var stop = this.el.dom;
47512 while(node && node != stop){
47513 if(this.findRE.test(node.className)){
47514 return this.getCellIndex(node);
47516 node = node.parentNode;
47521 getColumnId : function(index){
47522 return this.cm.getColumnId(index);
47525 getSplitters : function(){
47526 if(this.splitterSelector){
47527 return Roo.DomQuery.select(this.splitterSelector);
47533 getSplitter : function(index){
47534 return this.getSplitters()[index];
47537 onRowOver : function(e, t){
47539 if((row = this.findRowIndex(t)) !== false){
47540 this.getRowComposite(row).addClass("x-grid-row-over");
47544 onRowOut : function(e, t){
47546 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
47547 this.getRowComposite(row).removeClass("x-grid-row-over");
47551 renderHeaders : function(){
47553 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
47554 var cb = [], lb = [], sb = [], lsb = [], p = {};
47555 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47556 p.cellId = "x-grid-hd-0-" + i;
47557 p.splitId = "x-grid-csplit-0-" + i;
47558 p.id = cm.getColumnId(i);
47559 p.title = cm.getColumnTooltip(i) || "";
47560 p.value = cm.getColumnHeader(i) || "";
47561 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
47562 if(!cm.isLocked(i)){
47563 cb[cb.length] = ct.apply(p);
47564 sb[sb.length] = st.apply(p);
47566 lb[lb.length] = ct.apply(p);
47567 lsb[lsb.length] = st.apply(p);
47570 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
47571 ht.apply({cells: cb.join(""), splits:sb.join("")})];
47574 updateHeaders : function(){
47575 var html = this.renderHeaders();
47576 this.lockedHd.update(html[0]);
47577 this.mainHd.update(html[1]);
47581 * Focuses the specified row.
47582 * @param {Number} row The row index
47584 focusRow : function(row){
47585 var x = this.scroller.dom.scrollLeft;
47586 this.focusCell(row, 0, false);
47587 this.scroller.dom.scrollLeft = x;
47591 * Focuses the specified cell.
47592 * @param {Number} row The row index
47593 * @param {Number} col The column index
47594 * @param {Boolean} hscroll false to disable horizontal scrolling
47596 focusCell : function(row, col, hscroll){
47597 var el = this.ensureVisible(row, col, hscroll);
47598 this.focusEl.alignTo(el, "tl-tl");
47600 this.focusEl.focus();
47602 this.focusEl.focus.defer(1, this.focusEl);
47607 * Scrolls the specified cell into view
47608 * @param {Number} row The row index
47609 * @param {Number} col The column index
47610 * @param {Boolean} hscroll false to disable horizontal scrolling
47612 ensureVisible : function(row, col, hscroll){
47613 if(typeof row != "number"){
47614 row = row.rowIndex;
47616 if(row < 0 && row >= this.ds.getCount()){
47619 col = (col !== undefined ? col : 0);
47620 var cm = this.grid.colModel;
47621 while(cm.isHidden(col)){
47625 var el = this.getCell(row, col);
47629 var c = this.scroller.dom;
47631 var ctop = parseInt(el.offsetTop, 10);
47632 var cleft = parseInt(el.offsetLeft, 10);
47633 var cbot = ctop + el.offsetHeight;
47634 var cright = cleft + el.offsetWidth;
47636 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
47637 var stop = parseInt(c.scrollTop, 10);
47638 var sleft = parseInt(c.scrollLeft, 10);
47639 var sbot = stop + ch;
47640 var sright = sleft + c.clientWidth;
47643 c.scrollTop = ctop;
47644 }else if(cbot > sbot){
47645 c.scrollTop = cbot-ch;
47648 if(hscroll !== false){
47650 c.scrollLeft = cleft;
47651 }else if(cright > sright){
47652 c.scrollLeft = cright-c.clientWidth;
47658 updateColumns : function(){
47659 this.grid.stopEditing();
47660 var cm = this.grid.colModel, colIds = this.getColumnIds();
47661 //var totalWidth = cm.getTotalWidth();
47663 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47664 //if(cm.isHidden(i)) continue;
47665 var w = cm.getColumnWidth(i);
47666 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
47667 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
47669 this.updateSplitters();
47672 generateRules : function(cm){
47673 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
47674 Roo.util.CSS.removeStyleSheet(rulesId);
47675 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47676 var cid = cm.getColumnId(i);
47678 if(cm.config[i].align){
47679 align = 'text-align:'+cm.config[i].align+';';
47682 if(cm.isHidden(i)){
47683 hidden = 'display:none;';
47685 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
47687 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
47688 this.hdSelector, cid, " {\n", align, width, "}\n",
47689 this.tdSelector, cid, " {\n",hidden,"\n}\n",
47690 this.splitSelector, cid, " {\n", hidden , "\n}\n");
47692 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
47695 updateSplitters : function(){
47696 var cm = this.cm, s = this.getSplitters();
47697 if(s){ // splitters not created yet
47698 var pos = 0, locked = true;
47699 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
47700 if(cm.isHidden(i)) continue;
47701 var w = cm.getColumnWidth(i);
47702 if(!cm.isLocked(i) && locked){
47707 s[i].style.left = (pos-this.splitOffset) + "px";
47712 handleHiddenChange : function(colModel, colIndex, hidden){
47714 this.hideColumn(colIndex);
47716 this.unhideColumn(colIndex);
47720 hideColumn : function(colIndex){
47721 var cid = this.getColumnId(colIndex);
47722 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
47723 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
47725 this.updateHeaders();
47727 this.updateSplitters();
47731 unhideColumn : function(colIndex){
47732 var cid = this.getColumnId(colIndex);
47733 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
47734 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
47737 this.updateHeaders();
47739 this.updateSplitters();
47743 insertRows : function(dm, firstRow, lastRow, isUpdate){
47744 if(firstRow == 0 && lastRow == dm.getCount()-1){
47748 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
47750 var s = this.getScrollState();
47751 var markup = this.renderRows(firstRow, lastRow);
47752 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
47753 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
47754 this.restoreScroll(s);
47756 this.fireEvent("rowsinserted", this, firstRow, lastRow);
47757 this.syncRowHeights(firstRow, lastRow);
47758 this.stripeRows(firstRow);
47764 bufferRows : function(markup, target, index){
47765 var before = null, trows = target.rows, tbody = target.tBodies[0];
47766 if(index < trows.length){
47767 before = trows[index];
47769 var b = document.createElement("div");
47770 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
47771 var rows = b.firstChild.rows;
47772 for(var i = 0, len = rows.length; i < len; i++){
47774 tbody.insertBefore(rows[0], before);
47776 tbody.appendChild(rows[0]);
47783 deleteRows : function(dm, firstRow, lastRow){
47784 if(dm.getRowCount()<1){
47785 this.fireEvent("beforerefresh", this);
47786 this.mainBody.update("");
47787 this.lockedBody.update("");
47788 this.fireEvent("refresh", this);
47790 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
47791 var bt = this.getBodyTable();
47792 var tbody = bt.firstChild;
47793 var rows = bt.rows;
47794 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
47795 tbody.removeChild(rows[firstRow]);
47797 this.stripeRows(firstRow);
47798 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
47802 updateRows : function(dataSource, firstRow, lastRow){
47803 var s = this.getScrollState();
47805 this.restoreScroll(s);
47808 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
47812 this.updateHeaderSortState();
47815 getScrollState : function(){
47816 var sb = this.scroller.dom;
47817 return {left: sb.scrollLeft, top: sb.scrollTop};
47820 stripeRows : function(startRow){
47821 if(!this.grid.stripeRows || this.ds.getCount() < 1){
47824 startRow = startRow || 0;
47825 var rows = this.getBodyTable().rows;
47826 var lrows = this.getLockedTable().rows;
47827 var cls = ' x-grid-row-alt ';
47828 for(var i = startRow, len = rows.length; i < len; i++){
47829 var row = rows[i], lrow = lrows[i];
47830 var isAlt = ((i+1) % 2 == 0);
47831 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
47832 if(isAlt == hasAlt){
47836 row.className += " x-grid-row-alt";
47838 row.className = row.className.replace("x-grid-row-alt", "");
47841 lrow.className = row.className;
47846 restoreScroll : function(state){
47847 var sb = this.scroller.dom;
47848 sb.scrollLeft = state.left;
47849 sb.scrollTop = state.top;
47853 syncScroll : function(){
47854 var sb = this.scroller.dom;
47855 var sh = this.mainHd.dom;
47856 var bs = this.mainBody.dom;
47857 var lv = this.lockedBody.dom;
47858 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
47859 lv.scrollTop = bs.scrollTop = sb.scrollTop;
47862 handleScroll : function(e){
47864 var sb = this.scroller.dom;
47865 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
47869 handleWheel : function(e){
47870 var d = e.getWheelDelta();
47871 this.scroller.dom.scrollTop -= d*22;
47872 // set this here to prevent jumpy scrolling on large tables
47873 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
47877 renderRows : function(startRow, endRow){
47878 // pull in all the crap needed to render rows
47879 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
47880 var colCount = cm.getColumnCount();
47882 if(ds.getCount() < 1){
47886 // build a map for all the columns
47888 for(var i = 0; i < colCount; i++){
47889 var name = cm.getDataIndex(i);
47891 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
47892 renderer : cm.getRenderer(i),
47893 id : cm.getColumnId(i),
47894 locked : cm.isLocked(i)
47898 startRow = startRow || 0;
47899 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
47901 // records to render
47902 var rs = ds.getRange(startRow, endRow);
47904 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
47907 // As much as I hate to duplicate code, this was branched because FireFox really hates
47908 // [].join("") on strings. The performance difference was substantial enough to
47909 // branch this function
47910 doRender : Roo.isGecko ?
47911 function(cs, rs, ds, startRow, colCount, stripe){
47912 var ts = this.templates, ct = ts.cell, rt = ts.row;
47914 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
47915 for(var j = 0, len = rs.length; j < len; j++){
47916 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
47917 for(var i = 0; i < colCount; i++){
47919 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
47921 p.css = p.attr = "";
47922 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
47923 if(p.value == undefined || p.value === "") p.value = " ";
47924 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
47925 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47927 var markup = ct.apply(p);
47935 if(stripe && ((rowIndex+1) % 2 == 0)){
47936 alt[0] = "x-grid-row-alt";
47939 alt[1] = " x-grid-dirty-row";
47942 if(this.getRowClass){
47943 alt[2] = this.getRowClass(r, rowIndex);
47945 rp.alt = alt.join(" ");
47946 lbuf+= rt.apply(rp);
47948 buf+= rt.apply(rp);
47950 return [lbuf, buf];
47952 function(cs, rs, ds, startRow, colCount, stripe){
47953 var ts = this.templates, ct = ts.cell, rt = ts.row;
47955 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
47956 for(var j = 0, len = rs.length; j < len; j++){
47957 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
47958 for(var i = 0; i < colCount; i++){
47960 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
47962 p.css = p.attr = "";
47963 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
47964 if(p.value == undefined || p.value === "") p.value = " ";
47965 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
47966 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47968 var markup = ct.apply(p);
47970 cb[cb.length] = markup;
47972 lcb[lcb.length] = markup;
47976 if(stripe && ((rowIndex+1) % 2 == 0)){
47977 alt[0] = "x-grid-row-alt";
47980 alt[1] = " x-grid-dirty-row";
47983 if(this.getRowClass){
47984 alt[2] = this.getRowClass(r, rowIndex);
47986 rp.alt = alt.join(" ");
47987 rp.cells = lcb.join("");
47988 lbuf[lbuf.length] = rt.apply(rp);
47989 rp.cells = cb.join("");
47990 buf[buf.length] = rt.apply(rp);
47992 return [lbuf.join(""), buf.join("")];
47995 renderBody : function(){
47996 var markup = this.renderRows();
47997 var bt = this.templates.body;
47998 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
48002 * Refreshes the grid
48003 * @param {Boolean} headersToo
48005 refresh : function(headersToo){
48006 this.fireEvent("beforerefresh", this);
48007 this.grid.stopEditing();
48008 var result = this.renderBody();
48009 this.lockedBody.update(result[0]);
48010 this.mainBody.update(result[1]);
48011 if(headersToo === true){
48012 this.updateHeaders();
48013 this.updateColumns();
48014 this.updateSplitters();
48015 this.updateHeaderSortState();
48017 this.syncRowHeights();
48019 this.fireEvent("refresh", this);
48022 handleColumnMove : function(cm, oldIndex, newIndex){
48023 this.indexMap = null;
48024 var s = this.getScrollState();
48025 this.refresh(true);
48026 this.restoreScroll(s);
48027 this.afterMove(newIndex);
48030 afterMove : function(colIndex){
48031 if(this.enableMoveAnim && Roo.enableFx){
48032 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
48036 updateCell : function(dm, rowIndex, dataIndex){
48037 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
48038 if(typeof colIndex == "undefined"){ // not present in grid
48041 var cm = this.grid.colModel;
48042 var cell = this.getCell(rowIndex, colIndex);
48043 var cellText = this.getCellText(rowIndex, colIndex);
48046 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
48047 id : cm.getColumnId(colIndex),
48048 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
48050 var renderer = cm.getRenderer(colIndex);
48051 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
48052 if(typeof val == "undefined" || val === "") val = " ";
48053 cellText.innerHTML = val;
48054 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
48055 this.syncRowHeights(rowIndex, rowIndex);
48058 calcColumnWidth : function(colIndex, maxRowsToMeasure){
48060 if(this.grid.autoSizeHeaders){
48061 var h = this.getHeaderCellMeasure(colIndex);
48062 maxWidth = Math.max(maxWidth, h.scrollWidth);
48065 if(this.cm.isLocked(colIndex)){
48066 tb = this.getLockedTable();
48069 tb = this.getBodyTable();
48070 index = colIndex - this.cm.getLockedCount();
48073 var rows = tb.rows;
48074 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
48075 for(var i = 0; i < stopIndex; i++){
48076 var cell = rows[i].childNodes[index].firstChild;
48077 maxWidth = Math.max(maxWidth, cell.scrollWidth);
48080 return maxWidth + /*margin for error in IE*/ 5;
48083 * Autofit a column to its content.
48084 * @param {Number} colIndex
48085 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
48087 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
48088 if(this.cm.isHidden(colIndex)){
48089 return; // can't calc a hidden column
48092 var cid = this.cm.getColumnId(colIndex);
48093 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
48094 if(this.grid.autoSizeHeaders){
48095 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
48098 var newWidth = this.calcColumnWidth(colIndex);
48099 this.cm.setColumnWidth(colIndex,
48100 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
48101 if(!suppressEvent){
48102 this.grid.fireEvent("columnresize", colIndex, newWidth);
48107 * Autofits all columns to their content and then expands to fit any extra space in the grid
48109 autoSizeColumns : function(){
48110 var cm = this.grid.colModel;
48111 var colCount = cm.getColumnCount();
48112 for(var i = 0; i < colCount; i++){
48113 this.autoSizeColumn(i, true, true);
48115 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
48118 this.updateColumns();
48124 * Autofits all columns to the grid's width proportionate with their current size
48125 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
48127 fitColumns : function(reserveScrollSpace){
48128 var cm = this.grid.colModel;
48129 var colCount = cm.getColumnCount();
48133 for (i = 0; i < colCount; i++){
48134 if(!cm.isHidden(i) && !cm.isFixed(i)){
48135 w = cm.getColumnWidth(i);
48141 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
48142 if(reserveScrollSpace){
48145 var frac = (avail - cm.getTotalWidth())/width;
48146 while (cols.length){
48149 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
48151 this.updateColumns();
48155 onRowSelect : function(rowIndex){
48156 var row = this.getRowComposite(rowIndex);
48157 row.addClass("x-grid-row-selected");
48160 onRowDeselect : function(rowIndex){
48161 var row = this.getRowComposite(rowIndex);
48162 row.removeClass("x-grid-row-selected");
48165 onCellSelect : function(row, col){
48166 var cell = this.getCell(row, col);
48168 Roo.fly(cell).addClass("x-grid-cell-selected");
48172 onCellDeselect : function(row, col){
48173 var cell = this.getCell(row, col);
48175 Roo.fly(cell).removeClass("x-grid-cell-selected");
48179 updateHeaderSortState : function(){
48180 var state = this.ds.getSortState();
48184 this.sortState = state;
48185 var sortColumn = this.cm.findColumnIndex(state.field);
48186 if(sortColumn != -1){
48187 var sortDir = state.direction;
48188 var sc = this.sortClasses;
48189 var hds = this.el.select(this.headerSelector).removeClass(sc);
48190 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
48194 handleHeaderClick : function(g, index){
48195 if(this.headersDisabled){
48198 var dm = g.dataSource, cm = g.colModel;
48199 if(!cm.isSortable(index)){
48203 dm.sort(cm.getDataIndex(index));
48207 destroy : function(){
48209 this.colMenu.removeAll();
48210 Roo.menu.MenuMgr.unregister(this.colMenu);
48211 this.colMenu.getEl().remove();
48212 delete this.colMenu;
48215 this.hmenu.removeAll();
48216 Roo.menu.MenuMgr.unregister(this.hmenu);
48217 this.hmenu.getEl().remove();
48220 if(this.grid.enableColumnMove){
48221 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48223 for(var dd in dds){
48224 if(!dds[dd].config.isTarget && dds[dd].dragElId){
48225 var elid = dds[dd].dragElId;
48227 Roo.get(elid).remove();
48228 } else if(dds[dd].config.isTarget){
48229 dds[dd].proxyTop.remove();
48230 dds[dd].proxyBottom.remove();
48233 if(Roo.dd.DDM.locationCache[dd]){
48234 delete Roo.dd.DDM.locationCache[dd];
48237 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
48240 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
48241 this.bind(null, null);
48242 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
48245 handleLockChange : function(){
48246 this.refresh(true);
48249 onDenyColumnLock : function(){
48253 onDenyColumnHide : function(){
48257 handleHdMenuClick : function(item){
48258 var index = this.hdCtxIndex;
48259 var cm = this.cm, ds = this.ds;
48262 ds.sort(cm.getDataIndex(index), "ASC");
48265 ds.sort(cm.getDataIndex(index), "DESC");
48268 var lc = cm.getLockedCount();
48269 if(cm.getColumnCount(true) <= lc+1){
48270 this.onDenyColumnLock();
48274 cm.setLocked(index, true, true);
48275 cm.moveColumn(index, lc);
48276 this.grid.fireEvent("columnmove", index, lc);
48278 cm.setLocked(index, true);
48282 var lc = cm.getLockedCount();
48283 if((lc-1) != index){
48284 cm.setLocked(index, false, true);
48285 cm.moveColumn(index, lc-1);
48286 this.grid.fireEvent("columnmove", index, lc-1);
48288 cm.setLocked(index, false);
48292 index = cm.getIndexById(item.id.substr(4));
48294 if(item.checked && cm.getColumnCount(true) <= 1){
48295 this.onDenyColumnHide();
48298 cm.setHidden(index, item.checked);
48304 beforeColMenuShow : function(){
48305 var cm = this.cm, colCount = cm.getColumnCount();
48306 this.colMenu.removeAll();
48307 for(var i = 0; i < colCount; i++){
48308 this.colMenu.add(new Roo.menu.CheckItem({
48309 id: "col-"+cm.getColumnId(i),
48310 text: cm.getColumnHeader(i),
48311 checked: !cm.isHidden(i),
48317 handleHdCtx : function(g, index, e){
48319 var hd = this.getHeaderCell(index);
48320 this.hdCtxIndex = index;
48321 var ms = this.hmenu.items, cm = this.cm;
48322 ms.get("asc").setDisabled(!cm.isSortable(index));
48323 ms.get("desc").setDisabled(!cm.isSortable(index));
48324 if(this.grid.enableColLock !== false){
48325 ms.get("lock").setDisabled(cm.isLocked(index));
48326 ms.get("unlock").setDisabled(!cm.isLocked(index));
48328 this.hmenu.show(hd, "tl-bl");
48331 handleHdOver : function(e){
48332 var hd = this.findHeaderCell(e.getTarget());
48333 if(hd && !this.headersDisabled){
48334 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
48335 this.fly(hd).addClass("x-grid-hd-over");
48340 handleHdOut : function(e){
48341 var hd = this.findHeaderCell(e.getTarget());
48343 this.fly(hd).removeClass("x-grid-hd-over");
48347 handleSplitDblClick : function(e, t){
48348 var i = this.getCellIndex(t);
48349 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
48350 this.autoSizeColumn(i, true);
48355 render : function(){
48358 var colCount = cm.getColumnCount();
48360 if(this.grid.monitorWindowResize === true){
48361 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48363 var header = this.renderHeaders();
48364 var body = this.templates.body.apply({rows:""});
48365 var html = this.templates.master.apply({
48368 lockedHeader: header[0],
48372 //this.updateColumns();
48374 this.grid.getGridEl().dom.innerHTML = html;
48376 this.initElements();
48378 // a kludge to fix the random scolling effect in webkit
48379 this.el.on("scroll", function() {
48380 this.el.dom.scrollTop=0; // hopefully not recursive..
48383 this.scroller.on("scroll", this.handleScroll, this);
48384 this.lockedBody.on("mousewheel", this.handleWheel, this);
48385 this.mainBody.on("mousewheel", this.handleWheel, this);
48387 this.mainHd.on("mouseover", this.handleHdOver, this);
48388 this.mainHd.on("mouseout", this.handleHdOut, this);
48389 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
48390 {delegate: "."+this.splitClass});
48392 this.lockedHd.on("mouseover", this.handleHdOver, this);
48393 this.lockedHd.on("mouseout", this.handleHdOut, this);
48394 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
48395 {delegate: "."+this.splitClass});
48397 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
48398 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48401 this.updateSplitters();
48403 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
48404 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48405 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
48408 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
48409 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
48411 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
48412 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
48414 if(this.grid.enableColLock !== false){
48415 this.hmenu.add('-',
48416 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
48417 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
48420 if(this.grid.enableColumnHide !== false){
48422 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
48423 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
48424 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
48426 this.hmenu.add('-',
48427 {id:"columns", text: this.columnsText, menu: this.colMenu}
48430 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
48432 this.grid.on("headercontextmenu", this.handleHdCtx, this);
48435 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
48436 this.dd = new Roo.grid.GridDragZone(this.grid, {
48437 ddGroup : this.grid.ddGroup || 'GridDD'
48442 for(var i = 0; i < colCount; i++){
48443 if(cm.isHidden(i)){
48444 this.hideColumn(i);
48446 if(cm.config[i].align){
48447 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
48448 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
48452 this.updateHeaderSortState();
48454 this.beforeInitialResize();
48457 // two part rendering gives faster view to the user
48458 this.renderPhase2.defer(1, this);
48461 renderPhase2 : function(){
48462 // render the rows now
48464 if(this.grid.autoSizeColumns){
48465 this.autoSizeColumns();
48469 beforeInitialResize : function(){
48473 onColumnSplitterMoved : function(i, w){
48474 this.userResized = true;
48475 var cm = this.grid.colModel;
48476 cm.setColumnWidth(i, w, true);
48477 var cid = cm.getColumnId(i);
48478 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48479 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
48480 this.updateSplitters();
48482 this.grid.fireEvent("columnresize", i, w);
48485 syncRowHeights : function(startIndex, endIndex){
48486 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
48487 startIndex = startIndex || 0;
48488 var mrows = this.getBodyTable().rows;
48489 var lrows = this.getLockedTable().rows;
48490 var len = mrows.length-1;
48491 endIndex = Math.min(endIndex || len, len);
48492 for(var i = startIndex; i <= endIndex; i++){
48493 var m = mrows[i], l = lrows[i];
48494 var h = Math.max(m.offsetHeight, l.offsetHeight);
48495 m.style.height = l.style.height = h + "px";
48500 layout : function(initialRender, is2ndPass){
48502 var auto = g.autoHeight;
48503 var scrollOffset = 16;
48504 var c = g.getGridEl(), cm = this.cm,
48505 expandCol = g.autoExpandColumn,
48507 //c.beginMeasure();
48509 if(!c.dom.offsetWidth){ // display:none?
48511 this.lockedWrap.show();
48512 this.mainWrap.show();
48517 var hasLock = this.cm.isLocked(0);
48519 var tbh = this.headerPanel.getHeight();
48520 var bbh = this.footerPanel.getHeight();
48523 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
48524 var newHeight = ch + c.getBorderWidth("tb");
48526 newHeight = Math.min(g.maxHeight, newHeight);
48528 c.setHeight(newHeight);
48532 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
48535 var s = this.scroller;
48537 var csize = c.getSize(true);
48539 this.el.setSize(csize.width, csize.height);
48541 this.headerPanel.setWidth(csize.width);
48542 this.footerPanel.setWidth(csize.width);
48544 var hdHeight = this.mainHd.getHeight();
48545 var vw = csize.width;
48546 var vh = csize.height - (tbh + bbh);
48550 var bt = this.getBodyTable();
48551 var ltWidth = hasLock ?
48552 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
48554 var scrollHeight = bt.offsetHeight;
48555 var scrollWidth = ltWidth + bt.offsetWidth;
48556 var vscroll = false, hscroll = false;
48558 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
48560 var lw = this.lockedWrap, mw = this.mainWrap;
48561 var lb = this.lockedBody, mb = this.mainBody;
48563 setTimeout(function(){
48564 var t = s.dom.offsetTop;
48565 var w = s.dom.clientWidth,
48566 h = s.dom.clientHeight;
48569 lw.setSize(ltWidth, h);
48571 mw.setLeftTop(ltWidth, t);
48572 mw.setSize(w-ltWidth, h);
48574 lb.setHeight(h-hdHeight);
48575 mb.setHeight(h-hdHeight);
48577 if(is2ndPass !== true && !gv.userResized && expandCol){
48578 // high speed resize without full column calculation
48580 var ci = cm.getIndexById(expandCol);
48582 ci = cm.findColumnIndex(expandCol);
48584 ci = Math.max(0, ci); // make sure it's got at least the first col.
48585 var expandId = cm.getColumnId(ci);
48586 var tw = cm.getTotalWidth(false);
48587 var currentWidth = cm.getColumnWidth(ci);
48588 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
48589 if(currentWidth != cw){
48590 cm.setColumnWidth(ci, cw, true);
48591 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48592 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
48593 gv.updateSplitters();
48594 gv.layout(false, true);
48606 onWindowResize : function(){
48607 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
48613 appendFooter : function(parentEl){
48617 sortAscText : "Sort Ascending",
48618 sortDescText : "Sort Descending",
48619 lockText : "Lock Column",
48620 unlockText : "Unlock Column",
48621 columnsText : "Columns"
48625 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
48626 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
48627 this.proxy.el.addClass('x-grid3-col-dd');
48630 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
48631 handleMouseDown : function(e){
48635 callHandleMouseDown : function(e){
48636 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
48641 * Ext JS Library 1.1.1
48642 * Copyright(c) 2006-2007, Ext JS, LLC.
48644 * Originally Released Under LGPL - original licence link has changed is not relivant.
48647 * <script type="text/javascript">
48651 // This is a support class used internally by the Grid components
48652 Roo.grid.SplitDragZone = function(grid, hd, hd2){
48654 this.view = grid.getView();
48655 this.proxy = this.view.resizeProxy;
48656 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
48657 "gridSplitters" + this.grid.getGridEl().id, {
48658 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
48660 this.setHandleElId(Roo.id(hd));
48661 this.setOuterHandleElId(Roo.id(hd2));
48662 this.scroll = false;
48664 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
48665 fly: Roo.Element.fly,
48667 b4StartDrag : function(x, y){
48668 this.view.headersDisabled = true;
48669 this.proxy.setHeight(this.view.mainWrap.getHeight());
48670 var w = this.cm.getColumnWidth(this.cellIndex);
48671 var minw = Math.max(w-this.grid.minColumnWidth, 0);
48672 this.resetConstraints();
48673 this.setXConstraint(minw, 1000);
48674 this.setYConstraint(0, 0);
48675 this.minX = x - minw;
48676 this.maxX = x + 1000;
48678 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
48682 handleMouseDown : function(e){
48683 ev = Roo.EventObject.setEvent(e);
48684 var t = this.fly(ev.getTarget());
48685 if(t.hasClass("x-grid-split")){
48686 this.cellIndex = this.view.getCellIndex(t.dom);
48687 this.split = t.dom;
48688 this.cm = this.grid.colModel;
48689 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
48690 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
48695 endDrag : function(e){
48696 this.view.headersDisabled = false;
48697 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
48698 var diff = endX - this.startPos;
48699 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
48702 autoOffset : function(){
48703 this.setDelta(0,0);
48707 * Ext JS Library 1.1.1
48708 * Copyright(c) 2006-2007, Ext JS, LLC.
48710 * Originally Released Under LGPL - original licence link has changed is not relivant.
48713 * <script type="text/javascript">
48717 // This is a support class used internally by the Grid components
48718 Roo.grid.GridDragZone = function(grid, config){
48719 this.view = grid.getView();
48720 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
48721 if(this.view.lockedBody){
48722 this.setHandleElId(Roo.id(this.view.mainBody.dom));
48723 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
48725 this.scroll = false;
48727 this.ddel = document.createElement('div');
48728 this.ddel.className = 'x-grid-dd-wrap';
48731 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
48732 ddGroup : "GridDD",
48734 getDragData : function(e){
48735 var t = Roo.lib.Event.getTarget(e);
48736 var rowIndex = this.view.findRowIndex(t);
48737 if(rowIndex !== false){
48738 var sm = this.grid.selModel;
48739 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
48740 // sm.mouseDown(e, t);
48742 if (e.hasModifier()){
48743 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
48745 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
48750 onInitDrag : function(e){
48751 var data = this.dragData;
48752 this.ddel.innerHTML = this.grid.getDragDropText();
48753 this.proxy.update(this.ddel);
48754 // fire start drag?
48757 afterRepair : function(){
48758 this.dragging = false;
48761 getRepairXY : function(e, data){
48765 onEndDrag : function(data, e){
48769 onValidDrop : function(dd, e, id){
48774 beforeInvalidDrop : function(e, id){
48779 * Ext JS Library 1.1.1
48780 * Copyright(c) 2006-2007, Ext JS, LLC.
48782 * Originally Released Under LGPL - original licence link has changed is not relivant.
48785 * <script type="text/javascript">
48790 * @class Roo.grid.ColumnModel
48791 * @extends Roo.util.Observable
48792 * This is the default implementation of a ColumnModel used by the Grid. It defines
48793 * the columns in the grid.
48796 var colModel = new Roo.grid.ColumnModel([
48797 {header: "Ticker", width: 60, sortable: true, locked: true},
48798 {header: "Company Name", width: 150, sortable: true},
48799 {header: "Market Cap.", width: 100, sortable: true},
48800 {header: "$ Sales", width: 100, sortable: true, renderer: money},
48801 {header: "Employees", width: 100, sortable: true, resizable: false}
48806 * The config options listed for this class are options which may appear in each
48807 * individual column definition.
48808 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
48810 * @param {Object} config An Array of column config objects. See this class's
48811 * config objects for details.
48813 Roo.grid.ColumnModel = function(config){
48815 * The config passed into the constructor
48817 this.config = config;
48820 // if no id, create one
48821 // if the column does not have a dataIndex mapping,
48822 // map it to the order it is in the config
48823 for(var i = 0, len = config.length; i < len; i++){
48825 if(typeof c.dataIndex == "undefined"){
48828 if(typeof c.renderer == "string"){
48829 c.renderer = Roo.util.Format[c.renderer];
48831 if(typeof c.id == "undefined"){
48834 if(c.editor && c.editor.xtype){
48835 c.editor = Roo.factory(c.editor, Roo.grid);
48837 if(c.editor && c.editor.isFormField){
48838 c.editor = new Roo.grid.GridEditor(c.editor);
48840 this.lookup[c.id] = c;
48844 * The width of columns which have no width specified (defaults to 100)
48847 this.defaultWidth = 100;
48850 * Default sortable of columns which have no sortable specified (defaults to false)
48853 this.defaultSortable = false;
48857 * @event widthchange
48858 * Fires when the width of a column changes.
48859 * @param {ColumnModel} this
48860 * @param {Number} columnIndex The column index
48861 * @param {Number} newWidth The new width
48863 "widthchange": true,
48865 * @event headerchange
48866 * Fires when the text of a header changes.
48867 * @param {ColumnModel} this
48868 * @param {Number} columnIndex The column index
48869 * @param {Number} newText The new header text
48871 "headerchange": true,
48873 * @event hiddenchange
48874 * Fires when a column is hidden or "unhidden".
48875 * @param {ColumnModel} this
48876 * @param {Number} columnIndex The column index
48877 * @param {Boolean} hidden true if hidden, false otherwise
48879 "hiddenchange": true,
48881 * @event columnmoved
48882 * Fires when a column is moved.
48883 * @param {ColumnModel} this
48884 * @param {Number} oldIndex
48885 * @param {Number} newIndex
48887 "columnmoved" : true,
48889 * @event columlockchange
48890 * Fires when a column's locked state is changed
48891 * @param {ColumnModel} this
48892 * @param {Number} colIndex
48893 * @param {Boolean} locked true if locked
48895 "columnlockchange" : true
48897 Roo.grid.ColumnModel.superclass.constructor.call(this);
48899 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
48901 * @cfg {String} header The header text to display in the Grid view.
48904 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
48905 * {@link Roo.data.Record} definition from which to draw the column's value. If not
48906 * specified, the column's index is used as an index into the Record's data Array.
48909 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
48910 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
48913 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
48914 * Defaults to the value of the {@link #defaultSortable} property.
48915 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
48918 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
48921 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
48924 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
48927 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
48930 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
48931 * given the cell's data value. See {@link #setRenderer}. If not specified, the
48932 * default renderer uses the raw data value.
48935 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
48938 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
48942 * Returns the id of the column at the specified index.
48943 * @param {Number} index The column index
48944 * @return {String} the id
48946 getColumnId : function(index){
48947 return this.config[index].id;
48951 * Returns the column for a specified id.
48952 * @param {String} id The column id
48953 * @return {Object} the column
48955 getColumnById : function(id){
48956 return this.lookup[id];
48961 * Returns the column for a specified dataIndex.
48962 * @param {String} dataIndex The column dataIndex
48963 * @return {Object|Boolean} the column or false if not found
48965 getColumnByDataIndex: function(dataIndex){
48966 var index = this.findColumnIndex(dataIndex);
48967 return index > -1 ? this.config[index] : false;
48971 * Returns the index for a specified column id.
48972 * @param {String} id The column id
48973 * @return {Number} the index, or -1 if not found
48975 getIndexById : function(id){
48976 for(var i = 0, len = this.config.length; i < len; i++){
48977 if(this.config[i].id == id){
48985 * Returns the index for a specified column dataIndex.
48986 * @param {String} dataIndex The column dataIndex
48987 * @return {Number} the index, or -1 if not found
48990 findColumnIndex : function(dataIndex){
48991 for(var i = 0, len = this.config.length; i < len; i++){
48992 if(this.config[i].dataIndex == dataIndex){
49000 moveColumn : function(oldIndex, newIndex){
49001 var c = this.config[oldIndex];
49002 this.config.splice(oldIndex, 1);
49003 this.config.splice(newIndex, 0, c);
49004 this.dataMap = null;
49005 this.fireEvent("columnmoved", this, oldIndex, newIndex);
49008 isLocked : function(colIndex){
49009 return this.config[colIndex].locked === true;
49012 setLocked : function(colIndex, value, suppressEvent){
49013 if(this.isLocked(colIndex) == value){
49016 this.config[colIndex].locked = value;
49017 if(!suppressEvent){
49018 this.fireEvent("columnlockchange", this, colIndex, value);
49022 getTotalLockedWidth : function(){
49023 var totalWidth = 0;
49024 for(var i = 0; i < this.config.length; i++){
49025 if(this.isLocked(i) && !this.isHidden(i)){
49026 this.totalWidth += this.getColumnWidth(i);
49032 getLockedCount : function(){
49033 for(var i = 0, len = this.config.length; i < len; i++){
49034 if(!this.isLocked(i)){
49041 * Returns the number of columns.
49044 getColumnCount : function(visibleOnly){
49045 if(visibleOnly === true){
49047 for(var i = 0, len = this.config.length; i < len; i++){
49048 if(!this.isHidden(i)){
49054 return this.config.length;
49058 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
49059 * @param {Function} fn
49060 * @param {Object} scope (optional)
49061 * @return {Array} result
49063 getColumnsBy : function(fn, scope){
49065 for(var i = 0, len = this.config.length; i < len; i++){
49066 var c = this.config[i];
49067 if(fn.call(scope||this, c, i) === true){
49075 * Returns true if the specified column is sortable.
49076 * @param {Number} col The column index
49077 * @return {Boolean}
49079 isSortable : function(col){
49080 if(typeof this.config[col].sortable == "undefined"){
49081 return this.defaultSortable;
49083 return this.config[col].sortable;
49087 * Returns the rendering (formatting) function defined for the column.
49088 * @param {Number} col The column index.
49089 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
49091 getRenderer : function(col){
49092 if(!this.config[col].renderer){
49093 return Roo.grid.ColumnModel.defaultRenderer;
49095 return this.config[col].renderer;
49099 * Sets the rendering (formatting) function for a column.
49100 * @param {Number} col The column index
49101 * @param {Function} fn The function to use to process the cell's raw data
49102 * to return HTML markup for the grid view. The render function is called with
49103 * the following parameters:<ul>
49104 * <li>Data value.</li>
49105 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
49106 * <li>css A CSS style string to apply to the table cell.</li>
49107 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
49108 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
49109 * <li>Row index</li>
49110 * <li>Column index</li>
49111 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
49113 setRenderer : function(col, fn){
49114 this.config[col].renderer = fn;
49118 * Returns the width for the specified column.
49119 * @param {Number} col The column index
49122 getColumnWidth : function(col){
49123 return this.config[col].width || this.defaultWidth;
49127 * Sets the width for a column.
49128 * @param {Number} col The column index
49129 * @param {Number} width The new width
49131 setColumnWidth : function(col, width, suppressEvent){
49132 this.config[col].width = width;
49133 this.totalWidth = null;
49134 if(!suppressEvent){
49135 this.fireEvent("widthchange", this, col, width);
49140 * Returns the total width of all columns.
49141 * @param {Boolean} includeHidden True to include hidden column widths
49144 getTotalWidth : function(includeHidden){
49145 if(!this.totalWidth){
49146 this.totalWidth = 0;
49147 for(var i = 0, len = this.config.length; i < len; i++){
49148 if(includeHidden || !this.isHidden(i)){
49149 this.totalWidth += this.getColumnWidth(i);
49153 return this.totalWidth;
49157 * Returns the header for the specified column.
49158 * @param {Number} col The column index
49161 getColumnHeader : function(col){
49162 return this.config[col].header;
49166 * Sets the header for a column.
49167 * @param {Number} col The column index
49168 * @param {String} header The new header
49170 setColumnHeader : function(col, header){
49171 this.config[col].header = header;
49172 this.fireEvent("headerchange", this, col, header);
49176 * Returns the tooltip for the specified column.
49177 * @param {Number} col The column index
49180 getColumnTooltip : function(col){
49181 return this.config[col].tooltip;
49184 * Sets the tooltip for a column.
49185 * @param {Number} col The column index
49186 * @param {String} tooltip The new tooltip
49188 setColumnTooltip : function(col, tooltip){
49189 this.config[col].tooltip = tooltip;
49193 * Returns the dataIndex for the specified column.
49194 * @param {Number} col The column index
49197 getDataIndex : function(col){
49198 return this.config[col].dataIndex;
49202 * Sets the dataIndex for a column.
49203 * @param {Number} col The column index
49204 * @param {Number} dataIndex The new dataIndex
49206 setDataIndex : function(col, dataIndex){
49207 this.config[col].dataIndex = dataIndex;
49213 * Returns true if the cell is editable.
49214 * @param {Number} colIndex The column index
49215 * @param {Number} rowIndex The row index
49216 * @return {Boolean}
49218 isCellEditable : function(colIndex, rowIndex){
49219 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
49223 * Returns the editor defined for the cell/column.
49224 * return false or null to disable editing.
49225 * @param {Number} colIndex The column index
49226 * @param {Number} rowIndex The row index
49229 getCellEditor : function(colIndex, rowIndex){
49230 return this.config[colIndex].editor;
49234 * Sets if a column is editable.
49235 * @param {Number} col The column index
49236 * @param {Boolean} editable True if the column is editable
49238 setEditable : function(col, editable){
49239 this.config[col].editable = editable;
49244 * Returns true if the column is hidden.
49245 * @param {Number} colIndex The column index
49246 * @return {Boolean}
49248 isHidden : function(colIndex){
49249 return this.config[colIndex].hidden;
49254 * Returns true if the column width cannot be changed
49256 isFixed : function(colIndex){
49257 return this.config[colIndex].fixed;
49261 * Returns true if the column can be resized
49262 * @return {Boolean}
49264 isResizable : function(colIndex){
49265 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
49268 * Sets if a column is hidden.
49269 * @param {Number} colIndex The column index
49270 * @param {Boolean} hidden True if the column is hidden
49272 setHidden : function(colIndex, hidden){
49273 this.config[colIndex].hidden = hidden;
49274 this.totalWidth = null;
49275 this.fireEvent("hiddenchange", this, colIndex, hidden);
49279 * Sets the editor for a column.
49280 * @param {Number} col The column index
49281 * @param {Object} editor The editor object
49283 setEditor : function(col, editor){
49284 this.config[col].editor = editor;
49288 Roo.grid.ColumnModel.defaultRenderer = function(value){
49289 if(typeof value == "string" && value.length < 1){
49295 // Alias for backwards compatibility
49296 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
49299 * Ext JS Library 1.1.1
49300 * Copyright(c) 2006-2007, Ext JS, LLC.
49302 * Originally Released Under LGPL - original licence link has changed is not relivant.
49305 * <script type="text/javascript">
49309 * @class Roo.grid.AbstractSelectionModel
49310 * @extends Roo.util.Observable
49311 * Abstract base class for grid SelectionModels. It provides the interface that should be
49312 * implemented by descendant classes. This class should not be directly instantiated.
49315 Roo.grid.AbstractSelectionModel = function(){
49316 this.locked = false;
49317 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
49320 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
49321 /** @ignore Called by the grid automatically. Do not call directly. */
49322 init : function(grid){
49328 * Locks the selections.
49331 this.locked = true;
49335 * Unlocks the selections.
49337 unlock : function(){
49338 this.locked = false;
49342 * Returns true if the selections are locked.
49343 * @return {Boolean}
49345 isLocked : function(){
49346 return this.locked;
49350 * Ext JS Library 1.1.1
49351 * Copyright(c) 2006-2007, Ext JS, LLC.
49353 * Originally Released Under LGPL - original licence link has changed is not relivant.
49356 * <script type="text/javascript">
49359 * @extends Roo.grid.AbstractSelectionModel
49360 * @class Roo.grid.RowSelectionModel
49361 * The default SelectionModel used by {@link Roo.grid.Grid}.
49362 * It supports multiple selections and keyboard selection/navigation.
49364 * @param {Object} config
49366 Roo.grid.RowSelectionModel = function(config){
49367 Roo.apply(this, config);
49368 this.selections = new Roo.util.MixedCollection(false, function(o){
49373 this.lastActive = false;
49377 * @event selectionchange
49378 * Fires when the selection changes
49379 * @param {SelectionModel} this
49381 "selectionchange" : true,
49383 * @event afterselectionchange
49384 * Fires after the selection changes (eg. by key press or clicking)
49385 * @param {SelectionModel} this
49387 "afterselectionchange" : true,
49389 * @event beforerowselect
49390 * Fires when a row is selected being selected, return false to cancel.
49391 * @param {SelectionModel} this
49392 * @param {Number} rowIndex The selected index
49393 * @param {Boolean} keepExisting False if other selections will be cleared
49395 "beforerowselect" : true,
49398 * Fires when a row is selected.
49399 * @param {SelectionModel} this
49400 * @param {Number} rowIndex The selected index
49401 * @param {Roo.data.Record} r The record
49403 "rowselect" : true,
49405 * @event rowdeselect
49406 * Fires when a row is deselected.
49407 * @param {SelectionModel} this
49408 * @param {Number} rowIndex The selected index
49410 "rowdeselect" : true
49412 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
49413 this.locked = false;
49416 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
49418 * @cfg {Boolean} singleSelect
49419 * True to allow selection of only one row at a time (defaults to false)
49421 singleSelect : false,
49424 initEvents : function(){
49426 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
49427 this.grid.on("mousedown", this.handleMouseDown, this);
49428 }else{ // allow click to work like normal
49429 this.grid.on("rowclick", this.handleDragableRowClick, this);
49432 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
49433 "up" : function(e){
49435 this.selectPrevious(e.shiftKey);
49436 }else if(this.last !== false && this.lastActive !== false){
49437 var last = this.last;
49438 this.selectRange(this.last, this.lastActive-1);
49439 this.grid.getView().focusRow(this.lastActive);
49440 if(last !== false){
49444 this.selectFirstRow();
49446 this.fireEvent("afterselectionchange", this);
49448 "down" : function(e){
49450 this.selectNext(e.shiftKey);
49451 }else if(this.last !== false && this.lastActive !== false){
49452 var last = this.last;
49453 this.selectRange(this.last, this.lastActive+1);
49454 this.grid.getView().focusRow(this.lastActive);
49455 if(last !== false){
49459 this.selectFirstRow();
49461 this.fireEvent("afterselectionchange", this);
49466 var view = this.grid.view;
49467 view.on("refresh", this.onRefresh, this);
49468 view.on("rowupdated", this.onRowUpdated, this);
49469 view.on("rowremoved", this.onRemove, this);
49473 onRefresh : function(){
49474 var ds = this.grid.dataSource, i, v = this.grid.view;
49475 var s = this.selections;
49476 s.each(function(r){
49477 if((i = ds.indexOfId(r.id)) != -1){
49486 onRemove : function(v, index, r){
49487 this.selections.remove(r);
49491 onRowUpdated : function(v, index, r){
49492 if(this.isSelected(r)){
49493 v.onRowSelect(index);
49499 * @param {Array} records The records to select
49500 * @param {Boolean} keepExisting (optional) True to keep existing selections
49502 selectRecords : function(records, keepExisting){
49504 this.clearSelections();
49506 var ds = this.grid.dataSource;
49507 for(var i = 0, len = records.length; i < len; i++){
49508 this.selectRow(ds.indexOf(records[i]), true);
49513 * Gets the number of selected rows.
49516 getCount : function(){
49517 return this.selections.length;
49521 * Selects the first row in the grid.
49523 selectFirstRow : function(){
49528 * Select the last row.
49529 * @param {Boolean} keepExisting (optional) True to keep existing selections
49531 selectLastRow : function(keepExisting){
49532 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
49536 * Selects the row immediately following the last selected row.
49537 * @param {Boolean} keepExisting (optional) True to keep existing selections
49539 selectNext : function(keepExisting){
49540 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
49541 this.selectRow(this.last+1, keepExisting);
49542 this.grid.getView().focusRow(this.last);
49547 * Selects the row that precedes the last selected row.
49548 * @param {Boolean} keepExisting (optional) True to keep existing selections
49550 selectPrevious : function(keepExisting){
49552 this.selectRow(this.last-1, keepExisting);
49553 this.grid.getView().focusRow(this.last);
49558 * Returns the selected records
49559 * @return {Array} Array of selected records
49561 getSelections : function(){
49562 return [].concat(this.selections.items);
49566 * Returns the first selected record.
49569 getSelected : function(){
49570 return this.selections.itemAt(0);
49575 * Clears all selections.
49577 clearSelections : function(fast){
49578 if(this.locked) return;
49580 var ds = this.grid.dataSource;
49581 var s = this.selections;
49582 s.each(function(r){
49583 this.deselectRow(ds.indexOfId(r.id));
49587 this.selections.clear();
49594 * Selects all rows.
49596 selectAll : function(){
49597 if(this.locked) return;
49598 this.selections.clear();
49599 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
49600 this.selectRow(i, true);
49605 * Returns True if there is a selection.
49606 * @return {Boolean}
49608 hasSelection : function(){
49609 return this.selections.length > 0;
49613 * Returns True if the specified row is selected.
49614 * @param {Number/Record} record The record or index of the record to check
49615 * @return {Boolean}
49617 isSelected : function(index){
49618 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
49619 return (r && this.selections.key(r.id) ? true : false);
49623 * Returns True if the specified record id is selected.
49624 * @param {String} id The id of record to check
49625 * @return {Boolean}
49627 isIdSelected : function(id){
49628 return (this.selections.key(id) ? true : false);
49632 handleMouseDown : function(e, t){
49633 var view = this.grid.getView(), rowIndex;
49634 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
49637 if(e.shiftKey && this.last !== false){
49638 var last = this.last;
49639 this.selectRange(last, rowIndex, e.ctrlKey);
49640 this.last = last; // reset the last
49641 view.focusRow(rowIndex);
49643 var isSelected = this.isSelected(rowIndex);
49644 if(e.button !== 0 && isSelected){
49645 view.focusRow(rowIndex);
49646 }else if(e.ctrlKey && isSelected){
49647 this.deselectRow(rowIndex);
49648 }else if(!isSelected){
49649 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
49650 view.focusRow(rowIndex);
49653 this.fireEvent("afterselectionchange", this);
49656 handleDragableRowClick : function(grid, rowIndex, e)
49658 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
49659 this.selectRow(rowIndex, false);
49660 grid.view.focusRow(rowIndex);
49661 this.fireEvent("afterselectionchange", this);
49666 * Selects multiple rows.
49667 * @param {Array} rows Array of the indexes of the row to select
49668 * @param {Boolean} keepExisting (optional) True to keep existing selections
49670 selectRows : function(rows, keepExisting){
49672 this.clearSelections();
49674 for(var i = 0, len = rows.length; i < len; i++){
49675 this.selectRow(rows[i], true);
49680 * Selects a range of rows. All rows in between startRow and endRow are also selected.
49681 * @param {Number} startRow The index of the first row in the range
49682 * @param {Number} endRow The index of the last row in the range
49683 * @param {Boolean} keepExisting (optional) True to retain existing selections
49685 selectRange : function(startRow, endRow, keepExisting){
49686 if(this.locked) return;
49688 this.clearSelections();
49690 if(startRow <= endRow){
49691 for(var i = startRow; i <= endRow; i++){
49692 this.selectRow(i, true);
49695 for(var i = startRow; i >= endRow; i--){
49696 this.selectRow(i, true);
49702 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
49703 * @param {Number} startRow The index of the first row in the range
49704 * @param {Number} endRow The index of the last row in the range
49706 deselectRange : function(startRow, endRow, preventViewNotify){
49707 if(this.locked) return;
49708 for(var i = startRow; i <= endRow; i++){
49709 this.deselectRow(i, preventViewNotify);
49715 * @param {Number} row The index of the row to select
49716 * @param {Boolean} keepExisting (optional) True to keep existing selections
49718 selectRow : function(index, keepExisting, preventViewNotify){
49719 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
49720 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
49721 if(!keepExisting || this.singleSelect){
49722 this.clearSelections();
49724 var r = this.grid.dataSource.getAt(index);
49725 this.selections.add(r);
49726 this.last = this.lastActive = index;
49727 if(!preventViewNotify){
49728 this.grid.getView().onRowSelect(index);
49730 this.fireEvent("rowselect", this, index, r);
49731 this.fireEvent("selectionchange", this);
49737 * @param {Number} row The index of the row to deselect
49739 deselectRow : function(index, preventViewNotify){
49740 if(this.locked) return;
49741 if(this.last == index){
49744 if(this.lastActive == index){
49745 this.lastActive = false;
49747 var r = this.grid.dataSource.getAt(index);
49748 this.selections.remove(r);
49749 if(!preventViewNotify){
49750 this.grid.getView().onRowDeselect(index);
49752 this.fireEvent("rowdeselect", this, index);
49753 this.fireEvent("selectionchange", this);
49757 restoreLast : function(){
49759 this.last = this._last;
49764 acceptsNav : function(row, col, cm){
49765 return !cm.isHidden(col) && cm.isCellEditable(col, row);
49769 onEditorKey : function(field, e){
49770 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
49775 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
49777 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
49779 }else if(k == e.ENTER && !e.ctrlKey){
49783 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
49785 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
49787 }else if(k == e.ESC){
49791 g.startEditing(newCell[0], newCell[1]);
49796 * Ext JS Library 1.1.1
49797 * Copyright(c) 2006-2007, Ext JS, LLC.
49799 * Originally Released Under LGPL - original licence link has changed is not relivant.
49802 * <script type="text/javascript">
49805 * @class Roo.grid.CellSelectionModel
49806 * @extends Roo.grid.AbstractSelectionModel
49807 * This class provides the basic implementation for cell selection in a grid.
49809 * @param {Object} config The object containing the configuration of this model.
49811 Roo.grid.CellSelectionModel = function(config){
49812 Roo.apply(this, config);
49814 this.selection = null;
49818 * @event beforerowselect
49819 * Fires before a cell is selected.
49820 * @param {SelectionModel} this
49821 * @param {Number} rowIndex The selected row index
49822 * @param {Number} colIndex The selected cell index
49824 "beforecellselect" : true,
49826 * @event cellselect
49827 * Fires when a cell is selected.
49828 * @param {SelectionModel} this
49829 * @param {Number} rowIndex The selected row index
49830 * @param {Number} colIndex The selected cell index
49832 "cellselect" : true,
49834 * @event selectionchange
49835 * Fires when the active selection changes.
49836 * @param {SelectionModel} this
49837 * @param {Object} selection null for no selection or an object (o) with two properties
49839 <li>o.record: the record object for the row the selection is in</li>
49840 <li>o.cell: An array of [rowIndex, columnIndex]</li>
49843 "selectionchange" : true
49845 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
49848 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
49851 initEvents : function(){
49852 this.grid.on("mousedown", this.handleMouseDown, this);
49853 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
49854 var view = this.grid.view;
49855 view.on("refresh", this.onViewChange, this);
49856 view.on("rowupdated", this.onRowUpdated, this);
49857 view.on("beforerowremoved", this.clearSelections, this);
49858 view.on("beforerowsinserted", this.clearSelections, this);
49859 if(this.grid.isEditor){
49860 this.grid.on("beforeedit", this.beforeEdit, this);
49865 beforeEdit : function(e){
49866 this.select(e.row, e.column, false, true, e.record);
49870 onRowUpdated : function(v, index, r){
49871 if(this.selection && this.selection.record == r){
49872 v.onCellSelect(index, this.selection.cell[1]);
49877 onViewChange : function(){
49878 this.clearSelections(true);
49882 * Returns the currently selected cell,.
49883 * @return {Array} The selected cell (row, column) or null if none selected.
49885 getSelectedCell : function(){
49886 return this.selection ? this.selection.cell : null;
49890 * Clears all selections.
49891 * @param {Boolean} true to prevent the gridview from being notified about the change.
49893 clearSelections : function(preventNotify){
49894 var s = this.selection;
49896 if(preventNotify !== true){
49897 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
49899 this.selection = null;
49900 this.fireEvent("selectionchange", this, null);
49905 * Returns true if there is a selection.
49906 * @return {Boolean}
49908 hasSelection : function(){
49909 return this.selection ? true : false;
49913 handleMouseDown : function(e, t){
49914 var v = this.grid.getView();
49915 if(this.isLocked()){
49918 var row = v.findRowIndex(t);
49919 var cell = v.findCellIndex(t);
49920 if(row !== false && cell !== false){
49921 this.select(row, cell);
49927 * @param {Number} rowIndex
49928 * @param {Number} collIndex
49930 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
49931 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
49932 this.clearSelections();
49933 r = r || this.grid.dataSource.getAt(rowIndex);
49936 cell : [rowIndex, colIndex]
49938 if(!preventViewNotify){
49939 var v = this.grid.getView();
49940 v.onCellSelect(rowIndex, colIndex);
49941 if(preventFocus !== true){
49942 v.focusCell(rowIndex, colIndex);
49945 this.fireEvent("cellselect", this, rowIndex, colIndex);
49946 this.fireEvent("selectionchange", this, this.selection);
49951 isSelectable : function(rowIndex, colIndex, cm){
49952 return !cm.isHidden(colIndex);
49956 handleKeyDown : function(e){
49957 Roo.log('Cell Sel Model handleKeyDown');
49958 if(!e.isNavKeyPress()){
49961 var g = this.grid, s = this.selection;
49964 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
49966 this.select(cell[0], cell[1]);
49971 var walk = function(row, col, step){
49972 return g.walkCells(row, col, step, sm.isSelectable, sm);
49974 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
49979 // handled by onEditorKey
49980 if (g.isEditor && g.editing) {
49984 newCell = walk(r, c-1, -1);
49986 newCell = walk(r, c+1, 1);
49990 newCell = walk(r+1, c, 1);
49993 newCell = walk(r-1, c, -1);
49996 newCell = walk(r, c+1, 1);
49999 newCell = walk(r, c-1, -1);
50002 if(g.isEditor && !g.editing){
50003 g.startEditing(r, c);
50010 this.select(newCell[0], newCell[1]);
50015 acceptsNav : function(row, col, cm){
50016 return !cm.isHidden(col) && cm.isCellEditable(col, row);
50019 onEditorKey : function(field, e){
50021 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
50022 ///Roo.log('onEditorKey' + k);
50026 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
50028 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50031 }else if(k == e.ENTER && !e.ctrlKey){
50034 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
50035 }else if(k == e.ESC){
50041 //Roo.log('next cell after edit');
50042 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
50047 * Ext JS Library 1.1.1
50048 * Copyright(c) 2006-2007, Ext JS, LLC.
50050 * Originally Released Under LGPL - original licence link has changed is not relivant.
50053 * <script type="text/javascript">
50057 * @class Roo.grid.EditorGrid
50058 * @extends Roo.grid.Grid
50059 * Class for creating and editable grid.
50060 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50061 * The container MUST have some type of size defined for the grid to fill. The container will be
50062 * automatically set to position relative if it isn't already.
50063 * @param {Object} dataSource The data model to bind to
50064 * @param {Object} colModel The column model with info about this grid's columns
50066 Roo.grid.EditorGrid = function(container, config){
50067 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
50068 this.getGridEl().addClass("xedit-grid");
50070 if(!this.selModel){
50071 this.selModel = new Roo.grid.CellSelectionModel();
50074 this.activeEditor = null;
50078 * @event beforeedit
50079 * Fires before cell editing is triggered. The edit event object has the following properties <br />
50080 * <ul style="padding:5px;padding-left:16px;">
50081 * <li>grid - This grid</li>
50082 * <li>record - The record being edited</li>
50083 * <li>field - The field name being edited</li>
50084 * <li>value - The value for the field being edited.</li>
50085 * <li>row - The grid row index</li>
50086 * <li>column - The grid column index</li>
50087 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50089 * @param {Object} e An edit event (see above for description)
50091 "beforeedit" : true,
50094 * Fires after a cell is edited. <br />
50095 * <ul style="padding:5px;padding-left:16px;">
50096 * <li>grid - This grid</li>
50097 * <li>record - The record being edited</li>
50098 * <li>field - The field name being edited</li>
50099 * <li>value - The value being set</li>
50100 * <li>originalValue - The original value for the field, before the edit.</li>
50101 * <li>row - The grid row index</li>
50102 * <li>column - The grid column index</li>
50104 * @param {Object} e An edit event (see above for description)
50106 "afteredit" : true,
50108 * @event validateedit
50109 * Fires after a cell is edited, but before the value is set in the record.
50110 * You can use this to modify the value being set in the field, Return false
50111 * to cancel the change. The edit event object has the following properties <br />
50112 * <ul style="padding:5px;padding-left:16px;">
50113 * <li>editor - This editor</li>
50114 * <li>grid - This grid</li>
50115 * <li>record - The record being edited</li>
50116 * <li>field - The field name being edited</li>
50117 * <li>value - The value being set</li>
50118 * <li>originalValue - The original value for the field, before the edit.</li>
50119 * <li>row - The grid row index</li>
50120 * <li>column - The grid column index</li>
50121 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
50123 * @param {Object} e An edit event (see above for description)
50125 "validateedit" : true
50127 this.on("bodyscroll", this.stopEditing, this);
50128 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
50131 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
50133 * @cfg {Number} clicksToEdit
50134 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
50141 trackMouseOver: false, // causes very odd FF errors
50143 onCellDblClick : function(g, row, col){
50144 this.startEditing(row, col);
50147 onEditComplete : function(ed, value, startValue){
50148 this.editing = false;
50149 this.activeEditor = null;
50150 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
50152 var field = this.colModel.getDataIndex(ed.col);
50157 originalValue: startValue,
50164 if(String(value) !== String(startValue)){
50166 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
50167 r.set(field, e.value);
50168 // if we are dealing with a combo box..
50169 // then we also set the 'name' colum to be the displayField
50170 if (ed.field.displayField && ed.field.name) {
50171 r.set(ed.field.name, ed.field.el.dom.value);
50174 delete e.cancel; //?? why!!!
50175 this.fireEvent("afteredit", e);
50178 this.fireEvent("afteredit", e); // always fire it!
50180 this.view.focusCell(ed.row, ed.col);
50184 * Starts editing the specified for the specified row/column
50185 * @param {Number} rowIndex
50186 * @param {Number} colIndex
50188 startEditing : function(row, col){
50189 this.stopEditing();
50190 if(this.colModel.isCellEditable(col, row)){
50191 this.view.ensureVisible(row, col, true);
50192 var r = this.dataSource.getAt(row);
50193 var field = this.colModel.getDataIndex(col);
50198 value: r.data[field],
50203 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
50204 this.editing = true;
50205 var ed = this.colModel.getCellEditor(col, row);
50211 ed.render(ed.parentEl || document.body);
50214 (function(){ // complex but required for focus issues in safari, ie and opera
50218 ed.on("complete", this.onEditComplete, this, {single: true});
50219 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
50220 this.activeEditor = ed;
50221 var v = r.data[field];
50222 ed.startEdit(this.view.getCell(row, col), v);
50223 // combo's with 'displayField and name set
50224 if (ed.field.displayField && ed.field.name) {
50225 ed.field.el.dom.value = r.data[ed.field.name];
50229 }).defer(50, this);
50235 * Stops any active editing
50237 stopEditing : function(){
50238 if(this.activeEditor){
50239 this.activeEditor.completeEdit();
50241 this.activeEditor = null;
50245 * Ext JS Library 1.1.1
50246 * Copyright(c) 2006-2007, Ext JS, LLC.
50248 * Originally Released Under LGPL - original licence link has changed is not relivant.
50251 * <script type="text/javascript">
50254 // private - not really -- you end up using it !
50255 // This is a support class used internally by the Grid components
50258 * @class Roo.grid.GridEditor
50259 * @extends Roo.Editor
50260 * Class for creating and editable grid elements.
50261 * @param {Object} config any settings (must include field)
50263 Roo.grid.GridEditor = function(field, config){
50264 if (!config && field.field) {
50266 field = Roo.factory(config.field, Roo.form);
50268 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
50269 field.monitorTab = false;
50272 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
50275 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
50278 alignment: "tl-tl",
50281 cls: "x-small-editor x-grid-editor",
50286 * Ext JS Library 1.1.1
50287 * Copyright(c) 2006-2007, Ext JS, LLC.
50289 * Originally Released Under LGPL - original licence link has changed is not relivant.
50292 * <script type="text/javascript">
50297 Roo.grid.PropertyRecord = Roo.data.Record.create([
50298 {name:'name',type:'string'}, 'value'
50302 Roo.grid.PropertyStore = function(grid, source){
50304 this.store = new Roo.data.Store({
50305 recordType : Roo.grid.PropertyRecord
50307 this.store.on('update', this.onUpdate, this);
50309 this.setSource(source);
50311 Roo.grid.PropertyStore.superclass.constructor.call(this);
50316 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
50317 setSource : function(o){
50319 this.store.removeAll();
50322 if(this.isEditableValue(o[k])){
50323 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
50326 this.store.loadRecords({records: data}, {}, true);
50329 onUpdate : function(ds, record, type){
50330 if(type == Roo.data.Record.EDIT){
50331 var v = record.data['value'];
50332 var oldValue = record.modified['value'];
50333 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
50334 this.source[record.id] = v;
50336 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
50343 getProperty : function(row){
50344 return this.store.getAt(row);
50347 isEditableValue: function(val){
50348 if(val && val instanceof Date){
50350 }else if(typeof val == 'object' || typeof val == 'function'){
50356 setValue : function(prop, value){
50357 this.source[prop] = value;
50358 this.store.getById(prop).set('value', value);
50361 getSource : function(){
50362 return this.source;
50366 Roo.grid.PropertyColumnModel = function(grid, store){
50369 g.PropertyColumnModel.superclass.constructor.call(this, [
50370 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
50371 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
50373 this.store = store;
50374 this.bselect = Roo.DomHelper.append(document.body, {
50375 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
50376 {tag: 'option', value: 'true', html: 'true'},
50377 {tag: 'option', value: 'false', html: 'false'}
50380 Roo.id(this.bselect);
50383 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
50384 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
50385 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
50386 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
50387 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
50389 this.renderCellDelegate = this.renderCell.createDelegate(this);
50390 this.renderPropDelegate = this.renderProp.createDelegate(this);
50393 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
50397 valueText : 'Value',
50399 dateFormat : 'm/j/Y',
50402 renderDate : function(dateVal){
50403 return dateVal.dateFormat(this.dateFormat);
50406 renderBool : function(bVal){
50407 return bVal ? 'true' : 'false';
50410 isCellEditable : function(colIndex, rowIndex){
50411 return colIndex == 1;
50414 getRenderer : function(col){
50416 this.renderCellDelegate : this.renderPropDelegate;
50419 renderProp : function(v){
50420 return this.getPropertyName(v);
50423 renderCell : function(val){
50425 if(val instanceof Date){
50426 rv = this.renderDate(val);
50427 }else if(typeof val == 'boolean'){
50428 rv = this.renderBool(val);
50430 return Roo.util.Format.htmlEncode(rv);
50433 getPropertyName : function(name){
50434 var pn = this.grid.propertyNames;
50435 return pn && pn[name] ? pn[name] : name;
50438 getCellEditor : function(colIndex, rowIndex){
50439 var p = this.store.getProperty(rowIndex);
50440 var n = p.data['name'], val = p.data['value'];
50442 if(typeof(this.grid.customEditors[n]) == 'string'){
50443 return this.editors[this.grid.customEditors[n]];
50445 if(typeof(this.grid.customEditors[n]) != 'undefined'){
50446 return this.grid.customEditors[n];
50448 if(val instanceof Date){
50449 return this.editors['date'];
50450 }else if(typeof val == 'number'){
50451 return this.editors['number'];
50452 }else if(typeof val == 'boolean'){
50453 return this.editors['boolean'];
50455 return this.editors['string'];
50461 * @class Roo.grid.PropertyGrid
50462 * @extends Roo.grid.EditorGrid
50463 * This class represents the interface of a component based property grid control.
50464 * <br><br>Usage:<pre><code>
50465 var grid = new Roo.grid.PropertyGrid("my-container-id", {
50473 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50474 * The container MUST have some type of size defined for the grid to fill. The container will be
50475 * automatically set to position relative if it isn't already.
50476 * @param {Object} config A config object that sets properties on this grid.
50478 Roo.grid.PropertyGrid = function(container, config){
50479 config = config || {};
50480 var store = new Roo.grid.PropertyStore(this);
50481 this.store = store;
50482 var cm = new Roo.grid.PropertyColumnModel(this, store);
50483 store.store.sort('name', 'ASC');
50484 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
50487 enableColLock:false,
50488 enableColumnMove:false,
50490 trackMouseOver: false,
50493 this.getGridEl().addClass('x-props-grid');
50494 this.lastEditRow = null;
50495 this.on('columnresize', this.onColumnResize, this);
50498 * @event beforepropertychange
50499 * Fires before a property changes (return false to stop?)
50500 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50501 * @param {String} id Record Id
50502 * @param {String} newval New Value
50503 * @param {String} oldval Old Value
50505 "beforepropertychange": true,
50507 * @event propertychange
50508 * Fires after a property changes
50509 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
50510 * @param {String} id Record Id
50511 * @param {String} newval New Value
50512 * @param {String} oldval Old Value
50514 "propertychange": true
50516 this.customEditors = this.customEditors || {};
50518 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
50521 * @cfg {Object} customEditors map of colnames=> custom editors.
50522 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
50523 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
50524 * false disables editing of the field.
50528 * @cfg {Object} propertyNames map of property Names to their displayed value
50531 render : function(){
50532 Roo.grid.PropertyGrid.superclass.render.call(this);
50533 this.autoSize.defer(100, this);
50536 autoSize : function(){
50537 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
50539 this.view.fitColumns();
50543 onColumnResize : function(){
50544 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
50548 * Sets the data for the Grid
50549 * accepts a Key => Value object of all the elements avaiable.
50550 * @param {Object} data to appear in grid.
50552 setSource : function(source){
50553 this.store.setSource(source);
50557 * Gets all the data from the grid.
50558 * @return {Object} data data stored in grid
50560 getSource : function(){
50561 return this.store.getSource();
50565 * Ext JS Library 1.1.1
50566 * Copyright(c) 2006-2007, Ext JS, LLC.
50568 * Originally Released Under LGPL - original licence link has changed is not relivant.
50571 * <script type="text/javascript">
50575 * @class Roo.LoadMask
50576 * A simple utility class for generically masking elements while loading data. If the element being masked has
50577 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
50578 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
50579 * element's UpdateManager load indicator and will be destroyed after the initial load.
50581 * Create a new LoadMask
50582 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
50583 * @param {Object} config The config object
50585 Roo.LoadMask = function(el, config){
50586 this.el = Roo.get(el);
50587 Roo.apply(this, config);
50589 this.store.on('beforeload', this.onBeforeLoad, this);
50590 this.store.on('load', this.onLoad, this);
50591 this.store.on('loadexception', this.onLoad, this);
50592 this.removeMask = false;
50594 var um = this.el.getUpdateManager();
50595 um.showLoadIndicator = false; // disable the default indicator
50596 um.on('beforeupdate', this.onBeforeLoad, this);
50597 um.on('update', this.onLoad, this);
50598 um.on('failure', this.onLoad, this);
50599 this.removeMask = true;
50603 Roo.LoadMask.prototype = {
50605 * @cfg {Boolean} removeMask
50606 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
50607 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
50610 * @cfg {String} msg
50611 * The text to display in a centered loading message box (defaults to 'Loading...')
50613 msg : 'Loading...',
50615 * @cfg {String} msgCls
50616 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
50618 msgCls : 'x-mask-loading',
50621 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
50627 * Disables the mask to prevent it from being displayed
50629 disable : function(){
50630 this.disabled = true;
50634 * Enables the mask so that it can be displayed
50636 enable : function(){
50637 this.disabled = false;
50641 onLoad : function(){
50642 this.el.unmask(this.removeMask);
50646 onBeforeLoad : function(){
50647 if(!this.disabled){
50648 this.el.mask(this.msg, this.msgCls);
50653 destroy : function(){
50655 this.store.un('beforeload', this.onBeforeLoad, this);
50656 this.store.un('load', this.onLoad, this);
50657 this.store.un('loadexception', this.onLoad, this);
50659 var um = this.el.getUpdateManager();
50660 um.un('beforeupdate', this.onBeforeLoad, this);
50661 um.un('update', this.onLoad, this);
50662 um.un('failure', this.onLoad, this);
50667 * Ext JS Library 1.1.1
50668 * Copyright(c) 2006-2007, Ext JS, LLC.
50670 * Originally Released Under LGPL - original licence link has changed is not relivant.
50673 * <script type="text/javascript">
50675 Roo.XTemplate = function(){
50676 Roo.XTemplate.superclass.constructor.apply(this, arguments);
50679 s = ['<tpl>', s, '</tpl>'].join('');
50681 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
50683 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
50684 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
50685 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
50689 while(m = s.match(re)){
50690 var m2 = m[0].match(nameRe);
50691 var m3 = m[0].match(ifRe);
50692 var m4 = m[0].match(execRe);
50693 var exp = null, fn = null, exec = null;
50694 var name = m2 && m2[1] ? m2[1] : '';
50696 exp = m3 && m3[1] ? m3[1] : null;
50698 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
50702 exp = m4 && m4[1] ? m4[1] : null;
50704 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
50709 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
50710 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
50711 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
50721 s = s.replace(m[0], '{xtpl'+ id + '}');
50724 for(var i = tpls.length-1; i >= 0; --i){
50725 this.compileTpl(tpls[i]);
50727 this.master = tpls[tpls.length-1];
50730 Roo.extend(Roo.XTemplate, Roo.Template, {
50732 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
50734 applySubTemplate : function(id, values, parent){
50735 var t = this.tpls[id];
50736 if(t.test && !t.test.call(this, values, parent)){
50739 if(t.exec && t.exec.call(this, values, parent)){
50742 var vs = t.target ? t.target.call(this, values, parent) : values;
50743 parent = t.target ? values : parent;
50744 if(t.target && vs instanceof Array){
50746 for(var i = 0, len = vs.length; i < len; i++){
50747 buf[buf.length] = t.compiled.call(this, vs[i], parent);
50749 return buf.join('');
50751 return t.compiled.call(this, vs, parent);
50754 compileTpl : function(tpl){
50755 var fm = Roo.util.Format;
50756 var useF = this.disableFormats !== true;
50757 var sep = Roo.isGecko ? "+" : ",";
50758 var fn = function(m, name, format, args){
50759 if(name.substr(0, 4) == 'xtpl'){
50760 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
50763 if(name.indexOf('.') != -1){
50766 v = "values['" + name + "']";
50768 if(format && useF){
50769 args = args ? ',' + args : "";
50770 if(format.substr(0, 5) != "this."){
50771 format = "fm." + format + '(';
50773 format = 'this.call("'+ format.substr(5) + '", ';
50777 args= ''; format = "("+v+" === undefined ? '' : ";
50779 return "'"+ sep + format + v + args + ")"+sep+"'";
50782 // branched to use + in gecko and [].join() in others
50784 body = "tpl.compiled = function(values, parent){ return '" +
50785 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
50788 body = ["tpl.compiled = function(values, parent){ return ['"];
50789 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
50790 body.push("'].join('');};");
50791 body = body.join('');
50793 /** eval:var:zzzzzzz */
50798 applyTemplate : function(values){
50799 return this.master.compiled.call(this, values, {});
50803 apply : function(){
50804 return this.applyTemplate.apply(this, arguments);
50807 compile : function(){return this;}
50810 Roo.XTemplate.from = function(el){
50811 el = Roo.getDom(el);
50812 return new Roo.XTemplate(el.value || el.innerHTML);
50814 * Original code for Roojs - LGPL
50815 * <script type="text/javascript">
50819 * @class Roo.XComponent
50820 * A delayed Element creator...
50822 * Mypart.xyx = new Roo.XComponent({
50824 parent : 'Mypart.xyz', // empty == document.element.!!
50828 disabled : function() {}
50830 tree : function() { // return an tree of xtype declared components
50834 xtype : 'NestedLayoutPanel',
50839 * @extends Roo.util.Observable
50841 * @param cfg {Object} configuration of component
50844 Roo.XComponent = function(cfg) {
50845 Roo.apply(this, cfg);
50849 * Fires when this the componnt is built
50850 * @param {Roo.XComponent} c the component
50854 * @event buildcomplete
50855 * Fires on the top level element when all elements have been built
50856 * @param {Roo.XComponent} c the top level component.
50858 'buildcomplete' : true
50862 Roo.XComponent.register(this);
50863 this.modules = false;
50864 this.el = false; // where the layout goes..
50868 Roo.extend(Roo.XComponent, Roo.util.Observable, {
50871 * The created element (with Roo.factory())
50872 * @type {Roo.Layout}
50878 * for BC - use el in new code
50879 * @type {Roo.Layout}
50885 * for BC - use el in new code
50886 * @type {Roo.Layout}
50891 * @cfg {Function|boolean} disabled
50892 * If this module is disabled by some rule, return true from the funtion
50897 * @cfg {String} parent
50898 * Name of parent element which it get xtype added to..
50903 * @cfg {String} order
50904 * Used to set the order in which elements are created (usefull for multiple tabs)
50909 * @cfg {String} name
50910 * String to display while loading.
50914 * @cfg {Array} items
50915 * A single item array - the first element is the root of the tree..
50916 * It's done this way to stay compatible with the Xtype system...
50924 Roo.apply(Roo.XComponent, {
50927 * @property buildCompleted
50928 * True when the builder has completed building the interface.
50931 buildCompleted : false,
50934 * @property topModule
50935 * the upper most module - uses document.element as it's constructor.
50942 * @property modules
50943 * array of modules to be created by registration system.
50944 * @type Roo.XComponent
50951 * Register components to be built later.
50953 * This solves the following issues
50954 * - Building is not done on page load, but after an authentication process has occured.
50955 * - Interface elements are registered on page load
50956 * - Parent Interface elements may not be loaded before child, so this handles that..
50963 module : 'Pman.Tab.projectMgr',
50965 parent : 'Pman.layout',
50966 disabled : false, // or use a function..
50969 * * @param {Object} details about module
50971 register : function(obj) {
50972 this.modules.push(obj);
50976 * convert a string to an object..
50980 toObject : function(str)
50982 if (!str || typeof(str) == 'object') {
50985 var ar = str.split('.');
50989 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
50991 throw "Module not found : " + str;
50993 Roo.each(ar, function(e) {
50994 if (typeof(o[e]) == 'undefined') {
50995 throw "Module not found : " + str;
51005 * move modules into their correct place in the tree..
51008 preBuild : function ()
51011 Roo.each(this.modules , function (obj)
51013 obj.parent = this.toObject(obj.parent);
51016 this.topModule = obj;
51020 if (!obj.parent.modules) {
51021 obj.parent.modules = new Roo.util.MixedCollection(false,
51022 function(o) { return o.order + '' }
51026 obj.parent.modules.add(obj);
51031 * make a list of modules to build.
51032 * @return {Array} list of modules.
51035 buildOrder : function()
51038 var cmp = function(a,b) {
51039 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
51042 if (!this.topModule || !this.topModule.modules) {
51043 throw "No top level modules to build";
51046 // make a flat list in order of modules to build.
51047 var mods = [ this.topModule ];
51050 // add modules to their parents..
51051 var addMod = function(m) {
51052 // Roo.debug && Roo.log(m.modKey);
51056 m.modules.keySort('ASC', cmp );
51057 m.modules.each(addMod);
51059 // not sure if this is used any more..
51061 m.finalize.name = m.name + " (clean up) ";
51062 mods.push(m.finalize);
51066 this.topModule.modules.keySort('ASC', cmp );
51067 this.topModule.modules.each(addMod);
51072 * Build the registered modules.
51073 * @param {Object} parent element.
51074 * @param {Function} optional method to call after module has been added.
51082 var mods = this.buildOrder();
51084 //this.allmods = mods;
51085 //Roo.debug && Roo.log(mods);
51087 if (!mods.length) { // should not happen
51088 throw "NO modules!!!";
51093 // flash it up as modal - so we store the mask!?
51094 Roo.MessageBox.show({ title: 'loading' });
51095 Roo.MessageBox.show({
51096 title: "Please wait...",
51097 msg: "Building Interface...",
51104 var total = mods.length;
51107 var progressRun = function() {
51108 if (!mods.length) {
51109 Roo.debug && Roo.log('hide?');
51110 Roo.MessageBox.hide();
51111 _this.topModule.fireEvent('buildcomplete', _this.topModule);
51115 var m = mods.shift();
51116 Roo.debug && Roo.log(m);
51117 if (typeof(m) == 'function') { // not sure if this is supported any more..
51119 return progressRun.defer(10, _this);
51122 Roo.MessageBox.updateProgress(
51123 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
51125 (m.name ? (' - ' + m.name) : '')
51130 var disabled = (typeof(m.disabled) == 'function') ?
51131 m.disabled.call(m.module.disabled) : m.disabled;
51135 return progressRun(); // we do not update the display!
51139 // it's a top level one..
51140 var layoutbase = new Ext.BorderLayout(document.body, {
51146 tabPosition: 'top',
51147 //resizeTabs: true,
51148 alwaysShowTabs: true,
51152 var tree = m.tree();
51153 tree.region = 'center';
51154 m.el = layoutbase.addxtype(tree);
51156 m.layout = m.panel.layout;
51157 return progressRun.defer(10, _this);
51160 var tree = m.tree();
51161 tree.region = tree.region || m.region;
51162 m.el = m.parent.el.addxtype(tree);
51163 m.fireEvent('built', m);
51165 m.layout = m.panel.layout;
51166 progressRun.defer(10, _this);
51169 progressRun.defer(1, _this);
51179 //<script type="text/javascript">
51184 * @extends Roo.LayoutDialog
51185 * A generic Login Dialog..... - only one needed in theory!?!?
51187 * Fires XComponent builder on success...
51190 * username,password, lang = for login actions.
51191 * check = 1 for periodic checking that sesion is valid.
51192 * passwordRequest = email request password
51193 * logout = 1 = to logout
51195 * Affects: (this id="????" elements)
51196 * loading (removed) (used to indicate application is loading)
51197 * loading-mask (hides) (used to hide application when it's building loading)
51203 * Myapp.login = Roo.Login({
51219 Roo.Login = function(cfg)
51225 Roo.apply(this,cfg);
51227 Roo.onReady(function() {
51233 Roo.Login.superclass.constructor.call(this, this);
51234 //this.addxtype(this.items[0]);
51240 Roo.extend(Roo.Login, Roo.LayoutDialog, {
51243 * @cfg {String} method
51244 * Method used to query for login details.
51249 * @cfg {String} url
51250 * URL to query login data. - eg. baseURL + '/Login.php'
51256 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
51261 * @property checkFails
51262 * Number of times we have attempted to get authentication check, and failed.
51267 * @property intervalID
51268 * The window interval that does the constant login checking.
51274 onLoad : function() // called on page load...
51278 if (Roo.get('loading')) { // clear any loading indicator..
51279 Roo.get('loading').remove();
51282 //this.switchLang('en'); // set the language to english..
51285 success: function(response, opts) { // check successfull...
51287 var res = this.processResponse(response);
51288 this.checkFails =0;
51289 if (!res.success) { // error!
51290 this.checkFails = 5;
51291 //console.log('call failure');
51292 return this.failure(response,opts);
51295 if (!res.data.id) { // id=0 == login failure.
51296 return this.show();
51300 //console.log(success);
51301 this.fillAuth(res.data);
51302 this.checkFails =0;
51303 Roo.XComponent.build();
51305 failure : this.show
51311 check: function(cfg) // called every so often to refresh cookie etc..
51313 if (cfg.again) { // could be undefined..
51316 this.checkFails = 0;
51319 if (this.sending) {
51320 if ( this.checkFails > 4) {
51321 Roo.MessageBox.alert("Error",
51322 "Error getting authentication status. - try reloading, or wait a while", function() {
51323 _this.sending = false;
51328 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
51331 this.sending = true;
51338 method: this.method,
51339 success: cfg.success || this.success,
51340 failure : cfg.failure || this.failure,
51350 window.onbeforeunload = function() { }; // false does not work for IE..
51360 failure : function() {
51361 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
51362 document.location = document.location.toString() + '?ts=' + Math.random();
51366 success : function() {
51367 _this.user = false;
51368 this.checkFails =0;
51370 document.location = document.location.toString() + '?ts=' + Math.random();
51377 processResponse : function (response)
51381 res = Roo.decode(response.responseText);
51383 if (typeof(res) != 'object') {
51384 res = { success : false, errorMsg : res, errors : true };
51386 if (typeof(res.success) == 'undefined') {
51387 res.success = false;
51391 res = { success : false, errorMsg : response.responseText, errors : true };
51396 success : function(response, opts) // check successfull...
51398 this.sending = false;
51399 var res = this.processResponse(response);
51400 if (!res.success) {
51401 return this.failure(response, opts);
51403 if (!res.data || !res.data.id) {
51404 return this.failure(response,opts);
51406 //console.log(res);
51407 this.fillAuth(res.data);
51409 this.checkFails =0;
51414 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
51416 this.authUser = -1;
51417 this.sending = false;
51418 var res = this.processResponse(response);
51419 //console.log(res);
51420 if ( this.checkFails > 2) {
51422 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
51423 "Error getting authentication status. - try reloading");
51426 opts.callCfg.again = true;
51427 this.check.defer(1000, this, [ opts.callCfg ]);
51433 fillAuth: function(au) {
51434 this.startAuthCheck();
51435 this.authUserId = au.id;
51436 this.authUser = au;
51437 this.lastChecked = new Date();
51438 this.fireEvent('refreshed', au);
51439 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
51440 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
51441 au.lang = au.lang || 'en';
51442 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
51443 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
51444 this.switchLang(au.lang );
51447 // open system... - -on setyp..
51448 if (this.authUserId < 0) {
51449 Roo.MessageBox.alert("Warning",
51450 "This is an open system - please set up a admin user with a password.");
51453 //Pman.onload(); // which should do nothing if it's a re-auth result...
51458 startAuthCheck : function() // starter for timeout checking..
51460 if (this.intervalID) { // timer already in place...
51464 this.intervalID = window.setInterval(function() {
51465 _this.check(false);
51466 }, 120000); // every 120 secs = 2mins..
51472 switchLang : function (lang)
51474 _T = typeof(_T) == 'undefined' ? false : _T;
51475 if (!_T || !lang.length) {
51479 if (!_T && lang != 'en') {
51480 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51484 if (typeof(_T.en) == 'undefined') {
51486 Roo.apply(_T.en, _T);
51489 if (typeof(_T[lang]) == 'undefined') {
51490 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
51495 Roo.apply(_T, _T[lang]);
51496 // just need to set the text values for everything...
51498 /* this will not work ...
51502 function formLabel(name, val) {
51503 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
51506 formLabel('password', "Password"+':');
51507 formLabel('username', "Email Address"+':');
51508 formLabel('lang', "Language"+':');
51509 this.dialog.setTitle("Login");
51510 this.dialog.buttons[0].setText("Forgot Password");
51511 this.dialog.buttons[1].setText("Login");
51530 collapsible: false,
51532 center: { // needed??
51535 // tabPosition: 'top',
51538 alwaysShowTabs: false
51542 show : function(dlg)
51544 //console.log(this);
51545 this.form = this.layout.getRegion('center').activePanel.form;
51546 this.form.dialog = dlg;
51547 this.buttons[0].form = this.form;
51548 this.buttons[0].dialog = dlg;
51549 this.buttons[1].form = this.form;
51550 this.buttons[1].dialog = dlg;
51552 //this.resizeToLogo.defer(1000,this);
51553 // this is all related to resizing for logos..
51554 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
51556 // this.resizeToLogo.defer(1000,this);
51559 //var w = Ext.lib.Dom.getViewWidth() - 100;
51560 //var h = Ext.lib.Dom.getViewHeight() - 100;
51561 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
51563 if (this.disabled) {
51568 if (this.user.id < 0) { // used for inital setup situations.
51572 if (this.intervalID) {
51573 // remove the timer
51574 window.clearInterval(this.intervalID);
51575 this.intervalID = false;
51579 if (Roo.get('loading')) {
51580 Roo.get('loading').remove();
51582 if (Roo.get('loading-mask')) {
51583 Roo.get('loading-mask').hide();
51586 //incomming._node = tnode;
51588 //this.dialog.modal = !modal;
51589 //this.dialog.show();
51593 this.form.setValues({
51594 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
51595 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
51598 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
51599 if (this.form.findField('username').getValue().length > 0 ){
51600 this.form.findField('password').focus();
51602 this.form.findField('username').focus();
51610 xtype : 'ContentPanel',
51622 style : 'margin: 10px;',
51625 actionfailed : function(f, act) {
51626 // form can return { errors: .... }
51628 //act.result.errors // invalid form element list...
51629 //act.result.errorMsg// invalid form element list...
51631 this.dialog.el.unmask();
51632 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
51633 "Login failed - communication error - try again.");
51636 actioncomplete: function(re, act) {
51638 Roo.state.Manager.set(
51639 this.dialog.realm + '.username',
51640 this.findField('username').getValue()
51642 Roo.state.Manager.set(
51643 this.dialog.realm + '.lang',
51644 this.findField('lang').getValue()
51647 this.dialog.fillAuth(act.result.data);
51649 this.dialog.hide();
51651 if (Roo.get('loading-mask')) {
51652 Roo.get('loading-mask').show();
51654 Roo.XComponent.build();
51662 xtype : 'TextField',
51664 fieldLabel: "Email Address",
51667 autoCreate : {tag: "input", type: "text", size: "20"}
51670 xtype : 'TextField',
51672 fieldLabel: "Password",
51673 inputType: 'password',
51676 autoCreate : {tag: "input", type: "text", size: "20"},
51678 specialkey : function(e,ev) {
51679 if (ev.keyCode == 13) {
51680 this.form.dialog.el.mask("Logging in");
51681 this.form.doAction('submit', {
51682 url: this.form.dialog.url,
51683 method: this.form.dialog.method
51690 xtype : 'ComboBox',
51692 fieldLabel: "Language",
51695 xtype : 'SimpleStore',
51696 fields: ['lang', 'ldisp'],
51698 [ 'en', 'English' ],
51699 [ 'zh_HK' , '\u7E41\u4E2D' ],
51700 [ 'zh_CN', '\u7C21\u4E2D' ]
51704 valueField : 'lang',
51705 hiddenName: 'lang',
51707 displayField:'ldisp',
51711 triggerAction: 'all',
51712 emptyText:'Select a Language...',
51713 selectOnFocus:true,
51715 select : function(cb, rec, ix) {
51716 this.form.switchLang(rec.data.lang);
51732 text : "Forgot Password",
51734 click : function() {
51735 //console.log(this);
51736 var n = this.form.findField('username').getValue();
51738 Roo.MessageBox.alert("Error", "Fill in your email address");
51742 url: this.dialog.url,
51746 method: this.dialog.method,
51747 success: function(response, opts) { // check successfull...
51749 var res = this.dialog.processResponse(response);
51750 if (!res.success) { // error!
51751 Roo.MessageBox.alert("Error" ,
51752 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
51755 Roo.MessageBox.alert("Notice" ,
51756 "Please check you email for the Password Reset message");
51758 failure : function() {
51759 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
51772 click : function () {
51774 this.dialog.el.mask("Logging in");
51775 this.form.doAction('submit', {
51776 url: this.dialog.url,
51777 method: this.dialog.method